Add calendar integrations and collaboration updates
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user