From 1cab03afd9bdb6f1e6ceca09c3546f564994ba79 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Wed, 19 Jun 2024 14:56:30 +0700 Subject: [PATCH] Add OrgMemberById query This will allow org admins to see all details (including email addresses) of users in the orgs they manage. --- .../GraphQL/CustomTypes/OrgMemberDto.cs | 18 ++++++++++ backend/LexBoxApi/GraphQL/LexQueries.cs | 33 +++++++++++++++++++ backend/LexData/LexBoxDbContext.cs | 1 + frontend/schema.graphql | 16 +++++++++ 4 files changed, 68 insertions(+) create mode 100644 backend/LexBoxApi/GraphQL/CustomTypes/OrgMemberDto.cs diff --git a/backend/LexBoxApi/GraphQL/CustomTypes/OrgMemberDto.cs b/backend/LexBoxApi/GraphQL/CustomTypes/OrgMemberDto.cs new file mode 100644 index 000000000..ff2598078 --- /dev/null +++ b/backend/LexBoxApi/GraphQL/CustomTypes/OrgMemberDto.cs @@ -0,0 +1,18 @@ +namespace LexBoxApi.GraphQL.CustomTypes; + +public class OrgMemberDto +{ + public required Guid Id { get; set; } + public DateTimeOffset CreatedDate { get; set; } + public DateTimeOffset UpdatedDate { get; set; } + public DateTimeOffset LastActive { get; set; } + public required string Name { get; set; } + public required string? Email { get; set; } + public required string? Username { get; set; } + public required string LocalizationCode { get; set; } + public required bool EmailVerified { get; set; } + public required bool IsAdmin { get; set; } + public required bool Locked { get; set; } + public required bool CanCreateProjects { get; set; } +} + diff --git a/backend/LexBoxApi/GraphQL/LexQueries.cs b/backend/LexBoxApi/GraphQL/LexQueries.cs index 8607d0524..e62f87789 100644 --- a/backend/LexBoxApi/GraphQL/LexQueries.cs +++ b/backend/LexBoxApi/GraphQL/LexQueries.cs @@ -126,6 +126,39 @@ public IQueryable Users(LexBoxDbContext context) }; } + public async Task OrgMemberById(LexBoxDbContext context, LoggedInContext loggedInContext, Guid orgId, Guid userId) + { + var requestingUserId = loggedInContext.User.Id; + var requestingUser = await context.Users.Include(u => u.Organizations).Where(u => u.Id == requestingUserId).FirstOrDefaultAsync(); + if (requestingUser is null) return null; + + var isOrgAdmin = requestingUser.Organizations.Any(om => om.OrgId == orgId && om.UserId == requestingUserId && om.Role == OrgRole.Admin); + var allowed = isOrgAdmin || requestingUser.IsAdmin; + if (!allowed) return null; + + var user = await context.Users.Include(u => u.Organizations).Where(u => u.Id == userId).FirstOrDefaultAsync(); + if (user is null) return null; + + var userInOrg = user.Organizations.Any(om => om.OrgId == orgId); + if (!userInOrg) return null; + + return new OrgMemberDto + { + Id = user.Id, + CreatedDate = user.CreatedDate, + UpdatedDate = user.UpdatedDate, + LastActive = user.LastActive, + Name = user.Name, + Email = user.Email, + Username = user.Username, + LocalizationCode = user.LocalizationCode, + EmailVerified = user.EmailVerified, + IsAdmin = user.IsAdmin, + Locked = user.Locked, + CanCreateProjects = user.CanCreateProjects, + }; + } + public LexAuthUser MeAuth(LoggedInContext loggedInContext) { return loggedInContext.User; diff --git a/backend/LexData/LexBoxDbContext.cs b/backend/LexData/LexBoxDbContext.cs index 27489c257..4a06c4a99 100644 --- a/backend/LexData/LexBoxDbContext.cs +++ b/backend/LexData/LexBoxDbContext.cs @@ -29,6 +29,7 @@ protected override void ConfigureConventions(ModelConfigurationBuilder builder) public DbSet ProjectUsers => Set(); public DbSet DraftProjects => Set(); public DbSet Orgs => Set(); + public DbSet OrgMembers => Set(); public DbSet OrgProjects => Set(); public async Task HeathCheck(CancellationToken cancellationToken) diff --git a/frontend/schema.graphql b/frontend/schema.graphql index 517ac09a1..6c0a5bbfc 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -252,6 +252,21 @@ type OrgProjects { updatedDate: DateTime! } +type OrgMemberDto { + id: UUID! + createdDate: DateTime! + updatedDate: DateTime! + lastActive: DateTime! + name: String! + email: String + username: String + localizationCode: String! + emailVerified: Boolean! + isAdmin: Boolean! + locked: Boolean! + canCreateProjects: Boolean! +} + type Organization { createdDate: DateTime! name: String! @@ -328,6 +343,7 @@ type Query { orgById(orgId: UUID!): Organization users(skip: Int take: Int where: UserFilterInput orderBy: [UserSortInput!]): UsersCollectionSegment @authorize(policy: "AdminRequiredPolicy") me: MeDto + orgMemberById(orgId: UUID! userId: UUID!): OrgMemberDto meAuth: LexAuthUser! testingThrowsError: LexAuthUser! isAdmin: IsAdminResponse! @authorize(policy: "AdminRequiredPolicy")