file service вынесен в bll. EsppDataController UploadTemplates
This commit is contained in:
@@ -1,19 +1,27 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using PARR.API.Contracts.V1;
|
||||
using PARR.API.Contracts.V1.Responses.Base;
|
||||
using PARR.API.Controllers.V1.Base;
|
||||
using PARR.API.Services.Interfaces;
|
||||
using PARR.BLL.Services.Interfaces;
|
||||
using PARR.BLL.Settings;
|
||||
|
||||
namespace PARR.API.Controllers.V1
|
||||
{
|
||||
public class EsppDataController : BaseApiController
|
||||
{
|
||||
private readonly IFileService fileService;
|
||||
private readonly StorageSettings storageSettings;
|
||||
|
||||
public EsppDataController(ILogger<EsppDataController> logger, IFileService fileService)
|
||||
public EsppDataController(
|
||||
ILogger<EsppDataController> logger,
|
||||
IFileService fileService,
|
||||
StorageSettings storageSettings
|
||||
)
|
||||
{
|
||||
Logger = logger;
|
||||
this.fileService = fileService;
|
||||
this.storageSettings = storageSettings;
|
||||
}
|
||||
|
||||
public ILogger<EsppDataController> Logger { get; }
|
||||
@@ -23,9 +31,24 @@ namespace PARR.API.Controllers.V1
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost(ApiRoutes.EsppData.UploadTemplates)]
|
||||
public IActionResult UploadTemplates([BindRequired] IFormFile file)
|
||||
public async Task<IActionResult> UploadTemplates([BindRequired] IFormFile file)
|
||||
{
|
||||
return Ok();
|
||||
if (!fileService.IsExtensionAllowed(file, storageSettings.EsppTemplates!.AllowedExtensions))
|
||||
return BadRequest(
|
||||
new Response(false,
|
||||
new List<ErrorModel> {
|
||||
new ErrorModel {
|
||||
Message = $"Недопустимое расширение файла. Разрешенные расширения: {string.Join(", ", storageSettings.EsppTemplates.AllowedExtensions)}"
|
||||
} }));
|
||||
|
||||
if (!fileService.IsNotExceededLimit(file, storageSettings.EsppTemplates.MaxFileSizeMb))
|
||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(file), Message = $"Размер файла превышает {storageSettings.EsppTemplates.MaxFileSizeMb} МБайт" } }));
|
||||
|
||||
var uploadResult = await fileService.UploadAsync(file, storageSettings.EsppTemplates.TemplatePath);
|
||||
if (uploadResult == null)
|
||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при сохранении файла" } }));
|
||||
|
||||
return Ok(new Response<string>("", true, new List<ErrorModel>(), $"Файл загружен."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
PARR.API/Domain/.gitkeep
Normal file
17
PARR.API/Domain/.gitkeep
Normal file
@@ -0,0 +1,17 @@
|
||||
Import System.Runtime.InteropServices
|
||||
|
||||
' In SDK-style projects such as this one, several assembly attributes that were historically
|
||||
' defined in this file are now automatically added during build and populated with
|
||||
' values defined in project properties. For details of which attributes are included
|
||||
' and how to customise this process see: https://aka.ms/assembly-info-properties
|
||||
|
||||
|
||||
' Setting ComVisible to false makes the types in this assembly not visible to COM
|
||||
' components. If you need to access a type in this assembly from COM, set the ComVisible
|
||||
' attribute to true on that type.
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
' The following GUID is for the ID of the typelib if this project is exposed to COM.
|
||||
|
||||
<Assembly: Guid("b369a17a-5b45-4482-9c44-bceb865427d2")>
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace PARR.API.Domain
|
||||
{
|
||||
public class UploadResult
|
||||
{
|
||||
public required string FileName { get; set; }
|
||||
public required string Path { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace PARR.API.Installers
|
||||
});
|
||||
|
||||
services.AddTransient<IClientService, ClientService>();
|
||||
services.AddTransient<IFileService, FileService>();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace PARR.API.Installers
|
||||
{
|
||||
public static void InstallSettings(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var storageSettings = new StorageSettings();
|
||||
configuration.GetSection(nameof(StorageSettings)).Bind(storageSettings);
|
||||
services.AddSingleton(storageSettings);
|
||||
//var storageSettings = new StorageSettings();
|
||||
//configuration.GetSection(nameof(StorageSettings)).Bind(storageSettings);
|
||||
//services.AddSingleton(storageSettings);
|
||||
|
||||
//TODO: add other
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PARR.BLL\PARR.BLL.csproj" />
|
||||
<ProjectReference Include="..\PARR.DAL\PARR.DAL.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Domain\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
using PARR.API.Domain;
|
||||
using PARR.API.Services.Interfaces;
|
||||
using PARR.API.Settings;
|
||||
|
||||
namespace PARR.API.Services.Implementations
|
||||
{
|
||||
public class FileService : IFileService
|
||||
{
|
||||
private readonly StorageSettings storageSettings;
|
||||
private readonly ILogger<FileService> logger;
|
||||
|
||||
public FileService(StorageSettings storageSettings, ILogger<FileService> logger)
|
||||
{
|
||||
this.storageSettings = storageSettings;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public bool IsExtensionAllowed(IFormFile formFile, string[] allowedExtensions)
|
||||
{
|
||||
var extension = Path.GetExtension(formFile.FileName).ToLower();
|
||||
|
||||
return !string.IsNullOrEmpty(extension) && allowedExtensions.Contains(extension);
|
||||
}
|
||||
|
||||
public bool IsNotExceededLimit(IFormFile formFile, int limitMb)
|
||||
{
|
||||
var fileSizeByte = formFile.Length;
|
||||
var fileSizeMByte = fileSizeByte / 1024.0 / 1024.0;
|
||||
|
||||
return fileSizeMByte < limitMb;
|
||||
}
|
||||
|
||||
public async Task<UploadResult?> UploadAsync(IFormFile formFile, string[] rootFolderWithoutStorage)
|
||||
{
|
||||
InitRootFolders(rootFolderWithoutStorage);
|
||||
|
||||
//Генерим уникальное имя файла: старое имя + рандом в середину
|
||||
var newFileName = $"{Path.GetFileNameWithoutExtension(formFile.FileName)}-{Path.GetFileNameWithoutExtension(Path.GetRandomFileName())}{Path.GetExtension(formFile.FileName)}";
|
||||
|
||||
|
||||
var relativePath = Path.Combine(Path.Combine(rootFolderWithoutStorage), newFileName);
|
||||
var absPath = Path.Combine(storageSettings.StoragePath, relativePath);
|
||||
|
||||
if (File.Exists(absPath))
|
||||
{
|
||||
logger.LogError($"Не могу сохранить файл, такой файл уже существует: {absPath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var origFileName = Path.GetFileName(formFile.FileName);
|
||||
|
||||
using (var stream = new FileStream(absPath, FileMode.Create))
|
||||
{
|
||||
await formFile.CopyToAsync(stream);
|
||||
logger.LogInformation($"Файл сохранен {origFileName}, {absPath}");
|
||||
}
|
||||
|
||||
return new UploadResult { FileName = origFileName, Path = relativePath };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, $"Ошибка при сохранении файла {absPath}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitRootFolders(string[] rootFolderWithoutStorage)
|
||||
{
|
||||
if (!rootFolderWithoutStorage.Any())
|
||||
return;
|
||||
|
||||
var path = string.Empty;
|
||||
foreach (var item in rootFolderWithoutStorage)
|
||||
{
|
||||
path = Path.Combine(path, item);
|
||||
CreateDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateDirectory(string relativePath)
|
||||
{
|
||||
var absolutePath = Path.Combine(storageSettings.StoragePath, relativePath);
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(absolutePath))
|
||||
Directory.CreateDirectory(absolutePath);
|
||||
|
||||
// не нужно ничего возвращать, при сохраненнии файла будет ошибка и ее обработаем
|
||||
//return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, $"Не могу создать директорию: {absolutePath}");
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using PARR.API.Domain;
|
||||
|
||||
namespace PARR.API.Services.Interfaces
|
||||
{
|
||||
public interface IFileService
|
||||
{
|
||||
Task<UploadResult?> UploadAsync(IFormFile formFile, string[] rootFolderWithoutStorage);
|
||||
|
||||
/// <summary>
|
||||
/// Размер файла не превышает лимит?
|
||||
/// </summary>
|
||||
/// <param name="formFile"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <returns></returns>
|
||||
bool IsNotExceededLimit(IFormFile formFile, int limitMb);
|
||||
|
||||
/// <summary>
|
||||
/// Разрешено это расширение?
|
||||
/// </summary>
|
||||
/// <param name="formFile"></param>
|
||||
/// <param name="allowedExtensions"></param>
|
||||
/// <returns></returns>
|
||||
bool IsExtensionAllowed(IFormFile formFile, string[] allowedExtensions);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace PARR.API.Settings
|
||||
{
|
||||
public class StorageSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Путь к хранилищу
|
||||
/// </summary>
|
||||
public string StoragePath { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Настройки хранилища загрузки шаблонов ЕСПП
|
||||
/// </summary>
|
||||
public StorageSettingsEsspTemplates? EsppTemplates { get; set; }
|
||||
}
|
||||
|
||||
public class StorageSettingsEsspTemplates
|
||||
{
|
||||
public string[] TemplatePath => new string[] { "espp-templates" };
|
||||
|
||||
public string[] AllowedExtensions { get; set; } = Array.Empty<string>();
|
||||
|
||||
public int MaxFileSizeMb { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user