perf: optimize team admin check queries (#17681)

## What does this PR do?

Optimizes team and organization admin checks by:
- Removing unnecessary member data fetching in profile repository
- Simplifying team admin verification query to directly check membership
- Refactoring organization admin check to use the optimized team verification method

## Mandatory Tasks

- [x] I have self-reviewed the code
- [x] I have updated the developer docs in /docs
- [ ] I confirm automated tests are in place

## How should this be tested?

1. Log in as a team admin/owner
2. Verify team admin privileges still work correctly
3. Log in as an organization admin
4. Confirm organization admin permissions are maintained
5. Check that admin-only features remain accessible

Expected behavior:
- Team admins/owners should retain all their existing permissions
- Organization admins should maintain their administrative capabilities
- No degradation in admin functionality while improving query performance

## Checklist

- I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code doesn't follow the style guidelines of this project
- I haven't commented my code, particularly in hard-to-understand areas
- I haven't checked if my changes generate no new warnings
This commit is contained in:
Omar López
2024-11-15 19:00:18 -07:00
committed by GitHub
parent 1c05952077
commit f4f4afad39
3 changed files with 10 additions and 25 deletions
@@ -375,9 +375,6 @@ export class ProfileRepository {
lockEventTypeCreationForUsers: true,
},
},
members: {
select: membershipSelect,
},
},
},
},
+6 -13
View File
@@ -664,25 +664,18 @@ export class UserRepository {
return !!teams.length;
}
static async isAdminOrOwnerOfTeam({ userId, teamId }: { userId: number; teamId: number }) {
const team = await prisma.team.findUnique({
const isAdminOrOwnerOfTeam = await prisma.membership.findFirst({
where: {
id: teamId,
AND: [
{
members: {
some: {
userId,
role: { in: [MembershipRole.ADMIN, MembershipRole.OWNER] },
},
},
},
],
userId,
teamId,
role: { in: [MembershipRole.ADMIN, MembershipRole.OWNER] },
accepted: true,
},
select: {
id: true,
},
});
return !!team;
return !!isAdminOrOwnerOfTeam;
}
static async getTimeZoneAndDefaultScheduleId({ userId }: { userId: number }) {
return await prisma.user.findUnique({
@@ -102,21 +102,16 @@ export async function getUserFromSession(ctx: TRPCContextInner, session: Maybe<S
// This helps to prevent reaching the 4MB payload limit by avoiding base64 and instead passing the avatar url
const locale = user?.locale ?? ctx.locale;
const isOrgAdmin = !!user.profile?.organization?.members.filter(
(member) => (member.role === "ADMIN" || member.role === "OWNER") && member.userId === user.id
).length;
const isOrgAdmin = await UserRepository.isAdminOrOwnerOfTeam({
userId: user.id,
teamId: user.profile.organization?.id ?? -1,
});
if (isOrgAdmin) {
logger.debug("User is an org admin", safeStringify({ userId: user.id }));
} else {
logger.debug("User is not an org admin", safeStringify({ userId: user.id }));
}
// Want to reduce the amount of data being sent
if (isOrgAdmin && user.profile?.organization?.members) {
user.profile.organization.members = [];
}
const organization = {
...user.profile?.organization,
id: user.profile?.organization?.id ?? null,