forked from ddrilling/AsbCloudServer
176 lines
6.6 KiB
C#
176 lines
6.6 KiB
C#
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 Microsoft.Extensions.Configuration;
|
||
|
||
namespace AsbCloudInfrastructure.Services;
|
||
|
||
public class ManualCatalogService : IManualCatalogService
|
||
{
|
||
private const int IdFileCategory = 30000;
|
||
|
||
private readonly IEnumerable<string> validExtensions = new[]
|
||
{
|
||
".pdf",
|
||
".mp4"
|
||
};
|
||
|
||
private readonly string directoryFiles;
|
||
private readonly IFileStorageRepository fileStorageRepository;
|
||
private readonly IManualDirectoryRepository manualDirectoryRepository;
|
||
private readonly ICrudRepository<ManualDto> manualRepository;
|
||
|
||
public ManualCatalogService(IFileStorageRepository fileStorageRepository,
|
||
IManualDirectoryRepository manualDirectoryRepository,
|
||
ICrudRepository<ManualDto> manualRepository,
|
||
IConfiguration configuration)
|
||
{
|
||
this.fileStorageRepository = fileStorageRepository;
|
||
this.manualDirectoryRepository = manualDirectoryRepository;
|
||
this.manualRepository = manualRepository;
|
||
directoryFiles = configuration.GetValue<string>("DirectoryManualFiles", "manuals")!;
|
||
}
|
||
|
||
public async Task<int> SaveFileAsync(int idDirectory, int idAuthor, string name, Stream stream, CancellationToken cancellationToken)
|
||
{
|
||
var extension = Path.GetExtension(name);
|
||
|
||
if (!validExtensions.Contains(extension))
|
||
throw new ArgumentInvalidException(
|
||
nameof(name),
|
||
$"Невозможно загрузить файл с расширением '{extension}'. Допустимые форматы файлов: {string.Join(", ", validExtensions)}");
|
||
|
||
var path = await BuildFilePathAsync(idDirectory, name, cancellationToken);
|
||
|
||
await fileStorageRepository.SaveFileAsync(path, stream, cancellationToken);
|
||
|
||
var manual = new ManualDto
|
||
{
|
||
Name = name,
|
||
DateDownload = DateTimeOffset.UtcNow,
|
||
IdDirectory = idDirectory,
|
||
IdCategory = IdFileCategory,
|
||
IdAuthor = idAuthor
|
||
};
|
||
|
||
return await manualRepository.InsertAsync(manual, cancellationToken);
|
||
}
|
||
|
||
public async Task<int> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||
{
|
||
if (idParent.HasValue && !await manualDirectoryRepository.IsExistsAsync(idParent.Value, cancellationToken))
|
||
throw new ArgumentInvalidException(nameof(idParent), "Родительской директории не существует");
|
||
|
||
var directory = new ManualDirectoryDto
|
||
{
|
||
Name = name,
|
||
IdParent = idParent,
|
||
};
|
||
|
||
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||
throw new ArgumentInvalidException(name, "Директория с таким названием уже существует");
|
||
|
||
return await manualDirectoryRepository.InsertAsync(directory, cancellationToken);
|
||
}
|
||
|
||
public async Task UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken)
|
||
{
|
||
var directory = await manualDirectoryRepository.GetOrDefaultAsync(id, cancellationToken)
|
||
?? throw new ArgumentInvalidException(nameof(id), $"Директории с Id: {id} не существует");
|
||
|
||
directory.Name = name;
|
||
|
||
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||
throw new ArgumentInvalidException(name, "Директория с таким названием уже существует");
|
||
|
||
await manualDirectoryRepository.UpdateAsync(directory, cancellationToken);
|
||
}
|
||
|
||
public async Task<int> DeleteDirectoryAsync(int id, CancellationToken cancellationToken)
|
||
{
|
||
var directory = await manualDirectoryRepository.GetOrDefaultAsync(id, cancellationToken);
|
||
|
||
if (directory is null)
|
||
return 0;
|
||
|
||
var path = fileStorageRepository.MakeFilePath(directoryFiles, IdFileCategory.ToString(),
|
||
await BuildDirectoryPathAsync(id, cancellationToken));
|
||
|
||
try
|
||
{
|
||
fileStorageRepository.DeleteDirectory(path, true);
|
||
}
|
||
catch (InvalidOperationException ex)
|
||
{
|
||
throw new ArgumentInvalidException(nameof(id), ex.Message);
|
||
}
|
||
|
||
return await manualDirectoryRepository.DeleteAsync(directory.Id, cancellationToken);
|
||
}
|
||
|
||
public async Task<int> DeleteFileAsync(int id, CancellationToken cancellationToken)
|
||
{
|
||
var manual = await manualRepository.GetOrDefaultAsync(id, cancellationToken);
|
||
|
||
if (manual is null)
|
||
return 0;
|
||
|
||
var filePath = await BuildFilePathAsync(manual.IdDirectory, 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.IdDirectory, manual.Name, cancellationToken);
|
||
var fileStream = new FileStream(path, FileMode.Open);
|
||
return (fileStream, manual.Name);
|
||
}
|
||
|
||
private async Task<bool> IsExistDirectoryAsync(ManualDirectoryDto directory, CancellationToken cancellationToken)
|
||
{
|
||
var existingDirectory = await manualDirectoryRepository.GetOrDefaultAsync(directory.Name, directory.IdParent,
|
||
cancellationToken);
|
||
|
||
return existingDirectory is not null && directory.Id != existingDirectory.Id;
|
||
}
|
||
|
||
private async Task<string> BuildDirectoryPathAsync(int idDirectory, CancellationToken cancellationToken)
|
||
{
|
||
var directiories = await manualDirectoryRepository.GetAllAsync(cancellationToken);
|
||
|
||
var directory = directiories.FirstOrDefault(d => d.Id == idDirectory)
|
||
?? throw new ArgumentInvalidException(nameof(idDirectory), $"Директории с Id: {idDirectory} не существует");
|
||
|
||
var pathSegments = new List<int> { directory.Id };
|
||
|
||
while (directory.IdParent.HasValue)
|
||
{
|
||
directory = directiories.FirstOrDefault(d => d.Id == directory.IdParent.Value);
|
||
pathSegments.Insert(0, directory!.Id);
|
||
}
|
||
|
||
return string.Join("/", pathSegments);
|
||
}
|
||
|
||
private async Task<string> BuildFilePathAsync(int idDirectory, string name, CancellationToken cancellationToken)
|
||
{
|
||
var directoryPath = await BuildDirectoryPathAsync(idDirectory, cancellationToken);
|
||
|
||
return fileStorageRepository.MakeFilePath(directoryFiles, IdFileCategory.ToString(), Path.Combine(directoryPath, name));
|
||
}
|
||
} |