refactor: replace isTeamAdminOrOwner with PBAC permissions (#24037)

* refactor: replace isTeamAdminOrOwner with PBAC permissions

- Remove isTeamAdminOrOwner from team-members-view.tsx, rely on server-side permissions
- Replace role checks in addMembersToEventTypes.handler.ts with eventType.update permission
- Follow PBAC refactoring guide patterns for consistent permission checking
- Fix TypeScript any type usage and unused variable warnings

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* use enum

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Eunjae Lee
2025-09-24 13:46:24 +00:00
committed by GitHub
co-authored by Devin AI
parent 96855ea391
commit fe190f20f3
2 changed files with 22 additions and 12 deletions
+10 -6
View File
@@ -2,7 +2,6 @@
import { useState } from "react";
import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { MemberInvitationModalWithoutMembers } from "@calcom/features/ee/teams/components/MemberInvitationModal";
import MemberList from "@calcom/features/ee/teams/components/MemberList";
@@ -23,18 +22,23 @@ interface TeamMembersViewProps {
}[];
}[];
};
attributes?: any[];
attributes?: {
id: string;
name: string;
options: {
value: string;
}[];
}[];
permissions: MemberPermissions;
}
export const TeamMembersView = ({ team, facetedTeamValues, permissions }: TeamMembersViewProps) => {
const { t } = useLocale();
const [showMemberInvitationModal, setShowMemberInvitationModal] = useState(false);
const [showInviteLinkSettingsModal, setShowInviteLinkSettingsModal] = useState(false);
const [_showInviteLinkSettingsModal, setShowInviteLinkSettingsModal] = useState(false);
// Use PBAC permissions if available, otherwise fall back to role-based check
const isTeamAdminOrOwner = checkAdminOrOwner(team.membership.role);
const canLoggedInUserSeeMembers = permissions?.canListMembers ?? (!team.isPrivate || isTeamAdminOrOwner);
// Use PBAC permissions - server-side permission check should be done in parent component
const canLoggedInUserSeeMembers = permissions?.canListMembers ?? false;
return (
<LicenseRequired>
@@ -1,6 +1,7 @@
import { isTeamAdmin, isTeamOwner } from "@calcom/features/ee/teams/lib/queries";
import prisma from "@calcom/prisma";
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/enums";
import { TRPCError } from "@trpc/server";
@@ -17,11 +18,16 @@ type AddBulkToEventTypeHandler = {
export async function addMembersToEventTypesHandler({ ctx, input }: AddBulkToEventTypeHandler) {
const { eventTypeIds, userIds, teamId } = input;
const isTeamAdminOrOwner =
(await isTeamAdmin(ctx.user.id, teamId)) || (await isTeamOwner(ctx.user.id, teamId));
const permissionCheckService = new PermissionCheckService();
const hasPermission = await permissionCheckService.checkPermission({
userId: ctx.user.id,
teamId,
permission: "eventType.update",
fallbackRoles: [MembershipRole.ADMIN, MembershipRole.OWNER],
});
// check if user is admin or owner of team
if (!isTeamAdminOrOwner) throw new TRPCError({ code: "UNAUTHORIZED" });
// check if user has eventType.update permission
if (!hasPermission) throw new TRPCError({ code: "UNAUTHORIZED" });
const data: Prisma.HostCreateManyInput[] = eventTypeIds.flatMap((eventId) =>
userIds.map((userId) => ({