forked from ddrilling/AsbCloudServer
Добавление логики работы с инструкциями
1. Добавил сервисы и репозитории для инфструкций 2. Добавил контроллеры 3. Обновил конфиг
This commit is contained in:
parent
f94db74d6a
commit
e56530a10f
25
AsbCloudApp/Data/Manuals/CatalogItemManualDto.cs
Normal file
25
AsbCloudApp/Data/Manuals/CatalogItemManualDto.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Data.Manuals;
|
||||
|
||||
/// <summary>
|
||||
/// Элемент каталога инструкций
|
||||
/// </summary>
|
||||
public class CatalogItemManualDto
|
||||
{
|
||||
/// <summary>
|
||||
/// DTO категории
|
||||
/// </summary>
|
||||
public FileCategoryDto Category { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// DTO инструкций хранящиеся без папки
|
||||
/// </summary>
|
||||
public IEnumerable<ManualDto> ManualsWithoutFolder { get; set; } = Enumerable.Empty<ManualDto>();
|
||||
|
||||
/// <summary>
|
||||
/// DTO папок с инструкциями
|
||||
/// </summary>
|
||||
public IEnumerable<ManualFolderDto> Folders { get; set; } = Enumerable.Empty<ManualFolderDto>();
|
||||
}
|
32
AsbCloudApp/Data/Manuals/ManualDto.cs
Normal file
32
AsbCloudApp/Data/Manuals/ManualDto.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Data.Manuals;
|
||||
|
||||
/// <summary>
|
||||
/// DTO инструкции
|
||||
/// </summary>
|
||||
public class ManualDto : IId
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Название
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Дата загрузки
|
||||
/// </summary>
|
||||
public DateTime DateDownload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id папки
|
||||
/// </summary>
|
||||
public int? IdFolder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id категории файла
|
||||
/// </summary>
|
||||
public int? IdCategory { get; set; }
|
||||
}
|
38
AsbCloudApp/Data/Manuals/ManualFolderDto.cs
Normal file
38
AsbCloudApp/Data/Manuals/ManualFolderDto.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Data.Manuals;
|
||||
|
||||
/// <summary>
|
||||
/// DTO папки для хранения инструкций
|
||||
/// </summary>
|
||||
public class ManualFolderDto : IId
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Название
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Id родительской папки
|
||||
/// </summary>
|
||||
public int? IdParent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id категории
|
||||
/// </summary>
|
||||
public int IdCategory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Вложенные папки
|
||||
/// </summary>
|
||||
public IEnumerable<ManualFolderDto> Children { get; set; } = Enumerable.Empty<ManualFolderDto>();
|
||||
|
||||
/// <summary>
|
||||
/// Хранимые инструкции
|
||||
/// </summary>
|
||||
public IEnumerable<ManualDto> Manuals { get; set; } = Enumerable.Empty<ManualDto>();
|
||||
}
|
21
AsbCloudApp/Repositories/IFileCategoryRepository.cs
Normal file
21
AsbCloudApp/Repositories/IFileCategoryRepository.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
|
||||
namespace AsbCloudApp.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Репозиторий для работы с категориями файлов
|
||||
/// </summary>
|
||||
public interface IFileCategoryRepository : ICrudRepository<FileCategoryDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение всех записей по идентификатору типа
|
||||
/// </summary>
|
||||
/// <param name="idType"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<FileCategoryDto>> GetAllAsync(int idType, CancellationToken cancellationToken);
|
||||
}
|
@ -47,6 +47,12 @@ namespace AsbCloudApp.Repositories
|
||||
/// <param name="fileName"></param>
|
||||
void DeleteFile(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление директории
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
void DeleteDirectory(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление всех файлов с диска о которых нет информации в базе
|
||||
/// </summary>
|
||||
|
31
AsbCloudApp/Repositories/IManualFolderRepository.cs
Normal file
31
AsbCloudApp/Repositories/IManualFolderRepository.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Services;
|
||||
|
||||
namespace AsbCloudApp.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Репозиторий для работы с папки хранящими инструкциями
|
||||
/// </summary>
|
||||
public interface IManualFolderRepository : ICrudRepository<ManualFolderDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение дерева каталога папок
|
||||
/// </summary>
|
||||
/// <param name="idCategory"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ManualFolderDto>> GetTreeAsync(int idCategory, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получение одной папки по параметрам
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="idParent"></param>
|
||||
/// <param name="idCategory"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<ManualFolderDto?> GetOrDefaultAsync(string name, int? idParent, int idCategory, CancellationToken cancellationToken);
|
||||
}
|
21
AsbCloudApp/Repositories/IManualRepository.cs
Normal file
21
AsbCloudApp/Repositories/IManualRepository.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Services;
|
||||
|
||||
namespace AsbCloudApp.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Репозиторий для инструкций
|
||||
/// </summary>
|
||||
public interface IManualRepository : ICrudRepository<ManualDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение инструкций, которые не добавлены в папку
|
||||
/// </summary>
|
||||
/// <param name="idCategory"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ManualDto>> GetManualsWithoutFolderAsync(int idCategory, CancellationToken cancellationToken);
|
||||
}
|
76
AsbCloudApp/Services/IManualCatalogService.cs
Normal file
76
AsbCloudApp/Services/IManualCatalogService.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
|
||||
namespace AsbCloudApp.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис для работы c каталогом инструкций
|
||||
/// </summary>
|
||||
public interface IManualCatalogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Сохранение файла
|
||||
/// </summary>
|
||||
/// <param name="idCategory"></param>
|
||||
/// <param name="idFolder"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> SaveFileAsync(int? idCategory, int? idFolder, string name, Stream stream,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Добавление новой папки
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="idParent"></param>
|
||||
/// <param name="idCategory"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> AddFolderAsync(string name, int? idParent, int idCategory,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Обновление папки
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task UpdateFolderAsync(int id, string name, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление папки
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteFolderAsync(int id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление файла
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteFileAsync(int id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получение файла
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<(Stream stream, string fileName)?> GetFileAsync(int id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получение каталога
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<CatalogItemManualDto>> GetCatalogAsync(CancellationToken cancellationToken);
|
||||
}
|
@ -221,6 +221,11 @@ namespace AsbCloudInfrastructure
|
||||
|
||||
services.AddTransient<IAutoGeneratedDailyReportService, AutoGeneratedDailyReportService>();
|
||||
services.AddTransient<IAutoGeneratedDailyReportMakerService, AutoGeneratedDailyReportMakerService>();
|
||||
|
||||
services.AddTransient<IManualFolderRepository, ManualFolderRepository>();
|
||||
services.AddTransient<IManualCatalogService, ManualCatalogService>();
|
||||
services.AddTransient<IManualRepository, ManualRepository>();
|
||||
services.AddTransient<IFileCategoryRepository, FileCategoryRepository>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
32
AsbCloudInfrastructure/Repository/FileCategoryRepository.cs
Normal file
32
AsbCloudInfrastructure/Repository/FileCategoryRepository.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb.Model;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class FileCategoryRepository : CrudCacheRepositoryBase<FileCategoryDto, FileCategory>, IFileCategoryRepository
|
||||
{
|
||||
public FileCategoryRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache) : base(dbContext, memoryCache)
|
||||
{
|
||||
}
|
||||
|
||||
public FileCategoryRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache,
|
||||
Func<DbSet<FileCategory>, IQueryable<FileCategory>> makeQuery) : base(dbContext, memoryCache, makeQuery)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<FileCategoryDto>> GetAllAsync(int idType, CancellationToken cancellationToken)
|
||||
{
|
||||
return await dbContext.FileCategories.Where(f => f.IdType == idType)
|
||||
.Select(f => f.Adapt<FileCategoryDto>())
|
||||
.ToArrayAsync(cancellationToken);
|
||||
}
|
||||
}
|
@ -33,6 +33,21 @@ public class FileStorageRepository : IFileStorageRepository
|
||||
DeleteFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteDirectory(string path)
|
||||
{
|
||||
var fullPath = Path.Combine(RootPath, path);
|
||||
|
||||
if (!Directory.Exists(fullPath))
|
||||
return;
|
||||
|
||||
foreach (var file in Directory.GetFiles(fullPath))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
Directory.Delete(fullPath, true);
|
||||
}
|
||||
|
||||
public void DeleteFile(string fileName)
|
||||
{
|
||||
|
62
AsbCloudInfrastructure/Repository/ManualFolderRepository.cs
Normal file
62
AsbCloudInfrastructure/Repository/ManualFolderRepository.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Manuals;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class ManualFolderRepository : CrudRepositoryBase<ManualFolderDto, ManualFolder>, IManualFolderRepository
|
||||
{
|
||||
public ManualFolderRepository(IAsbCloudDbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ManualFolderDto>> GetTreeAsync(int idCategory,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var folders = await dbContext.ManualFolders
|
||||
.Where(m => m.IdCategory == idCategory)
|
||||
.AsNoTracking()
|
||||
.Include(m => m.Manuals)
|
||||
.Include(m => m.Parent)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return BuildTree(folders).Select(x => x.Adapt<ManualFolderDto>());
|
||||
}
|
||||
|
||||
public async Task<ManualFolderDto?> GetOrDefaultAsync(string name, int? idParent, int idCategory,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await dbContext.ManualFolders
|
||||
.FirstOrDefaultAsync(m => m.Name == name &&
|
||||
m.IdCategory == idCategory &&
|
||||
m.IdParent == idParent, cancellationToken);
|
||||
|
||||
if (entity is null)
|
||||
return null;
|
||||
|
||||
return Convert(entity);
|
||||
}
|
||||
|
||||
private IEnumerable<ManualFolder> BuildTree(IEnumerable<ManualFolder> folders)
|
||||
{
|
||||
var folderDict = folders.ToDictionary(f => f.Id);
|
||||
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
if (folder.IdParent.HasValue && folderDict.TryGetValue(folder.IdParent.Value, out var parent))
|
||||
{
|
||||
parent.Children ??= new List<ManualFolder>();
|
||||
parent.Children.Add(folder);
|
||||
}
|
||||
}
|
||||
|
||||
return folders.Where(f => f.IdParent == null);
|
||||
}
|
||||
}
|
33
AsbCloudInfrastructure/Repository/ManualRepository.cs
Normal file
33
AsbCloudInfrastructure/Repository/ManualRepository.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.Manuals;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Manuals;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class ManualRepository : CrudRepositoryBase<ManualDto, Manual>, IManualRepository
|
||||
{
|
||||
public ManualRepository(IAsbCloudDbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public ManualRepository(IAsbCloudDbContext context, Func<DbSet<Manual>, IQueryable<Manual>> makeQuery)
|
||||
: base(context, makeQuery)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ManualDto>> GetManualsWithoutFolderAsync(int idCategory, CancellationToken cancellationToken)
|
||||
{
|
||||
return await dbContext.Manuals.Where(m => m.IdCategory == idCategory &&
|
||||
m.IdFolder == null)
|
||||
.Select(m => m.Adapt<ManualDto>())
|
||||
.ToArrayAsync(cancellationToken);
|
||||
}
|
||||
}
|
202
AsbCloudInfrastructure/Services/ManualCatalogService.cs
Normal file
202
AsbCloudInfrastructure/Services/ManualCatalogService.cs
Normal file
@ -0,0 +1,202 @@
|
||||
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<string> 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<string>("DirectoryManualFiles");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(directoryFiles))
|
||||
directoryFiles = "manuals";
|
||||
}
|
||||
|
||||
public async Task<int> 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<int> 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<int> 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<int> 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<IEnumerable<CatalogItemManualDto>> GetCatalogAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var catalogItems = new List<CatalogItemManualDto>();
|
||||
|
||||
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<bool> 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<string> 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);
|
||||
}
|
||||
}
|
120
AsbCloudWebApi/Controllers/ManualController.cs
Normal file
120
AsbCloudWebApi/Controllers/ManualController.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ManualController : ControllerBase
|
||||
{
|
||||
private readonly IManualCatalogService manualCatalogService;
|
||||
private readonly IUserRepository userRepository;
|
||||
|
||||
public ManualController(IManualCatalogService manualCatalogService,
|
||||
IUserRepository userRepository)
|
||||
{
|
||||
this.manualCatalogService = manualCatalogService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение файла
|
||||
/// </summary>
|
||||
/// <param name="idCategory">Необязательный параметр. 30000 - АСУ ТП, 30001 - Технология бурения</param>
|
||||
/// <param name="idFolder">Необязательный параметр. Id папки</param>
|
||||
/// <param name="file">Загружаемый файл</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> SaveFileAsync(
|
||||
[Range(minimum: 30000, maximum: 30001, ErrorMessage = "Категория файла недопустима. Допустимые: 30000, 30001")]
|
||||
int? idCategory,
|
||||
int? idFolder,
|
||||
[Required] IFormFile file,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if(!CanUserAccess("Manual.edit"))
|
||||
return Forbid();
|
||||
|
||||
using var fileStream = file.OpenReadStream();
|
||||
|
||||
var id = await manualCatalogService.SaveFileAsync(idCategory, idFolder, file.FileName, fileStream, cancellationToken);
|
||||
|
||||
return Ok(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение файла
|
||||
/// </summary>
|
||||
/// <param name="id">Id инструкции</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id:int}")]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetFileAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
if(!CanUserAccess("Manual.view"))
|
||||
return Forbid();
|
||||
|
||||
var file = await manualCatalogService.GetFileAsync(id, cancellationToken);
|
||||
|
||||
if (!file.HasValue)
|
||||
return NoContent();
|
||||
|
||||
return File(file.Value.stream, "application/octet-stream", file.Value.fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаление файла
|
||||
/// </summary>
|
||||
/// <param name="id">Id инструкции</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> DeleteFileAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
if(!CanUserAccess("Manual.edit"))
|
||||
return Forbid();
|
||||
|
||||
return Ok(await manualCatalogService.DeleteFileAsync(id, cancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение каталога с инструкциями
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> GetCatalogAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if(!CanUserAccess("Manual.view"))
|
||||
return Forbid();
|
||||
|
||||
return Ok(await manualCatalogService.GetCatalogAsync(cancellationToken));
|
||||
}
|
||||
|
||||
private bool CanUserAccess(string permission)
|
||||
{
|
||||
var idUser = User.GetUserId();
|
||||
|
||||
return idUser.HasValue && userRepository.HasPermission(idUser.Value, permission);
|
||||
}
|
||||
}
|
94
AsbCloudWebApi/Controllers/ManualFolderController.cs
Normal file
94
AsbCloudWebApi/Controllers/ManualFolderController.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
namespace AsbCloudWebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ManualFolderController : ControllerBase
|
||||
{
|
||||
private readonly IManualCatalogService manualCatalogService;
|
||||
private readonly IUserRepository userRepository;
|
||||
|
||||
public ManualFolderController(IManualCatalogService manualCatalogService,
|
||||
IUserRepository userRepository)
|
||||
{
|
||||
this.manualCatalogService = manualCatalogService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание папки
|
||||
/// </summary>
|
||||
/// <param name="name">Название</param>
|
||||
/// <param name="idParent">Необязательный параметр. Id родительской папки</param>
|
||||
/// <param name="idCategory">Id категории. 30000 - АСУ ТП, 30001 - Технология бурения</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> AddFolderAsync(string name, int? idParent,
|
||||
[Required(ErrorMessage = "Обязательный параметр")]
|
||||
[Range(minimum: 30000, maximum: 30001, ErrorMessage = "Категория файла недопустима. Допустимые: 30000, 30001")]
|
||||
int idCategory,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!CanUserAccess())
|
||||
Forbid();
|
||||
|
||||
return Ok(await manualCatalogService.AddFolderAsync(name, idParent, idCategory, cancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновление папки
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="name">Новое название папки</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
[Permission]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> UpdateFolderAsync(int id, string name, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!CanUserAccess())
|
||||
Forbid();
|
||||
|
||||
await manualCatalogService.UpdateFolderAsync(id, name, cancellationToken);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удаление папки
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<IActionResult> DeleteFolderAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!CanUserAccess())
|
||||
Forbid();
|
||||
|
||||
return Ok(await manualCatalogService.DeleteFolderAsync(id, cancellationToken));
|
||||
}
|
||||
|
||||
private bool CanUserAccess()
|
||||
{
|
||||
var idUser = User.GetUserId();
|
||||
|
||||
return idUser.HasValue && userRepository.HasPermission(idUser.Value, "Manual.edit");
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"supportMail": "support@digitaldrilling.ru"
|
||||
},
|
||||
"DirectoryNameHelpPageFiles": "helpPages",
|
||||
"DirectoryManualFiles": "manuals",
|
||||
"Urls": "http://0.0.0.0:5000" //;https://0.0.0.0:5001" //,
|
||||
// See https man: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0
|
||||
//"Kestrel": {
|
||||
|
Loading…
Reference in New Issue
Block a user