213 lines
8.1 KiB
C#
213 lines
8.1 KiB
C#
using GozareshgirProgramManager.Application._Common.Interfaces;
|
|
using GozareshgirProgramManager.Application._Common.Models;
|
|
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
|
using GozareshgirProgramManager.Application.Services.FileManagement;
|
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
|
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
|
|
using MediatR;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.SendMessage;
|
|
|
|
public record SendMessageCommand(
|
|
Guid TaskId,
|
|
MessageType MessageType,
|
|
string? TextContent,
|
|
IFormFile? File,
|
|
Guid? ReplyToMessageId
|
|
) : IBaseCommand<MessageDto>;
|
|
|
|
public class SendMessageCommandHandler : IBaseCommandHandler<SendMessageCommand, MessageDto>
|
|
{
|
|
private readonly ITaskChatMessageRepository _messageRepository;
|
|
private readonly IUploadedFileRepository _fileRepository;
|
|
private readonly IProjectTaskRepository _taskRepository;
|
|
private readonly IFileStorageService _fileStorageService;
|
|
private readonly IThumbnailGeneratorService _thumbnailService;
|
|
private readonly IAuthHelper _authHelper;
|
|
|
|
public SendMessageCommandHandler(
|
|
ITaskChatMessageRepository messageRepository,
|
|
IUploadedFileRepository fileRepository,
|
|
IProjectTaskRepository taskRepository,
|
|
IFileStorageService fileStorageService,
|
|
IThumbnailGeneratorService thumbnailService, IAuthHelper authHelper)
|
|
{
|
|
_messageRepository = messageRepository;
|
|
_fileRepository = fileRepository;
|
|
_taskRepository = taskRepository;
|
|
_fileStorageService = fileStorageService;
|
|
_thumbnailService = thumbnailService;
|
|
_authHelper = authHelper;
|
|
}
|
|
|
|
public async Task<OperationResult<MessageDto>> Handle(SendMessageCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var currentUserId = _authHelper.GetCurrentUserId()
|
|
?? throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
|
|
|
var task = await _taskRepository.GetByIdAsync(request.TaskId, cancellationToken);
|
|
if (task == null)
|
|
{
|
|
return OperationResult<MessageDto>.NotFound("تسک یافت نشد");
|
|
}
|
|
|
|
Guid? uploadedFileId = null;
|
|
if (request.File != null)
|
|
{
|
|
if (request.File.Length == 0)
|
|
{
|
|
return OperationResult<MessageDto>.ValidationError("فایل خالی است");
|
|
}
|
|
|
|
const long maxFileSize = 100 * 1024 * 1024;
|
|
if (request.File.Length > maxFileSize)
|
|
{
|
|
return OperationResult<MessageDto>.ValidationError("حجم فایل بیش از حد مجاز است (حداکثر 100MB)");
|
|
}
|
|
|
|
var fileType = DetectFileType(request.File.ContentType, Path.GetExtension(request.File.FileName));
|
|
|
|
var uploadedFile = new UploadedFile(
|
|
originalFileName: request.File.FileName,
|
|
fileSizeBytes: request.File.Length,
|
|
mimeType: request.File.ContentType,
|
|
fileType: fileType,
|
|
category: FileCategory.TaskChatMessage,
|
|
uploadedByUserId: currentUserId,
|
|
storageProvider: StorageProvider.LocalFileSystem
|
|
);
|
|
|
|
await _fileRepository.AddAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
|
|
try
|
|
{
|
|
using var stream = request.File.OpenReadStream();
|
|
var uploadResult = await _fileStorageService.UploadAsync(
|
|
stream,
|
|
uploadedFile.UniqueFileName,
|
|
"TaskChatMessage"
|
|
);
|
|
|
|
uploadedFile.CompleteUpload(uploadResult.StoragePath, uploadResult.StorageUrl);
|
|
|
|
if (fileType == FileType.Image)
|
|
{
|
|
var dimensions = await _thumbnailService.GetImageDimensionsAsync(uploadResult.StoragePath);
|
|
if (dimensions.HasValue)
|
|
{
|
|
uploadedFile.SetImageDimensions(dimensions.Value.Width, dimensions.Value.Height);
|
|
}
|
|
|
|
var thumbnail = await _thumbnailService
|
|
.GenerateImageThumbnailAsync(uploadResult.StoragePath, category: "TaskChatMessage");
|
|
if (thumbnail.HasValue)
|
|
{
|
|
uploadedFile.SetThumbnail(thumbnail.Value.ThumbnailUrl);
|
|
}
|
|
}
|
|
|
|
await _fileRepository.UpdateAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
|
|
uploadedFileId = uploadedFile.Id;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await _fileRepository.DeleteAsync(uploadedFile);
|
|
await _fileRepository.SaveChangesAsync();
|
|
|
|
return OperationResult<MessageDto>.ValidationError($"خطا در آپلود فایل: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
var message = new TaskChatMessage(
|
|
taskId: request.TaskId,
|
|
senderUserId: currentUserId,
|
|
messageType: request.MessageType,
|
|
textContent: request.TextContent,
|
|
uploadedFileId
|
|
);
|
|
|
|
if (request.ReplyToMessageId.HasValue)
|
|
{
|
|
message.SetReplyTo(request.ReplyToMessageId.Value);
|
|
}
|
|
|
|
await _messageRepository.AddAsync(message);
|
|
await _messageRepository.SaveChangesAsync();
|
|
|
|
if (uploadedFileId.HasValue)
|
|
{
|
|
var file = await _fileRepository.GetByIdAsync(uploadedFileId.Value);
|
|
if (file != null)
|
|
{
|
|
file.SetReference("TaskChatMessage", message.Id.ToString());
|
|
await _fileRepository.UpdateAsync(file);
|
|
await _fileRepository.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
var dto = new MessageDto
|
|
{
|
|
Id = message.Id,
|
|
TaskId = message.TaskId,
|
|
SenderUserId = message.SenderUserId,
|
|
SenderName = "کاربر",
|
|
MessageType = message.MessageType.ToString(),
|
|
TextContent = message.TextContent,
|
|
ReplyToMessageId = message.ReplyToMessageId,
|
|
IsEdited = message.IsEdited,
|
|
IsPinned = message.IsPinned,
|
|
CreationDate = message.CreationDate,
|
|
IsMine = true
|
|
};
|
|
|
|
if (uploadedFileId.HasValue)
|
|
{
|
|
var file = await _fileRepository.GetByIdAsync(uploadedFileId.Value);
|
|
if (file != null)
|
|
{
|
|
dto.File = new MessageFileDto
|
|
{
|
|
Id = file.Id,
|
|
FileName = file.OriginalFileName,
|
|
FileUrl = file.StorageUrl ?? "",
|
|
FileSizeBytes = file.FileSizeBytes,
|
|
FileType = file.FileType.ToString(),
|
|
ThumbnailUrl = file.ThumbnailUrl,
|
|
ImageWidth = file.ImageWidth,
|
|
ImageHeight = file.ImageHeight,
|
|
DurationSeconds = file.DurationSeconds
|
|
};
|
|
}
|
|
}
|
|
|
|
return OperationResult<MessageDto>.Success(dto);
|
|
}
|
|
|
|
private FileType DetectFileType(string mimeType, string extension)
|
|
{
|
|
if (mimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Image;
|
|
|
|
if (mimeType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Video;
|
|
|
|
if (mimeType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase))
|
|
return FileType.Audio;
|
|
|
|
if (new[] { ".zip", ".rar", ".7z", ".tar", ".gz" }.Contains(extension.ToLower()))
|
|
return FileType.Archive;
|
|
|
|
return FileType.Document;
|
|
}
|
|
}
|