using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Knot.Shared.Kernel; using Knot.Shared.Kernel.Storage; using Knot.Contracts.Conversations.Domain; using Knot.Contracts.Conversations.Application.Abstractions; using MediatR; using System.Linq; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; namespace Knot.Modules.Conversations.Application.Chats.Avatar; public record UploadGroupAvatarCommand(Guid ChatId, Guid UserId, string FileName, string ContentType, Stream FileStream) : ICommand; internal sealed class UploadGroupAvatarCommandHandler : ICommandHandler { private readonly IChatRepository _chatRepository; private readonly IChatsUnitOfWork _uow; private readonly IFileStorageService _fileStorage; public UploadGroupAvatarCommandHandler(IChatRepository chatRepository, IChatsUnitOfWork uow, IFileStorageService fileStorage) { _chatRepository = chatRepository; _uow = uow; _fileStorage = fileStorage; } public async Task> Handle(UploadGroupAvatarCommand request, CancellationToken cancellationToken) { var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken); if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId)) { return Result.Failure(ChatErrors.ChatNotFound); } var fileId = await _fileStorage.UploadFileAsync(request.FileStream, request.FileName, request.ContentType); var url = $"/api/files/{fileId}"; chat.UpdateAvatar(url); _chatRepository.Update(chat); await _uow.SaveChangesAsync(cancellationToken); return Result.Success(request.ChatId); } } public record CropGroupAvatarCommand(Guid ChatId, Guid UserId, string FileName, string ContentType, Stream FileStream, int X, int Y, int Width, int Height) : ICommand; internal sealed class CropGroupAvatarCommandHandler : ICommandHandler { private readonly IChatRepository _chatRepository; private readonly IChatsUnitOfWork _uow; private readonly IFileStorageService _fileStorage; public CropGroupAvatarCommandHandler(IChatRepository chatRepository, IChatsUnitOfWork uow, IFileStorageService fileStorage) { _chatRepository = chatRepository; _uow = uow; _fileStorage = fileStorage; } public async Task> Handle(CropGroupAvatarCommand request, CancellationToken cancellationToken) { var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken); if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId)) { return Result.Failure(ChatErrors.ChatNotFound); } string url; using (var image = await SixLabors.ImageSharp.Image.LoadAsync(request.FileStream)) { int startX = Math.Max(0, Math.Min(request.X, image.Width - 1)); int startY = Math.Max(0, Math.Min(request.Y, image.Height - 1)); int rectWidth = Math.Max(1, Math.Min(request.Width, image.Width - startX)); int rectHeight = Math.Max(1, Math.Min(request.Height, image.Height - startY)); image.Mutate(ctx => ctx.Crop(new SixLabors.ImageSharp.Rectangle(startX, startY, rectWidth, rectHeight))); image.Mutate(ctx => ctx.Resize(400, 400)); using var outStream = new MemoryStream(); await image.SaveAsJpegAsync(outStream, cancellationToken); outStream.Position = 0; var fileName = request.FileName ?? "avatar.jpg"; var fileId = await _fileStorage.UploadFileAsync(outStream, fileName, "image/jpeg"); url = $"/api/files/{fileId}"; } chat.UpdateAvatar(url); _chatRepository.Update(chat); await _uow.SaveChangesAsync(cancellationToken); return Result.Success(request.ChatId); } } public record RemoveGroupAvatarCommand(Guid ChatId, Guid UserId) : ICommand; internal sealed class RemoveGroupAvatarCommandHandler : ICommandHandler { private readonly IChatRepository _chatRepository; private readonly IChatsUnitOfWork _uow; public RemoveGroupAvatarCommandHandler(IChatRepository chatRepository, IChatsUnitOfWork uow) { _chatRepository = chatRepository; _uow = uow; } public async Task> Handle(RemoveGroupAvatarCommand request, CancellationToken cancellationToken) { var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken); if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId)) { return Result.Failure(ChatErrors.ChatNotFound); } chat.UpdateAvatar(null); _chatRepository.Update(chat); await _uow.SaveChangesAsync(cancellationToken); return Result.Success(request.ChatId); } }