perf: routing forms loading time (#17518)
* perf: routing forms loading time * chore: add TODO * chore * chore: add type * chore: use Promise.all * fix: type err * fix: fetch id * refactor: don't fetch team * chore: add name
This commit is contained in:
@@ -87,20 +87,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
id: formId,
|
||||
...entityPrismaWhereClause({ userId: user.id }),
|
||||
},
|
||||
include: {
|
||||
team: {
|
||||
select: {
|
||||
members: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!form) {
|
||||
return res.status(404).json({ message: "Form not found or unauthorized" });
|
||||
}
|
||||
|
||||
if (!canEditEntity(form, user.id)) {
|
||||
if (!(await canEditEntity(form, user.id))) {
|
||||
return res.status(404).json({ message: "Form not found or unauthorized" });
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,6 @@ export async function isFormCreateEditAllowed({
|
||||
select: {
|
||||
userId: true,
|
||||
teamId: true,
|
||||
team: {
|
||||
select: {
|
||||
members: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -37,5 +32,5 @@ export async function isFormCreateEditAllowed({
|
||||
});
|
||||
}
|
||||
|
||||
return canEditEntity(form, userId);
|
||||
return await canEditEntity(form, userId);
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export const formMutationHandler = async ({ ctx, input }: FormMutationHandlerOpt
|
||||
});
|
||||
}
|
||||
|
||||
if (!canEditEntity(sourceForm, userId)) {
|
||||
if (!(await canEditEntity(sourceForm, userId))) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: `Form to duplicate: ${duplicateFrom} not found or you are unauthorized`,
|
||||
|
||||
@@ -36,8 +36,9 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => {
|
||||
],
|
||||
include: {
|
||||
team: {
|
||||
include: {
|
||||
members: true,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
@@ -54,15 +55,19 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => {
|
||||
}),
|
||||
});
|
||||
|
||||
const serializableForms = [];
|
||||
for (let i = 0; i < forms.length; i++) {
|
||||
const form = forms[i];
|
||||
const hasWriteAccess = canEditEntity(form, user.id);
|
||||
serializableForms.push({
|
||||
form: await getSerializableForm({ form: forms[i] }),
|
||||
readOnly: !hasWriteAccess,
|
||||
});
|
||||
}
|
||||
const serializableForms = await Promise.all(
|
||||
forms.map(async (form) => {
|
||||
const [hasWriteAccess, serializedForm] = await Promise.all([
|
||||
canEditEntity(form, user.id),
|
||||
getSerializableForm({ form }),
|
||||
]);
|
||||
|
||||
return {
|
||||
form: serializedForm,
|
||||
readOnly: !hasWriteAccess,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
filtered: serializableForms,
|
||||
|
||||
@@ -49,6 +49,7 @@ async function getResponseWithFormFieldsHandler({ ctx, input }: GetResponseWithF
|
||||
},
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
members: true,
|
||||
slug: true,
|
||||
parent: {
|
||||
@@ -74,7 +75,7 @@ async function getResponseWithFormFieldsHandler({ ctx, input }: GetResponseWithF
|
||||
|
||||
// TODO: To make the check stricter, we could check if the user is admin/owner of the team or a member that is the organizer.
|
||||
// But the exact criteria of showing a booking to the user could be trickier. Maybe we allow hosts as well to access the booking and thus should allow them as well to reroute
|
||||
if (!canAccessEntity(form, user.id)) {
|
||||
if (!(await canAccessEntity(form, user.id))) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: translate("you_dont_have_access_to_reroute_this_booking"),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Membership } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
export const enum ENTITY_PERMISSION_LEVEL {
|
||||
@@ -11,22 +10,22 @@ export const enum ENTITY_PERMISSION_LEVEL {
|
||||
TEAM_WRITE,
|
||||
}
|
||||
|
||||
export function canEditEntity(
|
||||
export async function canEditEntity(
|
||||
entity: Parameters<typeof getEntityPermissionLevel>[0],
|
||||
userId: Parameters<typeof getEntityPermissionLevel>[1]
|
||||
) {
|
||||
const permissionLevel = getEntityPermissionLevel(entity, userId);
|
||||
const permissionLevel = await getEntityPermissionLevel(entity, userId);
|
||||
return (
|
||||
permissionLevel === ENTITY_PERMISSION_LEVEL.TEAM_WRITE ||
|
||||
permissionLevel === ENTITY_PERMISSION_LEVEL.USER_ONLY_WRITE
|
||||
);
|
||||
}
|
||||
|
||||
export function canAccessEntity(
|
||||
export async function canAccessEntity(
|
||||
entity: Parameters<typeof getEntityPermissionLevel>[0],
|
||||
userId: Parameters<typeof getEntityPermissionLevel>[1]
|
||||
) {
|
||||
const permissionLevel = getEntityPermissionLevel(entity, userId);
|
||||
const permissionLevel = await getEntityPermissionLevel(entity, userId);
|
||||
return (
|
||||
permissionLevel === ENTITY_PERMISSION_LEVEL.TEAM_WRITE ||
|
||||
permissionLevel === ENTITY_PERMISSION_LEVEL.USER_ONLY_WRITE ||
|
||||
@@ -34,15 +33,24 @@ export function canAccessEntity(
|
||||
);
|
||||
}
|
||||
|
||||
export function getEntityPermissionLevel(
|
||||
export async function getEntityPermissionLevel(
|
||||
entity: {
|
||||
userId: number | null;
|
||||
team: { members: Membership[] } | null;
|
||||
teamId: number | null;
|
||||
},
|
||||
userId: number
|
||||
) {
|
||||
if (entity.team) {
|
||||
const roleForTeamMember = entity.team.members.find((member) => member.userId === userId)?.role;
|
||||
if (entity.teamId) {
|
||||
const { prisma } = await import("@calcom/prisma");
|
||||
const membership = await prisma.membership.findFirst({
|
||||
where: {
|
||||
teamId: entity.teamId,
|
||||
userId,
|
||||
accepted: true,
|
||||
},
|
||||
});
|
||||
const roleForTeamMember = membership?.role;
|
||||
|
||||
if (roleForTeamMember) {
|
||||
//TODO: Remove type assertion
|
||||
const hasWriteAccessToTeam = (
|
||||
|
||||
Reference in New Issue
Block a user