168 lines
5.9 KiB
C#
168 lines
5.9 KiB
C#
using FastEndpoints;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Socialize.Api.Data;
|
|
using Socialize.Api.Modules.Identity.Data;
|
|
using Socialize.Api.Modules.Organizations.Data;
|
|
using Socialize.Api.Modules.Organizations.Services;
|
|
using Socialize.Api.Modules.Workspaces.Handlers;
|
|
|
|
namespace Socialize.Api.Modules.Organizations.Handlers;
|
|
|
|
internal class GetOrganizationHandler(
|
|
AppDbContext dbContext,
|
|
OrganizationAccessService organizationAccessService)
|
|
: EndpointWithoutRequest<OrganizationDto>
|
|
{
|
|
public override void Configure()
|
|
{
|
|
Get("/api/organizations/{organizationId:guid}");
|
|
Options(o => o.WithTags("Organizations"));
|
|
}
|
|
|
|
public override async Task HandleAsync(CancellationToken ct)
|
|
{
|
|
Guid organizationId = Route<Guid>("organizationId");
|
|
|
|
Organization? organization = await dbContext.Organizations
|
|
.SingleOrDefaultAsync(candidate => candidate.Id == organizationId, ct);
|
|
if (organization is null)
|
|
{
|
|
await SendNotFoundAsync(ct);
|
|
return;
|
|
}
|
|
|
|
if (!await organizationAccessService.CanAccessOrganizationAsync(User, organizationId, ct))
|
|
{
|
|
await SendForbiddenAsync(ct);
|
|
return;
|
|
}
|
|
|
|
IReadOnlyCollection<string> currentUserPermissions = await organizationAccessService.GetUserOrganizationPermissionsAsync(
|
|
User,
|
|
organizationId,
|
|
ct);
|
|
|
|
IReadOnlyCollection<OrganizationMemberDto> members = await GetMembersAsync(organizationId, ct);
|
|
IReadOnlyCollection<WorkspaceDto> workspaces = await GetWorkspacesAsync(organizationId, ct);
|
|
OrganizationUsageDto usage = await GetUsageAsync(organization, ct);
|
|
|
|
await SendOkAsync(
|
|
OrganizationDto.FromOrganization(
|
|
organization,
|
|
currentUserPermissions,
|
|
members,
|
|
workspaces,
|
|
usage),
|
|
ct);
|
|
}
|
|
|
|
private async Task<IReadOnlyCollection<OrganizationMemberDto>> GetMembersAsync(
|
|
Guid organizationId,
|
|
CancellationToken ct)
|
|
{
|
|
var rows = await dbContext.OrganizationMemberships
|
|
.Where(membership => membership.OrganizationId == organizationId)
|
|
.Join(
|
|
dbContext.Users,
|
|
membership => membership.UserId,
|
|
user => user.Id,
|
|
(membership, user) => new { Membership = membership, User = user })
|
|
.OrderBy(row => row.User.Lastname)
|
|
.ThenBy(row => row.User.Firstname)
|
|
.ThenBy(row => row.User.Email)
|
|
.ToListAsync(ct);
|
|
|
|
return rows
|
|
.Select(row => new OrganizationMemberDto(
|
|
row.User.Id,
|
|
BuildDisplayName(row.User),
|
|
row.User.Email ?? string.Empty,
|
|
row.User.PortraitUrl,
|
|
row.Membership.Role,
|
|
OrganizationPermissionRules.GetPermissionsForRole(row.Membership.Role),
|
|
row.Membership.CreatedAt))
|
|
.ToArray();
|
|
}
|
|
|
|
private async Task<IReadOnlyCollection<WorkspaceDto>> GetWorkspacesAsync(
|
|
Guid organizationId,
|
|
CancellationToken ct)
|
|
{
|
|
var workspaces = await dbContext.Workspaces
|
|
.Where(workspace => workspace.OrganizationId == organizationId)
|
|
.OrderBy(workspace => workspace.Name)
|
|
.ToListAsync(ct);
|
|
|
|
return workspaces
|
|
.Select(workspace => WorkspaceDto.FromWorkspace(workspace, []))
|
|
.ToArray();
|
|
}
|
|
|
|
private async Task<OrganizationUsageDto> GetUsageAsync(
|
|
Organization organization,
|
|
CancellationToken ct)
|
|
{
|
|
Guid[] workspaceIds = await dbContext.Workspaces
|
|
.Where(workspace => workspace.OrganizationId == organization.Id)
|
|
.Select(workspace => workspace.Id)
|
|
.ToArrayAsync(ct);
|
|
|
|
Guid[] memberUserIds = await dbContext.OrganizationMemberships
|
|
.Where(membership => membership.OrganizationId == organization.Id)
|
|
.Select(membership => membership.UserId)
|
|
.Distinct()
|
|
.ToArrayAsync(ct);
|
|
int userCount = memberUserIds
|
|
.Append(organization.OwnerUserId)
|
|
.Distinct()
|
|
.Count();
|
|
|
|
int activeContentItemCount = workspaceIds.Length == 0
|
|
? 0
|
|
: await dbContext.ContentItems
|
|
.Where(contentItem => workspaceIds.Contains(contentItem.WorkspaceId) &&
|
|
contentItem.Status != "Approved" &&
|
|
contentItem.Status != "Scheduled")
|
|
.CountAsync(ct);
|
|
|
|
OrganizationUsageLimits limits = GetUsageLimits(organization.Name);
|
|
|
|
return new OrganizationUsageDto(
|
|
limits.PlanName,
|
|
[
|
|
new OrganizationUsageItemDto("users", userCount, limits.UserLimit),
|
|
new OrganizationUsageItemDto("workspaces", workspaceIds.Length, limits.WorkspaceLimit),
|
|
new OrganizationUsageItemDto("activeContent", activeContentItemCount, limits.ActiveContentLimit),
|
|
]);
|
|
}
|
|
|
|
private static OrganizationUsageLimits GetUsageLimits(string organizationName)
|
|
{
|
|
return string.Equals(organizationName, "Northstar Agency", StringComparison.OrdinalIgnoreCase)
|
|
? new OrganizationUsageLimits("Agency", 25, 15, 250)
|
|
: new OrganizationUsageLimits("Free", 2, 1, 3);
|
|
}
|
|
|
|
private sealed record OrganizationUsageLimits(
|
|
string PlanName,
|
|
int UserLimit,
|
|
int WorkspaceLimit,
|
|
int ActiveContentLimit);
|
|
|
|
private static string BuildDisplayName(User user)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.Alias))
|
|
{
|
|
return user.Alias;
|
|
}
|
|
|
|
string fullName = $"{user.Firstname} {user.Lastname}".Trim();
|
|
if (!string.IsNullOrWhiteSpace(fullName))
|
|
{
|
|
return fullName;
|
|
}
|
|
|
|
return user.Email ?? user.UserName ?? user.Id.ToString();
|
|
}
|
|
}
|