import { getProductPermissionByUserId, getTeamRoleByTeamIdUserId } from "@/modules/ee/teams/lib/roles"; import { TTeamPermission } from "@/modules/ee/teams/product-teams/types/teams"; import { TTeamRole } from "@/modules/ee/teams/team-list/types/teams"; import { returnValidationErrors } from "next-safe-action"; import { ZodIssue, z } from "zod"; import { getMembershipRole } from "@formbricks/lib/membership/hooks/actions"; import { AuthorizationError } from "@formbricks/types/errors"; import { TOrganizationRole } from "@formbricks/types/memberships"; const formatErrors = (issues: ZodIssue[]): Record => { return { ...issues.reduce((acc, issue) => { acc[issue.path.join(".")] = { _errors: [issue.message], }; return acc; }, {}), }; }; export type TAccess = | { type: "organization"; schema?: z.ZodObject; data?: z.ZodObject["_output"]; roles: TOrganizationRole[]; } | { type: "productTeam"; minPermission?: TTeamPermission; productId: string; } | { type: "team"; minPermission?: TTeamRole; teamId: string; }; const teamPermissionWeight = { read: 1, readWrite: 2, manage: 3, }; const teamRoleWeight = { contributor: 1, admin: 2, }; export const checkAuthorizationUpdated = async ({ userId, organizationId, access, }: { userId: string; organizationId: string; access: TAccess[]; }) => { const role = await getMembershipRole(userId, organizationId); for (let accessItem of access) { if (accessItem.type === "organization") { if (accessItem.schema) { const resultSchema = accessItem.schema.strict(); const parsedResult = resultSchema.safeParse(accessItem.data); if (!parsedResult.success) { // @ts-expect-error -- TODO: match dynamic next-safe-action types return returnValidationErrors(resultSchema, formatErrors(parsedResult.error.issues)); } } if (accessItem.roles.includes(role)) { return true; } } else { if (accessItem.type === "productTeam") { const productPermission = await getProductPermissionByUserId(userId, accessItem.productId); if ( !productPermission || (accessItem.minPermission !== undefined && teamPermissionWeight[productPermission] < teamPermissionWeight[accessItem.minPermission]) ) { continue; } } else { const teamRole = await getTeamRoleByTeamIdUserId(accessItem.teamId, userId); if ( !teamRole || (accessItem.minPermission !== undefined && teamRoleWeight[teamRole] < teamRoleWeight[accessItem.minPermission]) ) { continue; } } return true; } } throw new AuthorizationError("Not authorized"); };