diff --git a/apps/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm.ts b/apps/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm.ts index 75b19fe15d8c77..a8855ff3159770 100644 --- a/apps/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm.ts +++ b/apps/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm.ts @@ -1,9 +1,6 @@ import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData"; import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; -import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; -import { Resource } from "@calcom/features/pbac/domain/types/permission-registry"; -import { getResourcePermissions } from "@calcom/features/pbac/lib/resource-permissions"; -import { MembershipRole } from "@calcom/prisma/enums"; +import { getRoutingFormPermissions } from "@calcom/features/pbac/lib/resource-permissions"; import type { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps"; export const getServerSidePropsForSingleFormView = async function getServerSidePropsForSingleFormView( @@ -78,7 +75,7 @@ export const getServerSidePropsForSingleFormView = async function getServerSideP }; } - const { user: u, ...formWithoutUser } = form; + const { user: _u, ...formWithoutUser } = form; const formWithoutProfileInfo = { ...formWithoutUser, @@ -98,55 +95,17 @@ export const getServerSidePropsForSingleFormView = async function getServerSideP user: await userRepo.enrichUserWithItsProfile({ user: form.user }), }; - // Get PBAC permissions for team-scoped routing forms - let permissions = { - canCreate: false, - canRead: false, - canEdit: false, - canDelete: false, - }; - - if (!form.teamId) { - // For personal forms (teamId = null), - // check if the form belongs to the current user - if (form.userId !== user.id) { - return { - notFound: true, - }; - } + const permissions = await getRoutingFormPermissions({ + userId: user.id, + formUserId: form.userId, + formTeamId: form.teamId, + formTeamParentId: form.team?.parentId ?? null, + }); - permissions = { - canCreate: true, - canRead: true, - canEdit: true, - canDelete: true, + if (!permissions) { + return { + notFound: true, }; - } else { - // team-scoped routing form - // Get user's role in the team - const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ - userId: user.id, - teamId: form.teamId, - }); - - if (!membership) { - return { - notFound: true, - }; - } - - permissions = await getResourcePermissions({ - userId: user.id, - teamId: form.teamId, - resource: Resource.RoutingForm, - userRole: membership.role, - fallbackRoles: { - read: { roles: [MembershipRole.MEMBER, MembershipRole.ADMIN, MembershipRole.OWNER] }, - create: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, - update: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, - delete: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, - }, - }); } return { diff --git a/packages/features/pbac/lib/resource-permissions.ts b/packages/features/pbac/lib/resource-permissions.ts index 516608a96b4244..f68e690cbc708d 100644 --- a/packages/features/pbac/lib/resource-permissions.ts +++ b/packages/features/pbac/lib/resource-permissions.ts @@ -1,10 +1,11 @@ import { FeaturesRepository } from "@calcom/features/flags/features.repository"; +import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository"; import { prisma } from "@calcom/prisma"; -import type { MembershipRole } from "@calcom/prisma/enums"; +import { MembershipRole } from "@calcom/prisma/enums"; import { PermissionMapper } from "../domain/mappers/PermissionMapper"; -import type { Resource, CustomAction } from "../domain/types/permission-registry"; -import { CrudAction } from "../domain/types/permission-registry"; +import type { CustomAction } from "../domain/types/permission-registry"; +import { CrudAction, Resource } from "../domain/types/permission-registry"; import { PermissionCheckService } from "../services/permission-check.service"; interface RoleMapping { @@ -140,3 +141,72 @@ export const getSpecificPermissions = async ({ return permissions; }; + +export async function getRoutingFormPermissions({ + userId, + formUserId, + formTeamId, + formTeamParentId, +}: { + userId: number; + formUserId: number; + formTeamId: number | null; + formTeamParentId: number | null; +}): Promise { + if (!formTeamId) { + if (formUserId !== userId) { + return null; + } + + return { + canCreate: true, + canRead: true, + canEdit: true, + canDelete: true, + }; + } + + const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({ + userId, + teamId: formTeamId, + }); + + let isParentOrgAdmin = false; + if (!membership && formTeamParentId) { + const parentOrgMembership = await MembershipRepository.getAdminOrOwnerMembership( + userId, + formTeamParentId + ); + isParentOrgAdmin = !!parentOrgMembership; + } + + if (!membership && !isParentOrgAdmin) { + return null; + } + + if (!membership && isParentOrgAdmin) { + return { + canCreate: true, + canRead: true, + canEdit: true, + canDelete: true, + }; + } + + if (membership) { + return await getResourcePermissions({ + userId, + teamId: formTeamId, + resource: Resource.RoutingForm, + userRole: membership.role, + fallbackRoles: { + read: { roles: [MembershipRole.MEMBER, MembershipRole.ADMIN, MembershipRole.OWNER] }, + create: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, + update: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, + delete: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] }, + }, + }); + } + + return null; +}