diff --git a/packages/trpc/server/routers/viewer/organizations/addMembersToEventTypes.handler.ts b/packages/trpc/server/routers/viewer/organizations/addMembersToEventTypes.handler.ts index 925a36d54ae254..fd201bb578f5d5 100644 --- a/packages/trpc/server/routers/viewer/organizations/addMembersToEventTypes.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/addMembersToEventTypes.handler.ts @@ -1,6 +1,7 @@ -import { isOrganisationAdmin } from "@calcom/lib/server/queries/organisations"; +import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; +import { MembershipRole } from "@calcom/prisma/client"; import { TRPCError } from "@trpc/server"; @@ -18,9 +19,21 @@ type AddBulkToEventTypeHandler = { export async function addMembersToEventTypesHandler({ ctx, input }: AddBulkToEventTypeHandler) { if (!ctx.user.organizationId) throw new TRPCError({ code: "UNAUTHORIZED" }); - // check if user is admin of organization - if (!(await isOrganisationAdmin(ctx.user?.id, ctx.user.organizationId))) - throw new TRPCError({ code: "UNAUTHORIZED" }); + // Check if user has permission to manage event types in the organization + const permissionCheckService = new PermissionCheckService(); + const hasPermission = await permissionCheckService.checkPermission({ + userId: ctx.user.id, + teamId: ctx.user.organizationId, + permission: "eventType.update", + fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN], + }); + + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to manage event types in this organization", + }); + } const { eventTypeIds, teamIds, userIds } = input; diff --git a/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts b/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts index b3faf504a80489..a6a93a7792ec8e 100644 --- a/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts @@ -1,5 +1,6 @@ import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains"; import stripe from "@calcom/features/ee/payments/server/stripe"; +import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { UserRepository } from "@calcom/lib/server/repository/user"; @@ -41,24 +42,20 @@ export const createTeamsHandler = async ({ ctx, input }: CreateTeamsOptions) => throw new NotAuthorizedError(); } - // Validate user membership role - const userMembershipRole = await prisma.membership.findFirst({ - where: { - userId: organizationOwner.id, - teamId: orgId, - role: { - in: ["OWNER", "ADMIN"], - }, - // @TODO: not sure if this already setup earlier - // accepted: true, - }, - select: { - role: true, - }, + // Validate user has permission to create teams in the organization + const permissionCheckService = new PermissionCheckService(); + const hasPermission = await permissionCheckService.checkPermission({ + userId: organizationOwner.id, + teamId: orgId, + permission: "team.create", + fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN], }); - if (!userMembershipRole) { - log.error("User is not a member of the organization", safeStringify({ orgId, organizationOwner })); + if (!hasPermission) { + log.error( + "User is not authorized to create teams in the organization", + safeStringify({ orgId, organizationOwner }) + ); throw new NotAuthorizedError(); } diff --git a/packages/trpc/server/routers/viewer/organizations/deleteTeam.handler.ts b/packages/trpc/server/routers/viewer/organizations/deleteTeam.handler.ts index 2db525619dd2bb..812bcb41ce6be1 100644 --- a/packages/trpc/server/routers/viewer/organizations/deleteTeam.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/deleteTeam.handler.ts @@ -1,12 +1,52 @@ +import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import { prisma } from "@calcom/prisma"; +import { MembershipRole } from "@calcom/prisma/client"; +import { TRPCError } from "@trpc/server"; + +import type { TrpcSessionUser } from "../../../types"; import type { TDeleteTeamInputSchema } from "./deleteTeam.schema"; type DeleteOptions = { + ctx: { + user: NonNullable; + }; input: TDeleteTeamInputSchema; }; -export const deleteTeamHandler = async ({ input }: DeleteOptions) => { +export const deleteTeamHandler = async ({ ctx, input }: DeleteOptions) => { + const team = await prisma.team.findUnique({ + where: { id: input.teamId }, + select: { + id: true, + parentId: true, + }, + }); + + if (!team) { + throw new TRPCError({ code: "NOT_FOUND", message: "Team not found" }); + } + + if (!team.parentId) { + throw new TRPCError({ code: "BAD_REQUEST", message: "Can only delete teams within organizations" }); + } + + // Check if user has permission to delete teams in this organization + const permissionCheckService = new PermissionCheckService(); + const hasPermission = await permissionCheckService.checkPermission({ + userId: ctx.user.id, + teamId: team.parentId, + permission: "team.delete", + fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN], + }); + + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete teams in this organization", + }); + } + // delete all memberships await prisma.membership.deleteMany({ where: { diff --git a/packages/trpc/server/routers/viewer/organizations/publish.handler.ts b/packages/trpc/server/routers/viewer/organizations/publish.handler.ts index 8b9aca449707e4..096d0ff928ca10 100644 --- a/packages/trpc/server/routers/viewer/organizations/publish.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/publish.handler.ts @@ -1,8 +1,9 @@ import { getRequestedSlugError } from "@calcom/app-store/stripepayment/lib/team-billing"; import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments"; +import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants"; -import { isOrganisationAdmin } from "@calcom/lib/server/queries/organisations"; import { prisma } from "@calcom/prisma"; +import { MembershipRole } from "@calcom/prisma/client"; import { teamMetadataStrictSchema } from "@calcom/prisma/zod-utils"; import { TRPCError } from "@trpc/server"; @@ -20,7 +21,21 @@ export const publishHandler = async ({ ctx }: PublishOptions) => { if (!orgId) throw new TRPCError({ code: "UNAUTHORIZED", message: "You do not have an organization to upgrade" }); - if (!(await isOrganisationAdmin(ctx.user.id, orgId))) throw new TRPCError({ code: "UNAUTHORIZED" }); + // Check if user has permission to publish the organization + const permissionCheckService = new PermissionCheckService(); + const hasPermission = await permissionCheckService.checkPermission({ + userId: ctx.user.id, + teamId: orgId, + permission: "organization.update", + fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN], + }); + + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to publish this organization", + }); + } const prevTeam = await prisma.team.findUnique({ where: { @@ -66,7 +81,6 @@ export const publishHandler = async ({ ctx }: PublishOptions) => { const { requestedSlug, ...newMetadata } = metadata.data; let updatedTeam: Awaited>; - try { updatedTeam = await prisma.team.update({ where: { id: orgId },