fix: fetching event-types of org users apiv2 (#18004)

This commit is contained in:
Morgan
2024-12-05 06:02:19 +00:00
committed by GitHub
parent ab2ab31eef
commit 16a7cf6d04
7 changed files with 255 additions and 36 deletions
@@ -10,10 +10,12 @@ import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { PlatformOAuthClient, Team, User, Schedule } from "@prisma/client";
import { PlatformOAuthClient, Team, User, Schedule, EventType } from "@prisma/client";
import * as request from "supertest";
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";
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
@@ -75,18 +77,22 @@ describe("Event types Endpoints", () => {
let teamRepositoryFixture: TeamRepositoryFixture;
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
let schedulesRepostoryFixture: SchedulesRepositoryFixture;
let profileRepositoryFixture: ProfileRepositoryFixture;
let membershipsRepositoryFixture: MembershipRepositoryFixture;
const userEmail = "event-types-test-e2e@api.com";
const falseTestEmail = "false-event-types@api.com";
const name = "bob-the-builder";
const username = name;
let eventType: EventTypeOutput_2024_06_14;
let user: User;
let orgUser: User;
let falseTestUser: User;
let firstSchedule: Schedule;
let secondSchedule: Schedule;
let falseTestSchedule: Schedule;
let orgUserEventType1: EventType;
let orgUserEventType2: EventType;
let orgUserEventType3: EventType;
beforeAll(async () => {
const moduleRef = await withApiAuth(
userEmail,
@@ -109,8 +115,12 @@ describe("Event types Endpoints", () => {
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
schedulesRepostoryFixture = new SchedulesRepositoryFixture(moduleRef);
organization = await teamRepositoryFixture.create({ name: "organization" });
profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
organization = await teamRepositoryFixture.create({
name: "organization",
slug: "event-type-2024-06-14-org-slug",
});
oAuthClient = await createOAuthClient(organization.id);
user = await userRepositoryFixture.create({
email: userEmail,
@@ -118,6 +128,49 @@ describe("Event types Endpoints", () => {
username,
});
orgUser = await userRepositoryFixture.create({
email: "event-types-2024-06-14-org-user@example.com",
name: "event-types-2024-06-14-org-user",
username: "event-types-2024-06-14-org-user",
});
profileRepositoryFixture.create({
uid: `usr-${orgUser.id}`,
username: orgUser.username as string,
organization: {
connect: {
id: organization.id,
},
},
user: {
connect: {
id: orgUser.id,
},
},
});
orgUserEventType1 = await eventTypesRepositoryFixture.create(
{ title: "orgUserEventType1", slug: "org-event-type-1", length: 60, locations: [] },
orgUser.id
);
orgUserEventType2 = await eventTypesRepositoryFixture.create(
{ title: "orgUserEventType2", slug: "org-event-type-2", length: 60, locations: [] },
orgUser.id
);
orgUserEventType3 = await eventTypesRepositoryFixture.create(
{ title: "orgUserEventType3", slug: "org-event-type-3", length: 60, locations: [] },
orgUser.id
);
await membershipsRepositoryFixture.create({
role: "MEMBER",
user: { connect: { id: orgUser.id } },
team: { connect: { id: organization.id } },
accepted: true,
});
falseTestUser = await userRepositoryFixture.create({
email: falseTestEmail,
name: "false-test",
@@ -342,7 +395,7 @@ describe("Event types Endpoints", () => {
});
});
it(`/GET/even-types by username`, async () => {
it(`/GET/event-types by username`, async () => {
const response = await request(app.getHttpServer())
.get(`/api/v2/event-types?username=${username}`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
@@ -386,6 +439,61 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType.color).toEqual(eventType.color);
});
it(`/GET/event-types by username and orgSlug`, async () => {
console.log(organization);
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`)
.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(3);
expect(responseBody.data?.find((e) => e.id === orgUserEventType1.id)?.id).toBeDefined();
expect(responseBody.data?.find((e) => e.id === orgUserEventType2.id)?.id).toBeDefined();
expect(responseBody.data?.find((e) => e.id === orgUserEventType3.id)?.id).toBeDefined();
});
it(`/GET/event-types by username and orgSlug and eventSlug`, async () => {
const response = await request(app.getHttpServer())
.get(
`/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`)
.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?.find((e) => e.id === orgUserEventType1.id)?.id).toBeDefined();
});
it(`/GET/event-types by username and orgId`, async () => {
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`)
.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(3);
expect(responseBody.data?.find((e) => e.id === orgUserEventType1.id)?.id).toBeDefined();
expect(responseBody.data?.find((e) => e.id === orgUserEventType2.id)?.id).toBeDefined();
expect(responseBody.data?.find((e) => e.id === orgUserEventType3.id)?.id).toBeDefined();
});
it("should return an error when creating an event type with seats enabled and multiple locations", async () => {
const body: CreateEventTypeInput_2024_06_14 = {
title: "Coding class 2",
@@ -919,6 +1027,12 @@ describe("Event types Endpoints", () => {
} catch (e) {
// User might have been deleted by the test
}
try {
await userRepositoryFixture.delete(orgUser.id);
} catch (e) {
// User might have been deleted by the test
}
await app.close();
});
});
@@ -74,8 +74,13 @@ export class EventTypesService_2024_06_14 {
await this.checkUserOwnsSchedule(userId, body.scheduleId);
}
async getEventTypeByUsernameAndSlug(username: string, eventTypeSlug: string) {
const user = await this.usersRepository.findByUsername(username);
async getEventTypeByUsernameAndSlug(
username: string,
eventTypeSlug: string,
orgSlug?: string,
orgId?: number
) {
const user = await this.usersRepository.findByUsername(username, orgSlug, orgId);
if (!user) {
return null;
}
@@ -92,8 +97,8 @@ export class EventTypesService_2024_06_14 {
};
}
async getEventTypesByUsername(username: string) {
const user = await this.usersRepository.findByUsername(username);
async getEventTypesByUsername(username: string, orgSlug?: string, orgId?: number) {
const user = await this.usersRepository.findByUsername(username, orgSlug, orgId);
if (!user) {
return [];
}
@@ -152,27 +157,26 @@ export class EventTypesService_2024_06_14 {
}
async getEventTypes(queryParams: GetEventTypesQuery_2024_06_14) {
const { username, eventSlug, usernames } = queryParams;
const { username, eventSlug, usernames, orgSlug, orgId } = queryParams;
if (username && eventSlug) {
const eventType = await this.getEventTypeByUsernameAndSlug(username, eventSlug);
const eventType = await this.getEventTypeByUsernameAndSlug(username, eventSlug, orgSlug, orgId);
return eventType ? [eventType] : [];
}
if (username) {
return await this.getEventTypesByUsername(username);
return await this.getEventTypesByUsername(username, orgSlug, orgId);
}
if (usernames) {
const dynamicEventType = await this.getDynamicEventType(usernames);
const dynamicEventType = await this.getDynamicEventType(usernames, orgSlug, orgId);
return [dynamicEventType];
}
return [];
}
async getDynamicEventType(usernames: string[]) {
const users = await this.usersService.getByUsernames(usernames);
async getDynamicEventType(usernames: string[], orgSlug?: string, orgId?: number) {
const users = await this.usersService.getByUsernames(usernames, orgSlug, orgId);
const usersFiltered: UserWithProfile[] = [];
for (const user of users) {
if (user) {
@@ -7,9 +7,9 @@ import { User } from "@calcom/prisma/client";
export class UsersService {
constructor(private readonly usersRepository: UsersRepository) {}
async getByUsernames(usernames: string[]) {
async getByUsernames(usernames: string[], orgSlug?: string, orgId?: number) {
const users = await Promise.all(
usernames.map((username) => this.usersRepository.findByUsername(username))
usernames.map((username) => this.usersRepository.findByUsername(username, orgSlug, orgId))
);
const usersFiltered: User[] = [];
@@ -142,11 +142,21 @@ export class UsersRepository {
});
}
async findByUsername(username: string) {
async findByUsername(username: string, orgSlug?: string, orgId?: number) {
return this.dbRead.prisma.user.findFirst({
where: {
username,
},
where:
orgId || orgSlug
? {
profiles: {
some: {
organization: orgSlug ? { slug: orgSlug } : { id: orgId },
username: username,
},
},
}
: {
username,
},
});
}