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;
namespace ColaFlow.Modules.ProjectManagement.Application.Queries.GetEpicsByProjectId;
///
/// Handler for GetEpicsByProjectIdQuery
///
public sealed class GetEpicsByProjectIdQueryHandler(
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(GetEpicsByProjectIdQuery request, CancellationToken cancellationToken)
{
// Get current tenant ID (Defense in Depth - Layer 2)
var currentTenantId = _tenantContext.GetCurrentTenantId();
// CRITICAL SECURITY: Verify Project belongs to current tenant before querying epics
var projectId = ProjectId.From(request.ProjectId);
var project = await _projectRepository.GetByIdAsync(projectId, cancellationToken);
if (project == null)
throw new NotFoundException("Project", request.ProjectId);
// Explicit TenantId validation (Defense in Depth)
if (project.TenantId.Value != currentTenantId)
throw new NotFoundException("Project", request.ProjectId);
// Now fetch epics (already filtered by EF Core, but we verified project ownership)
var epics = await _projectRepository.GetEpicsByProjectIdAsync(projectId, cancellationToken);
return epics.Select(epic => new EpicDto
{
Id = epic.Id.Value,
Name = epic.Name,
Description = epic.Description,
ProjectId = epic.ProjectId.Value,
Status = epic.Status.Name,
Priority = epic.Priority.Name,
CreatedBy = epic.CreatedBy.Value,
CreatedAt = epic.CreatedAt,
UpdatedAt = epic.UpdatedAt,
Stories = new List() // Don't include stories in list view
}).ToList();
}
}