From 863749cfe1daf70496afdb3da69c1e2dfbdae0d2 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Wed, 28 Sep 2022 10:46:12 +0500 Subject: [PATCH] =?UTF-8?q?##6539681=20=D0=A4=D0=B0=D0=B9=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=D1=8B=D0=B9=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Services/IFileService.cs | 72 +---- AsbCloudInfrastructure/DependencyInjection.cs | 1 + .../Repository/FileRepository.cs | 275 +++++++++++++++++ .../Repository/IFileRepository.cs | 120 ++++++++ .../DrillingProgram/DrillingProgramService.cs | 12 +- .../Services/FileService.cs | 276 ++---------------- .../Services/ReportService.cs | 7 +- .../Services/WellFinalDocumentsService.cs | 10 +- AsbCloudWebApi/Controllers/FileController.cs | 39 ++- 9 files changed, 476 insertions(+), 336 deletions(-) create mode 100644 AsbCloudInfrastructure/Repository/FileRepository.cs create mode 100644 AsbCloudInfrastructure/Repository/IFileRepository.cs diff --git a/AsbCloudApp/Services/IFileService.cs b/AsbCloudApp/Services/IFileService.cs index 18d0829d..6b1a171f 100644 --- a/AsbCloudApp/Services/IFileService.cs +++ b/AsbCloudApp/Services/IFileService.cs @@ -31,23 +31,6 @@ namespace AsbCloudApp.Services /// Task SaveAsync(int idWell, int? idUser, int idCategory, string fileFullName, Stream fileStream, CancellationToken token = default); - /// - /// Получить список файлов в контейнере - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - Task> GetInfosAsync(int idWell, - int idCategory, string companyName = default, string fileName = default, DateTime begin = default, DateTime end = default, - int skip = 0, int take = 32, CancellationToken token = default); - /// /// Инфо о файле /// @@ -57,24 +40,6 @@ namespace AsbCloudApp.Services Task GetInfoAsync(int idFile, CancellationToken token); - /// - /// Пометить файл как удаленный - /// - /// - /// - /// - Task MarkAsDeletedAsync(int idFile, - CancellationToken token = default); - - /// - /// Получить файлы определенной категории - /// - /// - /// - /// - /// - Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token = default); - /// /// удалить файл /// @@ -103,7 +68,7 @@ namespace AsbCloudApp.Services /// /// /// - string GetUrl(int idFile); + Task GetUrl(int idFile); /// /// получить путь для скачивания @@ -115,15 +80,6 @@ namespace AsbCloudApp.Services /// string GetUrl(int idWell, int idCategory, int idFile, string dotExtention); - /// - /// добавить метку на файл - /// - /// - /// - /// - /// - Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token); - /// /// пометить метку файла как удаленную /// @@ -143,22 +99,6 @@ namespace AsbCloudApp.Services /// /// Task MoveAsync(int idWell, int? idUser, int idCategory, string destinationFileName, string srcFileFullName, CancellationToken token = default); - - /// - /// получить инфо о файле по метке - /// - /// - /// - /// - Task GetByMarkId(int idMark, CancellationToken token); - - /// - /// пометить метки файлов как удаленные - /// - /// - /// - /// - Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token); /// /// Инфо о файле @@ -166,14 +106,6 @@ namespace AsbCloudApp.Services /// /// /// - Task> GetInfoByIdsAsync(List idsFile, CancellationToken token); - - /// - /// Получение файлов по скважине - /// - /// - /// - /// - Task> GetInfosByWellIdAsync(int idWell, CancellationToken token); + Task> GetInfoByIdsAsync(IEnumerable idsFile, CancellationToken token); } } diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 04e707f6..e86a314b 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -106,6 +106,7 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Repository/FileRepository.cs b/AsbCloudInfrastructure/Repository/FileRepository.cs new file mode 100644 index 00000000..efa6296a --- /dev/null +++ b/AsbCloudInfrastructure/Repository/FileRepository.cs @@ -0,0 +1,275 @@ +using AsbCloudApp.Data; +using AsbCloudDb.Model; +using Mapster; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Repository +{ + public class FileRepository : IFileRepository + { + private readonly IQueryable dbSetConfigured; + private readonly IAsbCloudDbContext db; + + public FileRepository(IAsbCloudDbContext db) + { + this.db = db; + this.dbSetConfigured = db.Files + .Include(f => f.Author) + .ThenInclude(u => u.Company) + .ThenInclude(c => c.CompanyType) + .Include(f => f.FileMarks) + .ThenInclude(m => m.User) + .Include(f => f.Well); + } + + public async Task AddAsync(int idWell, int? idUser, int idCategory, + string destinationFileName, long fileSize, CancellationToken token = default) + { + var fileInfo = new AsbCloudDb.Model.FileInfo() + { + IdWell = idWell, + IdAuthor = idUser, + IdCategory = idCategory, + Name = destinationFileName, + UploadDate = DateTime.UtcNow, + IsDeleted = false, + Size = fileSize, + }; + + var entry = db.Files.Add(fileInfo); + await db.SaveChangesAsync(token).ConfigureAwait(false); + return entry.Entity.Id; + } + + public async Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token) + { + var entities = await dbSetConfigured + .Where(e => e.IdWell == idWell && e.IdCategory == idCategory && e.IsDeleted == false) + .AsNoTracking() + .ToListAsync(token) + .ConfigureAwait(false); + + var dtos = entities.Select(e => Convert(e)); + return dtos; + } + + public async Task> GetInfosAsync(int idWell, + int idCategory, string companyName = default, string fileName = default, DateTime begin = default, + DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default) + { + var query = dbSetConfigured + .Where(e => e.IdWell == idWell && + e.IdCategory == idCategory && + !e.IsDeleted); + + if (!string.IsNullOrEmpty(companyName)) + query = query.Where(e => (e.Author == null) || + (e.Author.Company == null) || + e.Author.Company.Caption.Contains(companyName)); + + if (!string.IsNullOrEmpty(fileName)) + query = query.Where(e => e.Name.ToLower().Contains(fileName.ToLower())); + + var firstFile = await query.FirstOrDefaultAsync(token); + if (firstFile is null) + return new PaginationContainer() + { + Skip = skip, + Take = take, + Count = 0, + }; + + var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; + + if (begin != default) + { + var beginUtc = begin.ToUtcDateTimeOffset(timezoneOffset); + query = query.Where(e => e.UploadDate >= beginUtc); + } + + if (end != default) + { + var endUtc = end.ToUtcDateTimeOffset(timezoneOffset); + query = query.Where(e => e.UploadDate <= endUtc); + } + + var count = await query.CountAsync(token).ConfigureAwait(false); + + var result = new PaginationContainer(count) + { + Skip = skip, + Take = take, + Count = count, + }; + + if (count <= skip) + return result; + + query = query.OrderBy(e => e.UploadDate); + + if (skip > 0) + query = query.Skip(skip); + query = query.Take(take); + + var entities = await query + .Take(take).AsNoTracking().ToListAsync(token) + .ConfigureAwait(false); + + var dtos = entities.Select(e => Convert(e, timezoneOffset)); + result.Items.AddRange(dtos); + return result; + } + + public async Task GetInfoAsync(int idFile, CancellationToken token) + { + var entity = await dbSetConfigured + .AsNoTracking() + .FirstOrDefaultAsync(f => f.Id == idFile, token) + .ConfigureAwait(false); + + if (entity is null) + { + throw new FileNotFoundException($"fileId:{idFile} not found"); + } + + var dto = Convert(entity); + return dto; + } + + public async Task> GetInfoByIdsAsync(IEnumerable idsFile, CancellationToken token) + { + var result = new List(); + + var entities = await dbSetConfigured + .AsNoTracking() + .Where(f => idsFile.Contains(f.Id)) + .ToListAsync(token) + .ConfigureAwait(false); + + foreach (var entity in entities) + { + if (entity is null) + { + throw new FileNotFoundException($"fileId:{entity.Id} not found"); + } + result.Add(Convert(entity)); + } + + return result; + } + + public async Task MarkAsDeletedAsync(int idFile, CancellationToken token = default) + { + var fileInfo = await db.Files.FirstOrDefaultAsync(f => f.Id == idFile, token).ConfigureAwait(false); + + if (fileInfo is null) + return 0; + + fileInfo.IsDeleted = true; + + return await db.SaveChangesAsync(token).ConfigureAwait(false); + } + + public async Task> DeleteAsync(IEnumerable ids, CancellationToken token) + { + var filesQuery = db.Files + .Where(f => ids.Contains(f.Id)); + + var files = await filesQuery.ToListAsync(token); + + var filesDtos = files.Select(x => new FileInfoDto { + Id = x.Id, + IdWell = x.Id, + IdCategory = x.IdCategory, + Name = x.Name + }); + + db.Files.RemoveRange(filesQuery); + await db.SaveChangesAsync(token).ConfigureAwait(false); + + return filesDtos; + } + + public async Task GetByMarkId(int idMark, + CancellationToken token) + { + var entity = await dbSetConfigured + .FirstOrDefaultAsync(f => f.FileMarks.Any(m => m.Id == idMark), token) + .ConfigureAwait(false); + + FileInfoDto dto = Convert(entity); + return dto; + } + + public async Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token) + { + var fileMark = await db.FileMarks + .FirstOrDefaultAsync(m => m.IdFile == fileMarkDto.IdFile && + m.IdMarkType == fileMarkDto.IdMarkType && + m.IdUser == idUser && + m.IsDeleted == false, + token) + .ConfigureAwait(false); + + if (fileMark is not null) + return 0; + + var newFileMark = fileMarkDto.Adapt(); + newFileMark.Id = default; + newFileMark.DateCreated = DateTime.UtcNow; + newFileMark.IdUser = idUser; + newFileMark.User = null; + + db.FileMarks.Add(newFileMark); + return await db.SaveChangesAsync(token); + } + + public async Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token) + { + var fileMarkQuery = db.FileMarks + .Where(m => idsMarks.Contains(m.Id)); + + foreach (var fileMark in fileMarkQuery) + fileMark.IsDeleted = true; + + return await db.SaveChangesAsync(token); + } + + public async Task> GetInfosByWellIdAsync(int idWell, CancellationToken token) + { + var entities = await dbSetConfigured + .Where(e => e.IdWell == idWell && e.IsDeleted == false) + .AsNoTracking() + .ToListAsync(token) + .ConfigureAwait(false); + + var dtos = entities.Select(e => Convert(e)); + return dtos; + } + + private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity) + { + var timezoneOffset = entity.Well.Timezone?.Hours ?? 5; + return Convert(entity, timezoneOffset); + } + + private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity, double timezoneOffset) + { + var dto = entity.Adapt(); + dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset); + dto.FileMarks = entity.FileMarks.Select(m => + { + var mark = m.Adapt(); + mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset); + return mark; + }); + return dto; + } + } +} diff --git a/AsbCloudInfrastructure/Repository/IFileRepository.cs b/AsbCloudInfrastructure/Repository/IFileRepository.cs new file mode 100644 index 00000000..73ae9b86 --- /dev/null +++ b/AsbCloudInfrastructure/Repository/IFileRepository.cs @@ -0,0 +1,120 @@ +using AsbCloudApp.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Repository +{ + /// + /// Сервис доступа к файлам + /// + public interface IFileRepository + { + /// + /// Добавление, в БД, информации о файле + /// + /// + /// + /// + /// + /// + /// + /// + Task AddAsync(int idWell, int? idUser, int idCategory, + string destinationFileName, long fileSize, CancellationToken token = default); + + /// + /// Получить файлы определенной категории + /// + /// + /// + /// + /// + Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token); + + /// + /// Получить список файлов в контейнере + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetInfosAsync(int idWell, + int idCategory, string companyName = default, string fileName = default, DateTime begin = default, + DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default); + + /// + /// Инфо о файле + /// + /// + /// + /// + Task GetInfoAsync(int idFile, CancellationToken token); + + /// + /// Пометить файл как удаленный + /// + /// + /// + /// + Task MarkAsDeletedAsync(int idFile, CancellationToken token = default); + + /// + /// удалить файлы + /// + /// + /// + /// + Task> DeleteAsync(IEnumerable ids, CancellationToken token); + + /// + /// получить инфо о файле по метке + /// + /// + /// + /// + Task GetByMarkId(int idMark, CancellationToken token); + + /// + /// добавить метку на файл + /// + /// + /// + /// + /// + Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token); + + /// + /// Инфо о файлах + /// + /// + /// + /// + Task> GetInfoByIdsAsync(IEnumerable idsFile, CancellationToken token); + + /// + /// пометить метки файлов как удаленные + /// + /// + /// + /// + Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token); + + /// + /// Получение файлов по скважине + /// + /// + /// + /// + Task> GetInfosByWellIdAsync(int idWell, CancellationToken token); + } +} diff --git a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs index 5fbc7301..c1973c11 100644 --- a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs +++ b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs @@ -2,6 +2,7 @@ using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -22,6 +23,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram private readonly IFileService fileService; private readonly IUserService userService; private readonly IWellService wellService; + private readonly IFileRepository fileRepository; private readonly IConfiguration configuration; private readonly IBackgroundWorkerService backgroundWorker; private readonly IEmailService emailService; @@ -52,6 +54,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram IFileService fileService, IUserService userService, IWellService wellService, + IFileRepository fileRepository, IConfiguration configuration, IBackgroundWorkerService backgroundWorker, IEmailService emailService) @@ -60,6 +63,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram this.fileService = fileService; this.userService = userService; this.wellService = wellService; + this.fileRepository = fileRepository; this.configuration = configuration; this.backgroundWorker = backgroundWorker; this.connectionString = configuration.GetConnectionString("DefaultConnection"); @@ -308,9 +312,9 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram .Select(m => m.Id); if (oldMarksIds?.Any() == true) - await fileService.MarkFileMarkAsDeletedAsync(oldMarksIds, token); + await fileRepository.MarkFileMarkAsDeletedAsync(oldMarksIds, token); - var result = await fileService.CreateFileMarkAsync(fileMarkDto, idUser, token) + var result = await fileRepository.CreateFileMarkAsync(fileMarkDto, idUser, token) .ConfigureAwait(false); if (fileMarkDto.IdMarkType == idMarkTypeReject) @@ -340,7 +344,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram public async Task MarkAsDeletedFileMarkAsync(int idMark, CancellationToken token) { - var fileInfo = await fileService.GetByMarkId(idMark, token) + var fileInfo = await fileRepository.GetByMarkId(idMark, token) .ConfigureAwait(false); if (fileInfo.IdCategory < idFileCategoryDrillingProgramPartsStart || @@ -479,7 +483,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram .UseNpgsql(connectionString) .Options; using var context = new AsbCloudDbContext(contextOptions); - var fileService = new FileService(context); + var fileService = new FileService(fileRepository); var files = state.Parts.Select(p => fileService.GetUrl(p.File)); DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well); await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token); diff --git a/AsbCloudInfrastructure/Services/FileService.cs b/AsbCloudInfrastructure/Services/FileService.cs index 947fd853..c30fd23b 100644 --- a/AsbCloudInfrastructure/Services/FileService.cs +++ b/AsbCloudInfrastructure/Services/FileService.cs @@ -2,6 +2,7 @@ using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; using Mapster; using Microsoft.EntityFrameworkCore; using System; @@ -16,21 +17,12 @@ namespace AsbCloudInfrastructure.Services public class FileService : IFileService { public string RootPath { get; private set; } + private readonly IFileRepository fileRepository; - private readonly IQueryable dbSetConfigured; - private readonly IAsbCloudDbContext db; - - public FileService(IAsbCloudDbContext db) + public FileService(IFileRepository fileRepository) { RootPath = "files"; - this.db = db; - dbSetConfigured = db.Files - .Include(f => f.Author) - .ThenInclude(u => u.Company) - .ThenInclude(c => c.CompanyType) - .Include(f => f.FileMarks) - .ThenInclude(m => m.User) - .Include(f => f.Well); + this.fileRepository = fileRepository; } public async Task MoveAsync(int idWell, int? idUser, int idCategory, @@ -44,45 +36,23 @@ namespace AsbCloudInfrastructure.Services var sysFileInfo = new System.IO.FileInfo(srcFilePath); //save info to db - var fileInfo = new AsbCloudDb.Model.FileInfo() - { - IdWell = idWell, - IdAuthor = idUser, - IdCategory = idCategory, - Name = destinationFileName, - UploadDate = DateTime.UtcNow, - IsDeleted = false, - Size = sysFileInfo.Length, - }; - - var entry = db.Files.Add(fileInfo); - await db.SaveChangesAsync(token).ConfigureAwait(false); - var fileId = entry.Entity.Id; + var fileId = await fileRepository.AddAsync(idWell, idUser, idCategory, destinationFileName, sysFileInfo.Length, token) + .ConfigureAwait(false); + string filePath = MakeFilePath(idWell, idCategory, destinationFileName, fileId); Directory.CreateDirectory(Path.GetDirectoryName(filePath)); File.Move(srcFilePath, filePath); - return await GetInfoAsync(entry.Entity.Id, token); + return await GetInfoAsync(fileId, token); } public async Task SaveAsync(int idWell, int? idUser, int idCategory, string fileFullName, Stream fileStream, CancellationToken token) { //save info to db - var fileInfo = new AsbCloudDb.Model.FileInfo() - { - IdWell = idWell, - IdAuthor = idUser, - IdCategory = idCategory, - Name = Path.GetFileName(fileFullName), - UploadDate = DateTime.UtcNow, - IsDeleted = false, - Size = fileStream?.Length ?? 0 - }; + var fileId = await fileRepository.AddAsync(idWell, idUser, idCategory, Path.GetFileName(fileFullName), fileStream?.Length ?? 0, token) + .ConfigureAwait(false); - var entry = db.Files.Add(fileInfo); - await db.SaveChangesAsync(token).ConfigureAwait(false); - var fileId = entry.Entity.Id; //save stream to disk string filePath = MakeFilePath(idWell, idCategory, fileFullName, fileId); @@ -91,7 +61,7 @@ namespace AsbCloudInfrastructure.Services using var newfileStream = new FileStream(filePath, FileMode.Create); await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false); - return await GetInfoAsync(entry.Entity.Id, token); + return await GetInfoAsync(fileId, token); } private string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) @@ -100,125 +70,23 @@ namespace AsbCloudInfrastructure.Services $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); } - public async Task> GetInfosByCategoryAsync(int idWell, - int idCategory, CancellationToken token) - { - var entities = await dbSetConfigured - .Where(e => e.IdWell == idWell && e.IdCategory == idCategory && e.IsDeleted == false) - .AsNoTracking() - .ToListAsync(token) - .ConfigureAwait(false); - - var dtos = entities.Select(e => Convert(e)); - return dtos; - } - - public async Task> GetInfosAsync(int idWell, - int idCategory, string companyName = default, string fileName = default, DateTime begin = default, - DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default) - { - var query = dbSetConfigured - .Where(e => e.IdWell == idWell && - e.IdCategory == idCategory && - !e.IsDeleted); - - if (!string.IsNullOrEmpty(companyName)) - query = query.Where(e => (e.Author == null) || - (e.Author.Company == null) || - e.Author.Company.Caption.Contains(companyName)); - - if (!string.IsNullOrEmpty(fileName)) - query = query.Where(e => e.Name.ToLower().Contains(fileName.ToLower())); - - var firstFile = await query.FirstOrDefaultAsync(token); - if (firstFile is null) - return new PaginationContainer() - { - Skip = skip, - Take = take, - Count = 0, - }; - - var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; - - if (begin != default) - { - var beginUtc = begin.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate >= beginUtc); - } - - if (end != default) - { - var endUtc = end.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate <= endUtc); - } - - var count = await query.CountAsync(token).ConfigureAwait(false); - - var result = new PaginationContainer(count) - { - Skip = skip, - Take = take, - Count = count, - }; - - if (count <= skip) - return result; - - query = query.OrderBy(e => e.UploadDate); - - if (skip > 0) - query = query.Skip(skip); - query = query.Take(take); - - var entities = await query - .Take(take).AsNoTracking().ToListAsync(token) - .ConfigureAwait(false); - - var dtos = entities.Select(e => Convert(e, timezoneOffset)); - result.Items.AddRange(dtos); - return result; - } - public async Task GetInfoAsync(int idFile, CancellationToken token) { - var entity = await dbSetConfigured - .AsNoTracking() - .FirstOrDefaultAsync(f => f.Id == idFile, token) - .ConfigureAwait(false); + var dto = await fileRepository.GetInfoAsync(idFile, token).ConfigureAwait(false); - if (entity is null) - { - throw new FileNotFoundException($"fileId:{idFile} not found"); - } + var ext = Path.GetExtension(dto.Name); - var ext = Path.GetExtension(entity.Name); - - var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext); + var relativePath = GetUrl(dto.IdWell, dto.IdCategory, dto.Id, ext); var fullPath = Path.GetFullPath(relativePath); if (!File.Exists(fullPath)) { throw new FileNotFoundException("not found", relativePath); } - var dto = Convert(entity); return dto; } - public async Task MarkAsDeletedAsync(int idFile, - CancellationToken token = default) - { - var fileInfo = await db.Files.FirstOrDefaultAsync(f => f.Id == idFile, token).ConfigureAwait(false); - - if (fileInfo is null) - return 0; - - fileInfo.IsDeleted = true; - - return await db.SaveChangesAsync(token).ConfigureAwait(false); - } - public Task DeleteAsync(int idFile, CancellationToken token) => DeleteAsync(new int[] { idFile }, token); @@ -227,10 +95,7 @@ namespace AsbCloudInfrastructure.Services if (ids is null || !ids.Any()) return 0; - var filesQuery = db.Files - .Where(f => ids.Contains(f.Id)); - - var files = await filesQuery.ToListAsync(token); + var files = await fileRepository.DeleteAsync(ids, token).ConfigureAwait(false); if (files is null || !files.Any()) return 0; @@ -242,18 +107,12 @@ namespace AsbCloudInfrastructure.Services File.Delete(fileName); } - db.Files.RemoveRange(filesQuery); - - return await db.SaveChangesAsync(token).ConfigureAwait(false); + return files.Any() ? 1 : 0; } - public string GetUrl(int idFile) + public async Task GetUrl(int idFile) { - var fileInfo = db.Files - .FirstOrDefault(f => f.Id == idFile); - - if (fileInfo is null) - return null; + var fileInfo = await fileRepository.GetInfoAsync(idFile, CancellationToken.None).ConfigureAwait(false); return GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name)); } @@ -264,116 +123,27 @@ namespace AsbCloudInfrastructure.Services public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) => Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}"); - public async Task GetByMarkId(int idMark, - CancellationToken token) - { - var entity = await dbSetConfigured - .FirstOrDefaultAsync(f => f.FileMarks.Any(m => m.Id == idMark), token) - .ConfigureAwait(false); - - FileInfoDto dto = Convert(entity); - return dto; - } - - private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity) - { - var timezoneOffset = entity.Well.Timezone?.Hours ?? 5; - return Convert(entity, timezoneOffset); - } - - private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity, double timezoneOffset) - { - var dto = entity.Adapt(); - dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset); - dto.FileMarks = entity.FileMarks.Select(m => - { - var mark = m.Adapt(); - mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset); - return mark; - }); - return dto; - } - public async Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token) - { - var fileMark = await db.FileMarks - .FirstOrDefaultAsync(m => m.IdFile == fileMarkDto.IdFile && - m.IdMarkType == fileMarkDto.IdMarkType && - m.IdUser == idUser && - m.IsDeleted == false, - token) - .ConfigureAwait(false); - - if (fileMark is not null) - return 0; - - var newFileMark = fileMarkDto.Adapt(); - newFileMark.Id = default; - newFileMark.DateCreated = DateTime.UtcNow; - newFileMark.IdUser = idUser; - newFileMark.User = null; - - db.FileMarks.Add(newFileMark); - return await db.SaveChangesAsync(token); - } - public Task MarkFileMarkAsDeletedAsync(int idMark, CancellationToken token) - => MarkFileMarkAsDeletedAsync(new int[] { idMark }, token); + => fileRepository.MarkFileMarkAsDeletedAsync(new int[] { idMark }, token); - public async Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, - CancellationToken token) + public async Task> GetInfoByIdsAsync(IEnumerable idsFile, CancellationToken token) { - var fileMarkQuery = db.FileMarks - .Where(m => idsMarks.Contains(m.Id)); + var result = await fileRepository.GetInfoByIdsAsync(idsFile, token).ConfigureAwait(false); - foreach (var fileMark in fileMarkQuery) - fileMark.IsDeleted = true; - - return await db.SaveChangesAsync(token); - } - - public async Task> GetInfoByIdsAsync(List idsFile, CancellationToken token) - { - var result = new List(); - - var entities = await dbSetConfigured - .AsNoTracking() - .Where(f => idsFile.Contains(f.Id)) - .ToListAsync(token) - .ConfigureAwait(false); - - foreach (var entity in entities) + foreach (var entity in result) { - if (entity is null) - { - throw new FileNotFoundException($"fileId:{entity.Id} not found"); - } - + var ext = Path.GetExtension(entity.Name); - var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext); var fullPath = Path.GetFullPath(relativePath); if (!File.Exists(fullPath)) { throw new FileNotFoundException("not found", relativePath); } - - result.Add(Convert(entity)); } return result; } - - public async Task> GetInfosByWellIdAsync(int idWell, CancellationToken token) - { - var entities = await dbSetConfigured - .Where(e => e.IdWell == idWell && e.IsDeleted == false) - .AsNoTracking() - .ToListAsync(token) - .ConfigureAwait(false); - - var dtos = entities.Select(e => Convert(e)); - return dtos; - } } } diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index 3c70915b..6265f6c6 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -1,6 +1,7 @@ using AsbCloudApp.Data; using AsbCloudApp.Services; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; using AsbSaubReport; using Mapster; using Microsoft.EntityFrameworkCore; @@ -21,15 +22,17 @@ namespace AsbCloudInfrastructure.Services private readonly ITelemetryService telemetryService; private readonly IWellService wellService; private readonly IBackgroundWorkerService backgroundWorkerService; + private readonly IFileRepository fileRepository; public ReportService(IAsbCloudDbContext db, IConfiguration configuration, - ITelemetryService telemetryService, IWellService wellService, IBackgroundWorkerService backgroundWorkerService) + ITelemetryService telemetryService, IWellService wellService, IBackgroundWorkerService backgroundWorkerService, IFileRepository fileRepository) { this.db = db; this.connectionString = configuration.GetConnectionString("DefaultConnection"); this.wellService = wellService; this.backgroundWorkerService = backgroundWorkerService; this.telemetryService = telemetryService; + this.fileRepository = fileRepository; ReportCategoryId = db.FileCategories.AsNoTracking() .FirstOrDefault(c => c.Name.Equals("Рапорт")).Id; @@ -65,7 +68,7 @@ namespace AsbCloudInfrastructure.Services }; generator.Make(reportFileName); - var fileService = new FileService(context); + var fileService = new FileService(fileRepository); var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token); progressHandler.Invoke(new diff --git a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs index 3885d0e3..dc90128c 100644 --- a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs +++ b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs @@ -2,6 +2,7 @@ using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -27,6 +28,7 @@ namespace AsbCloudInfrastructure.Services private readonly IConfiguration configuration; private readonly IEmailService emailService; private readonly IFileCategoryService fileCategoryService; + private readonly IFileRepository fileRepository; private const int FileServiceThrewException = -1; @@ -36,7 +38,8 @@ namespace AsbCloudInfrastructure.Services IWellService wellService, IConfiguration configuration, IEmailService emailService, - IFileCategoryService fileCategoryService) + IFileCategoryService fileCategoryService, + IFileRepository fileRepository) { this.context = context; this.fileService = fileService; @@ -45,6 +48,7 @@ namespace AsbCloudInfrastructure.Services this.configuration = configuration; this.emailService = emailService; this.fileCategoryService = fileCategoryService; + this.fileRepository = fileRepository; } public async Task UpdateRangeAsync(int idWell, IEnumerable? dtos, CancellationToken token) @@ -94,7 +98,7 @@ namespace AsbCloudInfrastructure.Services var categoriesIds = entitiesGroups .Select(g => g.Key); - var files = (await fileService + var files = (await fileRepository .GetInfosByWellIdAsync(idWell, token) .ConfigureAwait(false)) .Where(f => categoriesIds.Contains(f.IdCategory)) @@ -161,7 +165,7 @@ namespace AsbCloudInfrastructure.Services public async Task GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token) { - var files = await fileService.GetInfosByCategoryAsync(idWell, idCategory, token).ConfigureAwait(false); + var files = await fileRepository.GetInfosByCategoryAsync(idWell, idCategory, token).ConfigureAwait(false); return new WellFinalDocumentsHistoryDto { IdWell = idWell, diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 46f9d589..52b314f3 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Services; +using AsbCloudInfrastructure.Repository; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -20,11 +21,13 @@ namespace AsbCloudWebApi.Controllers { private readonly IFileService fileService; private readonly IWellService wellService; + private readonly IFileRepository fileRepository; - public FileController(IFileService fileService, IWellService wellService) + public FileController(IFileService fileService, IWellService wellService, IFileRepository fileRepository) { this.fileService = fileService; this.wellService = wellService; + this.fileRepository = fileRepository; } /// @@ -98,7 +101,7 @@ namespace AsbCloudWebApi.Controllers idWell, token).ConfigureAwait(false)) return Forbid(); - var filesInfo = await fileService.GetInfosAsync(idWell, idCategory, + var filesInfo = await fileRepository.GetInfosAsync(idWell, idCategory, companyName, fileName, begin, end, skip, take, token).ConfigureAwait(false); return Ok(filesInfo); @@ -168,7 +171,7 @@ namespace AsbCloudWebApi.Controllers if (!userService.HasPermission((int)idUser, $"File.edit{file.IdCategory}")) return Forbid(); - var result = await fileService.MarkAsDeletedAsync(idFile, token); + var result = await fileRepository.MarkAsDeletedAsync(idFile, token); return Ok(result); } @@ -193,7 +196,7 @@ namespace AsbCloudWebApi.Controllers idWell, token).ConfigureAwait(false)) return Forbid(); - var result = await fileService.CreateFileMarkAsync(markDto, (int)idUser, token) + var result = await fileRepository.CreateFileMarkAsync(markDto, (int)idUser, token) .ConfigureAwait(false); return Ok(result); @@ -223,5 +226,33 @@ namespace AsbCloudWebApi.Controllers return Ok(result); } + + /// + /// Возвращает информацию о файле + /// + /// id запрашиваемого файла + /// Токен отмены задачи + /// Запрашиваемый файл + [HttpGet] + [Route("/api/files/{idFile}")] + [Permission] + [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] + public async Task GetFileInfoByIdAsync([FromRoute] int idFile, CancellationToken token = default) + { + int? idCompany = User.GetCompanyId(); + + if (idCompany is null) + return Forbid(); + + try + { + var fileInfo = await fileRepository.GetInfoAsync(idFile, token).ConfigureAwait(false); + return Ok(fileInfo); + } + catch (FileNotFoundException ex) + { + return NotFound(ex.FileName); + } + } } }