using FastEndpoints; using Microsoft.EntityFrameworkCore; using Socialize.Api.Data; using Socialize.Api.Modules.Clients.Data; using Socialize.Api.Infrastructure.Security; namespace Socialize.Api.Modules.Clients.Handlers; public record CreateClientRequest( Guid WorkspaceId, string Name, string? PortraitUrl, string? PrimaryContactName, string? PrimaryContactEmail, string? PrimaryContactPortraitUrl); public class CreateClientRequestValidator : Validator { public CreateClientRequestValidator() { RuleFor(x => x.WorkspaceId).NotEmpty(); RuleFor(x => x.Name).NotEmpty().MaximumLength(256); RuleFor(x => x.PortraitUrl).MaximumLength(2048); RuleFor(x => x.PrimaryContactName).MaximumLength(256); RuleFor(x => x.PrimaryContactEmail).MaximumLength(256).EmailAddress().When(x => !string.IsNullOrWhiteSpace(x.PrimaryContactEmail)); RuleFor(x => x.PrimaryContactPortraitUrl).MaximumLength(2048); } } public class CreateClientHandler( AppDbContext dbContext, AccessScopeService accessScopeService) : Endpoint { public override void Configure() { Post("/api/clients"); Options(o => o.WithTags("Clients")); } public override async Task HandleAsync(CreateClientRequest request, CancellationToken ct) { if (!await accessScopeService.CanManageWorkspaceAsync(User, request.WorkspaceId, ct)) { await SendForbiddenAsync(ct); return; } bool workspaceExists = await dbContext.Workspaces .AnyAsync(workspace => workspace.Id == request.WorkspaceId, ct); if (!workspaceExists) { AddError(request => request.WorkspaceId, "The selected workspace does not exist."); await SendErrorsAsync(StatusCodes.Status400BadRequest, ct); return; } string normalizedName = request.Name.Trim(); string? normalizedPortraitUrl = request.PortraitUrl?.Trim(); string? normalizedPrimaryContactName = request.PrimaryContactName?.Trim(); string? normalizedPrimaryContactEmail = request.PrimaryContactEmail?.Trim(); string? normalizedPrimaryContactPortraitUrl = request.PrimaryContactPortraitUrl?.Trim(); bool duplicateClient = await dbContext.Clients .AnyAsync( client => client.WorkspaceId == request.WorkspaceId && client.Name == normalizedName, ct); if (duplicateClient) { AddError(request => request.Name, "A client with this name already exists in the active workspace."); await SendErrorsAsync(StatusCodes.Status409Conflict, ct); return; } Client client = new() { Id = Guid.NewGuid(), WorkspaceId = request.WorkspaceId, Name = normalizedName, Status = "Active", PortraitUrl = string.IsNullOrWhiteSpace(normalizedPortraitUrl) ? null : normalizedPortraitUrl, PrimaryContactName = string.IsNullOrWhiteSpace(normalizedPrimaryContactName) ? null : normalizedPrimaryContactName, PrimaryContactEmail = string.IsNullOrWhiteSpace(normalizedPrimaryContactEmail) ? null : normalizedPrimaryContactEmail, PrimaryContactPortraitUrl = string.IsNullOrWhiteSpace(normalizedPrimaryContactPortraitUrl) ? null : normalizedPrimaryContactPortraitUrl, CreatedAt = DateTimeOffset.UtcNow, }; dbContext.Clients.Add(client); await dbContext.SaveChangesAsync(ct); ClientDto dto = new( client.Id, client.WorkspaceId, client.Name, client.Status, client.PortraitUrl, client.PrimaryContactName, client.PrimaryContactEmail, client.PrimaryContactPortraitUrl); await SendAsync(dto, StatusCodes.Status201Created, ct); } }