fix: v2 hidden event types (#23584)
* fix: return hidden event types only if owner auth provided * chore: add tests * chore: remove optional chaining when defined
This commit is contained in:
1 parent
e7d2e0dc2f
commit
ad4cf0cc3a
7 files changed
+4002
-930
No files matched your search
+215
-40
@@ -12,6 +12,7 @@ import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { Test } from "@nestjs/testing";
|
||||
import { PlatformOAuthClient, Team, User, Schedule, EventType } from "@prisma/client";
|
||||
import * as request from "supertest";
|
||||
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
||||
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
||||
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
|
||||
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
|
||||
@@ -88,11 +89,16 @@ describe("Event types Endpoints", () => {
|
||||
let schedulesRepostoryFixture: SchedulesRepositoryFixture;
|
||||
let profileRepositoryFixture: ProfileRepositoryFixture;
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
let apiKeysRepositoryFixture: ApiKeysRepositoryFixture;
|
||||
let apiKeyString: string;
|
||||
let apiKeyOrgUser: string;
|
||||
|
||||
const userEmail = `event-types-2024-06-14-user-${randomString()}@api.com`;
|
||||
const falseTestEmail = `event-types-2024-06-14-false-user-${randomString()}@api.com`;
|
||||
const name = `event-types-2024-06-14-user-${randomString()}`;
|
||||
const username = name;
|
||||
let eventType: EventTypeOutput_2024_06_14;
|
||||
let hiddenEventType: EventTypeOutput_2024_06_14;
|
||||
let user: User;
|
||||
let orgUser: User;
|
||||
let falseTestUser: User;
|
||||
@@ -165,13 +171,10 @@ describe("Event types Endpoints", () => {
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withApiAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
providers: [PrismaExceptionFilter, HttpExceptionFilter],
|
||||
imports: [AppModule, UsersModule, EventTypesModule_2024_06_14, TokensModule],
|
||||
})
|
||||
)
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
providers: [PrismaExceptionFilter, HttpExceptionFilter],
|
||||
imports: [AppModule, UsersModule, EventTypesModule_2024_06_14, TokensModule],
|
||||
})
|
||||
.overrideGuard(PermissionsGuard)
|
||||
.useValue({
|
||||
canActivate: () => true,
|
||||
@@ -198,12 +201,20 @@ describe("Event types Endpoints", () => {
|
||||
name,
|
||||
username,
|
||||
});
|
||||
apiKeysRepositoryFixture = new ApiKeysRepositoryFixture(moduleRef);
|
||||
const { keyString } = await apiKeysRepositoryFixture.createApiKey(user.id, null);
|
||||
apiKeyString = `cal_test_${keyString}`;
|
||||
|
||||
orgUser = await userRepositoryFixture.create({
|
||||
email: `event-types-2024-06-14-org-user-${randomString()}@example.com`,
|
||||
name: `event-types-2024-06-14-org-user-${randomString()}`,
|
||||
username: `event-types-2024-06-14-org-user-${randomString()}`,
|
||||
});
|
||||
const { keyString: orgUserApiKeyString } = await apiKeysRepositoryFixture.createApiKey(
|
||||
orgUser.id,
|
||||
null
|
||||
);
|
||||
apiKeyOrgUser = `cal_test_${orgUserApiKeyString}`;
|
||||
|
||||
profileRepositoryFixture.create({
|
||||
uid: `usr-${orgUser.id}`,
|
||||
@@ -334,6 +345,7 @@ describe("Event types Endpoints", () => {
|
||||
return request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(404);
|
||||
});
|
||||
@@ -370,6 +382,7 @@ describe("Event types Endpoints", () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
|
||||
@@ -395,6 +408,7 @@ describe("Event types Endpoints", () => {
|
||||
return request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
});
|
||||
@@ -504,6 +518,7 @@ describe("Event types Endpoints", () => {
|
||||
return request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
@@ -576,21 +591,52 @@ describe("Event types Endpoints", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a hidden event type", async () => {
|
||||
const body: CreateEventTypeInput_2024_06_14 = {
|
||||
title: "Coding class hidden",
|
||||
slug: "coding-class-hidden",
|
||||
description: "Let's learn how to code like a pro.",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
hidden: true,
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(201);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14> = response.body;
|
||||
const createdEventType = responseBody.data;
|
||||
expect(createdEventType).toHaveProperty("id");
|
||||
expect(createdEventType.title).toEqual(body.title);
|
||||
expect(createdEventType.hidden).toEqual(body.hidden);
|
||||
expect(createdEventType.ownerId).toEqual(user.id);
|
||||
hiddenEventType = responseBody.data;
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${username}`)
|
||||
.get(`/api/v2/event-types?username=${user.username}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(1);
|
||||
expect(responseBody.data?.length).toEqual(2);
|
||||
|
||||
const fetchedEventType = responseBody.data?.[0];
|
||||
const fetchedEventType = responseBody.data?.find((et) => et.id === eventType.id);
|
||||
const fetchedHiddenEventType = responseBody.data?.find((et) => et.id === hiddenEventType.id);
|
||||
|
||||
expect(fetchedEventType?.id).toEqual(eventType.id);
|
||||
expect(fetchedEventType?.title).toEqual(eventType.title);
|
||||
@@ -602,33 +648,149 @@ describe("Event types Endpoints", () => {
|
||||
eventType.bookingFields.sort(orderBySlug).filter((f) => ("hidden" in f ? !f?.hidden : true))
|
||||
);
|
||||
expect(fetchedEventType?.ownerId).toEqual(user.id);
|
||||
expect(fetchedEventType.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
|
||||
expect(fetchedEventType.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
|
||||
expect(fetchedEventType.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
|
||||
expect(fetchedEventType.offsetStart).toEqual(eventType.offsetStart);
|
||||
expect(fetchedEventType.bookingWindow).toEqual(eventType.bookingWindow);
|
||||
expect(fetchedEventType.bookerLayouts).toEqual(eventType.bookerLayouts);
|
||||
expect(fetchedEventType.confirmationPolicy).toEqual(eventType.confirmationPolicy);
|
||||
expect(fetchedEventType.recurrence).toEqual(eventType.recurrence);
|
||||
expect(fetchedEventType.customName).toEqual(eventType.customName);
|
||||
expect(fetchedEventType.requiresBookerEmailVerification).toEqual(
|
||||
expect(fetchedEventType?.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
|
||||
expect(fetchedEventType?.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
|
||||
expect(fetchedEventType?.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
|
||||
expect(fetchedEventType?.offsetStart).toEqual(eventType.offsetStart);
|
||||
expect(fetchedEventType?.bookingWindow).toEqual(eventType.bookingWindow);
|
||||
expect(fetchedEventType?.bookerLayouts).toEqual(eventType.bookerLayouts);
|
||||
expect(fetchedEventType?.confirmationPolicy).toEqual(eventType.confirmationPolicy);
|
||||
expect(fetchedEventType?.recurrence).toEqual(eventType.recurrence);
|
||||
expect(fetchedEventType?.customName).toEqual(eventType.customName);
|
||||
expect(fetchedEventType?.requiresBookerEmailVerification).toEqual(
|
||||
eventType.requiresBookerEmailVerification
|
||||
);
|
||||
expect(fetchedEventType.hideCalendarNotes).toEqual(eventType.hideCalendarNotes);
|
||||
expect(fetchedEventType.hideCalendarEventDetails).toEqual(eventType.hideCalendarEventDetails);
|
||||
expect(fetchedEventType.hideOrganizerEmail).toEqual(eventType.hideOrganizerEmail);
|
||||
expect(fetchedEventType.lockTimeZoneToggleOnBookingPage).toEqual(
|
||||
expect(fetchedEventType?.hideCalendarNotes).toEqual(eventType.hideCalendarNotes);
|
||||
expect(fetchedEventType?.hideCalendarEventDetails).toEqual(eventType.hideCalendarEventDetails);
|
||||
expect(fetchedEventType?.hideOrganizerEmail).toEqual(eventType.hideOrganizerEmail);
|
||||
expect(fetchedEventType?.lockTimeZoneToggleOnBookingPage).toEqual(
|
||||
eventType.lockTimeZoneToggleOnBookingPage
|
||||
);
|
||||
expect(fetchedEventType.color).toEqual(eventType.color);
|
||||
expect(fetchedEventType?.color).toEqual(eventType.color);
|
||||
expect(fetchedEventType?.hidden).toEqual(false);
|
||||
|
||||
expect(fetchedHiddenEventType?.id).toEqual(hiddenEventType.id);
|
||||
expect(fetchedHiddenEventType?.hidden).toEqual(true);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username should not return hidden event type if auth of non event type owner provided`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${user.username}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyOrgUser}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(1);
|
||||
|
||||
const fetchedEventType = responseBody.data?.find((et) => et.id === eventType.id);
|
||||
|
||||
expect(fetchedEventType?.id).toEqual(eventType.id);
|
||||
expect(fetchedEventType?.ownerId).toEqual(user.id);
|
||||
expect(fetchedEventType?.hidden).toEqual(false);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username should not return hidden event type if no auth provided`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${user.username}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(1);
|
||||
|
||||
const fetchedEventType = responseBody.data?.find((et) => et.id === eventType.id);
|
||||
|
||||
expect(fetchedEventType?.id).toEqual(eventType.id);
|
||||
expect(fetchedEventType?.ownerId).toEqual(user.id);
|
||||
expect(fetchedEventType?.hidden).toEqual(false);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username and eventSlug`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${user.username}&eventSlug=${eventType.slug}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(1);
|
||||
|
||||
const fetchedEventType = responseBody.data?.find((et) => et.id === eventType.id);
|
||||
|
||||
expect(fetchedEventType?.id).toEqual(eventType.id);
|
||||
expect(fetchedEventType?.title).toEqual(eventType.title);
|
||||
expect(fetchedEventType?.description).toEqual(eventType.description);
|
||||
expect(fetchedEventType?.lengthInMinutes).toEqual(eventType.lengthInMinutes);
|
||||
expect(fetchedEventType?.lengthInMinutesOptions).toEqual(eventType.lengthInMinutesOptions);
|
||||
expect(fetchedEventType?.locations).toEqual(eventType.locations);
|
||||
expect(fetchedEventType?.bookingFields.sort(orderBySlug)).toEqual(
|
||||
eventType.bookingFields.sort(orderBySlug).filter((f) => ("hidden" in f ? !f?.hidden : true))
|
||||
);
|
||||
expect(fetchedEventType?.ownerId).toEqual(user.id);
|
||||
expect(fetchedEventType?.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
|
||||
expect(fetchedEventType?.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
|
||||
expect(fetchedEventType?.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
|
||||
expect(fetchedEventType?.offsetStart).toEqual(eventType.offsetStart);
|
||||
expect(fetchedEventType?.bookingWindow).toEqual(eventType.bookingWindow);
|
||||
expect(fetchedEventType?.bookerLayouts).toEqual(eventType.bookerLayouts);
|
||||
expect(fetchedEventType?.confirmationPolicy).toEqual(eventType.confirmationPolicy);
|
||||
expect(fetchedEventType?.recurrence).toEqual(eventType.recurrence);
|
||||
expect(fetchedEventType?.customName).toEqual(eventType.customName);
|
||||
expect(fetchedEventType?.requiresBookerEmailVerification).toEqual(
|
||||
eventType.requiresBookerEmailVerification
|
||||
);
|
||||
expect(fetchedEventType?.hideCalendarNotes).toEqual(eventType.hideCalendarNotes);
|
||||
expect(fetchedEventType?.hideCalendarEventDetails).toEqual(eventType.hideCalendarEventDetails);
|
||||
expect(fetchedEventType?.hideOrganizerEmail).toEqual(eventType.hideOrganizerEmail);
|
||||
expect(fetchedEventType?.lockTimeZoneToggleOnBookingPage).toEqual(
|
||||
eventType.lockTimeZoneToggleOnBookingPage
|
||||
);
|
||||
expect(fetchedEventType?.color).toEqual(eventType.color);
|
||||
expect(fetchedEventType?.hidden).toEqual(false);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username and eventSlug should not return hidden event type if auth of non event type owner provided`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${user.username}&eventSlug=${hiddenEventType.slug}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyOrgUser}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(0);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username and eventSlug should not return hidden event type if no auth provided`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${user.username}&eventSlug=${hiddenEventType.slug}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseBody.data?.length).toEqual(0);
|
||||
});
|
||||
|
||||
it(`/GET/event-types by username and orgSlug`, async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${orgUser.username}&orgSlug=${organization.slug}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
@@ -647,8 +809,7 @@ describe("Event types Endpoints", () => {
|
||||
`/api/v2/event-types?username=${orgUser.username}&orgSlug=${organization.slug}&eventSlug=${orgUserEventType1.slug}`
|
||||
)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
@@ -663,8 +824,7 @@ describe("Event types Endpoints", () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${orgUser.username}&orgId=${organization.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
@@ -705,6 +865,7 @@ describe("Event types Endpoints", () => {
|
||||
await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
});
|
||||
@@ -732,6 +893,7 @@ describe("Event types Endpoints", () => {
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(201);
|
||||
|
||||
@@ -748,6 +910,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${createdEventType.id}`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send({
|
||||
seats: {
|
||||
@@ -779,6 +942,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
@@ -799,6 +963,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(201);
|
||||
@@ -817,6 +982,7 @@ describe("Event types Endpoints", () => {
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${createdEventType.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send({
|
||||
seats: {
|
||||
seatsPerTimeSlot: 4,
|
||||
@@ -844,6 +1010,7 @@ describe("Event types Endpoints", () => {
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(201);
|
||||
|
||||
@@ -860,6 +1027,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${createdEventType.id}`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send({
|
||||
locations: [
|
||||
@@ -897,6 +1065,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
@@ -918,6 +1087,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post("/api/v2/event-types")
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(201);
|
||||
@@ -935,6 +1105,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${createdEventType.id}`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send({
|
||||
confirmationPolicy: {
|
||||
@@ -1034,6 +1205,7 @@ describe("Event types Endpoints", () => {
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${eventType.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.send(body)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
@@ -1135,6 +1307,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${eventType.id}`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(404);
|
||||
@@ -1152,6 +1325,7 @@ describe("Event types Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/event-types/${eventType.id}`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.send(body)
|
||||
.expect(400);
|
||||
@@ -1161,8 +1335,7 @@ describe("Event types Endpoints", () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types/${eventType.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14> = response.body;
|
||||
@@ -1203,8 +1376,7 @@ describe("Event types Endpoints", () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types?username=${username}&eventSlug=${eventType.slug}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14[]> = response.body;
|
||||
@@ -1245,13 +1417,16 @@ describe("Event types Endpoints", () => {
|
||||
await request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types/1000`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
// note: bearer token value mocked using "withAccessTokenAuth" for user which id is used when creating event type above
|
||||
.set("Authorization", `Bearer whatever`)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it("should delete event type", async () => {
|
||||
return request(app.getHttpServer()).delete(`/api/v2/event-types/${eventType.id}`).expect(200);
|
||||
return request(app.getHttpServer())
|
||||
.delete(`/api/v2/event-types/${eventType.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.set("Authorization", `Bearer ${apiKeyString}`)
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
+28
-24
@@ -6,11 +6,22 @@ import { UpdateEventTypeOutput_2024_06_14 } from "@/ee/event-types/event-types_2
|
||||
import { EventTypeResponseTransformPipe } from "@/ee/event-types/event-types_2024_06_14/pipes/event-type-response.transformer";
|
||||
import { EventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/event-types.service";
|
||||
import { InputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/input-event-types.service";
|
||||
import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service";
|
||||
import { VERSION_2024_06_14_VALUE } from "@/lib/api-versions";
|
||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
||||
import {
|
||||
API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||
OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||
} from "@/lib/docs/headers";
|
||||
import {
|
||||
AuthOptionalUser,
|
||||
GetOptionalUser,
|
||||
} from "@/modules/auth/decorators/get-optional-user/get-optional-user.decorator";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { OptionalApiAuthGuard } from "@/modules/auth/guards/optional-api-auth/optional-api-auth.guard";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import {
|
||||
@@ -40,7 +51,6 @@ import {
|
||||
UpdateEventTypeInput_2024_06_14,
|
||||
GetEventTypesQuery_2024_06_14,
|
||||
CreateEventTypeInput_2024_06_14,
|
||||
EventTypeOutput_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
@Controller({
|
||||
@@ -62,7 +72,8 @@ export class EventTypesController_2024_06_14 {
|
||||
constructor(
|
||||
private readonly eventTypesService: EventTypesService_2024_06_14,
|
||||
private readonly inputEventTypesService: InputEventTypesService_2024_06_14,
|
||||
private readonly eventTypeResponseTransformPipe: EventTypeResponseTransformPipe
|
||||
private readonly eventTypeResponseTransformPipe: EventTypeResponseTransformPipe,
|
||||
private readonly outputEventTypesService: OutputEventTypesService_2024_06_14
|
||||
) {}
|
||||
|
||||
@Post("/")
|
||||
@@ -109,30 +120,23 @@ export class EventTypesController_2024_06_14 {
|
||||
}
|
||||
|
||||
@Get("/")
|
||||
@ApiOperation({ summary: "Get all event types" })
|
||||
@ApiOperation({
|
||||
summary: "Get all event types",
|
||||
description:
|
||||
"Hidden event types are returned only if authentication is provided and it belongs to the event type owner.",
|
||||
})
|
||||
@UseGuards(OptionalApiAuthGuard)
|
||||
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||
async getEventTypes(
|
||||
@Query() queryParams: GetEventTypesQuery_2024_06_14
|
||||
@Query() queryParams: GetEventTypesQuery_2024_06_14,
|
||||
@GetOptionalUser() authUser: AuthOptionalUser
|
||||
): Promise<GetEventTypesOutput_2024_06_14> {
|
||||
const eventTypes = await this.eventTypesService.getEventTypes(queryParams);
|
||||
if (!eventTypes || eventTypes.length === 0) {
|
||||
throw new NotFoundException(`Event types not found`);
|
||||
}
|
||||
const eventTypes = await this.eventTypesService.getEventTypes(queryParams, authUser);
|
||||
const eventTypesFormatted = this.eventTypeResponseTransformPipe.transform(eventTypes);
|
||||
const eventTypesWithoutHiddenFields = eventTypesFormatted.map((eventType) => {
|
||||
return {
|
||||
...eventType,
|
||||
bookingFields: Array.isArray(eventType?.bookingFields)
|
||||
? eventType?.bookingFields
|
||||
.map((field) => {
|
||||
if ("hidden" in field) {
|
||||
return field.hidden !== true ? field : null;
|
||||
}
|
||||
return field;
|
||||
})
|
||||
.filter((f) => f)
|
||||
: [],
|
||||
};
|
||||
}) as EventTypeOutput_2024_06_14[];
|
||||
const eventTypesWithoutHiddenFields =
|
||||
this.outputEventTypesService.getResponseEventTypesWithoutHiddenFields(eventTypesFormatted);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
|
||||
@@ -75,6 +75,16 @@ export class EventTypesRepository_2024_06_14 {
|
||||
});
|
||||
}
|
||||
|
||||
async getUserEventTypesPublic(userId: number) {
|
||||
return this.dbRead.prisma.eventType.findMany({
|
||||
where: {
|
||||
userId,
|
||||
hidden: false,
|
||||
},
|
||||
include: { users: true, schedule: true, destinationCalendar: true },
|
||||
});
|
||||
}
|
||||
|
||||
async getEventTypeById(eventTypeId: number) {
|
||||
return this.dbRead.prisma.eventType.findUnique({
|
||||
where: { id: eventTypeId },
|
||||
|
||||
+47
-13
@@ -3,6 +3,7 @@ import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_20
|
||||
import { InputEventTransformed_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/transformed";
|
||||
import { SystemField, CustomField } from "@/ee/event-types/event-types_2024_06_14/transformers";
|
||||
import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository";
|
||||
import { AuthOptionalUser } from "@/modules/auth/decorators/get-optional-user/get-optional-user.decorator";
|
||||
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
|
||||
@@ -38,6 +39,7 @@ export class EventTypesService_2024_06_14 {
|
||||
}
|
||||
await this.checkCanCreateEventType(user.id, body);
|
||||
const eventTypeUser = await this.getUserToCreateEvent(user);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { destinationCalendar: _destinationCalendar, ...rest } = body;
|
||||
|
||||
const { eventType: eventTypeCreated } = await createEventType({
|
||||
@@ -93,34 +95,47 @@ export class EventTypesService_2024_06_14 {
|
||||
}
|
||||
}
|
||||
|
||||
async getEventTypeByUsernameAndSlug(
|
||||
username: string,
|
||||
eventTypeSlug: string,
|
||||
orgSlug?: string,
|
||||
orgId?: number
|
||||
) {
|
||||
const user = await this.usersRepository.findByUsername(username, orgSlug, orgId);
|
||||
async getEventTypeByUsernameAndSlug(params: {
|
||||
username: string;
|
||||
eventTypeSlug: string;
|
||||
orgSlug?: string;
|
||||
orgId?: number;
|
||||
authUser?: AuthOptionalUser;
|
||||
}) {
|
||||
const user = await this.usersRepository.findByUsername(params.username, params.orgSlug, params.orgId);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const eventType = await this.eventTypesRepository.getUserEventTypeBySlug(user.id, eventTypeSlug);
|
||||
const eventType = await this.eventTypesRepository.getUserEventTypeBySlug(user.id, params.eventTypeSlug);
|
||||
|
||||
if (!eventType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (eventType.hidden && params.authUser?.id !== user.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
ownerId: user.id,
|
||||
...eventType,
|
||||
};
|
||||
}
|
||||
|
||||
async getEventTypesByUsername(username: string, orgSlug?: string, orgId?: number) {
|
||||
const user = await this.usersRepository.findByUsername(username, orgSlug, orgId);
|
||||
async getEventTypesByUsername(params: {
|
||||
username: string;
|
||||
orgSlug?: string;
|
||||
orgId?: number;
|
||||
authUser?: AuthOptionalUser;
|
||||
}) {
|
||||
const user = await this.usersRepository.findByUsername(params.username, params.orgSlug, params.orgId);
|
||||
if (!user) {
|
||||
return [];
|
||||
}
|
||||
if (params.authUser?.id !== user.id) {
|
||||
return await this.getUserEventTypesPublic(user.id);
|
||||
}
|
||||
return await this.getUserEventTypes(user.id);
|
||||
}
|
||||
|
||||
@@ -172,6 +187,14 @@ export class EventTypesService_2024_06_14 {
|
||||
});
|
||||
}
|
||||
|
||||
async getUserEventTypesPublic(userId: number) {
|
||||
const eventTypes = await this.eventTypesRepository.getUserEventTypesPublic(userId);
|
||||
|
||||
return eventTypes.map((eventType) => {
|
||||
return { ownerId: userId, ...eventType };
|
||||
});
|
||||
}
|
||||
|
||||
async getEventTypesPublicByUsername(username: string): Promise<EventTypesPublic> {
|
||||
const user = await this.usersRepository.findByUsername(username);
|
||||
if (!user) {
|
||||
@@ -181,15 +204,26 @@ export class EventTypesService_2024_06_14 {
|
||||
return await getEventTypesPublic(user.id);
|
||||
}
|
||||
|
||||
async getEventTypes(queryParams: GetEventTypesQuery_2024_06_14) {
|
||||
async getEventTypes(queryParams: GetEventTypesQuery_2024_06_14, authUser?: AuthOptionalUser) {
|
||||
const { username, eventSlug, usernames, orgSlug, orgId } = queryParams;
|
||||
if (username && eventSlug) {
|
||||
const eventType = await this.getEventTypeByUsernameAndSlug(username, eventSlug, orgSlug, orgId);
|
||||
const eventType = await this.getEventTypeByUsernameAndSlug({
|
||||
username,
|
||||
eventTypeSlug: eventSlug,
|
||||
orgSlug,
|
||||
orgId,
|
||||
authUser,
|
||||
});
|
||||
return eventType ? [eventType] : [];
|
||||
}
|
||||
|
||||
if (username) {
|
||||
return await this.getEventTypesByUsername(username, orgSlug, orgId);
|
||||
return await this.getEventTypesByUsername({
|
||||
username,
|
||||
orgSlug,
|
||||
orgId,
|
||||
authUser,
|
||||
});
|
||||
}
|
||||
|
||||
if (usernames) {
|
||||
|
||||
+24
-1
@@ -31,6 +31,7 @@ import {
|
||||
EventTypeOutput_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
OutputUnknownBookingField_2024_06_14,
|
||||
OutputBookingField_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
type EventTypeRelations = {
|
||||
@@ -253,7 +254,7 @@ export class OutputEventTypesService_2024_06_14 {
|
||||
type: "unknown",
|
||||
slug: "unknown",
|
||||
bookingField: JSON.stringify(bookingField),
|
||||
});
|
||||
} satisfies OutputUnknownBookingField_2024_06_14);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,4 +345,26 @@ export class OutputEventTypesService_2024_06_14 {
|
||||
seatsShowAvailabilityCount: !!seatsShowAvailabilityCount,
|
||||
});
|
||||
}
|
||||
|
||||
getResponseEventTypesWithoutHiddenFields(
|
||||
eventTypes: EventTypeOutput_2024_06_14[]
|
||||
): EventTypeOutput_2024_06_14[] {
|
||||
return eventTypes.map((eventType) => this.getResponseEventTypeWithoutHiddenFields(eventType));
|
||||
}
|
||||
|
||||
getResponseEventTypeWithoutHiddenFields(eventType: EventTypeOutput_2024_06_14): EventTypeOutput_2024_06_14 {
|
||||
if (!Array.isArray(eventType?.bookingFields) || eventType.bookingFields.length === 0) return eventType;
|
||||
|
||||
const visibleBookingFields: OutputBookingField_2024_06_14[] = [];
|
||||
for (const bookingField of eventType.bookingFields) {
|
||||
if ("hidden" in bookingField && bookingField.hidden === true) {
|
||||
continue;
|
||||
}
|
||||
visibleBookingFields.push(bookingField);
|
||||
}
|
||||
return {
|
||||
...eventType,
|
||||
bookingFields: visibleBookingFields,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -9858,6 +9858,7 @@
|
||||
"get": {
|
||||
"operationId": "EventTypesController_2024_06_14_getEventTypes",
|
||||
"summary": "Get all event types",
|
||||
"description": "Hidden event types are returned only if authentication is provided and it belongs to the event type owner.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "cal-api-version",
|
||||
@@ -9913,6 +9914,33 @@
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"description": "value must be `Bearer <token>` where `<token>` is api key prefixed with cal_ or managed user access token",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x-cal-secret-key",
|
||||
"in": "header",
|
||||
"description": "For platform customers - OAuth client secret key",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x-cal-client-id",
|
||||
"in": "header",
|
||||
"description": "For platform customers - OAuth client ID",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
||||
+3650
-852
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user