133 lines
5.3 KiB
C#
133 lines
5.3 KiB
C#
using FastEndpoints;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Socialize.Api.Data;
|
|
using Socialize.Api.Infrastructure.Security;
|
|
using Socialize.Api.Modules.CalendarIntegrations.Data;
|
|
using Socialize.Api.Modules.CalendarIntegrations.Services;
|
|
using Socialize.Api.Modules.Organizations.Services;
|
|
|
|
namespace Socialize.Api.Modules.CalendarIntegrations.Handlers;
|
|
|
|
public class CreateCalendarSourceHandler(
|
|
AppDbContext dbContext,
|
|
AccessScopeService accessScopeService,
|
|
OrganizationAccessService organizationAccessService)
|
|
: Endpoint<UpsertCalendarSourceRequest, CalendarSourceDto>
|
|
{
|
|
public override void Configure()
|
|
{
|
|
Post("/api/calendar-integrations/sources");
|
|
Options(o => o.WithTags("Calendar Integrations"));
|
|
}
|
|
|
|
public override async Task HandleAsync(UpsertCalendarSourceRequest request, CancellationToken ct)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(request);
|
|
|
|
Guid currentUserId = User.GetUserId();
|
|
string scope = request.Scope.Trim();
|
|
Guid? organizationId = request.OrganizationId;
|
|
Guid? workspaceId = request.WorkspaceId;
|
|
|
|
if (!await CanCreateAsync(scope, organizationId, workspaceId, currentUserId, ct))
|
|
{
|
|
await SendForbiddenAsync(ct);
|
|
return;
|
|
}
|
|
|
|
string? sourceUrl = NormalizeOptional(request.SourceUrl);
|
|
string? catalogSourceReference = NormalizeOptional(request.CatalogSourceReference);
|
|
if (await SourceAlreadyExistsAsync(scope, organizationId, workspaceId, currentUserId, sourceUrl, catalogSourceReference, ct))
|
|
{
|
|
AddError(request => request.SourceUrl, "This calendar source has already been added.");
|
|
await SendErrorsAsync(cancellation: ct);
|
|
return;
|
|
}
|
|
|
|
CalendarSource source = new()
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Scope = scope,
|
|
OrganizationId = scope == CalendarSourceScopes.Organization ? organizationId : null,
|
|
WorkspaceId = scope == CalendarSourceScopes.Workspace ? workspaceId : null,
|
|
UserId = scope == CalendarSourceScopes.User ? currentUserId : null,
|
|
SourceUrl = sourceUrl,
|
|
CatalogSourceReference = catalogSourceReference,
|
|
DisplayTitle = request.DisplayTitle.Trim(),
|
|
Color = request.Color.Trim(),
|
|
Category = request.Category.Trim(),
|
|
IsEnabled = request.IsEnabled,
|
|
InheritanceMode = scope == CalendarSourceScopes.Organization
|
|
? NormalizeOptional(request.InheritanceMode) ?? CalendarSourceInheritanceModes.Optional
|
|
: null,
|
|
UpdatedAt = DateTimeOffset.UtcNow,
|
|
};
|
|
|
|
dbContext.CalendarSources.Add(source);
|
|
await dbContext.SaveChangesAsync(ct);
|
|
|
|
await SendAsync(CalendarSourceDto.FromSource(source, isReadOnly: false), StatusCodes.Status201Created, ct);
|
|
}
|
|
|
|
private async Task<bool> CanCreateAsync(
|
|
string scope,
|
|
Guid? organizationId,
|
|
Guid? workspaceId,
|
|
Guid currentUserId,
|
|
CancellationToken ct)
|
|
{
|
|
return scope switch
|
|
{
|
|
CalendarSourceScopes.Organization when organizationId.HasValue =>
|
|
await dbContext.Organizations.AnyAsync(organization => organization.Id == organizationId.Value, ct) &&
|
|
await organizationAccessService.HasOrganizationPermissionAsync(
|
|
User,
|
|
organizationId.Value,
|
|
OrganizationPermissions.ManageConnectors,
|
|
ct),
|
|
CalendarSourceScopes.Workspace when workspaceId.HasValue =>
|
|
await dbContext.Workspaces.AnyAsync(workspace => workspace.Id == workspaceId.Value, ct) &&
|
|
await accessScopeService.CanManageWorkspaceAsync(User, workspaceId.Value, ct),
|
|
CalendarSourceScopes.User => currentUserId != Guid.Empty,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
private Task<bool> SourceAlreadyExistsAsync(
|
|
string scope,
|
|
Guid? organizationId,
|
|
Guid? workspaceId,
|
|
Guid currentUserId,
|
|
string? sourceUrl,
|
|
string? catalogSourceReference,
|
|
CancellationToken ct)
|
|
{
|
|
IQueryable<CalendarSource> query = dbContext.CalendarSources
|
|
.Where(source => source.Scope == scope);
|
|
|
|
query = scope switch
|
|
{
|
|
CalendarSourceScopes.Organization => query.Where(source => source.OrganizationId == organizationId),
|
|
CalendarSourceScopes.Workspace => query.Where(source => source.WorkspaceId == workspaceId),
|
|
CalendarSourceScopes.User => query.Where(source => source.UserId == currentUserId),
|
|
_ => query.Where(_ => false),
|
|
};
|
|
|
|
string? normalizedUrl = sourceUrl?.Trim();
|
|
string? normalizedCatalogReference = catalogSourceReference?.Trim();
|
|
|
|
return query.AnyAsync(source =>
|
|
(!string.IsNullOrWhiteSpace(normalizedCatalogReference) &&
|
|
source.CatalogSourceReference == normalizedCatalogReference) ||
|
|
(!string.IsNullOrWhiteSpace(normalizedUrl) &&
|
|
source.SourceUrl != null &&
|
|
source.SourceUrl.ToUpper() == normalizedUrl.ToUpper()),
|
|
ct);
|
|
}
|
|
|
|
private static string? NormalizeOptional(string? value)
|
|
{
|
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
|
}
|
|
}
|