using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.Manuals; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using Microsoft.Extensions.Configuration; namespace AsbCloudInfrastructure.Services; public class ManualCatalogService : IManualCatalogService { private readonly IEnumerable validExtensions = new[] { ".pdf", ".mp4" }; private readonly string directoryFiles; private readonly IFileStorageRepository fileStorageRepository; private readonly IManualFolderRepository manualFolderRepository; private readonly IManualRepository manualRepository; private readonly IFileCategoryRepository fileCategoryRepository; public ManualCatalogService(IFileStorageRepository fileStorageRepository, IManualFolderRepository manualFolderRepository, IManualRepository manualRepository, IFileCategoryRepository fileCategoryRepository, IConfiguration configuration) { this.fileStorageRepository = fileStorageRepository; this.manualFolderRepository = manualFolderRepository; this.manualRepository = manualRepository; this.fileCategoryRepository = fileCategoryRepository; directoryFiles = configuration.GetValue("DirectoryManualFiles"); if (string.IsNullOrWhiteSpace(directoryFiles)) directoryFiles = "manuals"; } public async Task SaveFileAsync(int? idCategory, int? idFolder, string name, Stream stream, CancellationToken cancellationToken) { var extension = Path.GetExtension(name); if (!validExtensions.Contains(extension)) throw new ArgumentInvalidException( $"Невозможно загрузить файл с расширением '{extension}'. Допустимые форматы файлов: {string.Join(", ", validExtensions)}", extension); var path = await BuildFilePathAsync(idCategory, idFolder, name, cancellationToken); await fileStorageRepository.SaveFileAsync(path, stream, cancellationToken); var manual = new ManualDto { Name = name, DateDownload = DateTime.UtcNow, IdFolder = idFolder, IdCategory = idCategory }; return await manualRepository.InsertAsync(manual, cancellationToken); } public async Task AddFolderAsync(string name, int? idParent, int idCategory, CancellationToken cancellationToken) { if (idParent.HasValue) { var parent = await manualFolderRepository.GetOrDefaultAsync(idParent.Value, cancellationToken) ?? throw new ArgumentInvalidException("Родительской папки не существует", nameof(idParent)); if (parent.IdCategory != idCategory) throw new ArgumentInvalidException("Категория родительской папки не соответствует текущей категории", nameof(idCategory)); } var manualFolder = new ManualFolderDto { Name = name, IdParent = idParent, IdCategory = idCategory, }; if (await IsExistFolderAsync(manualFolder, cancellationToken)) throw new ArgumentInvalidException("Папка с таким названием уже существует", name); return await manualFolderRepository.InsertAsync(manualFolder, cancellationToken); } public async Task UpdateFolderAsync(int id, string name, CancellationToken cancellationToken) { var folder = await manualFolderRepository.GetOrDefaultAsync(id, cancellationToken) ?? throw new ArgumentInvalidException($"Папки с Id: {id} не сущесвует", nameof(id)); folder.Name = name; if (await IsExistFolderAsync(folder, cancellationToken)) throw new ArgumentInvalidException("Папка с таким названием уже существует", name); await manualFolderRepository.UpdateAsync(folder, cancellationToken); } public async Task DeleteFolderAsync(int id, CancellationToken cancellationToken) { var folder = await manualFolderRepository.GetOrDefaultAsync(id, cancellationToken); if (folder is null) return 0; var path = Path.Combine(directoryFiles, folder.IdCategory.ToString(), folder.Id.ToString()); fileStorageRepository.DeleteDirectory(path); return await manualFolderRepository.DeleteAsync(folder.Id, cancellationToken); } public async Task DeleteFileAsync(int id, CancellationToken cancellationToken) { var manual = await manualRepository.GetOrDefaultAsync(id, cancellationToken); if (manual is null) return 0; var filePath = await BuildFilePathAsync(manual.IdCategory, manual.IdFolder, manual.Name, cancellationToken); fileStorageRepository.DeleteFile(filePath); return await manualRepository.DeleteAsync(manual.Id, cancellationToken); } public async Task<(Stream stream, string fileName)?> GetFileAsync(int id, CancellationToken cancellationToken) { var manual = await manualRepository.GetOrDefaultAsync(id, cancellationToken); if (manual is null) return null; var path = await BuildFilePathAsync(manual.IdCategory, manual.IdFolder, manual.Name, cancellationToken); var fileStream = new FileStream(Path.GetFullPath(path), FileMode.Open); return (fileStream, manual.Name); } public async Task> GetCatalogAsync(CancellationToken cancellationToken) { var catalogItems = new List(); var categories = await fileCategoryRepository.GetAllAsync(FileCategory.IdFileCategoryTypeManuals, cancellationToken); foreach (var category in categories) { catalogItems.Add(new CatalogItemManualDto() { Category = category, ManualsWithoutFolder = await manualRepository.GetManualsWithoutFolderAsync(category.Id, cancellationToken), Folders = await manualFolderRepository.GetTreeAsync(category.Id, cancellationToken) }); } return catalogItems; } private async Task IsExistFolderAsync(ManualFolderDto folder, CancellationToken cancellationToken) { var existingFolder = await manualFolderRepository.GetOrDefaultAsync(folder.Name, folder.IdParent, folder.IdCategory, cancellationToken); return existingFolder is not null && folder.Id != existingFolder.Id; } private async Task BuildFilePathAsync(int? idCategory, int? idFolder, string name, CancellationToken cancellationToken) { if (idFolder.HasValue) { var folder = await manualFolderRepository.GetOrDefaultAsync(idFolder.Value, cancellationToken) ?? throw new ArgumentInvalidException($"Папки с Id: {idFolder} не сущесвует", nameof(idFolder)); return fileStorageRepository.MakeFilePath(directoryFiles, Path.Combine(folder.IdCategory.ToString(), folder.IdParent.ToString() ?? string.Empty, folder.Id.ToString()), name); } if (!idCategory.HasValue) throw new ArgumentInvalidException("Не указан идентификатор категории", nameof(idCategory)); return fileStorageRepository.MakeFilePath(directoryFiles, idCategory.Value.ToString(), name); } }