Files
work-club-manager/backend/WorkClub.Api/Services/TaskService.cs

185 lines
5.2 KiB
C#
Raw Permalink Normal View History

using Microsoft.EntityFrameworkCore;
using WorkClub.Application.Interfaces;
using WorkClub.Application.Tasks.DTOs;
using WorkClub.Domain.Entities;
using WorkClub.Domain.Enums;
using WorkClub.Infrastructure.Data;
namespace WorkClub.Api.Services;
public class TaskService
{
private readonly AppDbContext _context;
private readonly ITenantProvider _tenantProvider;
public TaskService(AppDbContext context, ITenantProvider tenantProvider)
{
_context = context;
_tenantProvider = tenantProvider;
}
public async Task<TaskListDto> GetTasksAsync(string? statusFilter, int page, int pageSize)
{
var query = _context.WorkItems.AsQueryable();
if (!string.IsNullOrEmpty(statusFilter))
{
if (Enum.TryParse<WorkItemStatus>(statusFilter, ignoreCase: true, out var status))
{
query = query.Where(w => w.Status == status);
}
}
var total = await query.CountAsync();
var items = await query
.OrderBy(w => w.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var itemDtos = items.Select(w => new TaskListItemDto(
w.Id,
w.Title,
w.Status.ToString(),
w.AssigneeId,
w.CreatedAt
)).ToList();
return new TaskListDto(itemDtos, total, page, pageSize);
}
public async Task<TaskDetailDto?> GetTaskByIdAsync(Guid id)
{
var workItem = await _context.WorkItems.FindAsync(id);
if (workItem == null)
return null;
return new TaskDetailDto(
workItem.Id,
workItem.Title,
workItem.Description,
workItem.Status.ToString(),
workItem.AssigneeId,
workItem.CreatedById,
workItem.ClubId,
workItem.DueDate,
workItem.CreatedAt,
workItem.UpdatedAt
);
}
public async Task<(TaskDetailDto? task, string? error)> CreateTaskAsync(CreateTaskRequest request, Guid createdById)
{
var tenantId = _tenantProvider.GetTenantId();
var workItem = new WorkItem
{
Id = Guid.NewGuid(),
TenantId = tenantId,
Title = request.Title,
Description = request.Description,
Status = WorkItemStatus.Open,
ClubId = request.ClubId,
AssigneeId = request.AssigneeId,
DueDate = request.DueDate,
CreatedById = createdById,
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow
};
_context.WorkItems.Add(workItem);
await _context.SaveChangesAsync();
var dto = new TaskDetailDto(
workItem.Id,
workItem.Title,
workItem.Description,
workItem.Status.ToString(),
workItem.AssigneeId,
workItem.CreatedById,
workItem.ClubId,
workItem.DueDate,
workItem.CreatedAt,
workItem.UpdatedAt
);
return (dto, null);
}
public async Task<(TaskDetailDto? task, string? error, bool isConflict)> UpdateTaskAsync(Guid id, UpdateTaskRequest request)
{
var workItem = await _context.WorkItems.FindAsync(id);
if (workItem == null)
return (null, "Task not found", false);
if (request.Title != null)
workItem.Title = request.Title;
if (request.Description != null)
workItem.Description = request.Description;
if (request.AssigneeId.HasValue)
workItem.AssigneeId = request.AssigneeId;
if (request.DueDate.HasValue)
workItem.DueDate = request.DueDate;
if (request.Status != null)
{
if (!Enum.TryParse<WorkItemStatus>(request.Status, ignoreCase: true, out var newStatus))
{
return (null, $"Invalid status: {request.Status}", false);
}
if (!workItem.CanTransitionTo(newStatus))
{
return (null, $"Cannot transition from {workItem.Status} to {newStatus}", false);
}
workItem.TransitionTo(newStatus);
}
workItem.UpdatedAt = DateTimeOffset.UtcNow;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
return (null, "Task was modified by another user. Please refresh and try again.", true);
}
var dto = new TaskDetailDto(
workItem.Id,
workItem.Title,
workItem.Description,
workItem.Status.ToString(),
workItem.AssigneeId,
workItem.CreatedById,
workItem.ClubId,
workItem.DueDate,
workItem.CreatedAt,
workItem.UpdatedAt
);
return (dto, null, false);
}
public async Task<bool> DeleteTaskAsync(Guid id)
{
var workItem = await _context.WorkItems.FindAsync(id);
if (workItem == null)
return false;
_context.WorkItems.Remove(workItem);
await _context.SaveChangesAsync();
return true;
}
}