feat: pivot to social media workflow app
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 12:58:35 -04:00
parent 0f4acc1b6d
commit df3e602015
349 changed files with 18685 additions and 16010 deletions

View File

@@ -0,0 +1,100 @@
using Socialize.Infrastructure.Security;
using Socialize.Modules.Identity.Contracts;
using Socialize.Modules.Workspaces.Data;
namespace Socialize.Modules.Workspaces.Handlers;
public record CreateWorkspaceInviteRequest(
string Email,
string Role);
public class CreateWorkspaceInviteRequestValidator
: Validator<CreateWorkspaceInviteRequest>
{
private static readonly string[] AllowedRoles =
[
KnownRoles.Client,
KnownRoles.Provider,
KnownRoles.WorkspaceMember,
];
public CreateWorkspaceInviteRequestValidator()
{
RuleFor(x => x.Email).NotEmpty().MaximumLength(256).EmailAddress();
RuleFor(x => x.Role).NotEmpty().Must(role => AllowedRoles.Contains(role));
}
}
public class CreateWorkspaceInviteHandler(
AppDbContext dbContext,
AccessScopeService accessScopeService)
: Endpoint<CreateWorkspaceInviteRequest, WorkspaceInviteDto>
{
public override void Configure()
{
Post("/api/workspaces/{workspaceId:guid}/invites");
Options(o => o.WithTags("Workspaces"));
}
public override async Task HandleAsync(CreateWorkspaceInviteRequest request, CancellationToken ct)
{
Guid workspaceId = Route<Guid>("workspaceId");
if (!accessScopeService.CanManageWorkspace(User, workspaceId))
{
await SendForbiddenAsync(ct);
return;
}
bool workspaceExists = await dbContext.Workspaces
.AnyAsync(workspace => workspace.Id == workspaceId, ct);
if (!workspaceExists)
{
AddError("workspaceId", "The selected workspace does not exist.");
await SendErrorsAsync(StatusCodes.Status400BadRequest, ct);
return;
}
string normalizedEmail = request.Email.Trim().ToLowerInvariant();
string normalizedRole = request.Role.Trim();
bool duplicateInvite = await dbContext.WorkspaceInvites.AnyAsync(
invite => invite.WorkspaceId == workspaceId &&
invite.Email == normalizedEmail &&
invite.Status == "Pending",
ct);
if (duplicateInvite)
{
AddError(request => request.Email, "A pending invite already exists for this email in the selected workspace.");
await SendErrorsAsync(StatusCodes.Status409Conflict, ct);
return;
}
WorkspaceInvite invite = new()
{
Id = Guid.NewGuid(),
WorkspaceId = workspaceId,
Email = normalizedEmail,
Role = normalizedRole,
Status = "Pending",
InvitedByUserId = User.GetUserId(),
CreatedAt = DateTimeOffset.UtcNow,
};
dbContext.WorkspaceInvites.Add(invite);
await dbContext.SaveChangesAsync(ct);
await SendAsync(
new WorkspaceInviteDto(
invite.Id,
invite.WorkspaceId,
invite.Email,
invite.Role,
invite.Status,
invite.CreatedAt),
StatusCodes.Status201Created,
ct);
}
}