using AsbCloudApp.Data; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Repository; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services { #nullable enable /// /// Сервис "Дело скважины" /// public class WellFinalDocumentsService : IWellFinalDocumentsService { private readonly IAsbCloudDbContext context; private readonly FileService fileService; private readonly IUserRepository userRepository; private readonly IWellService wellService; private readonly IConfiguration configuration; private readonly IEmailService emailService; private readonly IFileCategoryService fileCategoryService; private const int FileServiceThrewException = -1; public WellFinalDocumentsService(IAsbCloudDbContext context, FileService fileService, IUserRepository userRepository, IWellService wellService, IConfiguration configuration, IEmailService emailService, IFileCategoryService fileCategoryService) { this.context = context; this.fileService = fileService; this.userRepository = userRepository; this.wellService = wellService; this.configuration = configuration; this.emailService = emailService; this.fileCategoryService = fileCategoryService; } public async Task UpdateRangeAsync(int idWell, IEnumerable? dtos, CancellationToken token) { if (dtos is not null) { var entities = dtos .Where(dto => dto.IdsPublishers?.Any() == true) .SelectMany(dto => dto.IdsPublishers .Select(idUser => new WellFinalDocument { IdCategory = dto.IdCategory, IdWell = idWell, IdUser = idUser })); var itemsToDelete = context.WellFinalDocuments.Where(d => d.IdWell == idWell); context.WellFinalDocuments.RemoveRange(itemsToDelete); await context.WellFinalDocuments.AddRangeAsync(entities).ConfigureAwait(false); var data = await context.SaveChangesAsync(token).ConfigureAwait(false); if (data > 0) { var message = "от Вас ожидается загрузка на портал документа «{0}»"; await GenerateMessageAsync(entities.Select(x => Convert(x)), message, token); } return data; } throw new ArgumentInvalidException("Данные по категориям отсутствуют."); } public async Task GetByWellId(int idWell, int idUser, CancellationToken token) { var entities = await context.WellFinalDocuments .Include(d => d.Category) .Include(d => d.User) .Where(d => d.IdWell == idWell) .AsNoTracking() .ToArrayAsync(token) .ConfigureAwait(false); var entitiesGroups = entities .GroupBy(d => d.IdCategory); var categoriesIds = entitiesGroups .Select(g => g.Key); var files = (await fileService .GetInfosAsync(new FileRequest { IdWell = idWell}, token) .ConfigureAwait(false)) .Where(f => categoriesIds.Contains(f.IdCategory)) .ToArray(); var docs = entitiesGroups.Select((g) => new WellFinalDocumentDto { IdCategory = g.Key, FilesCount = files .Where(f => f.IdCategory == g.Key) .Count(), File = files .Where(f => f.IdCategory == g.Key) .OrderBy(f => f.UploadDate) .LastOrDefault(), NameCategory = g.First().Category.Name, Publishers = g.Select(i => i.User.Adapt()), PermissionToUpload = g.Any(i => i.IdUser == idUser), }); var result = new WellCaseDto { IdWell = idWell, PermissionToSetPubliher = userRepository.HasPermission(idUser, "WellFinalDocuments.editPublisher"), WellFinalDocuments = docs, }; return result; } public async Task> GetAvailableUsersAsync(int idWell, CancellationToken token) { var companyIds = await context.RelationCompaniesWells .Where(x => x.IdWell == idWell).Select(x => x.IdCompany) .ToListAsync(token) .ConfigureAwait(false); var allUsers = await userRepository.GetAllAsync(token) .ConfigureAwait(false); return allUsers.Where(x => { var idCompany = x.IdCompany ?? default(int); return companyIds.Contains(idCompany); }) .OrderBy(x => x.Surname) .ToArray(); } public async Task SaveCategoryFile(int idWell, int idCategory, int idUser, Stream fileStream, string fileName, CancellationToken token) { var entity = await context.WellFinalDocuments .AsNoTracking() .FirstOrDefaultAsync(x => x.IdWell == idWell && x.IdCategory == idCategory && x.IdUser == idUser); if (entity is null) throw new ArgumentInvalidException("Пользователь не является ответственным за загрузку файла для данной категории."); var dto = Convert(entity); var file = await fileService.SaveAsync(dto.IdWell, dto.IdUser, dto.IdCategory, fileName, fileStream, token).ConfigureAwait(false); return file?.Id ?? FileServiceThrewException; //TODO: изменить когда файловый сервис будет переведен на nullable } public async Task GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token) { var request = new FileRequest { IdWell = idWell, IdCategory = idCategory, }; var files = await fileService.GetInfosAsync(request, token).ConfigureAwait(false); return new WellFinalDocumentsHistoryDto { IdWell = idWell, IdCategory = idCategory, File = files }; } private async Task GenerateMessageAsync(IEnumerable dtos, string message, CancellationToken token) { foreach (var item in dtos) { var user = await userRepository.GetOrDefaultAsync(item.IdUser, token); if (user?.Email is not null) { var category = await fileCategoryService.GetOrDefaultAsync(item.IdCategory, token); var well = await wellService.GetOrDefaultAsync(item.IdWell, token); SendMessage(well, user, category.Name, message, token); } } } private void SendMessage(WellDto? well, UserDto user, string documentCategory, string message, CancellationToken token) { var factory = new WellFinalDocumentMailBodyFactory(configuration); var subject = factory.MakeSubject(well, documentCategory); var body = factory.MakeMailBodyForWellFinalDocument(well, user.Name ?? user.Surname, string.Format(message, documentCategory)); emailService.EnqueueSend(user.Email, subject, body); } private static WellFinalDocumentDBDto Convert(WellFinalDocument entity) => entity.Adapt(); } #nullable disable }