Skip to content

Commit f9db1d6

Browse files
authored
fix: getTeamIdsWithPermission (calcom#25387)
1 parent 1d9aee7 commit f9db1d6

3 files changed

Lines changed: 763 additions & 9 deletions

File tree

packages/features/pbac/infrastructure/repositories/PermissionRepository.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logger from "@calcom/lib/logger";
12
import db from "@calcom/prisma";
23
import type { PrismaClient as PrismaClientWithExtensions } from "@calcom/prisma";
34
import type { MembershipRole } from "@calcom/prisma/enums";
@@ -15,6 +16,7 @@ import {
1516
export class PermissionRepository implements IPermissionRepository {
1617
private readonly PBAC_FEATURE_FLAG = "pbac" as const;
1718
private client: PrismaClientWithExtensions;
19+
private readonly logger = logger.getSubLogger({ prefix: ["PermissionRepository"] });
1820

1921
constructor(client: PrismaClientWithExtensions = db) {
2022
this.client = client;
@@ -237,7 +239,16 @@ export class PermissionRepository implements IPermissionRepository {
237239
return { resource, action };
238240
});
239241

242+
const permissionPairsJson = JSON.stringify(permissionPairs);
243+
244+
// Teams with PBAC permissions (direct memberships + child teams via org membership)
240245
const teamsWithPermissionPromise = this.client.$queryRaw<{ teamId: number }[]>`
246+
WITH required_permissions AS (
247+
SELECT
248+
required_perm->>'resource' as resource,
249+
required_perm->>'action' as action
250+
FROM jsonb_array_elements(${permissionPairsJson}::jsonb) AS required_perm
251+
)
241252
SELECT DISTINCT m."teamId"
242253
FROM "Membership" m
243254
INNER JOIN "Role" r ON m."customRoleId" = r.id
@@ -246,26 +257,61 @@ export class PermissionRepository implements IPermissionRepository {
246257
AND m."customRoleId" IS NOT NULL
247258
AND (
248259
SELECT COUNT(*)
249-
FROM jsonb_array_elements(${JSON.stringify(permissionPairs)}::jsonb) AS required_perm(perm)
260+
FROM required_permissions rp_req
261+
WHERE EXISTS (
262+
SELECT 1
263+
FROM "RolePermission" rp
264+
WHERE rp."roleId" = r.id
265+
AND (
266+
(rp."resource" = '*' AND rp."action" = '*') OR
267+
(rp."resource" = '*' AND rp."action" = rp_req.action) OR
268+
(rp."resource" = rp_req.resource AND rp."action" = '*') OR
269+
(rp."resource" = rp_req.resource AND rp."action" = rp_req.action)
270+
)
271+
)
272+
) = ${permissions.length}
273+
UNION
274+
SELECT DISTINCT child."id"
275+
FROM "Membership" m
276+
INNER JOIN "Role" r ON m."customRoleId" = r.id
277+
INNER JOIN "Team" org ON m."teamId" = org.id
278+
INNER JOIN "Team" child ON child."parentId" = org.id
279+
WHERE m."userId" = ${userId}
280+
AND m."accepted" = true
281+
AND m."customRoleId" IS NOT NULL
282+
AND (
283+
SELECT COUNT(*)
284+
FROM required_permissions rp_req
250285
WHERE EXISTS (
251286
SELECT 1
252287
FROM "RolePermission" rp
253288
WHERE rp."roleId" = r.id
254289
AND (
255290
(rp."resource" = '*' AND rp."action" = '*') OR
256-
(rp."resource" = '*' AND rp."action" = required_perm.perm->>'action') OR
257-
(rp."resource" = required_perm.perm->>'resource' AND rp."action" = '*') OR
258-
(rp."resource" = required_perm.perm->>'resource' AND rp."action" = required_perm.perm->>'action')
291+
(rp."resource" = '*' AND rp."action" = rp_req.action) OR
292+
(rp."resource" = rp_req.resource AND rp."action" = '*') OR
293+
(rp."resource" = rp_req.resource AND rp."action" = rp_req.action)
259294
)
260295
)
261296
) = ${permissions.length}
262297
`;
263298

299+
// Teams with fallback roles (direct memberships + child teams via org membership, PBAC disabled)
264300
const teamsWithFallbackRolesPromise = this.client.$queryRaw<{ teamId: number }[]>`
265301
SELECT DISTINCT m."teamId"
266302
FROM "Membership" m
267303
INNER JOIN "Team" t ON m."teamId" = t.id
268-
LEFT JOIN "TeamFeatures" f ON t.id = f."teamId" AND f."featureId" = ${this.PBAC_FEATURE_FLAG}
304+
LEFT JOIN "TeamFeatures" f ON f."teamId" = t.id AND f."featureId" = ${this.PBAC_FEATURE_FLAG}
305+
WHERE m."userId" = ${userId}
306+
AND m."accepted" = true
307+
AND m."role"::text = ANY(${fallbackRoles})
308+
AND f."teamId" IS NULL
309+
UNION
310+
SELECT DISTINCT child."id"
311+
FROM "Membership" m
312+
INNER JOIN "Team" org ON m."teamId" = org.id
313+
INNER JOIN "Team" child ON child."parentId" = org.id
314+
LEFT JOIN "TeamFeatures" f ON f."teamId" = org.id AND f."featureId" = ${this.PBAC_FEATURE_FLAG}
269315
WHERE m."userId" = ${userId}
270316
AND m."accepted" = true
271317
AND m."role"::text = ANY(${fallbackRoles})

0 commit comments

Comments
 (0)