#6539681 file storage repository + tests

This commit is contained in:
ai.astrakhantsev 2022-10-06 13:41:46 +05:00
parent f30e2737e7
commit b6ce4cad77
10 changed files with 150 additions and 50 deletions

View File

@ -13,4 +13,12 @@
<ItemGroup> <ItemGroup>
<None Remove="Data\DailyReport\" /> <None Remove="Data\DailyReport\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>
<ItemGroup>
<None Include="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>
</Project> </Project>

View File

@ -14,11 +14,6 @@ namespace AsbCloudApp.Services
/// </summary> /// </summary>
public interface IFileService public interface IFileService
{ {
/// <summary>
/// Директория хранения файлов
/// </summary>
string RootPath { get; }
/// <summary> /// <summary>
/// Сохранить файл /// Сохранить файл
/// </summary> /// </summary>

View File

@ -0,0 +1,51 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
/// <summary>
/// Репозиторий хранения фалов
/// </summary>
public interface IFileStorageRepository
{
/// <summary>
/// Директория хранения файлов
/// </summary>
string RootPath { get; }
/// <summary>
/// Получение длинны фала и проверка его наличия, если отсутствует падает исключение
/// </summary>
/// <param name="srcFilePath"></param>
/// <returns></returns>
long GetLengthFile(string srcFilePath);
/// <summary>
/// Перемещение файла
/// </summary>
/// <param name="srcFilePath"></param>
/// <param name="filePath"></param>
void MoveFile (string srcFilePath, string filePath);
/// <summary>
/// Копирование файла
/// </summary>
/// <returns></returns>
Task CopyFileAsync(string filePath, Stream fileStream, CancellationToken token);
/// <summary>
/// Удаление файла
/// </summary>
/// <param name="fileName"></param>
void DeleteFile(string fileName);
/// <summary>
/// Проверка наличия файла
/// </summary>
/// <param name="fullPath"></param>
/// <param name="fileName"></param>
/// <returns></returns>
bool FileExists(string fullPath, string fileName);
}
}

View File

@ -155,6 +155,7 @@ namespace AsbCloudInfrastructure
.Include(c => c.Wells) .Include(c => c.Wells)
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService .Include(c => c.Deposit))); // может быть включен в сервис ClusterService
services.AddTransient<IFileRepository, FileRepository>(); services.AddTransient<IFileRepository, FileRepository>();
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
// Subsystem service // Subsystem service
services.AddTransient<ICrudService<SubsystemDto>, CrudCacheServiceBase<SubsystemDto, Subsystem>>(); services.AddTransient<ICrudService<SubsystemDto>, CrudCacheServiceBase<SubsystemDto, Subsystem>>();
services.AddTransient<ISubsystemService, SubsystemService>(); services.AddTransient<ISubsystemService, SubsystemService>();

View File

@ -0,0 +1,59 @@
using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
public class FileStorageRepository : IFileStorageRepository
{
public string RootPath { get; private set; }
public FileStorageRepository()
{
RootPath = "files";
}
public async Task CopyFileAsync(string filePath, Stream fileStream, CancellationToken token)
{
CreateDirectory(filePath);
using var newfileStream = new FileStream(filePath, FileMode.Create);
await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false);
}
public void DeleteFile(string fileName)
{
if (File.Exists(fileName))
File.Delete(fileName);
}
public long GetLengthFile(string srcFilePath)
{
if (!File.Exists(srcFilePath))
throw new ArgumentInvalidException($"file {srcFilePath} doesn't exist", nameof(srcFilePath));
var sysFileInfo = new FileInfo(srcFilePath);
return sysFileInfo.Length;
}
public void MoveFile(string srcFilePath, string filePath)
{
CreateDirectory(filePath);
File.Move(srcFilePath, filePath);
}
public bool FileExists(string fullPath, string fileName)
{
if (!File.Exists(fullPath))
throw new FileNotFoundException("not found", fileName);
return true;
}
private void CreateDirectory(string filePath)
{
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
}
}
}

View File

@ -481,7 +481,8 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
.Options; .Options;
using var context = new AsbCloudDbContext(contextOptions); using var context = new AsbCloudDbContext(contextOptions);
var fileRepository = new FileRepository(context); var fileRepository = new FileRepository(context);
var fileService = new FileService(fileRepository); var fileStorageRepository = new FileStorageRepository();
var fileService = new FileService(fileRepository, fileStorageRepository);
var files = state.Parts.Select(p => fileService.GetUrl(p.File)); var files = state.Parts.Select(p => fileService.GetUrl(p.File));
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well); DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token); await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token);

View File

@ -16,13 +16,13 @@ namespace AsbCloudInfrastructure.Services
{ {
public class FileService : IFileService public class FileService : IFileService
{ {
public string RootPath { get; private set; }
private readonly IFileRepository fileRepository; private readonly IFileRepository fileRepository;
private readonly IFileStorageRepository fileStorageRepository;
public FileService(IFileRepository fileRepository) public FileService(IFileRepository fileRepository, IFileStorageRepository fileStorageRepository)
{ {
RootPath = "files";
this.fileRepository = fileRepository; this.fileRepository = fileRepository;
this.fileStorageRepository = fileStorageRepository;
} }
public async Task<FileInfoDto> MoveAsync(int idWell, int? idUser, int idCategory, public async Task<FileInfoDto> MoveAsync(int idWell, int? idUser, int idCategory,
@ -30,10 +30,7 @@ namespace AsbCloudInfrastructure.Services
{ {
destinationFileName = Path.GetFileName(destinationFileName); destinationFileName = Path.GetFileName(destinationFileName);
srcFilePath = Path.GetFullPath(srcFilePath); srcFilePath = Path.GetFullPath(srcFilePath);
if (!File.Exists(srcFilePath)) var fileSize = fileStorageRepository.GetLengthFile(srcFilePath);
throw new ArgumentInvalidException($"file {srcFilePath} doesn't exist", nameof(srcFilePath));
var sysFileInfo = new System.IO.FileInfo(srcFilePath);
//save info to db //save info to db
var dto = new FileInfoDto { var dto = new FileInfoDto {
@ -41,14 +38,13 @@ namespace AsbCloudInfrastructure.Services
IdAuthor = idUser, IdAuthor = idUser,
IdCategory = idCategory, IdCategory = idCategory,
Name = destinationFileName, Name = destinationFileName,
Size = sysFileInfo.Length Size = fileSize
}; };
var fileId = await fileRepository.InsertAsync(dto, token) var fileId = await fileRepository.InsertAsync(dto, token)
.ConfigureAwait(false); .ConfigureAwait(false);
string filePath = MakeFilePath(idWell, idCategory, destinationFileName, fileId); string filePath = MakeFilePath(idWell, idCategory, destinationFileName, fileId);
Directory.CreateDirectory(Path.GetDirectoryName(filePath)); fileStorageRepository.MoveFile(srcFilePath, filePath);
File.Move(srcFilePath, filePath);
return await GetInfoAsync(fileId, token); return await GetInfoAsync(fileId, token);
} }
@ -71,18 +67,14 @@ namespace AsbCloudInfrastructure.Services
//save stream to disk //save stream to disk
string filePath = MakeFilePath(idWell, idCategory, fileFullName, fileId); string filePath = MakeFilePath(idWell, idCategory, fileFullName, fileId);
await fileStorageRepository.CopyFileAsync(filePath, fileStream, token);
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
using var newfileStream = new FileStream(filePath, FileMode.Create);
await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false);
return await GetInfoAsync(fileId, token); return await GetInfoAsync(fileId, token);
} }
private string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) private string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId)
{ {
return Path.Combine(RootPath, $"{idWell}", return Path.Combine(fileStorageRepository.RootPath, $"{idWell}",
$"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}"); $"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}");
} }
@ -95,10 +87,7 @@ namespace AsbCloudInfrastructure.Services
var relativePath = GetUrl(dto.IdWell, dto.IdCategory, dto.Id, ext); var relativePath = GetUrl(dto.IdWell, dto.IdCategory, dto.Id, ext);
var fullPath = Path.GetFullPath(relativePath); var fullPath = Path.GetFullPath(relativePath);
if (!File.Exists(fullPath)) fileStorageRepository.FileExists(fullPath, relativePath);
{
throw new FileNotFoundException("not found", relativePath);
}
return dto; return dto;
} }
@ -119,8 +108,7 @@ namespace AsbCloudInfrastructure.Services
foreach (var file in files) foreach (var file in files)
{ {
var fileName = GetUrl(file.IdWell, file.IdCategory, file.Id, Path.GetExtension(file.Name)); var fileName = GetUrl(file.IdWell, file.IdCategory, file.Id, Path.GetExtension(file.Name));
if (File.Exists(fileName)) fileStorageRepository.DeleteFile(fileName);
File.Delete(fileName);
} }
return files.Any() ? 1 : 0; return files.Any() ? 1 : 0;
@ -137,7 +125,7 @@ namespace AsbCloudInfrastructure.Services
GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name)); GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) => public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) =>
Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}"); Path.Combine(fileStorageRepository.RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}");
public Task<int> MarkFileMarkAsDeletedAsync(int idMark, public Task<int> MarkFileMarkAsDeletedAsync(int idMark,
CancellationToken token) CancellationToken token)
@ -153,12 +141,9 @@ namespace AsbCloudInfrastructure.Services
var ext = Path.GetExtension(entity.Name); var ext = Path.GetExtension(entity.Name);
var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext); var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext);
var fullPath = Path.GetFullPath(relativePath); var fullPath = Path.GetFullPath(relativePath);
if (!File.Exists(fullPath)) fileStorageRepository.FileExists(fullPath, relativePath);
{
throw new FileNotFoundException("not found", relativePath);
}
} }
return result; return result;
} }

View File

@ -67,7 +67,8 @@ namespace AsbCloudInfrastructure.Services
generator.Make(reportFileName); generator.Make(reportFileName);
var fileRepository = new FileRepository(context); var fileRepository = new FileRepository(context);
var fileService = new FileService(fileRepository); var fileStorageRepository = new FileStorageRepository();
var fileService = new FileService(fileRepository, fileStorageRepository);
var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token); var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token);
progressHandler.Invoke(new progressHandler.Invoke(new

View File

@ -1,9 +1,7 @@
using AsbCloudApp.Services; using AsbCloudApp.Services;
using Moq; using Moq;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -11,7 +9,7 @@ namespace AsbCloudWebApi.Tests
{ {
public class RepositoryFactory public class RepositoryFactory
{ {
public static Mock<TRepository> Make<TRepository, TDto>(IList<TDto> data) public static Mock<TRepository> Make<TRepository, TDto>(ICollection<TDto> data)
where TDto : AsbCloudApp.Data.IId where TDto : AsbCloudApp.Data.IId
where TRepository : class, ICrudService<TDto> where TRepository : class, ICrudService<TDto>
{ {

View File

@ -1,6 +1,7 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services; using AsbCloudInfrastructure.Services;
using DocumentFormat.OpenXml.Spreadsheet; using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing; using DocumentFormat.OpenXml.Wordprocessing;
@ -136,7 +137,11 @@ namespace AsbCloudWebApi.Tests.ServicesTests
return Task.FromResult(result); return Task.FromResult(result);
}); });
fileService = new FileService(repositoryMock.Object); var storageRepositoryMock = new Mock<IFileStorageRepository>();
storageRepositoryMock.Setup(x => x.RootPath).Returns("files");
fileService = new FileService(repositoryMock.Object, storageRepositoryMock.Object);
} }
[Fact] [Fact]
@ -147,27 +152,23 @@ namespace AsbCloudWebApi.Tests.ServicesTests
} }
[Fact] [Fact]
public async Task GetInfoAsync_throws_FileNotFoundException() public async Task GetInfoAsync_returns_FileInfo()
{ {
await Assert.ThrowsAsync<FileNotFoundException>(async () => var data = await fileService.GetInfoAsync(1742, CancellationToken.None);
{ Assert.NotNull(data);
await fileService.GetInfoAsync(1743, CancellationToken.None);
});
} }
[Fact] [Fact]
public async Task GetInfoByIdsAsync_throws_FileNotFoundException() public async Task GetInfoByIdsAsync_returns_FileInfo()
{ {
await Assert.ThrowsAsync<FileNotFoundException>(async () => var data = await fileService.GetInfoByIdsAsync(new int[] { 1742, 1743 }, CancellationToken.None);
{ Assert.NotNull(data);
await fileService.GetInfoByIdsAsync(new int[] { 1742, 1743 }, CancellationToken.None);
});
} }
[Fact] [Fact]
public async Task SaveAsync_returns_FileInfoa() public async Task SaveAsync_returns_FileInfoa()
{ {
var stream = new FileStream("D:\\test\\test.txt", FileMode.Open); using var stream = new MemoryStream();
var data = await fileService.SaveAsync(90, 1, 10040, "test.txt", stream, CancellationToken.None); var data = await fileService.SaveAsync(90, 1, 10040, "test.txt", stream, CancellationToken.None);
Assert.NotNull(data); Assert.NotNull(data);
} }