feat: v2 api allow switching event type between collective and round robin (#25045)
* refactor: create team event type hosts * refactor: update team event type hosts * feat: allow switching between collective and round robin * fix: make schedulingType optional when updating * fix: e2e tests * fix: e2e and add more tests * test: only hosts update * fix: remove test that makes no sense
This commit is contained in:
@@ -15,6 +15,10 @@ import {
|
||||
HostPriority,
|
||||
EmailSettings_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
import type { EventType } from "@calcom/prisma/client";
|
||||
|
||||
export const HOSTS_REQUIRED_WHEN_SWITCHING_SCHEDULING_TYPE_ERROR =
|
||||
"Hosts required when switching schedulingType. Please provide 'hosts' or set 'assignAllTeamMembers: true' to specify how hosts should be configured for the new scheduling type.";
|
||||
|
||||
export type TransformedCreateTeamEventTypeInput = Awaited<
|
||||
ReturnType<InstanceType<typeof InputOrganizationsEventTypesService>["transformInputCreateTeamEventType"]>
|
||||
@@ -116,10 +120,12 @@ export class InputOrganizationsEventTypesService {
|
||||
teamId: number,
|
||||
inputEventType: CreateTeamEventTypeInput_2024_06_14
|
||||
) {
|
||||
const { hosts, assignAllTeamMembers, locations, emailSettings, ...rest } = inputEventType;
|
||||
const { assignAllTeamMembers, locations, emailSettings, ...rest } = inputEventType;
|
||||
|
||||
const eventType = this.inputEventTypesService.transformInputCreateEventType(rest);
|
||||
|
||||
const isManagedEventType = rest.schedulingType === "MANAGED";
|
||||
|
||||
const defaultLocations: CreateTeamEventTypeInput_2024_06_14["locations"] = [
|
||||
{
|
||||
type: "integration",
|
||||
@@ -127,12 +133,13 @@ export class InputOrganizationsEventTypesService {
|
||||
},
|
||||
];
|
||||
|
||||
const children = await this.getChildEventTypesForManagedEventTypeCreate(inputEventType, teamId);
|
||||
const children = isManagedEventType
|
||||
? await this.getChildEventTypesForManagedEventTypeCreate(inputEventType, teamId)
|
||||
: undefined;
|
||||
|
||||
let metadata =
|
||||
rest.schedulingType === "MANAGED"
|
||||
? { managedEventConfig: {}, ...eventType.metadata }
|
||||
: eventType.metadata;
|
||||
let metadata = isManagedEventType
|
||||
? { managedEventConfig: {}, ...eventType.metadata }
|
||||
: eventType.metadata;
|
||||
|
||||
if (emailSettings) {
|
||||
metadata = this.addEmailSettingsToMetadata(emailSettings, metadata);
|
||||
@@ -140,12 +147,7 @@ export class InputOrganizationsEventTypesService {
|
||||
|
||||
const teamEventType = {
|
||||
...eventType,
|
||||
// note(Lauris): we don't populate hosts for managed event-types because they are handled by the children
|
||||
hosts: !(rest.schedulingType === "MANAGED")
|
||||
? assignAllTeamMembers
|
||||
? await this.getAllTeamMembers(teamId, inputEventType.schedulingType)
|
||||
: this.transformInputHosts(hosts, inputEventType.schedulingType)
|
||||
: undefined,
|
||||
hosts: await this.transformInputCreateTeamEventTypeHosts(teamId, inputEventType),
|
||||
assignAllTeamMembers,
|
||||
locations: this.transformInputTeamLocations(locations || defaultLocations),
|
||||
metadata,
|
||||
@@ -155,6 +157,24 @@ export class InputOrganizationsEventTypesService {
|
||||
return teamEventType;
|
||||
}
|
||||
|
||||
private async transformInputCreateTeamEventTypeHosts(
|
||||
teamId: number,
|
||||
inputEventType: CreateTeamEventTypeInput_2024_06_14
|
||||
) {
|
||||
const { hosts, assignAllTeamMembers, schedulingType } = inputEventType;
|
||||
|
||||
// note(Lauris): we don't populate hosts for managed event-types because they are handled by the children - each child managed event type is associated with
|
||||
// a specific user and hosts property is only for team event types e.g round robin and collective.
|
||||
if (schedulingType === "MANAGED") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (assignAllTeamMembers) {
|
||||
return await this.getAllTeamMembers(teamId, inputEventType.schedulingType);
|
||||
}
|
||||
return this.transformInputHosts(hosts, inputEventType.schedulingType);
|
||||
}
|
||||
|
||||
private addEmailSettingsToMetadata(
|
||||
emailSettings: EmailSettings_2024_06_14,
|
||||
metadata: NonNullable<EventTypeMetadata>
|
||||
@@ -190,7 +210,7 @@ export class InputOrganizationsEventTypesService {
|
||||
teamId: number,
|
||||
inputEventType: UpdateTeamEventTypeInput_2024_06_14
|
||||
) {
|
||||
const { hosts, assignAllTeamMembers, locations, emailSettings, ...rest } = inputEventType;
|
||||
const { assignAllTeamMembers, locations, emailSettings, ...rest } = inputEventType;
|
||||
|
||||
const eventType = await this.inputEventTypesService.transformInputUpdateEventType(rest, eventTypeId);
|
||||
const dbEventType = await this.teamsEventTypesRepository.getTeamEventType(teamId, eventTypeId);
|
||||
@@ -213,11 +233,11 @@ export class InputOrganizationsEventTypesService {
|
||||
const teamEventType = {
|
||||
...eventType,
|
||||
// note(Lauris): we don't populate hosts for managed event-types because they are handled by the children
|
||||
hosts: !children
|
||||
? assignAllTeamMembers
|
||||
? await this.getAllTeamMembers(teamId, dbEventType.schedulingType)
|
||||
: this.transformInputHosts(hosts, dbEventType.schedulingType)
|
||||
: undefined,
|
||||
hosts: await this.transformInputUpdateTeamEventTypeHosts(
|
||||
teamId,
|
||||
dbEventType.schedulingType,
|
||||
inputEventType
|
||||
),
|
||||
assignAllTeamMembers,
|
||||
children,
|
||||
locations: locations ? this.transformInputTeamLocations(locations) : undefined,
|
||||
@@ -227,6 +247,33 @@ export class InputOrganizationsEventTypesService {
|
||||
return teamEventType;
|
||||
}
|
||||
|
||||
private async transformInputUpdateTeamEventTypeHosts(
|
||||
teamId: number,
|
||||
dbEventTypeSchedulingType: EventType["schedulingType"],
|
||||
inputEventType: UpdateTeamEventTypeInput_2024_06_14
|
||||
) {
|
||||
const { hosts, assignAllTeamMembers } = inputEventType;
|
||||
|
||||
if (dbEventTypeSchedulingType === "MANAGED") {
|
||||
// note(Lauris): we don't populate hosts for managed event-types because they are handled by the event type children
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isSchedulingTypeChanging =
|
||||
inputEventType.schedulingType && inputEventType.schedulingType !== dbEventTypeSchedulingType;
|
||||
|
||||
if (isSchedulingTypeChanging && !assignAllTeamMembers && !hosts) {
|
||||
throw new BadRequestException(HOSTS_REQUIRED_WHEN_SWITCHING_SCHEDULING_TYPE_ERROR);
|
||||
}
|
||||
|
||||
const nextSchedulingType = inputEventType.schedulingType || dbEventTypeSchedulingType;
|
||||
if (assignAllTeamMembers) {
|
||||
return await this.getAllTeamMembers(teamId, nextSchedulingType);
|
||||
}
|
||||
|
||||
return this.transformInputHosts(hosts, nextSchedulingType);
|
||||
}
|
||||
|
||||
async getChildEventTypesForManagedEventTypeUpdate(
|
||||
eventTypeId: number,
|
||||
inputEventType: UpdateTeamEventTypeInput_2024_06_14,
|
||||
@@ -273,7 +320,7 @@ export class InputOrganizationsEventTypesService {
|
||||
}
|
||||
|
||||
async getChildEventTypesForManagedEventTypeCreate(
|
||||
inputEventType: UpdateTeamEventTypeInput_2024_06_14,
|
||||
inputEventType: Pick<CreateTeamEventTypeInput_2024_06_14, "assignAllTeamMembers" | "hosts">,
|
||||
teamId: number
|
||||
) {
|
||||
const ownersIds = await this.getOwnersIdsForManagedEventTypeCreate(teamId, inputEventType);
|
||||
@@ -289,7 +336,7 @@ export class InputOrganizationsEventTypesService {
|
||||
|
||||
async getOwnersIdsForManagedEventTypeCreate(
|
||||
teamId: number,
|
||||
inputEventType: UpdateTeamEventTypeInput_2024_06_14
|
||||
inputEventType: Pick<CreateTeamEventTypeInput_2024_06_14, "assignAllTeamMembers" | "hosts">
|
||||
) {
|
||||
if (inputEventType.assignAllTeamMembers) {
|
||||
return await this.getTeamUsersIds(teamId);
|
||||
|
||||
+581
@@ -1,5 +1,6 @@
|
||||
import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { HOSTS_REQUIRED_WHEN_SWITCHING_SCHEDULING_TYPE_ERROR } from "@/modules/organizations/event-types/services/input.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
@@ -758,6 +759,586 @@ describe("Organizations Event Types Endpoints", () => {
|
||||
expect(expected.priority).toEqual(received?.priority);
|
||||
}
|
||||
|
||||
describe("updating scheduling type", () => {
|
||||
it("should return 400 error if schedulingType: managed is passed", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
description: "Test collective event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "COLLECTIVE",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "managed",
|
||||
};
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(400);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should require hosts when changing round robin event type to collective without providing hosts", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
description: "Test round robin event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "ROUND_ROBIN",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
priority: "high",
|
||||
},
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
priority: "low",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "collective",
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody);
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error.message).toBe(HOSTS_REQUIRED_WHEN_SWITCHING_SCHEDULING_TYPE_ERROR);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should require hosts when changing collective event type to roundRobin without providing hosts", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
description: "Test collective event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "COLLECTIVE",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
},
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "roundRobin",
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody);
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error.message).toBe(HOSTS_REQUIRED_WHEN_SWITCHING_SCHEDULING_TYPE_ERROR);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should change round robin event type to collective and pass new hosts", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
description: "Test round robin event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "ROUND_ROBIN",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
priority: "high",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "collective",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const updateResponse = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = updateResponse.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("collective");
|
||||
expect(responseBody.data.hosts).toHaveLength(1);
|
||||
expect(responseBody.data.hosts[0].userId).toEqual(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should change collective event type to roundRobin and pass new hosts", async () => {
|
||||
const createBody = {
|
||||
title: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
description: "Test collective event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "collective",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "roundRobin",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
priority: "medium",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const updateResponse = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = updateResponse.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("roundRobin");
|
||||
expect(responseBody.data.hosts).toHaveLength(1);
|
||||
expect(responseBody.data.hosts[0].userId).toEqual(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should change collective event type to roundRobin with assignAllTeamMembers: true", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-collective-${randomString()}`,
|
||||
description: "Test collective event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "COLLECTIVE",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "roundRobin",
|
||||
assignAllTeamMembers: true,
|
||||
};
|
||||
|
||||
const updateResponse = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = updateResponse.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("roundRobin");
|
||||
expect(responseBody.data.hosts).toHaveLength(3);
|
||||
const hostUserIds = responseBody.data.hosts.map((host) => host.userId);
|
||||
expect(hostUserIds).toContain(teamMember1.id);
|
||||
expect(hostUserIds).toContain(teamMember2.id);
|
||||
expect(hostUserIds).toContain(userAdmin.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should change round robin event type to collective with assignAllTeamMembers: true", async () => {
|
||||
const createBody: CreateTeamEventTypeInput_2024_06_14 = {
|
||||
title: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-roundrobin-${randomString()}`,
|
||||
description: "Test round robin event type",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "ROUND_ROBIN",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
priority: "high",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
schedulingType: "collective",
|
||||
assignAllTeamMembers: true,
|
||||
};
|
||||
|
||||
const updateResponse = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = updateResponse.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("collective");
|
||||
expect(responseBody.data.hosts).toHaveLength(3);
|
||||
const hostUserIds = responseBody.data.hosts.map((host) => host.userId);
|
||||
expect(hostUserIds).toContain(teamMember1.id);
|
||||
expect(hostUserIds).toContain(teamMember2.id);
|
||||
expect(hostUserIds).toContain(userAdmin.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
|
||||
it("should preserve existing hosts when updating without changing scheduling type", async () => {
|
||||
const createBody = {
|
||||
title: `teams-event-types-scheduling-preserve-${randomString()}`,
|
||||
slug: `teams-event-types-scheduling-preserve-${randomString()}`,
|
||||
description: "Test preserve hosts",
|
||||
lengthInMinutes: 60,
|
||||
locations: [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
},
|
||||
],
|
||||
schedulingType: "collective",
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
},
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post(`/v2/teams/${team.id}/event-types`)
|
||||
.send(createBody)
|
||||
.expect(201);
|
||||
|
||||
const createdEventType: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = createResponse.body;
|
||||
|
||||
const updateBody = {
|
||||
title: "Updated title",
|
||||
};
|
||||
|
||||
const updateResponse = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${createdEventType.data.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = updateResponse.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.title).toEqual("Updated title");
|
||||
expect(responseBody.data.schedulingType).toEqual("collective");
|
||||
expect(responseBody.data.hosts).toHaveLength(2);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember1.id);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(createdEventType.data.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe("should update event type title", () => {
|
||||
it("should preserve hosts when updating collective event type title", async () => {
|
||||
const collectiveEventType = await eventTypesRepositoryFixture.create(
|
||||
{
|
||||
title: `collective-preserve-hosts-${randomString()}`,
|
||||
slug: `collective-preserve-hosts-${randomString()}`,
|
||||
length: 60,
|
||||
team: {
|
||||
connect: {
|
||||
id: team.id,
|
||||
},
|
||||
},
|
||||
schedulingType: "COLLECTIVE",
|
||||
hosts: {
|
||||
create: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
isFixed: true,
|
||||
},
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
isFixed: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
userAdmin.id
|
||||
);
|
||||
|
||||
const newTitle = `updated-collective-title-${randomString()}`;
|
||||
const updateBody = {
|
||||
title: newTitle,
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${collectiveEventType.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.title).toEqual(newTitle);
|
||||
expect(responseBody.data.schedulingType).toEqual("collective");
|
||||
expect(responseBody.data.hosts).toHaveLength(2);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember1.id);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(collectiveEventType.id);
|
||||
});
|
||||
|
||||
it("should preserve hosts when updating round robin event type title", async () => {
|
||||
const roundRobinEventType = await eventTypesRepositoryFixture.create(
|
||||
{
|
||||
title: `roundrobin-preserve-hosts-${randomString()}`,
|
||||
slug: `roundrobin-preserve-hosts-${randomString()}`,
|
||||
length: 60,
|
||||
team: {
|
||||
connect: {
|
||||
id: team.id,
|
||||
},
|
||||
},
|
||||
schedulingType: "ROUND_ROBIN",
|
||||
hosts: {
|
||||
create: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
isFixed: false,
|
||||
priority: 2,
|
||||
},
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
isFixed: true,
|
||||
priority: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
userAdmin.id
|
||||
);
|
||||
|
||||
const newTitle = `updated-roundrobin-title-${randomString()}`;
|
||||
const updateBody = {
|
||||
title: newTitle,
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${roundRobinEventType.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.title).toEqual(newTitle);
|
||||
expect(responseBody.data.schedulingType).toEqual("roundRobin");
|
||||
expect(responseBody.data.hosts).toHaveLength(2);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember1.id);
|
||||
expect(responseBody.data.hosts.map((h) => h.userId)).toContain(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(roundRobinEventType.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe("should update event type hosts", () => {
|
||||
it("should update collective event type hosts", async () => {
|
||||
const collectiveEventType = await eventTypesRepositoryFixture.create(
|
||||
{
|
||||
title: `collective-update-hosts-${randomString()}`,
|
||||
slug: `collective-update-hosts-${randomString()}`,
|
||||
length: 60,
|
||||
team: {
|
||||
connect: {
|
||||
id: team.id,
|
||||
},
|
||||
},
|
||||
schedulingType: "COLLECTIVE",
|
||||
hosts: {
|
||||
create: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
isFixed: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
userAdmin.id
|
||||
);
|
||||
|
||||
const updateBody = {
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${collectiveEventType.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("collective");
|
||||
expect(responseBody.data.hosts).toHaveLength(1);
|
||||
expect(responseBody.data.hosts[0].userId).toEqual(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(collectiveEventType.id);
|
||||
});
|
||||
|
||||
it("should update round robin event type hosts", async () => {
|
||||
const roundRobinEventType = await eventTypesRepositoryFixture.create(
|
||||
{
|
||||
title: `roundrobin-update-hosts-${randomString()}`,
|
||||
slug: `roundrobin-update-hosts-${randomString()}`,
|
||||
length: 60,
|
||||
team: {
|
||||
connect: {
|
||||
id: team.id,
|
||||
},
|
||||
},
|
||||
schedulingType: "ROUND_ROBIN",
|
||||
hosts: {
|
||||
create: [
|
||||
{
|
||||
userId: teamMember1.id,
|
||||
isFixed: true,
|
||||
priority: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
userAdmin.id
|
||||
);
|
||||
|
||||
const updateBody = {
|
||||
hosts: [
|
||||
{
|
||||
userId: teamMember2.id,
|
||||
priority: "high",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.patch(`/v2/teams/${team.id}/event-types/${roundRobinEventType.id}`)
|
||||
.send(updateBody)
|
||||
.expect(200);
|
||||
|
||||
const responseBody: ApiSuccessResponse<TeamEventTypeOutput_2024_06_14> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data.schedulingType).toEqual("roundRobin");
|
||||
expect(responseBody.data.hosts).toHaveLength(1);
|
||||
expect(responseBody.data.hosts[0].userId).toEqual(teamMember2.id);
|
||||
|
||||
await eventTypesRepositoryFixture.delete(roundRobinEventType.id);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.deleteByEmail(userAdmin.email);
|
||||
await userRepositoryFixture.deleteByEmail(teamMember1.email);
|
||||
|
||||
Reference in New Issue
Block a user