Files
239e6085ba feat: pbac - private teams (#23998)
* Add permission + migration for listMembersPrivate + depends on lsitMember

* Add legacy list members PBAC private logic

* Add checks in team pages + handler

* add list memeber checks for private orgs

* Add permision visibility scope to loading permissions

* getMembers handler

* fix fallback permission

* Verify private teams work with private org

* Apply suggestion from @eunjae-lee

Co-authored-by: Eunjae Lee <[email protected]>

* Remove and private scope function and add param to old

---------

Co-authored-by: Eunjae Lee <[email protected]>
2025-09-29 11:30:54 +01:00

95 lines
2.5 KiB
TypeScript

import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service";
import { prisma } from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import type { TrpcSessionUser } from "../../../types";
import type { TGetMembersInputSchema } from "./getMembers.schema";
type CreateOptions = {
ctx: {
user: NonNullable<TrpcSessionUser>;
};
input: TGetMembersInputSchema;
};
export const getMembersHandler = async ({ input, ctx }: CreateOptions) => {
const { teamIdToExclude, accepted, distinctUser } = input;
if (!ctx.user.organizationId) return [];
const isOrgPrivate = ctx.user.organization.isPrivate;
const permissionCheckService = new PermissionCheckService();
const hasPermissionToViewMembers = await permissionCheckService.checkPermission({
userId: ctx.user.id,
teamId: ctx.user.organizationId,
permission: ctx.user.organization.isPrivate
? "organization.listMembersPrivate"
: "organization.listMembers",
fallbackRoles: ctx.user.organization.isPrivate
? [MembershipRole.ADMIN, MembershipRole.OWNER]
: [MembershipRole.MEMBER, MembershipRole.ADMIN, MembershipRole.OWNER],
});
if (!hasPermissionToViewMembers) return [];
const teamQuery = await prisma.team.findUnique({
where: {
id: ctx.user.organizationId,
},
select: {
members: {
where: {
teamId: {
not: teamIdToExclude,
},
accepted,
},
select: {
accepted: true,
disableImpersonation: true,
id: true,
teamId: true,
role: true,
userId: true,
user: {
select: {
id: true,
username: true,
avatarUrl: true,
email: true,
completedOnboarding: true,
name: true,
},
},
},
...(distinctUser && {
distinct: ["userId"],
}),
},
},
});
if (teamIdToExclude && teamQuery?.members) {
const excludedteamUsers = await prisma.team.findUnique({
where: {
id: teamIdToExclude,
},
select: {
members: {
select: {
userId: true,
},
},
},
});
const excludedUserIds = excludedteamUsers?.members.map((item) => item.userId) ?? [];
teamQuery.members = teamQuery?.members.filter((member) => !excludedUserIds.includes(member.userId));
}
return teamQuery?.members || [];
};
export default getMembersHandler;