using AutoMapper; using MediatR; using Mws.Application.Common; using Mws.Domain.Tasks; using TaskPriority = Mws.Domain.Tasks.TaskPriority; using TaskStatus = Mws.Domain.Tasks.TaskStatus; namespace Mws.Application.Tasks; public record CreateTaskCommand(Guid UserId, Guid ProjectId, CreateTaskRequest Request) : IRequest; public class CreateTaskHandler(IUnitOfWork uow, IMapper mapper) : IRequestHandler { public async Task Handle(CreateTaskCommand command, CancellationToken ct) { await TaskAccess.EnsureMemberAccessAsync(uow, command.UserId, command.ProjectId, ct); var request = command.Request; if (string.IsNullOrWhiteSpace(request.Title)) { throw new BadRequestException("Task title is required"); } if (request.AssigneeId.HasValue && !await uow.Projects.IsMemberAsync(command.ProjectId, request.AssigneeId.Value, ct)) { throw new BadRequestException("Assignee must be a member of the project"); } var now = DateTime.UtcNow; var task = new TaskItem { Id = Guid.NewGuid(), ProjectId = command.ProjectId, Title = request.Title.Trim(), Description = request.Description, Status = request.Status ?? TaskStatus.Todo, Priority = request.Priority ?? TaskPriority.Medium, AssigneeId = request.AssigneeId, DueDate = request.DueDate, CreatedBy = command.UserId, CreatedAt = now, UpdatedAt = now, }; uow.Tasks.Add(task); await uow.SaveChangesAsync(ct); return await TaskAccess.GetDtoAsync(uow, mapper, task.Id, ct); } }