From dbe5618a567b8f9205a229b4d5380eda18b221e1 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Tue, 11 Oct 2022 08:28:37 +0500 Subject: [PATCH 1/7] =?UTF-8?q?#6385536=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Repositories/IFileRepository.cs | 20 ++--- .../Repositories/IFileStorageRepository.cs | 31 +++++++- AsbCloudApp/Requests/FileServiceRequest.cs | 60 ++++++++++++++ AsbCloudApp/Services/FileService.cs | 79 ++++++++++++++----- .../Repository/FileRepository.cs | 39 +++++---- .../Repository/FileStorageRepository.cs | 69 +++++++++++++++- .../ServicesTests/FileServiceTest.cs | 7 +- AsbCloudWebApi/Controllers/FileController.cs | 32 +++----- 8 files changed, 263 insertions(+), 74 deletions(-) create mode 100644 AsbCloudApp/Requests/FileServiceRequest.cs diff --git a/AsbCloudApp/Repositories/IFileRepository.cs b/AsbCloudApp/Repositories/IFileRepository.cs index e36d1001..488630ae 100644 --- a/AsbCloudApp/Repositories/IFileRepository.cs +++ b/AsbCloudApp/Repositories/IFileRepository.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using System; using System.Collections.Generic; @@ -7,6 +8,7 @@ using System.Threading.Tasks; namespace AsbCloudApp.Repositories { +#nullable enable /// /// Сервис доступа к файлам /// @@ -24,19 +26,10 @@ namespace AsbCloudApp.Repositories /// /// Получить список файлов в контейнере /// - /// - /// - /// - /// - /// - /// - /// - /// + /// /// /// - 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> GetInfosAsync(FileServiceRequest request, CancellationToken token = default); /// /// Пометить файл как удаленный @@ -90,9 +83,10 @@ namespace AsbCloudApp.Repositories /// /// Получение файлов по скважине /// - /// + /// /// /// - Task> GetInfosByWellIdAsync(int idWell, CancellationToken token); + Task> GetInfosByWellIdAsync(FileServiceRequest request, CancellationToken token); } +#nullable disable } diff --git a/AsbCloudApp/Repositories/IFileStorageRepository.cs b/AsbCloudApp/Repositories/IFileStorageRepository.cs index 9d821861..72c11d21 100644 --- a/AsbCloudApp/Repositories/IFileStorageRepository.cs +++ b/AsbCloudApp/Repositories/IFileStorageRepository.cs @@ -1,9 +1,12 @@ -using System.IO; +using AsbCloudApp.Data; +using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; namespace AsbCloudApp.Repositories { +#nullable enable /// /// Репозиторий хранения фалов /// @@ -47,5 +50,31 @@ namespace AsbCloudApp.Repositories /// /// bool FileExists(string fullPath, string fileName); + + /// + /// Удаление всех файлов с диска о которых нет информации в базе + /// + /// + /// + int DeleteFilesNotExistStorage(int idWell, IEnumerable idsFiles); + + /// + /// Вывод списка всех файлов из базы, для которых нет файла на диске + /// + /// + /// + /// + IEnumerable GetListFilesNotDisc(int idWell, IEnumerable files); + + /// + /// Получение пути к файлу + /// + /// + /// + /// + /// + /// + string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId); } +#nullable disable } diff --git a/AsbCloudApp/Requests/FileServiceRequest.cs b/AsbCloudApp/Requests/FileServiceRequest.cs new file mode 100644 index 00000000..bc561bdd --- /dev/null +++ b/AsbCloudApp/Requests/FileServiceRequest.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace AsbCloudApp.Requests +{ +#nullable enable + /// + /// Параметры запроса для файлового сервиса + /// + public class FileServiceRequest : RequestBase + { + /// + /// Идентификатор скважины + /// + [Required] + public int? IdWell { get; set; } + + /// + /// Идентификатор категории файла + /// + [Required] + public int? IdCategory { get; set; } + + /// + /// Наименование компании + /// + public string? CompanyName { get; set; } + + /// + /// Имя файла + /// + public string? FileName { get; set; } + + /// + /// Дата начала периода + /// + public DateTime? Begin { get; set; } + + /// + /// Дата окончания периода + /// + public DateTime? End { get; set; } + + /// + /// Идентификатор файла + /// + public int? IdFile { get; set; } + + /// + /// Идентификатор отметки + /// + public int? IdMark { get; set; } + + /// + /// Признак удаления + /// + public bool? IsDeleted { get; set; } + } +#nullable disable +} diff --git a/AsbCloudApp/Services/FileService.cs b/AsbCloudApp/Services/FileService.cs index b27c4383..934e5dc3 100644 --- a/AsbCloudApp/Services/FileService.cs +++ b/AsbCloudApp/Services/FileService.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using System; using System.Collections.Generic; using System.IO; @@ -9,6 +10,7 @@ using System.Threading.Tasks; namespace AsbCloudApp.Services { +#nullable enable /// /// Сервис доступа к файлам /// @@ -56,7 +58,7 @@ namespace AsbCloudApp.Services var fileId = await fileRepository.InsertAsync(dto, token) .ConfigureAwait(false); - string filePath = MakeFilePath(idWell, idCategory, destinationFileName, fileId); + string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, destinationFileName, fileId); fileStorageRepository.MoveFile(srcFilePath, filePath); return await GetInfoAsync(fileId, token); @@ -89,7 +91,7 @@ namespace AsbCloudApp.Services .ConfigureAwait(false); //save stream to disk - string filePath = MakeFilePath(idWell, idCategory, fileFullName, fileId); + string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId); await fileStorageRepository.CopyFileAsync(filePath, fileStream, token); return await GetInfoAsync(fileId, token); @@ -215,20 +217,11 @@ namespace AsbCloudApp.Services /// /// Получить список файлов в контейнере /// - /// - /// - /// - /// - /// - /// - /// - /// + /// /// /// - 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) - => await fileRepository.GetInfosAsync(idWell, idCategory, companyName, fileName, begin, end, skip, take, token) + public async Task> GetInfosAsync(FileServiceRequest request, CancellationToken token) + => await fileRepository.GetInfosAsync(request, token) .ConfigureAwait(false); /// @@ -275,7 +268,7 @@ namespace AsbCloudApp.Services /// /// получить инфо о файле по метке /// - /// + /// /// /// public async Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token) @@ -289,7 +282,7 @@ namespace AsbCloudApp.Services /// /// public async Task> GetInfosByWellIdAsync(int idWell, CancellationToken token) - => await fileRepository.GetInfosByWellIdAsync(idWell, token) + => await fileRepository.GetInfosByWellIdAsync(new FileServiceRequest { IdWell = idWell, IsDeleted = false }, token) .ConfigureAwait(false); /// @@ -303,10 +296,58 @@ namespace AsbCloudApp.Services => await fileRepository.GetInfosByCategoryAsync(idWell, idCategory, token) .ConfigureAwait(false); - private string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) + /// + /// Удаление всех файлов по скважине помеченных как удаленные + /// + /// + /// + /// + public async Task DeleteFilesFromDbMarkedDeletionByIdWell(int idWell, CancellationToken token) { - return Path.Combine(fileStorageRepository.RootPath, $"{idWell}", - $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); + var files = await fileRepository.GetInfosByWellIdAsync( + new FileServiceRequest + { + IdWell = idWell, + IsDeleted = true + }, + token); + var result = await DeleteAsync(files.Select(x => x.Id), token); + return result; + } + + /// + /// Удаление всех файлов с диска о которых нет информации в базе + /// + /// + /// + public async Task DeleteFilesNotExistStorage(int idWell, CancellationToken token) + { + var files = await fileRepository.GetInfosByWellIdAsync( + new FileServiceRequest + { + IdWell = idWell + }, + token); + var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotExistStorage(idWell, files.Select(x => x.Id))); + return result; + } + + /// + /// Вывод списка всех файлов из базы, для которых нет файла на диске + /// + /// + /// + public async Task> GetListFilesNotDisc(int idWell, CancellationToken token) + { + var files = await fileRepository.GetInfosByWellIdAsync( + new FileServiceRequest + { + IdWell = idWell + }, + token); + var result = fileStorageRepository.GetListFilesNotDisc(idWell, files); + return result; } } +#nullable disable } diff --git a/AsbCloudInfrastructure/Repository/FileRepository.cs b/AsbCloudInfrastructure/Repository/FileRepository.cs index 0cca5b8b..16367b09 100644 --- a/AsbCloudInfrastructure/Repository/FileRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileRepository.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudDb.Model; using Mapster; using Microsoft.EntityFrameworkCore; @@ -12,6 +13,7 @@ using System.Threading.Tasks; namespace AsbCloudInfrastructure.Repository { +#nullable enable public class FileRepository : IFileRepository { private readonly IQueryable dbSetConfigured; @@ -41,22 +43,23 @@ namespace AsbCloudInfrastructure.Repository 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) + public async Task> GetInfosAsync(FileServiceRequest request, CancellationToken token = default) { var query = dbSetConfigured - .Where(e => e.IdWell == idWell && - e.IdCategory == idCategory && + .Where(e => e.IdWell == request.IdWell && + e.IdCategory == request.IdCategory && !e.IsDeleted); - if (!string.IsNullOrEmpty(companyName)) + if (request.CompanyName is not null) query = query.Where(e => (e.Author == null) || (e.Author.Company == null) || - e.Author.Company.Caption.Contains(companyName)); + e.Author.Company.Caption.Contains(request.CompanyName)); - if (!string.IsNullOrEmpty(fileName)) - query = query.Where(e => e.Name.ToLower().Contains(fileName.ToLower())); + if (request.FileName is not null) + query = query.Where(e => e.Name.ToLower().Contains(request.FileName.ToLower())); + + var skip = request.Skip ?? 0; + var take = request.Take ?? 32; var firstFile = await query.FirstOrDefaultAsync(token); if (firstFile is null) @@ -69,15 +72,15 @@ namespace AsbCloudInfrastructure.Repository var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; - if (begin != default) + if (request.Begin is not null) { - var beginUtc = begin.ToUtcDateTimeOffset(timezoneOffset); + var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffset); query = query.Where(e => e.UploadDate >= beginUtc); } - if (end != default) + if (request.End is not null) { - var endUtc = end.ToUtcDateTimeOffset(timezoneOffset); + var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffset); query = query.Where(e => e.UploadDate <= endUtc); } @@ -201,10 +204,13 @@ namespace AsbCloudInfrastructure.Repository return await db.SaveChangesAsync(token); } - public async Task> GetInfosByWellIdAsync(int idWell, CancellationToken token) + public async Task> GetInfosByWellIdAsync(FileServiceRequest request, CancellationToken token) { - var entities = await dbSetConfigured - .Where(e => e.IdWell == idWell && e.IsDeleted == false) + var query = dbSetConfigured.Where(e => e.IdWell == request.IdWell); + if (request.IsDeleted is not null) + query = query.Where(x => x.IsDeleted == request.IsDeleted); + + var entities = await query .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); @@ -302,4 +308,5 @@ namespace AsbCloudInfrastructure.Repository throw new NotImplementedException(); } } +#nullable disable } diff --git a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs index 7466f3a3..2b1f84f1 100644 --- a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs @@ -1,11 +1,17 @@ -using AsbCloudApp.Exceptions; +using AsbCloudApp.Data; +using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using FileInfo = System.IO.FileInfo; namespace AsbCloudInfrastructure.Repository { +#nullable enable public class FileStorageRepository : IFileStorageRepository { public string RootPath { get; private set; } @@ -51,9 +57,68 @@ namespace AsbCloudInfrastructure.Repository return true; } - private void CreateDirectory(string filePath) + public string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) + { + return Path.Combine(RootPath, $"{idWell}", + $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); + } + + public int DeleteFilesNotExistStorage(int idWell, IEnumerable idsFiles) + { + var allFilesPath = GetFilesPath(idWell); + var resutl = 0; + + foreach (var filePath in allFilesPath) + { + var idFile = Path.GetFileNameWithoutExtension(filePath); + if (!idsFiles.Any(x => x.ToString() == idFile)) + { + File.Delete(filePath); + resutl++; + } + } + + return resutl; + } + + public IEnumerable GetListFilesNotDisc(int idWell, IEnumerable files) + { + var resutl = new List(); + var idsFilesStorage = GetIdsFiles(idWell); + + foreach (var file in files) + { + if (!idsFilesStorage.Any(x => x == file.Id)) + resutl.Add(file); + } + + return resutl; + } + + private IEnumerable GetIdsFiles(int idWell) + { + var result = new List(); + var allFilesPath = GetFilesPath(idWell); + + foreach (var filePath in allFilesPath) + { + var idFileStr = Path.GetFileNameWithoutExtension(filePath); + result.Add(Convert.ToInt32(idFileStr)); + } + + return result; + } + + private IEnumerable GetFilesPath(int idWell) + { + var path = Path.Combine(RootPath, $"{idWell}"); + return Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); + } + + private static void CreateDirectory(string filePath) { Directory.CreateDirectory(Path.GetDirectoryName(filePath)); } } +#nullable disable } diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs index 025cc7bb..91b2af74 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Repository; @@ -115,9 +116,9 @@ namespace AsbCloudWebApi.Tests.ServicesTests return Task.FromResult(result); }); - repositoryMock.Setup(x => x.GetInfosByWellIdAsync(It.IsAny(), It.IsAny())) - .Returns((int idWell, CancellationToken token) => { - var data = Files.Where(x => x.IdWell == idWell); + repositoryMock.Setup(x => x.GetInfosByWellIdAsync(It.IsAny(), It.IsAny())) + .Returns((FileServiceRequest request, CancellationToken token) => { + var data = Files.Where(x => x.IdWell == request.IdWell); return Task.FromResult(data); }); diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 378b5a50..499129f2 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -12,6 +13,7 @@ using System.Threading.Tasks; namespace AsbCloudWebApi.Controllers { +#nullable enable /// /// Хранение файлов /// @@ -70,38 +72,27 @@ namespace AsbCloudWebApi.Controllers /// /// Возвращает информацию о файлах для скважины в выбраной категории /// - /// id скважины - /// id категории файла - /// id компаний для фильтрации возвращаемых файлов - /// часть имени файла для поиска - /// дата начала - /// дата окончания - /// для пагинации кол-во записей пропустить - /// для пагинации кол-во записей взять + /// /// Токен отмены задачи /// Список информации о файлах в этой категории [HttpGet] + [Route("/api/files")] [Permission] [ProducesResponseType(typeof(PaginationContainer), (int)System.Net.HttpStatusCode.OK)] public async Task GetFilesInfoAsync( - [FromRoute] int idWell, - int idCategory = default, - string companyName = default, - string fileName = default, - DateTime begin = default, - DateTime end = default, - int skip = 0, - int take = 32, + [FromQuery] FileServiceRequest request, CancellationToken token = default) { int? idCompany = User.GetCompanyId(); - if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, - idWell, token).ConfigureAwait(false)) + if (request.IdWell is null || request.IdCategory is null || idCompany is null) return Forbid(); - var filesInfo = await fileService.GetInfosAsync(idWell, idCategory, - companyName, fileName, begin, end, skip, take, token).ConfigureAwait(false); + if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, + request.IdWell.Value, token).ConfigureAwait(false)) + return Forbid(); + + var filesInfo = await fileService.GetInfosAsync(request, token).ConfigureAwait(false); return Ok(filesInfo); } @@ -254,4 +245,5 @@ namespace AsbCloudWebApi.Controllers } } } +#nullable disable } From 9de5f04fbc6e81674616309ef5e6bf484873f9c6 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Tue, 11 Oct 2022 09:08:25 +0500 Subject: [PATCH 2/7] =?UTF-8?q?#6385536=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Repositories/IFileRepository.cs | 1 - AsbCloudApp/Services/FileService.cs | 1 - AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs | 7 ------- AsbCloudWebApi/Controllers/FileController.cs | 3 --- 4 files changed, 12 deletions(-) diff --git a/AsbCloudApp/Repositories/IFileRepository.cs b/AsbCloudApp/Repositories/IFileRepository.cs index 488630ae..9e3e41c9 100644 --- a/AsbCloudApp/Repositories/IFileRepository.cs +++ b/AsbCloudApp/Repositories/IFileRepository.cs @@ -1,7 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/AsbCloudApp/Services/FileService.cs b/AsbCloudApp/Services/FileService.cs index 934e5dc3..34cb1fe5 100644 --- a/AsbCloudApp/Services/FileService.cs +++ b/AsbCloudApp/Services/FileService.cs @@ -1,7 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; -using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs index 91b2af74..5710f40b 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs @@ -2,21 +2,14 @@ using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudDb.Model; -using AsbCloudInfrastructure.Repository; -using AsbCloudInfrastructure.Services; -using DocumentFormat.OpenXml.Spreadsheet; -using DocumentFormat.OpenXml.Wordprocessing; using Moq; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; -using static AsbCloudWebApi.Tests.TestHelpter; namespace AsbCloudWebApi.Tests.ServicesTests { diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 499129f2..1c29b902 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -4,9 +4,6 @@ using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections; -using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; From 0b2ae0b361d7caa9a5be36cf2780a29e9cefc56c Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Tue, 11 Oct 2022 09:38:19 +0500 Subject: [PATCH 3/7] + --- AsbCloudApp/Repositories/IFileRepository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsbCloudApp/Repositories/IFileRepository.cs b/AsbCloudApp/Repositories/IFileRepository.cs index 9e3e41c9..4363c204 100644 --- a/AsbCloudApp/Repositories/IFileRepository.cs +++ b/AsbCloudApp/Repositories/IFileRepository.cs @@ -1,5 +1,5 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Requests; +using AsbCloudApp.Requests; +using AsbCloudApp.Data; using AsbCloudApp.Services; using System.Collections.Generic; using System.Threading; From b54de8fe0624364a975d45e9caa32e8b902d4bb3 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Tue, 11 Oct 2022 14:42:04 +0500 Subject: [PATCH 4/7] =?UTF-8?q?#6385536=20=D0=97=D0=B0=D0=BC=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/IFileStorageRepository.cs | 38 ++++----- AsbCloudApp/Services/FileService.cs | 34 +++----- .../Repository/FileStorageRepository.cs | 83 ++++++++++--------- .../ServicesTests/FileServiceTest.cs | 2 - AsbCloudWebApi/Controllers/FileController.cs | 7 +- 5 files changed, 76 insertions(+), 88 deletions(-) diff --git a/AsbCloudApp/Repositories/IFileStorageRepository.cs b/AsbCloudApp/Repositories/IFileStorageRepository.cs index 72c11d21..68ce51e9 100644 --- a/AsbCloudApp/Repositories/IFileStorageRepository.cs +++ b/AsbCloudApp/Repositories/IFileStorageRepository.cs @@ -12,17 +12,12 @@ namespace AsbCloudApp.Repositories /// public interface IFileStorageRepository { - /// - /// Директория хранения файлов - /// - string RootPath { get; } - /// /// Получение длинны фала и проверка его наличия, если отсутствует падает исключение /// /// /// - long GetLengthFile(string srcFilePath); + long GetFileLength(string srcFilePath); /// /// Перемещение файла @@ -34,29 +29,24 @@ namespace AsbCloudApp.Repositories /// /// Копирование файла /// + /// + /// + /// /// - Task CopyFileAsync(string filePath, Stream fileStream, CancellationToken token); + Task SaveFileAsync(string filePathRec, Stream fileStreamSrc, CancellationToken token); /// /// Удаление файла /// - /// - void DeleteFile(string fileName); - - /// - /// Проверка наличия файла - /// - /// - /// - /// - bool FileExists(string fullPath, string fileName); + /// + void DeleteFile(IEnumerable filesName); /// /// Удаление всех файлов с диска о которых нет информации в базе /// /// /// - int DeleteFilesNotExistStorage(int idWell, IEnumerable idsFiles); + int DeleteFilesNotList(int idWell, IEnumerable idsFiles); /// /// Вывод списка всех файлов из базы, для которых нет файла на диске @@ -64,7 +54,7 @@ namespace AsbCloudApp.Repositories /// /// /// - IEnumerable GetListFilesNotDisc(int idWell, IEnumerable files); + IEnumerable GetListFilesNotDisc(IEnumerable files); /// /// Получение пути к файлу @@ -75,6 +65,16 @@ namespace AsbCloudApp.Repositories /// /// string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId); + + /// + /// Получить путь для скачивания + /// + /// + /// + /// + /// + /// + string GetUrl(int idWell, int idCategory, int idFile, string dotExtention); } #nullable disable } diff --git a/AsbCloudApp/Services/FileService.cs b/AsbCloudApp/Services/FileService.cs index 34cb1fe5..d16006e1 100644 --- a/AsbCloudApp/Services/FileService.cs +++ b/AsbCloudApp/Services/FileService.cs @@ -6,6 +6,8 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using static Npgsql.PostgresTypes.PostgresCompositeType; +using static System.Net.WebRequestMethods; namespace AsbCloudApp.Services { @@ -44,7 +46,7 @@ namespace AsbCloudApp.Services { destinationFileName = Path.GetFileName(destinationFileName); srcFilePath = Path.GetFullPath(srcFilePath); - var fileSize = fileStorageRepository.GetLengthFile(srcFilePath); + var fileSize = fileStorageRepository.GetFileLength(srcFilePath); //save info to db var dto = new FileInfoDto { @@ -91,7 +93,7 @@ namespace AsbCloudApp.Services //save stream to disk string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId); - await fileStorageRepository.CopyFileAsync(filePath, fileStream, token); + await fileStorageRepository.SaveFileAsync(filePath, fileStream, token); return await GetInfoAsync(fileId, token); } @@ -111,7 +113,6 @@ namespace AsbCloudApp.Services var relativePath = GetUrl(dto.IdWell, dto.IdCategory, dto.Id, ext); var fullPath = Path.GetFullPath(relativePath); - fileStorageRepository.FileExists(fullPath, relativePath); return dto; } @@ -141,27 +142,12 @@ namespace AsbCloudApp.Services if (files is null || !files.Any()) return 0; - foreach (var file in files) - { - var fileName = GetUrl(file.IdWell, file.IdCategory, file.Id, Path.GetExtension(file.Name)); - fileStorageRepository.DeleteFile(fileName); - } + var filesName = files.Select(x => GetUrl(x.IdWell, x.IdCategory, x.Id, Path.GetExtension(x.Name))); + fileStorageRepository.DeleteFile(filesName); return files.Any() ? 1 : 0; } - /// - /// получить путь для скачивания - /// - /// - /// - public async Task GetUrl(int idFile) - { - var fileInfo = await fileRepository.GetOrDefaultAsync(idFile, CancellationToken.None).ConfigureAwait(false); - - return GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name)); - } - /// /// получить путь для скачивания /// @@ -179,7 +165,7 @@ namespace AsbCloudApp.Services /// /// public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) => - Path.Combine(fileStorageRepository.RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}"); + fileStorageRepository.GetUrl(idWell, idCategory, idFile, dotExtention); /// /// пометить метку файла как удаленную @@ -207,7 +193,6 @@ namespace AsbCloudApp.Services var ext = Path.GetExtension(entity.Name); var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext); var fullPath = Path.GetFullPath(relativePath); - fileStorageRepository.FileExists(fullPath, relativePath); } return result; @@ -327,7 +312,7 @@ namespace AsbCloudApp.Services IdWell = idWell }, token); - var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotExistStorage(idWell, files.Select(x => x.Id))); + var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotList(idWell, files.Select(x => x.Id))); return result; } @@ -335,6 +320,7 @@ namespace AsbCloudApp.Services /// Вывод списка всех файлов из базы, для которых нет файла на диске /// /// + /// /// public async Task> GetListFilesNotDisc(int idWell, CancellationToken token) { @@ -344,7 +330,7 @@ namespace AsbCloudApp.Services IdWell = idWell }, token); - var result = fileStorageRepository.GetListFilesNotDisc(idWell, files); + var result = fileStorageRepository.GetListFilesNotDisc(files); return result; } } diff --git a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs index 2b1f84f1..37a041b7 100644 --- a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs @@ -14,31 +14,33 @@ namespace AsbCloudInfrastructure.Repository #nullable enable public class FileStorageRepository : IFileStorageRepository { - public string RootPath { get; private set; } + /// + /// Директория хранения файлов + /// + private readonly string RootPath = "files"; public FileStorageRepository() { - RootPath = "files"; } - public async Task CopyFileAsync(string filePath, Stream fileStream, CancellationToken token) + public async Task SaveFileAsync(string filePathRec, Stream fileStreamSrc, CancellationToken token) { - CreateDirectory(filePath); - using var newfileStream = new FileStream(filePath, FileMode.Create); - await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false); + CreateDirectory(filePathRec); + using var newfileStream = new FileStream(filePathRec, FileMode.Create); + await fileStreamSrc.CopyToAsync(newfileStream, token).ConfigureAwait(false); } - public void DeleteFile(string fileName) + public void DeleteFile(IEnumerable filesName) { - if (File.Exists(fileName)) - File.Delete(fileName); + foreach (var fileName in filesName) + { + if (File.Exists(fileName)) + File.Delete(fileName); + } } - public long GetLengthFile(string srcFilePath) + public long GetFileLength(string srcFilePath) { - if (!File.Exists(srcFilePath)) - throw new ArgumentInvalidException($"file {srcFilePath} doesn't exist", nameof(srcFilePath)); - var sysFileInfo = new FileInfo(srcFilePath); return sysFileInfo.Length; } @@ -49,51 +51,50 @@ namespace AsbCloudInfrastructure.Repository File.Move(srcFilePath, filePath); } - public bool FileExists(string fullPath, string fileName) - { - if (!File.Exists(fullPath)) - throw new FileNotFoundException("not found", fileName); - - return true; - } - public string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) { return Path.Combine(RootPath, $"{idWell}", $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); } - public int DeleteFilesNotExistStorage(int idWell, IEnumerable idsFiles) + public int DeleteFilesNotList(int idWell, IEnumerable idsFilesList) { var allFilesPath = GetFilesPath(idWell); - var resutl = 0; + var result = 0; foreach (var filePath in allFilesPath) { - var idFile = Path.GetFileNameWithoutExtension(filePath); - if (!idsFiles.Any(x => x.ToString() == idFile)) + if (int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile) + || !idsFilesList.Any(x => x == idFile)) { File.Delete(filePath); - resutl++; + result++; + } + } + + return result; + } + + public IEnumerable GetListFilesNotDisc(IEnumerable files) + { + var resutl = new List(); + var groupFiles = files.GroupBy(x => x.IdWell); + + foreach (var itemGroupFiles in groupFiles) + { + var idsFilesStorage = GetIdsFiles(itemGroupFiles.Key); + foreach (var file in files) + { + if (!idsFilesStorage.Any(x => x == file.Id)) + resutl.Add(file); } } return resutl; } - public IEnumerable GetListFilesNotDisc(int idWell, IEnumerable files) - { - var resutl = new List(); - var idsFilesStorage = GetIdsFiles(idWell); - - foreach (var file in files) - { - if (!idsFilesStorage.Any(x => x == file.Id)) - resutl.Add(file); - } - - return resutl; - } + public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) => + Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}"); private IEnumerable GetIdsFiles(int idWell) { @@ -102,8 +103,8 @@ namespace AsbCloudInfrastructure.Repository foreach (var filePath in allFilesPath) { - var idFileStr = Path.GetFileNameWithoutExtension(filePath); - result.Add(Convert.ToInt32(idFileStr)); + int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile); + result.Add(idFile); } return result; diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs index 5710f40b..cf35bcab 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs @@ -134,8 +134,6 @@ namespace AsbCloudWebApi.Tests.ServicesTests var storageRepositoryMock = new Mock(); - storageRepositoryMock.Setup(x => x.RootPath).Returns("files"); - fileService = new FileService(repositoryMock.Object, storageRepositoryMock.Object); } diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 1c29b902..85c095a3 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Mvc; using System.IO; using System.Threading; using System.Threading.Tasks; +using System.Text; +using static System.Net.WebRequestMethods; namespace AsbCloudWebApi.Controllers { @@ -120,9 +122,10 @@ namespace AsbCloudWebApi.Controllers try { var fileInfo = await fileService.GetInfoAsync(fileId, token); - var relativePath = fileService.GetUrl(fileInfo); - return PhysicalFile(Path.GetFullPath(relativePath), "application/octet-stream", fileInfo.Name); + + var fileStream = new FileStream(Path.GetFullPath(relativePath), FileMode.Open); + return File(fileStream, "application/octet-stream", fileInfo.Name); } catch (FileNotFoundException ex) { From ceb088519abe5b8ae794c5ec66adb64b80cb3795 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Wed, 12 Oct 2022 09:47:25 +0500 Subject: [PATCH 5/7] =?UTF-8?q?#6385536=20=D0=98=D0=BD=D1=81=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=BA=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D1=8F=20=D0=B2=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudInfrastructure/Services/_Readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 AsbCloudInfrastructure/Services/_Readme.md diff --git a/AsbCloudInfrastructure/Services/_Readme.md b/AsbCloudInfrastructure/Services/_Readme.md new file mode 100644 index 00000000..d05ae29e --- /dev/null +++ b/AsbCloudInfrastructure/Services/_Readme.md @@ -0,0 +1,9 @@ +# Создание репозитория для сервися + +1. Создать интерфейс репозитория в AsbCloudApp.Services +2. Создать репозиторий в AsbCloudInfrastructure.Repository, наследоваться от созданного интерфейса, в нем добавить работу с БД +3. Добавить репозиторий в AsbCloudInfrastructure.DependencyInjection +4. Добавить в конструктор сервиса новый репозиторий и использовать его методы +5. Перенести сервис из AsbCloudInfrastructure.Services в AsbCloudApp.Services +6. Добавить или поправить тесты на изменяемый сервис используя AsbCloudWebApi.Tests.RepositoryFactory +7. В тестах сделать мок данных для репозитория \ No newline at end of file From 8a83194187dda20f97fa2dd77ef6cd911b80a663 Mon Sep 17 00:00:00 2001 From: "ai.astrakhantsev" Date: Mon, 17 Oct 2022 08:58:28 +0500 Subject: [PATCH 6/7] =?UTF-8?q?#6385536=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2.=20=D0=97=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/IFileStorageRepository.cs | 2 +- AsbCloudApp/Services/FileService.cs | 16 ++- .../Repository/FileRepository.cs | 109 ++++++++++-------- .../Repository/FileStorageRepository.cs | 2 +- .../ServicesTests/FileServiceTest.cs | 4 + AsbCloudWebApi/Controllers/FileController.cs | 3 +- 6 files changed, 81 insertions(+), 55 deletions(-) diff --git a/AsbCloudApp/Repositories/IFileStorageRepository.cs b/AsbCloudApp/Repositories/IFileStorageRepository.cs index 68ce51e9..0d867db0 100644 --- a/AsbCloudApp/Repositories/IFileStorageRepository.cs +++ b/AsbCloudApp/Repositories/IFileStorageRepository.cs @@ -46,7 +46,7 @@ namespace AsbCloudApp.Repositories /// /// /// - int DeleteFilesNotList(int idWell, IEnumerable idsFiles); + int DeleteFilesNotInList(int idWell, IEnumerable idsFiles); /// /// Вывод списка всех файлов из базы, для которых нет файла на диске diff --git a/AsbCloudApp/Services/FileService.cs b/AsbCloudApp/Services/FileService.cs index d16006e1..04b2c65d 100644 --- a/AsbCloudApp/Services/FileService.cs +++ b/AsbCloudApp/Services/FileService.cs @@ -312,7 +312,7 @@ namespace AsbCloudApp.Services IdWell = idWell }, token); - var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotList(idWell, files.Select(x => x.Id))); + var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotInList(idWell, files.Select(x => x.Id))); return result; } @@ -333,6 +333,20 @@ namespace AsbCloudApp.Services var result = fileStorageRepository.GetListFilesNotDisc(files); return result; } + + /// + /// Получить файловый поток по идентификатору файла + /// + /// + /// + /// + public FileStream GetFileStream(FileInfoDto fileInfo) + { + var relativePath = GetUrl(fileInfo); + var fileStream = new FileStream(Path.GetFullPath(relativePath), FileMode.Open); + + return fileStream; + } } #nullable disable } diff --git a/AsbCloudInfrastructure/Repository/FileRepository.cs b/AsbCloudInfrastructure/Repository/FileRepository.cs index 16367b09..6eacf56b 100644 --- a/AsbCloudInfrastructure/Repository/FileRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileRepository.cs @@ -45,23 +45,11 @@ namespace AsbCloudInfrastructure.Repository public async Task> GetInfosAsync(FileServiceRequest request, CancellationToken token = default) { - var query = dbSetConfigured - .Where(e => e.IdWell == request.IdWell && - e.IdCategory == request.IdCategory && - !e.IsDeleted); - - if (request.CompanyName is not null) - query = query.Where(e => (e.Author == null) || - (e.Author.Company == null) || - e.Author.Company.Caption.Contains(request.CompanyName)); - - if (request.FileName is not null) - query = query.Where(e => e.Name.ToLower().Contains(request.FileName.ToLower())); - + var query = GetQuery(request, token); + var firstFile = query.FirstOrDefault(); var skip = request.Skip ?? 0; var take = request.Take ?? 32; - var firstFile = await query.FirstOrDefaultAsync(token); if (firstFile is null) return new PaginationContainer() { @@ -71,21 +59,7 @@ namespace AsbCloudInfrastructure.Repository }; var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; - - if (request.Begin is not null) - { - var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate >= beginUtc); - } - - if (request.End is not null) - { - var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate <= endUtc); - } - var count = await query.CountAsync(token).ConfigureAwait(false); - var result = new PaginationContainer(count) { Skip = skip, @@ -206,9 +180,7 @@ namespace AsbCloudInfrastructure.Repository public async Task> GetInfosByWellIdAsync(FileServiceRequest request, CancellationToken token) { - var query = dbSetConfigured.Where(e => e.IdWell == request.IdWell); - if (request.IsDeleted is not null) - query = query.Where(x => x.IsDeleted == request.IsDeleted); + var query = GetQuery(request, token); var entities = await query .AsNoTracking() @@ -219,25 +191,6 @@ namespace AsbCloudInfrastructure.Repository 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; - } - public async Task> GetAllAsync(CancellationToken token) => await dbSetConfigured.AsNoTracking() .Select(x => Convert(x)) @@ -307,6 +260,62 @@ namespace AsbCloudInfrastructure.Repository { throw new NotImplementedException(); } + + private IQueryable GetQuery(FileServiceRequest request, CancellationToken token = default) + { + var query = dbSetConfigured + .Where(e => e.IdWell == request.IdWell && + e.IdCategory == request.IdCategory); + + if (request.IsDeleted is not null) + query = query.Where(x => x.IsDeleted == request.IsDeleted); + + if (request.CompanyName is not null) + query = query.Where(e => (e.Author == null) || + (e.Author.Company == null) || + e.Author.Company.Caption.Contains(request.CompanyName)); + + if (request.FileName is not null) + query = query.Where(e => e.Name.ToLower().Contains(request.FileName.ToLower())); + + var firstFile = query.FirstOrDefault(); + if (firstFile is null) + return Enumerable.Empty().AsQueryable(); + + var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; + if (request.Begin is not null) + { + var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffset); + query = query.Where(e => e.UploadDate >= beginUtc); + } + + if (request.End is not null) + { + var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffset); + query = query.Where(e => e.UploadDate <= endUtc); + } + + return query; + } + + 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; + } } #nullable disable } diff --git a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs index 37a041b7..0d7a2cf8 100644 --- a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs @@ -57,7 +57,7 @@ namespace AsbCloudInfrastructure.Repository $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); } - public int DeleteFilesNotList(int idWell, IEnumerable idsFilesList) + public int DeleteFilesNotInList(int idWell, IEnumerable idsFilesList) { var allFilesPath = GetFilesPath(idWell); var result = 0; diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs index cf35bcab..4f83e996 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs @@ -133,6 +133,10 @@ namespace AsbCloudWebApi.Tests.ServicesTests }); var storageRepositoryMock = new Mock(); + storageRepositoryMock.Setup(x => x.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns((int idWell, int idCategory, int idFile, string dotExtention) => { + return Path.Combine("files", idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}"); + }); fileService = new FileService(repositoryMock.Object, storageRepositoryMock.Object); } diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 85c095a3..7d4e395b 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -122,9 +122,8 @@ namespace AsbCloudWebApi.Controllers try { var fileInfo = await fileService.GetInfoAsync(fileId, token); - var relativePath = fileService.GetUrl(fileInfo); + var fileStream = fileService.GetFileStream(fileInfo); - var fileStream = new FileStream(Path.GetFullPath(relativePath), FileMode.Open); return File(fileStream, "application/octet-stream", fileInfo.Name); } catch (FileNotFoundException ex) From 8b68b8276ab772e3410912228392c2aae60e104e Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Mon, 17 Oct 2022 14:42:47 +0500 Subject: [PATCH 7/7] #6385536 refactoring --- AsbCloudApp/Data/FileInfoDto.cs | 5 + AsbCloudApp/Repositories/IFileRepository.cs | 16 +- .../{FileServiceRequest.cs => FileRequest.cs} | 18 +- AsbCloudApp/Services/FileService.cs | 108 ++++------- AsbCloudDb/EFExtentions.cs | 11 ++ .../Repository/FileRepository.cs | 176 ++++++++---------- .../Repository/FileStorageRepository.cs | 12 +- .../DrillingProgram/DrillingProgramService.cs | 7 +- .../Services/WellFinalDocumentsService.cs | 10 +- .../DrillingProgramServiceTest.cs | 4 +- .../ServicesTests/FileServiceTest.cs | 28 +-- AsbCloudWebApi/Controllers/FileController.cs | 45 +++-- 12 files changed, 177 insertions(+), 263 deletions(-) rename AsbCloudApp/Requests/{FileServiceRequest.cs => FileRequest.cs} (71%) diff --git a/AsbCloudApp/Data/FileInfoDto.cs b/AsbCloudApp/Data/FileInfoDto.cs index 63abba8f..badcd5a4 100644 --- a/AsbCloudApp/Data/FileInfoDto.cs +++ b/AsbCloudApp/Data/FileInfoDto.cs @@ -39,6 +39,11 @@ namespace AsbCloudApp.Data /// public long Size { get; set; } + /// + /// Помечен как удаленный + /// + public bool IsDeleted { get; set; } + /// /// DTO автора /// diff --git a/AsbCloudApp/Repositories/IFileRepository.cs b/AsbCloudApp/Repositories/IFileRepository.cs index 4363c204..a05cf909 100644 --- a/AsbCloudApp/Repositories/IFileRepository.cs +++ b/AsbCloudApp/Repositories/IFileRepository.cs @@ -14,13 +14,12 @@ namespace AsbCloudApp.Repositories public interface IFileRepository : ICrudService { /// - /// Получить файлы определенной категории + /// Получение файлов по скважине /// - /// - /// + /// /// /// - Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token); + Task> GetInfosAsync(FileRequest request, CancellationToken token); /// /// Получить список файлов в контейнере @@ -28,7 +27,7 @@ namespace AsbCloudApp.Repositories /// /// /// - Task> GetInfosAsync(FileServiceRequest request, CancellationToken token = default); + Task> GetInfosPaginatedAsync(FileRequest request, CancellationToken token = default); /// /// Пометить файл как удаленный @@ -79,13 +78,6 @@ namespace AsbCloudApp.Repositories /// Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token); - /// - /// Получение файлов по скважине - /// - /// - /// - /// - Task> GetInfosByWellIdAsync(FileServiceRequest request, CancellationToken token); } #nullable disable } diff --git a/AsbCloudApp/Requests/FileServiceRequest.cs b/AsbCloudApp/Requests/FileRequest.cs similarity index 71% rename from AsbCloudApp/Requests/FileServiceRequest.cs rename to AsbCloudApp/Requests/FileRequest.cs index bc561bdd..14a799e0 100644 --- a/AsbCloudApp/Requests/FileServiceRequest.cs +++ b/AsbCloudApp/Requests/FileRequest.cs @@ -7,13 +7,13 @@ namespace AsbCloudApp.Requests /// /// Параметры запроса для файлового сервиса /// - public class FileServiceRequest : RequestBase + public class FileRequest : RequestBase { /// /// Идентификатор скважины /// [Required] - public int? IdWell { get; set; } + public int IdWell { get; set; } /// /// Идентификатор категории файла @@ -24,12 +24,12 @@ namespace AsbCloudApp.Requests /// /// Наименование компании /// - public string? CompanyName { get; set; } + public string? CompanyNamePart { get; set; } /// /// Имя файла /// - public string? FileName { get; set; } + public string? FileNamePart { get; set; } /// /// Дата начала периода @@ -41,16 +41,6 @@ namespace AsbCloudApp.Requests /// public DateTime? End { get; set; } - /// - /// Идентификатор файла - /// - public int? IdFile { get; set; } - - /// - /// Идентификатор отметки - /// - public int? IdMark { get; set; } - /// /// Признак удаления /// diff --git a/AsbCloudApp/Services/FileService.cs b/AsbCloudApp/Services/FileService.cs index 04b2c65d..3ba250aa 100644 --- a/AsbCloudApp/Services/FileService.cs +++ b/AsbCloudApp/Services/FileService.cs @@ -6,8 +6,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using static Npgsql.PostgresTypes.PostgresCompositeType; -using static System.Net.WebRequestMethods; namespace AsbCloudApp.Services { @@ -41,7 +39,7 @@ namespace AsbCloudApp.Services /// /// /// - public async Task MoveAsync(int idWell, int? idUser, int idCategory, + public async Task MoveAsync(int idWell, int? idUser, int idCategory, string destinationFileName, string srcFilePath, CancellationToken token = default) { destinationFileName = Path.GetFileName(destinationFileName); @@ -61,8 +59,8 @@ namespace AsbCloudApp.Services string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, destinationFileName, fileId); fileStorageRepository.MoveFile(srcFilePath, filePath); - - return await GetInfoAsync(fileId, token); + + return await GetOrDefaultAsync(fileId, token); } /// @@ -75,7 +73,7 @@ namespace AsbCloudApp.Services /// /// /// - public async Task SaveAsync(int idWell, int? idUser, int idCategory, + public async Task SaveAsync(int idWell, int? idUser, int idCategory, string fileFullName, Stream fileStream, CancellationToken token) { //save info to db @@ -85,7 +83,7 @@ namespace AsbCloudApp.Services IdAuthor = idUser, IdCategory = idCategory, Name = Path.GetFileName(fileFullName), - Size = fileStream?.Length ?? 0 + Size = fileStream.Length }; var fileId = await fileRepository.InsertAsync(dto, token) @@ -95,26 +93,7 @@ namespace AsbCloudApp.Services string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId); await fileStorageRepository.SaveFileAsync(filePath, fileStream, token); - return await GetInfoAsync(fileId, token); - } - - /// - /// Инфо о файле - /// - /// - /// - /// - public async Task GetInfoAsync(int idFile, - CancellationToken token) - { - var dto = await fileRepository.GetOrDefaultAsync(idFile, token).ConfigureAwait(false); - - var ext = Path.GetExtension(dto.Name); - - var relativePath = GetUrl(dto.IdWell, dto.IdCategory, dto.Id, ext); - var fullPath = Path.GetFullPath(relativePath); - - return dto; + return await GetOrDefaultAsync(fileId, token); } /// @@ -198,15 +177,23 @@ namespace AsbCloudApp.Services return result; } + /// + /// Получить файлы определенной категории + /// + /// + /// + /// + public Task> GetInfosAsync(FileRequest request, CancellationToken token) + => fileRepository.GetInfosAsync(request, token); + /// /// Получить список файлов в контейнере /// /// /// /// - public async Task> GetInfosAsync(FileServiceRequest request, CancellationToken token) - => await fileRepository.GetInfosAsync(request, token) - .ConfigureAwait(false); + public Task> GetInfosPaginatedAsync(FileRequest request, CancellationToken token) + => fileRepository.GetInfosPaginatedAsync(request, token); /// /// Пометить файл как удаленный @@ -214,9 +201,8 @@ namespace AsbCloudApp.Services /// /// /// - public async Task MarkAsDeletedAsync(int idFile, CancellationToken token = default) - => await fileRepository.MarkAsDeletedAsync(idFile, token) - .ConfigureAwait(false); + public Task MarkAsDeletedAsync(int idFile, CancellationToken token = default) + => fileRepository.MarkAsDeletedAsync(idFile, token); /// /// добавить метку на файл @@ -225,9 +211,8 @@ namespace AsbCloudApp.Services /// /// /// - public async Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token) - => await fileRepository.CreateFileMarkAsync(fileMarkDto, idUser, token) - .ConfigureAwait(false); + public Task CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token) + => fileRepository.CreateFileMarkAsync(fileMarkDto, idUser, token); /// /// Получить запись по id @@ -235,9 +220,8 @@ namespace AsbCloudApp.Services /// /// /// - public async Task GetOrDefaultAsync(int id, CancellationToken token) - => await fileRepository.GetOrDefaultAsync(id, token) - .ConfigureAwait(false); + public Task GetOrDefaultAsync(int id, CancellationToken token) + => fileRepository.GetOrDefaultAsync(id, token); /// /// получить инфо о файле по метке @@ -245,9 +229,8 @@ namespace AsbCloudApp.Services /// /// /// - public async Task GetByMarkId(int idMark, CancellationToken token) - => await fileRepository.GetByMarkId(idMark, token) - .ConfigureAwait(false); + public Task GetByMarkId(int idMark, CancellationToken token) + => fileRepository.GetByMarkId(idMark, token); /// /// получить инфо о файле по метке @@ -255,30 +238,8 @@ namespace AsbCloudApp.Services /// /// /// - public async Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token) - => await fileRepository.MarkFileMarkAsDeletedAsync(idsMarks, token) - .ConfigureAwait(false); - - /// - /// Получение файлов по скважине - /// - /// - /// - /// - public async Task> GetInfosByWellIdAsync(int idWell, CancellationToken token) - => await fileRepository.GetInfosByWellIdAsync(new FileServiceRequest { IdWell = idWell, IsDeleted = false }, token) - .ConfigureAwait(false); - - /// - /// Получить файлы определенной категории - /// - /// - /// - /// - /// - public async Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token) - => await fileRepository.GetInfosByCategoryAsync(idWell, idCategory, token) - .ConfigureAwait(false); + public Task MarkFileMarkAsDeletedAsync(IEnumerable idsMarks, CancellationToken token) + => fileRepository.MarkFileMarkAsDeletedAsync(idsMarks, token); /// /// Удаление всех файлов по скважине помеченных как удаленные @@ -288,8 +249,8 @@ namespace AsbCloudApp.Services /// public async Task DeleteFilesFromDbMarkedDeletionByIdWell(int idWell, CancellationToken token) { - var files = await fileRepository.GetInfosByWellIdAsync( - new FileServiceRequest + var files = await fileRepository.GetInfosAsync( + new FileRequest { IdWell = idWell, IsDeleted = true @@ -306,8 +267,8 @@ namespace AsbCloudApp.Services /// public async Task DeleteFilesNotExistStorage(int idWell, CancellationToken token) { - var files = await fileRepository.GetInfosByWellIdAsync( - new FileServiceRequest + var files = await fileRepository.GetInfosAsync( + new FileRequest { IdWell = idWell }, @@ -324,8 +285,8 @@ namespace AsbCloudApp.Services /// public async Task> GetListFilesNotDisc(int idWell, CancellationToken token) { - var files = await fileRepository.GetInfosByWellIdAsync( - new FileServiceRequest + var files = await fileRepository.GetInfosAsync( + new FileRequest { IdWell = idWell }, @@ -338,9 +299,8 @@ namespace AsbCloudApp.Services /// Получить файловый поток по идентификатору файла /// /// - /// /// - public FileStream GetFileStream(FileInfoDto fileInfo) + public Stream GetFileStream(FileInfoDto fileInfo) { var relativePath = GetUrl(fileInfo); var fileStream = new FileStream(Path.GetFullPath(relativePath), FileMode.Open); diff --git a/AsbCloudDb/EFExtentions.cs b/AsbCloudDb/EFExtentions.cs index f0523294..3cbf3509 100644 --- a/AsbCloudDb/EFExtentions.cs +++ b/AsbCloudDb/EFExtentions.cs @@ -117,6 +117,17 @@ namespace AsbCloudDb } return stat; } + + public static IQueryable SkipTake(this IQueryable query, int? skip, int? take) + { + if (skip > 0) + query = query.Skip((int)skip); + + if (take > 0) + query = query.Take((int)take); + + return query; + } } interface IQueryStringFactory { } diff --git a/AsbCloudInfrastructure/Repository/FileRepository.cs b/AsbCloudInfrastructure/Repository/FileRepository.cs index 6eacf56b..deb43445 100644 --- a/AsbCloudInfrastructure/Repository/FileRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileRepository.cs @@ -1,12 +1,17 @@ using AsbCloudApp.Data; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudDb; using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services; +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.Wordprocessing; using Mapster; using Microsoft.EntityFrameworkCore; +using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,7 +21,7 @@ namespace AsbCloudInfrastructure.Repository #nullable enable public class FileRepository : IFileRepository { - private readonly IQueryable dbSetConfigured; + private readonly IQueryable dbSetConfigured; private readonly IAsbCloudDbContext db; public FileRepository(IAsbCloudDbContext db) @@ -31,10 +36,55 @@ namespace AsbCloudInfrastructure.Repository .Include(f => f.Well); } - public async Task> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token) + private IQueryable BuildQuery(FileRequest request) { - var entities = await dbSetConfigured - .Where(e => e.IdWell == idWell && e.IdCategory == idCategory && e.IsDeleted == false) + var query = dbSetConfigured + .Where(e => e.IdWell == request.IdWell); + + double timezoneOffsetHours = query.FirstOrDefault() + ?.Well.Timezone.Hours ?? 5d; + + if (request.IdCategory is not null) + query = query.Where(x => x.IdCategory == request.IdCategory); + + if (request.IsDeleted is not null) + query = query.Where(x => x.IsDeleted == request.IsDeleted); + + if (request.CompanyNamePart is not null) + query = query.Where(e => e.Author.Company.Caption.ToLower().Contains(request.CompanyNamePart.ToLower())); + + if (request.FileNamePart is not null) + query = query.Where(e => e.Name.ToLower().Contains(request.FileNamePart.ToLower())); + + if (request.Begin is not null) + { + var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffsetHours); + query = query.Where(e => e.UploadDate >= beginUtc); + } + + if (request.End is not null) + { + var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffsetHours); + query = query.Where(e => e.UploadDate <= endUtc); + } + + if (request?.SortFields?.Any() == true) + { + query = query.SortBy(request.SortFields); + } + else + query = query + .OrderBy(o => o.UploadDate); + + return query; + } + + public async Task> GetInfosAsync(FileRequest request, CancellationToken token) + { + var query = BuildQuery(request); + + var entities = await query + .SkipTake(request.Skip, request.Take) .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); @@ -43,51 +93,37 @@ namespace AsbCloudInfrastructure.Repository return dtos; } - public async Task> GetInfosAsync(FileServiceRequest request, CancellationToken token = default) + public async Task> GetInfosPaginatedAsync(FileRequest request, CancellationToken token = default) { - var query = GetQuery(request, token); - var firstFile = query.FirstOrDefault(); var skip = request.Skip ?? 0; var take = request.Take ?? 32; - if (firstFile is null) - return new PaginationContainer() - { - Skip = skip, - Take = take, - Count = 0, - }; + var query = BuildQuery(request); - var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; - var count = await query.CountAsync(token).ConfigureAwait(false); - var result = new PaginationContainer(count) + var result = new PaginationContainer() { Skip = skip, Take = take, - Count = count, + Count = await query.CountAsync(token), }; - if (count <= skip) + if (result.Count == 0) 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) + .SkipTake(skip, take) + .AsNoTracking() + .ToListAsync(token) .ConfigureAwait(false); - var dtos = entities.Select(e => Convert(e, timezoneOffset)); - result.Items.AddRange(dtos); + result.Items = entities.Select(e => Convert(e)).ToList(); + return result; } public async Task> GetInfoByIdsAsync(IEnumerable idsFile, CancellationToken token) { - var result = new List(); + var result = Enumerable.Empty(); var entities = await dbSetConfigured .AsNoTracking() @@ -95,14 +131,8 @@ namespace AsbCloudInfrastructure.Repository .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)); - } + if (entities is not null) + result = entities.Select(entity => Convert(entity)); return result; } @@ -140,7 +170,7 @@ namespace AsbCloudInfrastructure.Repository .FirstOrDefaultAsync(f => f.FileMarks.Any(m => m.Id == idMark), token) .ConfigureAwait(false); - FileInfoDto dto = Convert(entity); + FileInfoDto dto = Convert(entity!); return dto; } @@ -178,26 +208,13 @@ namespace AsbCloudInfrastructure.Repository return await db.SaveChangesAsync(token); } - public async Task> GetInfosByWellIdAsync(FileServiceRequest request, CancellationToken token) - { - var query = GetQuery(request, token); - - var entities = await query - .AsNoTracking() - .ToListAsync(token) - .ConfigureAwait(false); - - var dtos = entities.Select(e => Convert(e)); - return dtos; - } - public async Task> GetAllAsync(CancellationToken token) => await dbSetConfigured.AsNoTracking() .Select(x => Convert(x)) .ToListAsync(token) .ConfigureAwait(false); - public async Task GetOrDefaultAsync(int id, CancellationToken token) + public async Task GetOrDefaultAsync(int id, CancellationToken token) { var entity = await dbSetConfigured .AsNoTracking() @@ -205,24 +222,20 @@ namespace AsbCloudInfrastructure.Repository .ConfigureAwait(false); if (entity is null) - { - throw new FileNotFoundException($"fileId:{id} not found"); - } + return null; var dto = Convert(entity); return dto; } - public FileInfoDto GetOrDefault(int id) + public FileInfoDto? GetOrDefault(int id) { var entity = dbSetConfigured .AsNoTracking() .FirstOrDefault(f => f.Id == id); if (entity is null) - { - throw new FileNotFoundException($"fileId:{id} not found"); - } + return null; var dto = Convert(entity); return dto; @@ -230,7 +243,7 @@ namespace AsbCloudInfrastructure.Repository public async Task InsertAsync(FileInfoDto newItem, CancellationToken token) { - var fileInfo = new AsbCloudDb.Model.FileInfo() + var fileInfo = new FileInfo() { IdWell = newItem.IdWell, IdAuthor = newItem.IdAuthor, @@ -261,50 +274,13 @@ namespace AsbCloudInfrastructure.Repository throw new NotImplementedException(); } - private IQueryable GetQuery(FileServiceRequest request, CancellationToken token = default) - { - var query = dbSetConfigured - .Where(e => e.IdWell == request.IdWell && - e.IdCategory == request.IdCategory); - - if (request.IsDeleted is not null) - query = query.Where(x => x.IsDeleted == request.IsDeleted); - - if (request.CompanyName is not null) - query = query.Where(e => (e.Author == null) || - (e.Author.Company == null) || - e.Author.Company.Caption.Contains(request.CompanyName)); - - if (request.FileName is not null) - query = query.Where(e => e.Name.ToLower().Contains(request.FileName.ToLower())); - - var firstFile = query.FirstOrDefault(); - if (firstFile is null) - return Enumerable.Empty().AsQueryable(); - - var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5; - if (request.Begin is not null) - { - var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate >= beginUtc); - } - - if (request.End is not null) - { - var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffset); - query = query.Where(e => e.UploadDate <= endUtc); - } - - return query; - } - - private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity) + private static FileInfoDto Convert(FileInfo entity) { var timezoneOffset = entity.Well.Timezone?.Hours ?? 5; return Convert(entity, timezoneOffset); } - private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity, double timezoneOffset) + private static FileInfoDto Convert(FileInfo entity, double timezoneOffset) { var dto = entity.Adapt(); dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset); diff --git a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs index 0d7a2cf8..8bd61e2f 100644 --- a/AsbCloudInfrastructure/Repository/FileStorageRepository.cs +++ b/AsbCloudInfrastructure/Repository/FileStorageRepository.cs @@ -1,13 +1,10 @@ using AsbCloudApp.Data; -using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; -using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using FileInfo = System.IO.FileInfo; namespace AsbCloudInfrastructure.Repository { @@ -102,10 +99,8 @@ namespace AsbCloudInfrastructure.Repository var allFilesPath = GetFilesPath(idWell); foreach (var filePath in allFilesPath) - { - int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile); - result.Add(idFile); - } + if(int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile)) + result.Add(idFile); return result; } @@ -118,7 +113,8 @@ namespace AsbCloudInfrastructure.Repository private static void CreateDirectory(string filePath) { - Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + var directoryName = Path.GetDirectoryName(filePath)!; + Directory.CreateDirectory(directoryName); } } #nullable disable diff --git a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs index ca0827b0..e926a886 100644 --- a/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs +++ b/AsbCloudInfrastructure/Services/DrillingProgram/DrillingProgramService.cs @@ -282,7 +282,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram fileMarkDto.IdMarkType != idMarkTypeReject) throw new ArgumentInvalidException($"В этом методе допустимы только отметки о принятии или отклонении.", nameof(fileMarkDto)); - var fileInfo = await fileService.GetInfoAsync(fileMarkDto.IdFile, token) + var fileInfo = await fileService.GetOrDefaultAsync(fileMarkDto.IdFile, token) .ConfigureAwait(false); if (fileInfo is null) @@ -357,7 +357,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token) { - var file = await fileService.GetInfoAsync(fileMark.IdFile, token); + var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token); var well = await wellService.GetOrDefaultAsync(file.IdWell, token); var user = file.Author; var factory = new DrillingMailBodyFactory(configuration); @@ -369,7 +369,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token) { - var file = await fileService.GetInfoAsync(fileMark.IdFile, token); + var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token); var well = await wellService.GetOrDefaultAsync(file.IdWell, token); var user = file.Author; var factory = new DrillingMailBodyFactory(configuration); @@ -473,7 +473,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram var well = await wellService.GetOrDefaultAsync(idWell, token); var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx"; var tempResultFilePath = Path.Combine(Path.GetTempPath(), "drillingProgram", resultFileName); - var mailService = new EmailService(backgroundWorker, configuration); async Task funcProgramMake(string id, CancellationToken token) { var contextOptions = new DbContextOptionsBuilder() diff --git a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs index 62d82522..4d44f38c 100644 --- a/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs +++ b/AsbCloudInfrastructure/Services/WellFinalDocumentsService.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Exceptions; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Repository; @@ -96,7 +97,7 @@ namespace AsbCloudInfrastructure.Services .Select(g => g.Key); var files = (await fileService - .GetInfosByWellIdAsync(idWell, token) + .GetInfosAsync(new FileRequest { IdWell = idWell}, token) .ConfigureAwait(false)) .Where(f => categoriesIds.Contains(f.IdCategory)) .ToArray(); @@ -162,7 +163,12 @@ namespace AsbCloudInfrastructure.Services public async Task GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token) { - var files = await fileService.GetInfosByCategoryAsync(idWell, idCategory, token).ConfigureAwait(false); + var request = new FileRequest + { + IdWell = idWell, + IdCategory = idCategory, + }; + var files = await fileService.GetInfosAsync(request, token).ConfigureAwait(false); return new WellFinalDocumentsHistoryDto { IdWell = idWell, diff --git a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs index fa72df35..a1e275b9 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs @@ -220,7 +220,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests { ConfigureNotApproved(); fileServiceMock - .Setup(s => s.GetInfoAsync(It.IsAny(), It.IsAny())) + .Setup(s => s.GetOrDefaultAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(file1002.Adapt())); fileServiceMock @@ -251,7 +251,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests { ConfigureNotApproved(); fileServiceMock - .Setup(s => s.GetInfoAsync(It.IsAny(), It.IsAny())) + .Setup(s => s.GetOrDefaultAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(file1002.Adapt())); fileServiceMock diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs index 4f83e996..698f83cd 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileServiceTest.cs @@ -109,18 +109,12 @@ namespace AsbCloudWebApi.Tests.ServicesTests return Task.FromResult(result); }); - repositoryMock.Setup(x => x.GetInfosByWellIdAsync(It.IsAny(), It.IsAny())) - .Returns((FileServiceRequest request, CancellationToken token) => { + repositoryMock.Setup(x => x.GetInfosAsync(It.IsAny(), It.IsAny())) + .Returns((FileRequest request, CancellationToken token) => { var data = Files.Where(x => x.IdWell == request.IdWell); return Task.FromResult(data); }); - repositoryMock.Setup(x => x.GetInfosByCategoryAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns((int idWell, int idCategory, CancellationToken token) => { - var data = Files.Where(x => x.IdWell == idWell && x.IdCategory == idCategory); - return Task.FromResult(data); - }); - repositoryMock.Setup(x => x.CreateFileMarkAsync(It.IsAny(), It.IsAny(), It.IsAny())) .Returns((FileMarkDto dto, int idUser, CancellationToken token) => { dto.Id = FileMarks.Max(x => x.Id) + 1; @@ -149,9 +143,9 @@ namespace AsbCloudWebApi.Tests.ServicesTests } [Fact] - public async Task GetInfoAsync_returns_FileInfo() + public async Task GetOrDefaultAsync_returns_FileInfo() { - var data = await fileService.GetInfoAsync(1742, CancellationToken.None); + var data = await fileService.GetOrDefaultAsync(1742, CancellationToken.None); Assert.NotNull(data); } @@ -191,20 +185,6 @@ namespace AsbCloudWebApi.Tests.ServicesTests Assert.True(result > 0); } - [Fact] - public async Task GetInfosByWellIdAsync_returns_FileInfo() - { - var data = await fileService.GetInfosByWellIdAsync(90, CancellationToken.None); - Assert.NotNull(data); - } - - [Fact] - public async Task GetInfosByCategoryAsync_returns_FileInfo() - { - var data = await fileService.GetInfosByCategoryAsync(90, 10040, CancellationToken.None); - Assert.NotNull(data); - } - [Fact] public async Task CreateFileMarkAsync() { diff --git a/AsbCloudWebApi/Controllers/FileController.cs b/AsbCloudWebApi/Controllers/FileController.cs index 7d4e395b..d4dfad33 100644 --- a/AsbCloudWebApi/Controllers/FileController.cs +++ b/AsbCloudWebApi/Controllers/FileController.cs @@ -7,8 +7,7 @@ using Microsoft.AspNetCore.Mvc; using System.IO; using System.Threading; using System.Threading.Tasks; -using System.Text; -using static System.Net.WebRequestMethods; +using AsbCloudDb.Model; namespace AsbCloudWebApi.Controllers { @@ -79,19 +78,19 @@ namespace AsbCloudWebApi.Controllers [Permission] [ProducesResponseType(typeof(PaginationContainer), (int)System.Net.HttpStatusCode.OK)] public async Task GetFilesInfoAsync( - [FromQuery] FileServiceRequest request, + [FromQuery] FileRequest request, CancellationToken token = default) { int? idCompany = User.GetCompanyId(); - if (request.IdWell is null || request.IdCategory is null || idCompany is null) + if (request.IdCategory is null || idCompany is null) return Forbid(); if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, - request.IdWell.Value, token).ConfigureAwait(false)) + request.IdWell, token).ConfigureAwait(false)) return Forbid(); - var filesInfo = await fileService.GetInfosAsync(request, token).ConfigureAwait(false); + var filesInfo = await fileService.GetInfosPaginatedAsync(request, token).ConfigureAwait(false); return Ok(filesInfo); } @@ -100,36 +99,33 @@ namespace AsbCloudWebApi.Controllers /// Возвращает файл с диска на сервере /// /// id скважины - /// id запрашиваемого файла + /// id запрашиваемого файла /// Токен отмены задачи /// Запрашиваемый файл [HttpGet] - [Route("{fileId}")] + [Route("{idFile}")] [Permission] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] public async Task GetFileAsync([FromRoute] int idWell, - int fileId, CancellationToken token = default) + int idFile, CancellationToken token = default) { int? idCompany = User.GetCompanyId(); if (idCompany is null) return Forbid(); + var fileInfo = await fileService.GetOrDefaultAsync(idFile, token); + + if (fileInfo is null) + return NotFound(idFile); + if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, - idWell, token).ConfigureAwait(false)) + fileInfo.IdWell, token).ConfigureAwait(false)) return Forbid(); - try - { - var fileInfo = await fileService.GetInfoAsync(fileId, token); - var fileStream = fileService.GetFileStream(fileInfo); + var fileStream = fileService.GetFileStream(fileInfo); - return File(fileStream, "application/octet-stream", fileInfo.Name); - } - catch (FileNotFoundException ex) - { - return NotFound(ex.FileName); - } + return File(fileStream, "application/octet-stream", fileInfo.Name); } /// @@ -151,13 +147,16 @@ namespace AsbCloudWebApi.Controllers int? idCompany = User.GetCompanyId(); - if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, + if (idUser is null || idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token).ConfigureAwait(false)) return Forbid(); - var file = await fileService.GetInfoAsync((int)idFile, token); + var fileInfo = await fileService.GetOrDefaultAsync(idFile, token); - if (!userService.HasPermission((int)idUser, $"File.edit{file.IdCategory}")) + if (fileInfo is null) + return NotFound(idFile); + + if (!userService.HasPermission((int)idUser, $"File.edit{fileInfo?.IdCategory}")) return Forbid(); var result = await fileService.MarkAsDeletedAsync(idFile, token);