Files
social-media/backend/src/Socialize.Api/Modules/Workspaces/Handlers/CreateWorkspace.cs
2026-04-29 20:58:36 -04:00

84 lines
2.4 KiB
C#

using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using Socialize.Api.Data;
using Socialize.Api.Infrastructure.Security;
using Socialize.Api.Modules.Workspaces.Data;
namespace Socialize.Api.Modules.Workspaces.Handlers;
public record CreateWorkspaceRequest(
string Name,
string Slug,
string TimeZone);
public class CreateWorkspaceRequestValidator
: Validator<CreateWorkspaceRequest>
{
public CreateWorkspaceRequestValidator()
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(256);
RuleFor(x => x.Slug)
.NotEmpty()
.MaximumLength(128)
.Matches("^[a-z0-9]+(?:-[a-z0-9]+)*$");
RuleFor(x => x.TimeZone).NotEmpty().MaximumLength(128);
}
}
public class CreateWorkspaceHandler(
AppDbContext dbContext,
AccessScopeService accessScopeService)
: Endpoint<CreateWorkspaceRequest, WorkspaceDto>
{
public override void Configure()
{
Post("/api/workspaces");
Options(o => o.WithTags("Workspaces"));
}
public override async Task HandleAsync(CreateWorkspaceRequest request, CancellationToken ct)
{
if (!accessScopeService.IsManager(User))
{
await SendForbiddenAsync(ct);
return;
}
string normalizedName = request.Name.Trim();
string normalizedSlug = request.Slug.Trim().ToLowerInvariant();
string normalizedTimeZone = request.TimeZone.Trim();
bool duplicateWorkspace = await dbContext.Workspaces
.AnyAsync(workspace => workspace.Slug == normalizedSlug, ct);
if (duplicateWorkspace)
{
AddError(request => request.Slug, "A workspace with this slug already exists.");
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
return;
}
Workspace workspace = new()
{
Id = Guid.NewGuid(),
Name = normalizedName,
Slug = normalizedSlug,
OwnerUserId = User.GetUserId(),
TimeZone = normalizedTimeZone,
CreatedAt = DateTimeOffset.UtcNow,
};
dbContext.Workspaces.Add(workspace);
await dbContext.SaveChangesAsync(ct);
WorkspaceDto dto = new(
workspace.Id,
workspace.Name,
workspace.Slug,
workspace.TimeZone,
workspace.CreatedAt);
await SendAsync(dto, StatusCodes.Status201Created, ct);
}
}