using MediatR;
using ColaFlow.Modules.ProjectManagement.Application.DTOs;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
namespace ColaFlow.Modules.ProjectManagement.Application.Queries.GetTaskById;
///
/// Handler for GetTaskByIdQuery
///
public sealed class GetTaskByIdQueryHandler(
IProjectRepository projectRepository,
ITenantContext tenantContext)
: IRequestHandler
{
private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
private readonly ITenantContext _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
public async Task Handle(GetTaskByIdQuery request, CancellationToken cancellationToken)
{
// Get current tenant ID (Defense in Depth - Layer 2)
var currentTenantId = _tenantContext.GetCurrentTenantId();
// Use read-only method for query (AsNoTracking for better performance)
var taskId = TaskId.From(request.TaskId);
var task = await _projectRepository.GetTaskByIdReadOnlyAsync(taskId, cancellationToken);
if (task == null)
throw new NotFoundException("Task", request.TaskId);
// CRITICAL SECURITY: Explicit TenantId validation (Defense in Depth)
if (task.TenantId.Value != currentTenantId)
throw new NotFoundException("Task", request.TaskId);
// Map to DTO
return new TaskDto
{
Id = task.Id.Value,
Title = task.Title,
Description = task.Description,
StoryId = task.StoryId.Value,
Status = task.Status.Name,
Priority = task.Priority.Name,
AssigneeId = task.AssigneeId?.Value,
EstimatedHours = task.EstimatedHours,
ActualHours = task.ActualHours,
CreatedBy = task.CreatedBy.Value,
CreatedAt = task.CreatedAt,
UpdatedAt = task.UpdatedAt
};
}
}