diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateBugSection/CreateBugSectionCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateBugSection/CreateBugSectionCommandHandler.cs new file mode 100644 index 00000000..e350f507 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateBugSection/CreateBugSectionCommandHandler.cs @@ -0,0 +1,146 @@ +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; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.FileManagementAgg.Entities; +using GozareshgirProgramManager.Domain.FileManagementAgg.Enums; +using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using Microsoft.AspNetCore.Http; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateBugSection; + +public class CreateBugSectionCommandHandler : IBaseCommandHandler +{ + readonly IUnitOfWork _unitOfWork; + readonly IBugSectionRepository _bugSectionRepository; + readonly IUploadedFileRepository _uploadedFileRepository; + private readonly IFileStorageService _fileStorageService; + private readonly IThumbnailGeneratorService _thumbnailService; + private readonly IAuthHelper _authHelper; + + public CreateBugSectionCommandHandler(IUnitOfWork unitOfWork, IBugSectionRepository bugSectionRepository, IUploadedFileRepository uploadedFileRepository, IAuthHelper authHelper, IFileStorageService fileStorageService, IThumbnailGeneratorService thumbnailService) + { + _unitOfWork = unitOfWork; + _bugSectionRepository = bugSectionRepository; + _uploadedFileRepository = uploadedFileRepository; + _authHelper = authHelper; + _fileStorageService = fileStorageService; + _thumbnailService = thumbnailService; + } + + public async Task Handle(CreateBugSectionCommand request, CancellationToken cancellationToken) + { + var currentUserId = _authHelper.GetCurrentUserId() + ?? throw new UnAuthorizedException("کاربر احراز هویت نشده است"); + + #region Validation + if (_bugSectionRepository.Exists(x => x.TaskId == request.TaskId)) + return OperationResult.Failure("برای این بخش قبلا تسک باگ ایجاد شده است"); + + if (string.IsNullOrWhiteSpace(request.InitialDescription)) + return OperationResult.Failure("توضیحات باگ خالی است"); + + if (request.OriginalAssignedUserId == 0) + return OperationResult.Failure("کاربر انتخاب نشده است"); + #endregion + + var bug = new BugSection(request.TaskId, request.InitialDescription, request.OriginalAssignedUserId, + request.Priority); + await _bugSectionRepository.CreateAsync(bug); + + if (request.Files.Any()) + { + foreach (var file in request.Files) + { + const long maxFileSize = 100 * 1024 * 1024; + if (file.Length > maxFileSize) + return OperationResult.Failure("حجم فایل بیش از حد مجاز است (حداکثر 100MB)"); + + var fileType = DetectFileType(file.ContentType, Path.GetExtension(file.FileName)); + + var uploadedFile = new UploadedFile( + originalFileName: file.FileName, + fileSizeBytes: file.Length, + mimeType: file.ContentType, + fileType: fileType, + category: FileCategory.TaskChatMessage, + uploadedByUserId: currentUserId, + storageProvider: StorageProvider.LocalFileSystem + ); + + await _uploadedFileRepository.AddAsync(uploadedFile); + + + try + { + using var stream = 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 _uploadedFileRepository.UpdateAsync(uploadedFile); + + + } + catch (Exception ex) + { + await _uploadedFileRepository.DeleteAsync(uploadedFile); + + + return OperationResult.ValidationError($"خطا در آپلود فایل: {ex.Message}"); + } + + bug.AddDocument(new BugDocument(uploadedFile.Id)); + + } + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + 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; + } +} + +public record CreateBugSectionCommand(Guid TaskId, string InitialDescription, long OriginalAssignedUserId, ProjectTaskPriority Priority, List Files) : IBaseCommand; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetBugModalDetails/GetBugModalDetailsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetBugModalDetails/GetBugModalDetailsQueryHandler.cs new file mode 100644 index 00000000..6f5ef492 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetBugModalDetails/GetBugModalDetailsQueryHandler.cs @@ -0,0 +1,29 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetBugModalDetails; + +public class GetBugModalDetailsQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetBugModalDetailsQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetBugModalDetailsQuery request, CancellationToken cancellationToken) + { + var projectTask =await _context.ProjectTasks.FirstOrDefaultAsync(x=>x.Id == request.TaskId); + if(projectTask == null) + return OperationResult.NotFound("کاربر یافت نشد"); + + var response = new GetBugModalDetailsResponse(projectTask.Name); + return OperationResult.Success(response); + } +} + +public record GetBugModalDetailsQuery(Guid TaskId) : IBaseQuery; + +public record GetBugModalDetailsResponse(string Name); \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IBugSectionRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IBugSectionRepository.cs new file mode 100644 index 00000000..f30609d0 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IBugSectionRepository.cs @@ -0,0 +1,9 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +public interface IBugSectionRepository : IRepository +{ + +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs index 20618330..283e2b82 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs @@ -80,7 +80,8 @@ public static class DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); - + services.AddScoped(); + services.AddScoped(); services.AddScoped(); diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/BugSectionRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/BugSectionRepository.cs new file mode 100644 index 00000000..db09f3e7 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/BugSectionRepository.cs @@ -0,0 +1,16 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class BugSectionRepository : RepositoryBase, IBugSectionRepository +{ + private readonly ProgramManagerDbContext _context; + public BugSectionRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs index 7be0b240..89835e7c 100644 --- a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs +++ b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs @@ -1,29 +1,31 @@ -using System.Runtime.InteropServices; -using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application._Common.Models; using GozareshgirProgramManager.Application.Modules.Projects.Commands.ApproveTaskSectionCompletion; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoPendingFullTimeTaskSections; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoStopOverTimeTaskSections; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus; using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeDeployStatusProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeTaskPriority; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateBugSection; using GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.EditProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.TransferSection; using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectAssignDetails; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardDetail; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; -using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; using MediatR; using Microsoft.AspNetCore.Mvc; using ServiceHost.BaseControllers; -using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeTaskPriority; -using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoPendingFullTimeTaskSections; +using System.Runtime.InteropServices; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetBugModalDetails; namespace ServiceHost.Areas.Admin.Controllers.ProgramManager; @@ -176,5 +178,27 @@ public class ProjectController : ProgramManagerBaseController var res = await _mediator.Send(command); return res; } + + [HttpGet("GetCreateBugModalDetails")] + public async Task>> GetCreateBugModalDetails( + [FromQuery] GetBugModalDetailsQuery query) + { + var res = await _mediator.Send(query); + return res; + } + + /// + /// ایجاد تسک باگ + /// + /// + /// + [HttpPost("CreateBugSection")] + public async Task> CreateBugSection([FromBody] CreateBugSectionCommand commnd) + { + var res = await _mediator.Send(commnd); + return res; + } + + } \ No newline at end of file