Commit MWS backend source tree

The ASP.NET Core solution (mws.api/mws.application/mws.domain/
mws.infrastructure) existed only as untracked working files. Adding
it to version control, plus a .gitignore for build output and local
tooling directories, so the CQRS/mediator refactor plan has a real
git history to branch and diff against.
This commit is contained in:
2026-08-13 23:10:22 +07:00
parent 96944ad2c3
commit f72aaa2329
94 changed files with 7758 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
using AutoMapper;
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 class TaskService(IUnitOfWork uow, IMapper mapper) : ITaskService
{
public async Task<List<TaskDto>> GetTasksAsync(Guid userId, Guid projectId, TaskStatus? status, TaskPriority? priority, Guid? assigneeId, CancellationToken ct = default)
{
await EnsureMemberAccessAsync(userId, projectId, ct);
var tasks = await uow.Tasks.GetForProjectAsync(projectId, status, priority, assigneeId, ct);
return mapper.Map<List<TaskDto>>(tasks);
}
public async Task<TaskDto> GetAsync(Guid userId, Guid taskId, CancellationToken ct = default)
{
var task = await GetTaskForUserAsync(userId, taskId, ct);
return await GetDtoAsync(task.Id, ct);
}
public async Task<TaskDto> CreateAsync(Guid userId, Guid projectId, CreateTaskRequest request, CancellationToken ct = default)
{
await EnsureMemberAccessAsync(userId, projectId, ct);
if (string.IsNullOrWhiteSpace(request.Title))
{
throw new BadRequestException("Task title is required");
}
if (request.AssigneeId.HasValue && !await IsMemberAsync(request.AssigneeId.Value, projectId, ct))
{
throw new BadRequestException("Assignee must be a member of the project");
}
var now = DateTime.UtcNow;
var task = new TaskItem
{
Id = Guid.NewGuid(),
ProjectId = 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 = userId,
CreatedAt = now,
UpdatedAt = now,
};
uow.Tasks.Add(task);
await uow.SaveChangesAsync(ct);
return await GetDtoAsync(task.Id, ct);
}
public async Task<TaskDto> UpdateAsync(Guid userId, Guid taskId, UpdateTaskRequest request, CancellationToken ct = default)
{
var task = await GetTaskForUserAsync(userId, taskId, ct);
if (string.IsNullOrWhiteSpace(request.Title))
{
throw new BadRequestException("Task title is required");
}
if (request.AssigneeId.HasValue && !await IsMemberAsync(request.AssigneeId.Value, task.ProjectId, ct))
{
throw new BadRequestException("Assignee must be a member of the project");
}
task.Title = request.Title.Trim();
task.Description = request.Description;
task.Status = request.Status;
task.Priority = request.Priority;
task.AssigneeId = request.AssigneeId;
task.DueDate = request.DueDate;
task.UpdatedAt = DateTime.UtcNow;
await uow.SaveChangesAsync(ct);
return await GetDtoAsync(task.Id, ct);
}
public async Task DeleteAsync(Guid userId, Guid taskId, CancellationToken ct = default)
{
var task = await GetTaskForUserAsync(userId, taskId, ct);
uow.Tasks.Remove(task);
await uow.SaveChangesAsync(ct);
}
public async Task<List<TaskDto>> SearchAsync(Guid userId, string term, CancellationToken ct = default)
{
var projectIds = await uow.Projects.GetProjectIdsForUserAsync(userId, ct);
var tasks = await uow.Tasks.SearchWithAssigneeAsync(projectIds, term, 20, ct);
return mapper.Map<List<TaskDto>>(tasks);
}
private async Task<TaskDto> GetDtoAsync(Guid id, CancellationToken ct)
{
var task = await uow.Tasks.GetWithAssigneeAsync(id, ct)
?? throw new NotFoundException("Task not found");
return mapper.Map<TaskDto>(task);
}
private async Task<TaskItem> GetTaskForUserAsync(Guid userId, Guid taskId, CancellationToken ct = default)
{
var task = await uow.Tasks.GetByIdAsync(taskId, ct)
?? throw new NotFoundException("Task not found");
if (!await IsMemberAsync(userId, task.ProjectId, ct))
{
throw new NotFoundException("Task not found");
}
return task;
}
private async Task EnsureMemberAccessAsync(Guid userId, Guid projectId, CancellationToken ct = default)
{
if (!await IsMemberAsync(userId, projectId, ct))
{
throw new NotFoundException("Project not found");
}
}
private Task<bool> IsMemberAsync(Guid userId, Guid projectId, CancellationToken ct = default) =>
uow.Projects.IsMemberAsync(projectId, userId, ct);
}