Skip to content

feat: update recording, transcript endpoint and add tests #95

Open
tomerqodo wants to merge 2 commits into
qodo_combined_20260121_qodo_grep_cursor_copilot_1_base_feat_update_recording_transcript_endpoint_and_add_tests__pr692from
qodo_combined_20260121_qodo_grep_cursor_copilot_1_head_feat_update_recording_transcript_endpoint_and_add_tests__pr692
Open

feat: update recording, transcript endpoint and add tests #95
tomerqodo wants to merge 2 commits into
qodo_combined_20260121_qodo_grep_cursor_copilot_1_base_feat_update_recording_transcript_endpoint_and_add_tests__pr692from
qodo_combined_20260121_qodo_grep_cursor_copilot_1_head_feat_update_recording_transcript_endpoint_and_add_tests__pr692

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#692

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Missing await in recordings 📘 Rule violation ✓ Correctness
Description
getBookingRecordings() assigns the Promise returned by this.calVideoService.getRecordings() to
  recordings without awaiting it, then returns it as data.
• This can break the endpoint contract (GetBookingRecordingsOutput.data becomes a Promise), and
  errors from the Promise may surface as unhandled rejections rather than being managed gracefully.
• This violates the requirement to identify and handle failure points and edge cases with meaningful
  context.
Code

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[R226-232]

  async getBookingRecordings(@Param("bookingUid") bookingUid: string): Promise<GetBookingRecordingsOutput> {
-    const recordings = await this.calVideoService.getRecordings(bookingUid);
+    const recordings = this.calVideoService.getRecordings(bookingUid);

    return {
      status: SUCCESS_STATUS,
      data: recordings,
-      message:
-        "This endpoint will require authentication in a future release. Please update your integration to include valid credentials. See https://cal.com/docs/api-reference/v2/introduction#authentication for details.",
    };
Evidence
Compliance ID 3 requires robust handling of failure points. The updated controller code no longer
awaits the async dependency call and directly returns the unresolved Promise in the response
payload, which undermines graceful error handling and predictable behavior.

Rule 3: Generic: Robust Error Handling and Edge Case Management
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[226-232]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getBookingRecordings()` returns a Promise in `data` because the CalVideo call is not awaited, which can lead to incorrect responses and unhandled async failures.

## Issue Context
This endpoint depends on an async service call (`calVideoService.getRecordings`). The compliance requirement expects failure points to be handled gracefully with actionable internal context.

## Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[226-232]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. E2E tests use jest.spyOn 📘 Rule violation ⛯ Reliability
Description
• The new e2e tests use Jest-specific APIs (jest.spyOn) instead of Vitest equivalents.
• This violates the requirement that all tests use the Vitest framework, and risks inconsistent
  behavior in the standardized test runner configuration.
Code

apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-access-auth.e2e-spec.ts[R188-215]

+    describe("GET /v2/bookings/:bookingUid/recordings - Authorization", () => {
+      it("should allow booking organizer to access recordings", async () => {
+        const calVideoService = app.get(CalVideoService);
+        jest.spyOn(calVideoService, "getRecordings").mockResolvedValue([]);
+
+        const response = await request(app.getHttpServer())
+          .get(`/v2/bookings/${testBooking.uid}/recordings`)
+          .set("Authorization", `Bearer ${ownerApiKey}`)
+          .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
+          .expect(200);
+
+        expect(response.body.status).toEqual(SUCCESS_STATUS);
+      });
+
+      it("should return 403 when unauthorized user tries to access recordings", async () => {
+        await request(app.getHttpServer())
+          .get(`/v2/bookings/${testBooking.uid}/recordings`)
+          .set("Authorization", `Bearer ${unauthorizedApiKey}`)
+          .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
+          .expect(403);
+      });
+    });
+
+    describe("GET /v2/bookings/:bookingUid/transcripts - Authorization", () => {
+      it("should allow booking organizer to access transcripts", async () => {
+        const calVideoService = app.get(CalVideoService);
+        jest.spyOn(calVideoService, "getTranscripts").mockResolvedValue([]);
+
Evidence
Compliance ID 13 mandates using Vitest APIs in tests. The added test cases explicitly use
jest.spyOn, which is a Jest-only global and not the required Vitest vi API.

AGENTS.md
apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-access-auth.e2e-spec.ts[188-215]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The e2e test file uses Jest-specific APIs (`jest.spyOn`) instead of Vitest (`vi.spyOn`), violating the standardized test framework requirement.

## Issue Context
The repository compliance requires Vitest syntax in all test files.

## Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-access-auth.e2e-spec.ts[188-215]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Guard order blocks auth 🐞 Bug ⛨ Security
Description
@UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard) runs BookingPbacGuard before
  authentication, but BookingPbacGuard requires request.user.
• This will cause the transcripts endpoint to always throw UnauthorizedException, making it
  effectively unusable.
Code

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[R236-239]

+  @Pbac(["booking.readRecordings"])
  @Permissions([BOOKING_READ])
-  @UseGuards(BookingUidGuard)
-  // @UseGuards(ApiAuthGuard, BookingUidGuard, BookingPbacGuard)
+  @UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard)
  @ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)
Evidence
BookingPbacGuard explicitly throws when request.user is missing. Since ApiAuthGuard is the
component that populates request.user, placing it after BookingPbacGuard will reject all
requests. The same controller demonstrates the correct ordering pattern on another PBAC-protected
endpoint.

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[235-239]
apps/api/v2/src/ee/bookings/2024-08-13/guards/booking-pbac.guard.ts[23-36]
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[559-564]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The transcripts endpoint runs `BookingPbacGuard` before `ApiAuthGuard`, but `BookingPbacGuard` requires `request.user`.

### Issue Context
`ApiAuthGuard`/strategy is what populates `request.user`. PBAC checks should run after authentication.

### Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[235-239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Wrong permission scope 🐞 Bug ⛨ Security
Description
• The recordings endpoint is a GET/read operation but is annotated with
  @Permissions([BOOKING_WRITE]), which is inconsistent with other read-only booking endpoints.
• PermissionsGuard enforces these permission bits for platform OAuth clients / managed-user access
  tokens; requiring write will block clients that only requested booking read access and violates
  least-privilege.
Code

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[R215-217]

+  @Pbac(["booking.readRecordings"])
+  @Permissions([BOOKING_WRITE])
+  @UseGuards(ApiAuthGuard, BookingUidGuard, BookingPbacGuard)
Evidence
BOOKING_READ and BOOKING_WRITE are different permission bits. PermissionsGuard checks required
permissions against the OAuth client’s permission bitmask and throws Forbidden when missing. Nearby
read-only endpoints (like conferencing-sessions) require BOOKING_READ, suggesting this is
unintended.

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[214-218]
packages/platform/constants/permissions.ts[1-4]
apps/api/v2/src/modules/auth/guards/permissions/permissions.guard.ts[27-69]
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[561-563]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
A read-only recordings endpoint currently requires `BOOKING_WRITE` permission.

### Issue Context
`PermissionsGuard` enforces OAuth client permission bits; using the write bit will block integrations that only requested booking read access.

### Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[214-217]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Unused type import 🐞 Bug ⛯ Reliability
Description
GetBookingRecordingsOutput adds an unused import type { BookingRepository } ....
• This increases coupling between packages and can trigger lint/module-resolution issues in some
  build environments.
Code

packages/platform/types/bookings/2024-08-13/outputs/get-booking-recordings.output.ts[6]

+import type { BookingRepository } from "@calcom/features/bookings/lib/BookingRepository";
Evidence
The import is present but not referenced anywhere in the DTO file.

packages/platform/types/bookings/2024-08-13/outputs/get-booking-recordings.output.ts[1-7]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
An unused type-only import was added to a shared DTO file.

### Issue Context
Even type-only imports can introduce unwanted coupling and tooling failures if the referenced package isn’t meant to be a dependency.

### Fix Focus Areas
- packages/platform/types/bookings/2024-08-13/outputs/get-booking-recordings.output.ts[5-7]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



ⓘ The new review experience is currently in Beta. Learn more

Qodo Logo

Comment on lines 226 to 232
async getBookingRecordings(@Param("bookingUid") bookingUid: string): Promise<GetBookingRecordingsOutput> {
const recordings = await this.calVideoService.getRecordings(bookingUid);
const recordings = this.calVideoService.getRecordings(bookingUid);

return {
status: SUCCESS_STATUS,
data: recordings,
message:
"This endpoint will require authentication in a future release. Please update your integration to include valid credentials. See https://cal.com/docs/api-reference/v2/introduction#authentication for details.",
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Missing await in recordings 📘 Rule violation ✓ Correctness

getBookingRecordings() assigns the Promise returned by this.calVideoService.getRecordings() to
  recordings without awaiting it, then returns it as data.
• This can break the endpoint contract (GetBookingRecordingsOutput.data becomes a Promise), and
  errors from the Promise may surface as unhandled rejections rather than being managed gracefully.
• This violates the requirement to identify and handle failure points and edge cases with meaningful
  context.
Agent prompt
## Issue description
`getBookingRecordings()` returns a Promise in `data` because the CalVideo call is not awaited, which can lead to incorrect responses and unhandled async failures.

## Issue Context
This endpoint depends on an async service call (`calVideoService.getRecordings`). The compliance requirement expects failure points to be handled gracefully with actionable internal context.

## Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[226-232]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +188 to +215
describe("GET /v2/bookings/:bookingUid/recordings - Authorization", () => {
it("should allow booking organizer to access recordings", async () => {
const calVideoService = app.get(CalVideoService);
jest.spyOn(calVideoService, "getRecordings").mockResolvedValue([]);

const response = await request(app.getHttpServer())
.get(`/v2/bookings/${testBooking.uid}/recordings`)
.set("Authorization", `Bearer ${ownerApiKey}`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(200);

expect(response.body.status).toEqual(SUCCESS_STATUS);
});

it("should return 403 when unauthorized user tries to access recordings", async () => {
await request(app.getHttpServer())
.get(`/v2/bookings/${testBooking.uid}/recordings`)
.set("Authorization", `Bearer ${unauthorizedApiKey}`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(403);
});
});

describe("GET /v2/bookings/:bookingUid/transcripts - Authorization", () => {
it("should allow booking organizer to access transcripts", async () => {
const calVideoService = app.get(CalVideoService);
jest.spyOn(calVideoService, "getTranscripts").mockResolvedValue([]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. E2e tests use jest.spyon 📘 Rule violation ⛯ Reliability

• The new e2e tests use Jest-specific APIs (jest.spyOn) instead of Vitest equivalents.
• This violates the requirement that all tests use the Vitest framework, and risks inconsistent
  behavior in the standardized test runner configuration.
Agent prompt
## Issue description
The e2e test file uses Jest-specific APIs (`jest.spyOn`) instead of Vitest (`vi.spyOn`), violating the standardized test framework requirement.

## Issue Context
The repository compliance requires Vitest syntax in all test files.

## Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-access-auth.e2e-spec.ts[188-215]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +236 to 239
@Pbac(["booking.readRecordings"])
@Permissions([BOOKING_READ])
@UseGuards(BookingUidGuard)
// @UseGuards(ApiAuthGuard, BookingUidGuard, BookingPbacGuard)
@UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard)
@ApiHeader(API_KEY_OR_ACCESS_TOKEN_HEADER)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Guard order blocks auth 🐞 Bug ⛨ Security

@UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard) runs BookingPbacGuard before
  authentication, but BookingPbacGuard requires request.user.
• This will cause the transcripts endpoint to always throw UnauthorizedException, making it
  effectively unusable.
Agent prompt
### Issue description
The transcripts endpoint runs `BookingPbacGuard` before `ApiAuthGuard`, but `BookingPbacGuard` requires `request.user`.

### Issue Context
`ApiAuthGuard`/strategy is what populates `request.user`. PBAC checks should run after authentication.

### Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[235-239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +215 to +217
@Pbac(["booking.readRecordings"])
@Permissions([BOOKING_WRITE])
@UseGuards(ApiAuthGuard, BookingUidGuard, BookingPbacGuard)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Wrong permission scope 🐞 Bug ⛨ Security

• The recordings endpoint is a GET/read operation but is annotated with
  @Permissions([BOOKING_WRITE]), which is inconsistent with other read-only booking endpoints.
• PermissionsGuard enforces these permission bits for platform OAuth clients / managed-user access
  tokens; requiring write will block clients that only requested booking read access and violates
  least-privilege.
Agent prompt
### Issue description
A read-only recordings endpoint currently requires `BOOKING_WRITE` permission.

### Issue Context
`PermissionsGuard` enforces OAuth client permission bits; using the write bit will block integrations that only requested booking read access.

### Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[214-217]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

import { IsEnum, ValidateNested, IsNumber, IsString, IsOptional, IsUrl } from "class-validator";

import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
import type { BookingRepository } from "@calcom/features/bookings/lib/BookingRepository";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Unused type import 🐞 Bug ⛯ Reliability

GetBookingRecordingsOutput adds an unused import type { BookingRepository } ....
• This increases coupling between packages and can trigger lint/module-resolution issues in some
  build environments.
Agent prompt
### Issue description
An unused type-only import was added to a shared DTO file.

### Issue Context
Even type-only imports can introduce unwanted coupling and tooling failures if the referenced package isn’t meant to be a dependency.

### Fix Focus Areas
- packages/platform/types/bookings/2024-08-13/outputs/get-booking-recordings.output.ts[5-7]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant