Files
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.6
7ff2eaf293 fix: consolidate booking access checks into doesUserIdHaveAccessToBooking (#28071)
* fix: align checkBookingAccessWithPBAC with listing logic for personal event types

Co-Authored-By: [email protected] <[email protected]>

* fix: align permission strings with doesUserIdHaveAccessToBooking granular permissions

Co-Authored-By: [email protected] <[email protected]>

* change implementation

* remove unused code

* test: add getBookingDetails tests for personal event type booking access

Co-Authored-By: [email protected] <[email protected]>

* fix: remove unused MembershipRole import

Co-Authored-By: [email protected] <[email protected]>

* test: convert BookingDetailsService tests to integration tests

Replace unit tests with mocks by integration tests using real database.
Tests verify org/team admin access to personal event type bookings.

- Org admin viewing team member's personal event booking (fails on main, passes on PR)
- Team admin viewing team member's personal event booking (fails on main, passes on PR)
- Non-admin denied access (passes on both)
- Owner viewing own booking (passes on both)
- Non-existent booking returns Forbidden (passes on both)

Co-Authored-By: [email protected] <[email protected]>

* test: refactor integration tests to use repositories instead of direct prisma calls

Co-Authored-By: [email protected] <[email protected]>

* test: replace direct prisma usage with TestXXXRepository pattern in integration tests

Co-Authored-By: [email protected] <[email protected]>

* test: use production repositories (OrganizationRepository, BookingRepository, UserRepository) instead of test repos for setup

Co-Authored-By: [email protected] <[email protected]>

* test: inline test repository logic into integration test file

The TestXXXRepository classes were thin wrappers around single prisma
calls with barely any logic, so the indirection wasn't justified.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-11 14:46:57 -03:00

49 lines
1.7 KiB
TypeScript

import { ErrorWithCode } from "@calcom/lib/errors";
import type { PrismaClient } from "@calcom/prisma";
import { BookingRepository } from "../repositories/BookingRepository";
import { BookingAccessService } from "./BookingAccessService";
export class BookingDetailsService {
private bookingRepo: BookingRepository;
private bookingAccessService: BookingAccessService;
constructor(prismaClient: PrismaClient) {
this.bookingRepo = new BookingRepository(prismaClient);
this.bookingAccessService = new BookingAccessService(prismaClient);
}
async getBookingDetails({ userId, bookingUid }: { userId: number; bookingUid: string }) {
const hasAccess = await this.bookingAccessService.doesUserIdHaveAccessToBooking({
userId,
bookingUid,
});
if (!hasAccess) {
throw ErrorWithCode.Factory.Forbidden("You do not have permission to view this booking");
}
const booking = await this.bookingRepo.findByUidForDetails({ bookingUid });
if (!booking) {
throw ErrorWithCode.Factory.BookingNotFound("Booking not found");
}
const [rescheduledToBooking, previousBooking] = await Promise.all([
// For old rescheduled bookings, find the new booking
booking.rescheduled
? this.bookingRepo.findRescheduledToBooking({ bookingUid: booking.uid })
: Promise.resolve(null),
// For new bookings that replaced an old one, fetch the previous booking's schedule
booking.fromReschedule
? this.bookingRepo.findPreviousBooking({ fromReschedule: booking.fromReschedule })
: Promise.resolve(null),
]);
return {
rescheduledToBooking,
previousBooking,
tracking: booking.tracking,
};
}
}