using Projects.APP.Domain;
using CORE.APP.Features;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
namespace Projects.APP.Features.Projects
{
/// <summary>
/// Represents a request to update an existing project.
/// </summary>
public class ProjectUpdateRequest : Request, IRequest<CommandResponse>
{
/// <summary>
/// The name of the project (required, must be between 5 and 200 characters).
/// </summary>
[Required, Length(5, 200)]
public string Name { get; set; }
/// <summary>
/// The description of the project (optional, maximum length 1000 characters).
/// </summary>
[StringLength(1000)]
public string Description { get; set; }
/// <summary>
/// The URL associated with the project (optional, maximum length 400 characters).
/// </summary>
[StringLength(400)]
public string Url { get; set; }
/// <summary>
/// The version of the project (optional, must be a positive number).
/// </summary>
[Range(0, double.MaxValue)]
public double? Version { get; set; }
/// <summary>
/// List of tag IDs associated with the project.
/// </summary>
public List<int> TagIds { get; set; }
}
/// <summary>
/// Handles the update of an existing project.
/// </summary>
public class ProjectUpdateHandler : ProjectsDbHandler, IRequestHandler<ProjectUpdateRequest, CommandResponse>
{
/// <summary>
/// Initializes a new instance of the <see cref="ProjectUpdateHandler"/> class.
/// </summary>
/// <param name="projectsDb">Database context for projects.</param>
public ProjectUpdateHandler(ProjectsDb projectsDb) : base(projectsDb)
{
}
/// <summary>
/// Handles the request to update a project.
/// </summary>
/// <param name="request">The project update request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>A command response indicating success or failure.</returns>
public async Task<CommandResponse> Handle(ProjectUpdateRequest request, CancellationToken cancellationToken)
{
// Check if a project with the same name already exists (excluding the current project)
if (await _projectsDb.Projects.AnyAsync(p => p.Id != request.Id && p.Name.ToUpper() == request.Name.ToUpper().Trim(), cancellationToken))
return Error("Project with the same name exists!");
// Retrieve the project along with its associated tags
var entity = await _projectsDb.Projects
.Include(p => p.ProjectTags)
.SingleOrDefaultAsync(p => p.Id == request.Id, cancellationToken);
// Return an error if the project does not exist
if (entity is null)
return Error("Project not found!");
// Remove existing project tags before updating
_projectsDb.ProjectTags.RemoveRange(entity.ProjectTags);
// Update project properties
entity.Name = request.Name.Trim();
entity.Description = request.Description?.Trim();
entity.Url = request.Url?.Trim();
entity.Version = request.Version;
entity.TagIds = request.TagIds;
// Apply the updates to the database
_projectsDb.Projects.Update(entity);
await _projectsDb.SaveChangesAsync(cancellationToken);
return Success("Project updated successfully.", entity.Id);
}
}
}