Skip to content

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

Open
tomerqodo wants to merge 2 commits into
qodo_action_req_1_base_feat_update_recording_transcript_endpoint_and_add_tests__pr16from
qodo_action_req_1_head_feat_update_recording_transcript_endpoint_and_add_tests__pr16
Open

feat: update recording, transcript endpoint and add tests #111
tomerqodo wants to merge 2 commits into
qodo_action_req_1_base_feat_update_recording_transcript_endpoint_and_add_tests__pr16from
qodo_action_req_1_head_feat_update_recording_transcript_endpoint_and_add_tests__pr16

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#16

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. getRecordings() missing await 📘 Rule violation ✓ Correctness
Description
• The controller assigns recordings to the Promise returned by
  this.calVideoService.getRecordings(bookingUid) instead of awaiting it, then returns it in the
  response data field.
• This creates an unhandled/incorrect async failure point where the endpoint can return a
  non-serializable Promise (or incorrect payload shape) rather than the expected recordings array,
  making failures harder to diagnose and breaking edge-case behavior.
• This violates the requirement to identify and handle failure points/edge cases in request
  handling.
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
PR Compliance ID 3 requires handling potential failure points and edge cases; returning a Promise in
the response instead of awaited data introduces a failure mode where the response is invalid and
errors may surface unclearly. The cited controller code shows getRecordings() is not awaited and
its Promise is returned as data.

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 `data: recordings` where `recordings` is a Promise because `await` is missing. This can break the API response shape and makes async failures/edge cases harder to handle.

## Issue Context
`GetBookingRecordingsOutput.data` is expected to be a `RecordingItem[]`, not a Promise. The service call is a potential failure point that should be awaited and handled.

## 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. jest.spyOn used in tests 📘 Rule violation ⛯ Reliability
Description
• The newly added e2e tests use Jest-specific APIs (jest.spyOn(...)) rather than Vitest
  (vi.spyOn(...)).
• This violates the requirement to standardize on Vitest (and UTC timezone) for consistent test
  execution, and can cause test failures or inconsistent behavior in the repo’s expected test runner
  setup.
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
PR Compliance ID 13 requires tests to use Vitest; the cited test code uses Jest APIs (jest.spyOn)
which directly violates the failure criteria mentioning Jest-specific APIs.

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 added tests use Jest-specific mocking (`jest.spyOn`) which violates the requirement that all tests use Vitest.

## Issue Context
The compliance rule explicitly disallows Jest-specific APIs in tests. These e2e tests should use `vi.spyOn` (and any other Vitest equivalents) and rely on the repo’s UTC timezone test configuration.

## 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. Transcripts guards misordered 🐞 Bug ⛯ Reliability
Description
• The transcripts route runs BookingPbacGuard before ApiAuthGuard.
• BookingPbacGuard requires request.user and throws UnauthorizedException if absent, so the
  endpoint will 401 even with valid credentials.
• This makes GET /v2/bookings/:bookingUid/transcripts 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
The controller declares guards in an order where the PBAC guard executes before authentication. The
PBAC guard explicitly throws if request.user is missing.

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[235-252]
apps/api/v2/src/ee/bookings/2024-08-13/guards/booking-pbac.guard.ts[23-33]
apps/api/v2/src/modules/auth/guards/api-auth/api-auth.guard.ts[7-19]

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

### Issue description
`GET /v2/bookings/:bookingUid/transcripts` has `@UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard)`. `BookingPbacGuard` requires `request.user`, which is only populated after `ApiAuthGuard` runs.

### Issue Context
`BookingPbacGuard` throws `UnauthorizedException` when `request.user` is missing.

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

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


View more (1)
4. Wrong permission for read 🐞 Bug ⛨ Security
Description
• The recordings endpoint is a GET/read operation but now requires BOOKING_WRITE.
• Platform permissions are independent bits; BOOKING_WRITE does not imply BOOKING_READ, so
  clients with only BOOKING_READ will start failing with 403.
• This is inconsistent with other read endpoints (e.g., transcripts, conferencing-sessions) which
  require BOOKING_READ.
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
The controller now requires BOOKING_WRITE for a read endpoint. The permission-checking utility
uses exact bit checks per permission, so requiring WRITE will not accept READ-only clients.

apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[214-218]
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[235-239]
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[559-563]
packages/platform/utils/permissions.ts[16-24]

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

### Issue description
`GET /v2/bookings/:bookingUid/recordings` requires `BOOKING_WRITE`, which will reject OAuth clients that only have `BOOKING_READ`.

### Issue Context
Permissions are checked via bitwise equality; WRITE does not include READ.

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

ⓘ 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. getrecordings() missing await 📘 Rule violation ✓ Correctness

• The controller assigns recordings to the Promise returned by
  this.calVideoService.getRecordings(bookingUid) instead of awaiting it, then returns it in the
  response data field.
• This creates an unhandled/incorrect async failure point where the endpoint can return a
  non-serializable Promise (or incorrect payload shape) rather than the expected recordings array,
  making failures harder to diagnose and breaking edge-case behavior.
• This violates the requirement to identify and handle failure points/edge cases in request
  handling.
Agent prompt
## Issue description
`getBookingRecordings()` returns `data: recordings` where `recordings` is a Promise because `await` is missing. This can break the API response shape and makes async failures/edge cases harder to handle.

## Issue Context
`GetBookingRecordingsOutput.data` is expected to be a `RecordingItem[]`, not a Promise. The service call is a potential failure point that should be awaited and handled.

## 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. jest.spyon used in tests 📘 Rule violation ⛯ Reliability

• The newly added e2e tests use Jest-specific APIs (jest.spyOn(...)) rather than Vitest
  (vi.spyOn(...)).
• This violates the requirement to standardize on Vitest (and UTC timezone) for consistent test
  execution, and can cause test failures or inconsistent behavior in the repo’s expected test runner
  setup.
Agent prompt
## Issue description
The added tests use Jest-specific mocking (`jest.spyOn`) which violates the requirement that all tests use Vitest.

## Issue Context
The compliance rule explicitly disallows Jest-specific APIs in tests. These e2e tests should use `vi.spyOn` (and any other Vitest equivalents) and rely on the repo’s UTC timezone test configuration.

## 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. Transcripts guards misordered 🐞 Bug ⛯ Reliability

• The transcripts route runs BookingPbacGuard before ApiAuthGuard.
• BookingPbacGuard requires request.user and throws UnauthorizedException if absent, so the
  endpoint will 401 even with valid credentials.
• This makes GET /v2/bookings/:bookingUid/transcripts effectively unusable.
Agent prompt
### Issue description
`GET /v2/bookings/:bookingUid/transcripts` has `@UseGuards(BookingPbacGuard, ApiAuthGuard, BookingUidGuard)`. `BookingPbacGuard` requires `request.user`, which is only populated after `ApiAuthGuard` runs.

### Issue Context
`BookingPbacGuard` throws `UnauthorizedException` when `request.user` is missing.

### Fix Focus Areas
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts[236-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 for read 🐞 Bug ⛨ Security

• The recordings endpoint is a GET/read operation but now requires BOOKING_WRITE.
• Platform permissions are independent bits; BOOKING_WRITE does not imply BOOKING_READ, so
  clients with only BOOKING_READ will start failing with 403.
• This is inconsistent with other read endpoints (e.g., transcripts, conferencing-sessions) which
  require BOOKING_READ.
Agent prompt
### Issue description
`GET /v2/bookings/:bookingUid/recordings` requires `BOOKING_WRITE`, which will reject OAuth clients that only have `BOOKING_READ`.

### Issue Context
Permissions are checked via bitwise equality; WRITE does not include READ.

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

ⓘ 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