Skip to content

Commit 59492ae

Browse files
committed
refactor: move check to create handler
1 parent bec9f67 commit 59492ae

File tree

4 files changed

+92
-8
lines changed

4 files changed

+92
-8
lines changed

apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { checkSuccessRedirectUrlAllowed, dynamicEvent } from "@calcom/platform-libraries";
1+
import { dynamicEvent } from "@calcom/platform-libraries";
22
import {
33
createEventType,
44
EventTypesPublic,
@@ -42,12 +42,6 @@ export class EventTypesService_2024_06_14 {
4242
this.checkHasUserAccessibleEmailBookingField(body.bookingFields);
4343
}
4444
await this.checkCanCreateEventType(user.id, body);
45-
if (body.successRedirectUrl) {
46-
const redirectUrlCheck = await checkSuccessRedirectUrlAllowed({ userId: user.id });
47-
if (!redirectUrlCheck.allowed) {
48-
throw new ForbiddenException(redirectUrlCheck.reason);
49-
}
50-
}
5145
const eventTypeUser = await this.getUserToCreateEvent(user);
5246

5347
const { destinationCalendar: _destinationCalendar, ...rest } = body;

packages/platform/libraries/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ export { getBookingInfo };
6666
export { handleCancelBooking };
6767

6868
export { dynamicEvent } from "@calcom/features/eventtypes/lib/defaultEvents";
69-
export { checkSuccessRedirectUrlAllowed } from "@calcom/features/eventtypes/lib/successRedirectUrlAllowed";
7069
export { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits";
7170
export { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
7271
export { bookingMetadataSchema, teamMetadataSchema, userMetadata } from "@calcom/prisma/zod-utils";
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
import { TRPCError } from "@trpc/server";
4+
5+
import { createHandler } from "./create.handler";
6+
7+
const mockCreateEventType = vi.fn();
8+
const mockCheckSuccessRedirectUrlAllowed = vi.fn();
9+
10+
vi.mock("@calcom/features/eventtypes/repositories/eventTypeRepository");
11+
vi.mock("@calcom/features/eventtypes/lib/successRedirectUrlAllowed", () => ({
12+
checkSuccessRedirectUrlAllowed: (...args: unknown[]) => mockCheckSuccessRedirectUrlAllowed(...args),
13+
}));
14+
15+
describe("createHandler", () => {
16+
type CreateHandlerInput = Parameters<typeof createHandler>[0];
17+
18+
const ctx = {
19+
user: {
20+
id: 1,
21+
role: "USER",
22+
organizationId: null,
23+
organization: { isOrgAdmin: false },
24+
profile: { id: 1 },
25+
metadata: {},
26+
email: "user@cal.com",
27+
},
28+
prisma: {},
29+
} as unknown as CreateHandlerInput["ctx"];
30+
31+
const input = {
32+
title: "Test Event",
33+
slug: "test-event",
34+
length: 30,
35+
locations: [{ type: "phone" }],
36+
successRedirectUrl: "https://cal.com/success",
37+
} as unknown as CreateHandlerInput["input"];
38+
39+
beforeEach(async () => {
40+
vi.resetAllMocks();
41+
const { EventTypeRepository } = await import(
42+
"@calcom/features/eventtypes/repositories/eventTypeRepository"
43+
);
44+
vi.mocked(EventTypeRepository).mockImplementation(function () {
45+
return {
46+
create: mockCreateEventType,
47+
} as unknown as InstanceType<typeof EventTypeRepository>;
48+
});
49+
mockCreateEventType.mockResolvedValue({ id: 999 });
50+
mockCheckSuccessRedirectUrlAllowed.mockResolvedValue({ allowed: true });
51+
});
52+
53+
it("throws FORBIDDEN when successRedirectUrl is not allowed", async () => {
54+
const reason =
55+
"Redirect on booking is a feature for team plan users. Please upgrade to a team plan to use this feature.";
56+
mockCheckSuccessRedirectUrlAllowed.mockResolvedValue({
57+
allowed: false,
58+
reason,
59+
});
60+
61+
await expect(createHandler({ ctx, input })).rejects.toThrow(
62+
new TRPCError({
63+
code: "FORBIDDEN",
64+
message: reason,
65+
})
66+
);
67+
expect(mockCreateEventType).not.toHaveBeenCalled();
68+
});
69+
70+
it("creates event type when successRedirectUrl is allowed", async () => {
71+
await expect(createHandler({ ctx, input })).resolves.toEqual({ eventType: { id: 999 } });
72+
expect(mockCheckSuccessRedirectUrlAllowed).toHaveBeenCalledWith({ userId: 1 });
73+
expect(mockCreateEventType).toHaveBeenCalledWith(
74+
expect.objectContaining({
75+
successRedirectUrl: "https://cal.com/success",
76+
})
77+
);
78+
});
79+
});

packages/trpc/server/routers/viewer/eventTypes/heavy/create.handler.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { z } from "zod";
22

33
import { getDefaultLocations } from "@calcom/app-store/_utils/getDefaultLocations";
44
import { DailyLocationType } from "@calcom/app-store/constants";
5+
import { checkSuccessRedirectUrlAllowed } from "@calcom/features/eventtypes/lib/successRedirectUrlAllowed";
56
import { EventTypeRepository } from "@calcom/features/eventtypes/repositories/eventTypeRepository";
67
import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service";
78
import type { PrismaClient } from "@calcom/prisma";
@@ -144,6 +145,17 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => {
144145
}
145146
}
146147

148+
const successRedirectUrl = (rest as { successRedirectUrl?: string }).successRedirectUrl;
149+
if (successRedirectUrl) {
150+
const redirectUrlCheck = await checkSuccessRedirectUrlAllowed({ userId: ctx.user.id });
151+
if (!redirectUrlCheck.allowed) {
152+
throw new TRPCError({
153+
code: "FORBIDDEN",
154+
message: redirectUrlCheck.reason,
155+
});
156+
}
157+
}
158+
147159
const profile = ctx.user.profile;
148160
try {
149161
const eventTypeRepo = new EventTypeRepository(ctx.prisma);

0 commit comments

Comments
 (0)