Merge branch '7912198_WellCase_add_notification' into dev

This commit is contained in:
ngfrolov 2022-11-25 12:45:36 +05:00
commit 0d9f9296df
11 changed files with 304 additions and 96 deletions

View File

@ -21,7 +21,7 @@ namespace AsbCloudApp.Data
/// <summary>
/// Файлы
/// </summary>
public IEnumerable<FileInfoDto>? File { get; set; }
public IEnumerable<FileInfoDto> Files { get; set; } = null!;
}
#nullable disable
}

View File

@ -25,10 +25,10 @@ namespace AsbCloudApp.Services
/// Получение всех записей
/// </summary>
/// <param name = "idWell" ></param >
/// <param name = "idUser" ></param >
/// <param name = "idUser" >запрашивающий пользователь, для проверки его прав и текста сообщения</param >
/// <param name="token"></param>
/// <returns></returns>
Task<WellCaseDto> GetByWellId(int idWell, int idUser, CancellationToken token);
Task<WellCaseDto> GetByWellIdAsync(int idWell, int idUser, CancellationToken token);
/// <summary>
/// Получение списка ответственных
@ -45,19 +45,29 @@ namespace AsbCloudApp.Services
/// <param name="idCategory"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<WellFinalDocumentsHistoryDto> GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token);
Task<WellFinalDocumentsHistoryDto> GetFilesHistoryByIdCategoryAsync(int idWell, int idCategory, CancellationToken token);
/// <summary>
/// Сохранение файла
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="idUser"></param>
/// <param name="idUser">пользователь, который сохраняет файл</param>
/// <param name="fileStream"></param>
/// <param name="fileName"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> SaveCategoryFile(int idWell, int idCategory, int idUser, Stream fileStream, string fileName, CancellationToken token);
Task<int> SaveCategoryFileAsync(int idWell, int idCategory, int idUser, Stream fileStream, string fileName, CancellationToken token);
/// <summary>
/// Повторно оповестить ответственных за загрузку
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser">запрашивающий пользователь, для проверки его прав и текста сообщения</param>
/// <param name="idCategory"></param>
/// <param name="token"></param>
/// <returns>count of notified publishers</returns>
Task<int> ReNotifyPublishersAsync(int idWell, int idUser, int idCategory, CancellationToken token);
}
#nullable disable
}

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
namespace AsbCloudDb.Model.DefaultData
{
public static class DefaultContextData
{
public static Dictionary<Type, IEntityFiller> GetFillers()
{
var fillers = new Dictionary<Type, IEntityFiller>
{
// Order does meter
{ typeof(UserRole), new EntityFillerUserRole() },
{ typeof(RelationUserRoleUserRole), new EntityFillerRelationUserRoleUserRole()},
{ typeof(Permission), new EntityFillerPermission()},
{ typeof(RelationUserRolePermission), new EntityFillerRelationUserRolePermission()},
{ typeof(User), new EntityFillerUser()},
{ typeof(RelationUserUserRole), new EntityFillerRelationUserUserRole()},
{ typeof(Company), new EntityFillerCompany()},
{ typeof(WellOperationCategory), new EntityFillerWellOperationCategory()},
{ typeof(FileCategory), new EntityFillerFileCategory()},
{ typeof(WellSectionType), new EntityFillerWellSectionType()},
{ typeof(WellType), new EntityFillerWellType()},
{ typeof(MeasureCategory), new EntityFillerMeasureCategory()},
{ typeof(CompanyType), new EntityFillerCompanyType()},
{ typeof(AsbCloudDb.Model.Subsystems.Subsystem), new EntityFillerSubsystem() },
};
return fillers;
}
public static void Fill(ModelBuilder modelBuilder)
{
var fillers = GetFillers();
foreach (var filler in fillers.Values)
filler.FillData(modelBuilder);
}
}
}

View File

@ -1,39 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace AsbCloudDb.Model.DefaultData
{
internal static class DefaultContextData
{
public static IEnumerable<IEntityFiller> GetFillers()
{
var fillers = new IEntityFiller[]
{
// Order does meter
new EntityFillerUserRole(),
new EntityFillerRelationUserRoleUserRole(),
new EntityFillerPermission(),
new EntityFillerRelationUserRolePermission(),
new EntityFillerUser(),
new EntityFillerRelationUserUserRole(),
new EntityFillerCompany(),
new EntityFillerWellOperationCategory(),
new EntityFillerFileCategory(),
new EntityFillerWellSectionType(),
new EntityFillerWellType(),
new EntityFillerMeasureCategory(),
new EntityFillerCompanyType(),
new EntityFillerSubsystem(),
};
return fillers;
}
public static void Fill(ModelBuilder modelBuilder)
{
var fillers = GetFillers();
foreach (var filler in fillers)
filler.FillData(modelBuilder);
}
}
}

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace AsbCloudDb.Model.DefaultData
{
internal abstract class EntityFiller<TEntity> : IEntityFiller
public abstract class EntityFiller<TEntity> : IEntityFiller
where TEntity : class
{
public abstract TEntity[] GetData();

View File

@ -2,7 +2,7 @@
namespace AsbCloudDb.Model.DefaultData
{
internal interface IEntityFiller
public interface IEntityFiller
{
void FillData(ModelBuilder modelBuilder);
}

View File

@ -54,8 +54,6 @@ SELECT timescaledb_pre_restore();
### Step 3. Restore DB, then [Longest operation]
Terminal:
```
sudo -u postgres psql -p 5499 -U postgres postgres -W < dump_2021-11-26.bak
or
sudo -u postgres pg_restore -Fc -d postgres dump_2021-11-26.bak
```
OR psql:

View File

@ -29,7 +29,8 @@ namespace AsbCloudInfrastructure.Services.Email
var resoursesDir = "Res";
var logoFilePath = Path.Combine(baseDir, resoursesDir, resourceFileName);
if(!File.Exists(logoFilePath))
return string.Empty;
var imageBytes = File.ReadAllBytes(logoFilePath);
var format = Path.GetExtension(resourceFileName).Trim('.');
return "data:image/" + format + ";base64," + Convert.ToBase64String(imageBytes);

View File

@ -4,7 +4,6 @@ using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -50,6 +49,7 @@ namespace AsbCloudInfrastructure.Services
this.fileCategoryService = fileCategoryService;
}
///<inheritdoc/>
public async Task<int> UpdateRangeAsync(int idWell, IEnumerable<WellFinalDocumentInputDto>? dtos, CancellationToken token)
{
if (dtos is not null)
@ -81,7 +81,8 @@ namespace AsbCloudInfrastructure.Services
throw new ArgumentInvalidException("Данные по категориям отсутствуют.");
}
public async Task<WellCaseDto> GetByWellId(int idWell, int idUser, CancellationToken token)
///<inheritdoc/>
public async Task<WellCaseDto> GetByWellIdAsync(int idWell, int idUser, CancellationToken token)
{
var entities = await context.WellFinalDocuments
.Include(d => d.Category)
@ -127,6 +128,7 @@ namespace AsbCloudInfrastructure.Services
return result;
}
///<inheritdoc/>
public async Task<IEnumerable<UserDto>> GetAvailableUsersAsync(int idWell, CancellationToken token)
{
var companyIds = await context.RelationCompaniesWells
@ -134,18 +136,18 @@ namespace AsbCloudInfrastructure.Services
.ToListAsync(token)
.ConfigureAwait(false);
var allUsers = await userRepository.GetAllAsync(token)
var allUsers = await userRepository
.GetAllAsync(token)
.ConfigureAwait(false);
return allUsers.Where(x => {
var idCompany = x.IdCompany ?? default(int);
return companyIds.Contains(idCompany);
})
return allUsers.Where(x => x.IdCompany is not null && companyIds.Contains(x.IdCompany ?? int.MinValue))
.OrderBy(x => x.Surname)
.Select(u => u as UserDto)
.ToArray();
}
public async Task<int> SaveCategoryFile(int idWell, int idCategory, int idUser, Stream fileStream, string fileName, CancellationToken token)
///<inheritdoc/>
public async Task<int> SaveCategoryFileAsync(int idWell, int idCategory, int idUser, Stream fileStream, string fileName, CancellationToken token)
{
var entity = await context.WellFinalDocuments
.AsNoTracking()
@ -162,7 +164,8 @@ namespace AsbCloudInfrastructure.Services
return file?.Id ?? FileServiceThrewException; //TODO: изменить когда файловый сервис будет переведен на nullable
}
public async Task<WellFinalDocumentsHistoryDto> GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token)
///<inheritdoc/>
public async Task<WellFinalDocumentsHistoryDto> GetFilesHistoryByIdCategoryAsync(int idWell, int idCategory, CancellationToken token)
{
var request = new FileRequest
{
@ -174,10 +177,41 @@ namespace AsbCloudInfrastructure.Services
return new WellFinalDocumentsHistoryDto {
IdWell = idWell,
IdCategory = idCategory,
File = files
Files = files
};
}
///<inheritdoc/>
public async Task<int> ReNotifyPublishersAsync(int idWell, int idUser, int idCategory, CancellationToken token)
{
WellCaseDto wellCase = await GetByWellIdAsync(idWell, idUser, token);
if (!wellCase.PermissionToSetPubliher)
throw new ForbidException("Повторная отправка оповещений Вам не разрешена");
var requester = await userRepository.GetOrDefaultAsync(idUser, token);
if (requester is null)
throw new ForbidException("Не удается вас опознать");
var docs = wellCase.WellFinalDocuments
.Where(doc => doc.IdCategory == idCategory)
.Where(doc => doc.File is null)
.SelectMany(doc => doc.Publishers
.Select(pub => new WellFinalDocumentDBDto {
IdCategory = idCategory,
IdUser = pub.Id,
IdWell = idWell
}));
if(!docs.Any())
throw new Exception("Нет такой категории, или в нее уже загружен документ");
var message = requester.MakeDisplayName() + " ожидает от Вас загрузку на портал документа «{{0}}»";
await GenerateMessageAsync(docs, message, token);
return docs.Count();
}
private async Task GenerateMessageAsync(IEnumerable<WellFinalDocumentDBDto> dtos, string message, CancellationToken token)
{
foreach (var item in dtos)
@ -203,6 +237,7 @@ namespace AsbCloudInfrastructure.Services
private static WellFinalDocumentDBDto Convert(WellFinalDocument entity)
=> entity.Adapt<WellFinalDocumentDBDto>();
}
#nullable disable
}

View File

@ -2,100 +2,243 @@
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services;
using Microsoft.Extensions.Configuration;
using Moq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using AsbCloudApp.Repositories;
using AsbCloudInfrastructure.Repository;
using AsbCloudApp.Exceptions;
namespace AsbCloudWebApi.Tests.ServicesTests
{
public class WellFinalDocumentsServiceTest
{
private readonly AsbCloudDbContext context;
private WellFinalDocumentsService service;
private readonly Mock<FileService> fileServiceMock;
private const int validInsertedFileId = 555;
private const int idWellFinalDocCategory = 10_000;
private const string editPublisherPermission = "WellFinalDocuments.editPublisher";
private readonly WellFinalDocumentsService service;
private readonly Mock<IUserRepository> userRepositoryMock;
private readonly Mock<IWellService> wellServiceMock;
private readonly Mock<IConfiguration> configurationMock;
private readonly Mock<IEmailService> emailServiceMock;
private readonly Mock<IFileCategoryService> fileCategoryService;
private readonly IEnumerable<UserDto> users = new List<UserDto> {
new UserDto {
private static readonly UserExtendedDto[] users = new []{
new UserExtendedDto {
Id = 1,
IdCompany = 1,
Name = "test",
Surname = "Tester 1",
Name = "Peppa",
Email = "test@test.com"
},
new UserDto {
new UserExtendedDto {
Id = 3,
IdCompany = 1,
Name = "test1",
Surname = "Tester 3",
Name = "Jourge",
Email = "test1@test1.com"
}
};
private static readonly WellFinalDocument[] wellFinalDocuments = new[]
{
new WellFinalDocument {
IdCategory = idWellFinalDocCategory,
IdUser = users[0].Id,
User = new User{
Id = users[0].Id,
Surname = users[0].Surname,
Email = users[0].Email,
},
IdWell = 1,
Category = new (){ Id = idWellFinalDocCategory, Name = "Проект на бурение транспортного и горизонтального участков скважины"},
},
};
private static readonly RelationCompanyWell[] relationCompanyWell = new[]
{
new RelationCompanyWell {IdWell = 1, IdCompany= 1}
};
private readonly Mock<IFileRepository> fileRepositoryMock;
private readonly Mock<IFileStorageRepository> fileStorageRepositoryMock;
private readonly FileService fileService;
private readonly Mock<IAsbCloudDbContext> contextMock;
public WellFinalDocumentsServiceTest()
{
context = TestHelpter.MakeRealTestContext();
context.SaveChanges();
contextMock = new Mock<IAsbCloudDbContext>();
contextMock.AddDbSetMock(users);
contextMock.AddDbSetMock(wellFinalDocuments);
contextMock.AddDbSetMock(relationCompanyWell);
fileRepositoryMock = new Mock<IFileRepository>();
fileRepositoryMock.Setup(r => r.InsertAsync(It.IsAny<FileInfoDto>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(validInsertedFileId);
fileRepositoryMock.Setup(r => r.GetOrDefaultAsync(validInsertedFileId, It.IsAny<CancellationToken>()))
.ReturnsAsync(new FileInfoDto {Id = validInsertedFileId});
fileStorageRepositoryMock = new Mock<IFileStorageRepository>();
fileService = new FileService(fileRepositoryMock.Object, fileStorageRepositoryMock.Object);
fileServiceMock = new Mock<FileService>();
userRepositoryMock = new Mock<IUserRepository>();
userRepositoryMock.Setup(x => x.GetAllAsync(CancellationToken.None)).Returns(Task.Run(() => users.Select(x => (UserExtendedDto)x)));
userRepositoryMock.Setup(x => x.GetAllAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(users);
userRepositoryMock.Setup(x => x.GetOrDefault(It.IsAny<int>()))
.Returns<int>(id => GetOrDefaultUserById(id));
userRepositoryMock.Setup(x => x.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.ReturnsAsync((int id, CancellationToken token) => GetOrDefaultUserById(id));
UserExtendedDto? GetOrDefaultUserById(int id)
=> users
.Where(u => u.Id == id)
.Select(u => new UserExtendedDto {
Id = u.Id,
IdCompany = u.IdCompany,
Email = u.Email,
Name = u.Name,
Patronymic = u.Patronymic,
Surname = u.Surname,
IdState = u.IdState,
Login = u.Login,
Position = u.Position
})
.FirstOrDefault();
userRepositoryMock.Setup(x => x.HasPermission(users[0].Id, editPublisherPermission))
.Returns(true);
wellServiceMock = new Mock<IWellService>();
configurationMock = new Mock<IConfiguration>();
wellServiceMock.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.ReturnsAsync((int id, CancellationToken _) => new WellDto {
Id = id,
Caption = "well 1",
Cluster = "cluster 1",
Deposit = "deposit 1" });
var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder().Build();
emailServiceMock = new Mock<IEmailService>();
fileCategoryService = new Mock<IFileCategoryService>();
fileCategoryService.Setup(s => s.GetOrDefaultAsync(idWellFinalDocCategory, It.IsAny<CancellationToken>()))
.ReturnsAsync((int id, CancellationToken _) => new FileCategoryDto
{
Id = idWellFinalDocCategory,
Name = "Проект на бурение транспортного и горизонтального участков скважины"
});
service = new WellFinalDocumentsService(
context: context,
fileService: fileServiceMock.Object,
context: contextMock.Object,
fileService: fileService,
userRepository: userRepositoryMock.Object,
wellService: wellServiceMock.Object,
configuration: configurationMock.Object,
configuration: configuration,
emailService: emailServiceMock.Object,
fileCategoryService: fileCategoryService.Object);
}
~WellFinalDocumentsServiceTest()
[Fact]
public async Task UpdateRangeAsync_sends_mail()
{
WellFinalDocumentInputDto[] docs = {
new (){
IdCategory = idWellFinalDocCategory,
IdsPublishers = new int[]{ users[0].Id }
}};
contextMock.Invocations.Clear();
contextMock.Setup(c => c.SaveChanges())
.Returns(1);
contextMock.Setup(c => c.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(1);
var count = await service.UpdateRangeAsync(1, docs, CancellationToken.None);
Assert.Equal(1, count);
emailServiceMock.Verify(s => s.EnqueueSend(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
}
[Fact]
public async Task GetWellFinalDocument_return_collection_rows()
public async Task GetByWellIdAsync_return_empty_case()
{
var data = await service.GetByWellId(90, 1,CancellationToken.None);
var data = await service.GetByWellIdAsync(90, 1,CancellationToken.None);
Assert.NotNull(data);
Assert.Empty(data.WellFinalDocuments);
}
[Fact]
public async Task GetListResponsibles_return_cnt_users()
public async Task GetByWellIdAsync_return_one_document()
{
var data = await service.GetByWellIdAsync(1, 1, CancellationToken.None);
Assert.NotNull(data);
Assert.Single(data.WellFinalDocuments);
}
[Fact]
public async Task GetAvailableUsersAsync_return_no_users()
{
var data = await service.GetAvailableUsersAsync(90, CancellationToken.None);
Assert.NotNull(data);
Assert.Empty(data);
}
[Fact]
public async Task GetHistoryFileByIdCategory_return_data_hitory()
public async Task GetAvailableUsersAsync_return_two_users()
{
var data = await service.GetFilesHistoryByIdCategory(90, 10018, CancellationToken.None);
var data = await service.GetAvailableUsersAsync(1, CancellationToken.None);
Assert.NotNull(data);
Assert.Equal(2, data.Count());
}
[Fact]
public async Task SaveCategoryFile_return_id_edit_record()
public async Task GetHistoryFileByIdCategory_return_empty_hitory()
{
var stream = new FileStream("D:\\test\\test.txt", FileMode.Open);
var data = await service.SaveCategoryFile(21, 10018, 78, stream, "test.txt", CancellationToken.None);
Assert.Equal(21, data);
var data = await service.GetFilesHistoryByIdCategoryAsync(1, 13 * idWellFinalDocCategory, CancellationToken.None);
Assert.NotNull(data);
Assert.Empty(data.Files);
}
[Fact]
public async Task SaveCategoryFile_throws_wrong_user()
{
var content = new byte[] {0xAA, 0xBB};
var stream = new MemoryStream(content);
await Assert.ThrowsAsync<ArgumentInvalidException>(
async () => await service.SaveCategoryFileAsync(21, 13 * idWellFinalDocCategory, 78, stream, "test.txt", CancellationToken.None)
);
}
[Fact]
public async Task SaveCategoryFile_returns_file_id()
{
var content = new byte[] { 0xAA, 0xBB };
var stream = new MemoryStream(content);
var token = CancellationToken.None;
var idFile = await service.SaveCategoryFileAsync(1, idWellFinalDocCategory, users[0].Id, stream, "test.txt", CancellationToken.None);
Assert.Equal(validInsertedFileId, idFile);
fileRepositoryMock.Verify(m => m.InsertAsync(It.IsAny<FileInfoDto>(), token));
fileStorageRepositoryMock.Verify(m=>m.SaveFileAsync(It.IsAny<string>(), stream, token));
}
[Fact]
public async Task ReNotifyPublishersAsync_deny_to_non_editors()
{
await Assert.ThrowsAsync<ForbidException>(
async() => await service.ReNotifyPublishersAsync(1, users[1].Id, idWellFinalDocCategory, CancellationToken.None));
}
[Fact]
public async Task ReNotifyPublishersAsync_deny_to_non_wrong_category()
{
await Assert.ThrowsAsync<System.Exception>(
async () => await service.ReNotifyPublishersAsync(1, users[0].Id, 13 * idWellFinalDocCategory, CancellationToken.None));
}
[Fact]
public async Task ReNotifyPublishersAsync_returns_2()
{
var emailsCount = await service.ReNotifyPublishersAsync(1, users[0].Id, idWellFinalDocCategory, CancellationToken.None);
Assert.Equal(1, emailsCount);
emailServiceMock.Verify(s => s.EnqueueSend(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
}
}
}

View File

@ -47,7 +47,7 @@ namespace AsbCloudWebApi.Controllers
return Forbid();
var idUser = User?.GetUserId();
var data = await this.wellFinalDocumentsService.GetByWellId(idWell, idUser ?? default, token);
var data = await this.wellFinalDocumentsService.GetByWellIdAsync(idWell, idUser ?? default, token);
return Ok(data);
}
@ -84,7 +84,27 @@ namespace AsbCloudWebApi.Controllers
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var data = await this.wellFinalDocumentsService.UpdateRangeAsync(idWell, dtos, token);
var data = await wellFinalDocumentsService.UpdateRangeAsync(idWell, dtos, token);
return Ok(data);
}
/// <summary>
/// Повторно оповестить ответственных за загрузку
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="token"></param>
/// <returns>количество оповещенных публикаторов</returns>
[HttpPut("{idWell}")]
[Permission("WellFinalDocuments.editPublisher")]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> ReNotifyPublishersAsync(int idWell, [Required] int idCategory, CancellationToken token = default)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var idUser = User.GetUserId() ?? -1;
var data = await wellFinalDocumentsService.ReNotifyPublishersAsync(idWell, idUser, idCategory, token);
return Ok(data);
}
@ -98,14 +118,14 @@ namespace AsbCloudWebApi.Controllers
[HttpGet("{idWell}/history")]
[Permission]
[ProducesResponseType(typeof(WellFinalDocumentsHistoryDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetFilesHistoryByIdCategory(int idWell,
public async Task<IActionResult> GetFilesHistoryByIdCategoryAsync(int idWell,
[Required] int idCategory,
CancellationToken token = default)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var data = await this.wellFinalDocumentsService.GetFilesHistoryByIdCategory(idWell, idCategory, token);
var data = await this.wellFinalDocumentsService.GetFilesHistoryByIdCategoryAsync(idWell, idCategory, token);
return Ok(data);
}
@ -120,14 +140,14 @@ namespace AsbCloudWebApi.Controllers
[HttpPost("{idWell}")]
[Permission]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> SaveCategoryFile(int idWell, [Required] int idCategory, [Required] IFormFile file, CancellationToken token = default)
public async Task<IActionResult> SaveCategoryFileAsync(int idWell, [Required] int idCategory, [Required] IFormFile file, CancellationToken token = default)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
var idUser = User.GetUserId() ?? -1;
var fileStream = file.OpenReadStream();
var data = await this.wellFinalDocumentsService.SaveCategoryFile(idWell, idCategory, idUser, fileStream, file.FileName, token);
var data = await this.wellFinalDocumentsService.SaveCategoryFileAsync(idWell, idCategory, idUser, fileStream, file.FileName, token);
return Ok(data);
}