Skip to content

Commit 38890da

Browse files
authored
fix: org admin/owner can access routng form (calcom#25412)
1 parent 0776657 commit 38890da

2 files changed

Lines changed: 84 additions & 55 deletions

File tree

apps/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm.ts

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData";
22
import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm";
3-
import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository";
4-
import { Resource } from "@calcom/features/pbac/domain/types/permission-registry";
5-
import { getResourcePermissions } from "@calcom/features/pbac/lib/resource-permissions";
6-
import { MembershipRole } from "@calcom/prisma/enums";
3+
import { getRoutingFormPermissions } from "@calcom/features/pbac/lib/resource-permissions";
74
import type { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps";
85

96
export const getServerSidePropsForSingleFormView = async function getServerSidePropsForSingleFormView(
@@ -78,7 +75,7 @@ export const getServerSidePropsForSingleFormView = async function getServerSideP
7875
};
7976
}
8077

81-
const { user: u, ...formWithoutUser } = form;
78+
const { user: _u, ...formWithoutUser } = form;
8279

8380
const formWithoutProfileInfo = {
8481
...formWithoutUser,
@@ -98,55 +95,17 @@ export const getServerSidePropsForSingleFormView = async function getServerSideP
9895
user: await userRepo.enrichUserWithItsProfile({ user: form.user }),
9996
};
10097

101-
// Get PBAC permissions for team-scoped routing forms
102-
let permissions = {
103-
canCreate: false,
104-
canRead: false,
105-
canEdit: false,
106-
canDelete: false,
107-
};
108-
109-
if (!form.teamId) {
110-
// For personal forms (teamId = null),
111-
// check if the form belongs to the current user
112-
if (form.userId !== user.id) {
113-
return {
114-
notFound: true,
115-
};
116-
}
98+
const permissions = await getRoutingFormPermissions({
99+
userId: user.id,
100+
formUserId: form.userId,
101+
formTeamId: form.teamId,
102+
formTeamParentId: form.team?.parentId ?? null,
103+
});
117104

118-
permissions = {
119-
canCreate: true,
120-
canRead: true,
121-
canEdit: true,
122-
canDelete: true,
105+
if (!permissions) {
106+
return {
107+
notFound: true,
123108
};
124-
} else {
125-
// team-scoped routing form
126-
// Get user's role in the team
127-
const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
128-
userId: user.id,
129-
teamId: form.teamId,
130-
});
131-
132-
if (!membership) {
133-
return {
134-
notFound: true,
135-
};
136-
}
137-
138-
permissions = await getResourcePermissions({
139-
userId: user.id,
140-
teamId: form.teamId,
141-
resource: Resource.RoutingForm,
142-
userRole: membership.role,
143-
fallbackRoles: {
144-
read: { roles: [MembershipRole.MEMBER, MembershipRole.ADMIN, MembershipRole.OWNER] },
145-
create: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
146-
update: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
147-
delete: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
148-
},
149-
});
150109
}
151110

152111
return {

packages/features/pbac/lib/resource-permissions.ts

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
2+
import { MembershipRepository } from "@calcom/features/membership/repositories/MembershipRepository";
23
import { prisma } from "@calcom/prisma";
3-
import type { MembershipRole } from "@calcom/prisma/enums";
4+
import { MembershipRole } from "@calcom/prisma/enums";
45

56
import { PermissionMapper } from "../domain/mappers/PermissionMapper";
6-
import type { Resource, CustomAction } from "../domain/types/permission-registry";
7-
import { CrudAction } from "../domain/types/permission-registry";
7+
import type { CustomAction } from "../domain/types/permission-registry";
8+
import { CrudAction, Resource } from "../domain/types/permission-registry";
89
import { PermissionCheckService } from "../services/permission-check.service";
910

1011
interface RoleMapping {
@@ -140,3 +141,72 @@ export const getSpecificPermissions = async ({
140141

141142
return permissions;
142143
};
144+
145+
export async function getRoutingFormPermissions({
146+
userId,
147+
formUserId,
148+
formTeamId,
149+
formTeamParentId,
150+
}: {
151+
userId: number;
152+
formUserId: number;
153+
formTeamId: number | null;
154+
formTeamParentId: number | null;
155+
}): Promise<ResourcePermissions | null> {
156+
if (!formTeamId) {
157+
if (formUserId !== userId) {
158+
return null;
159+
}
160+
161+
return {
162+
canCreate: true,
163+
canRead: true,
164+
canEdit: true,
165+
canDelete: true,
166+
};
167+
}
168+
169+
const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
170+
userId,
171+
teamId: formTeamId,
172+
});
173+
174+
let isParentOrgAdmin = false;
175+
if (!membership && formTeamParentId) {
176+
const parentOrgMembership = await MembershipRepository.getAdminOrOwnerMembership(
177+
userId,
178+
formTeamParentId
179+
);
180+
isParentOrgAdmin = !!parentOrgMembership;
181+
}
182+
183+
if (!membership && !isParentOrgAdmin) {
184+
return null;
185+
}
186+
187+
if (!membership && isParentOrgAdmin) {
188+
return {
189+
canCreate: true,
190+
canRead: true,
191+
canEdit: true,
192+
canDelete: true,
193+
};
194+
}
195+
196+
if (membership) {
197+
return await getResourcePermissions({
198+
userId,
199+
teamId: formTeamId,
200+
resource: Resource.RoutingForm,
201+
userRole: membership.role,
202+
fallbackRoles: {
203+
read: { roles: [MembershipRole.MEMBER, MembershipRole.ADMIN, MembershipRole.OWNER] },
204+
create: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
205+
update: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
206+
delete: { roles: [MembershipRole.ADMIN, MembershipRole.OWNER] },
207+
},
208+
});
209+
}
210+
211+
return null;
212+
}

0 commit comments

Comments
 (0)