Skip to content

Commit aa618db

Browse files
fix: Missing bookingId in BOOKING_CANCELLED webhook payload (calcom#22713)
* send bookingId in BOOKING_CANCELLED through requestReschedule * fix: make customInputs nullable in BookingWebhookFactory * fix: make customInputs nullable in BookingWebhookFactory
1 parent 6e3de84 commit aa618db

4 files changed

Lines changed: 483 additions & 29 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import type { Person } from "@calcom/types/Calendar";
2+
import type { JsonValue } from "@calcom/types/JsonObject";
3+
4+
function isObjectButNotArray(obj: unknown): obj is Record<string, unknown> {
5+
return typeof obj === "object" && !Array.isArray(obj);
6+
}
7+
8+
type DestinationCalendar = {
9+
id: number;
10+
integration: string;
11+
externalId: string;
12+
primaryEmail: string | null;
13+
userId: number | null;
14+
eventTypeId: number | null;
15+
credentialId: number | null;
16+
createdAt: Date | null;
17+
updatedAt: Date | null;
18+
delegationCredentialId: string | null;
19+
domainWideDelegationCredentialId: string | null;
20+
};
21+
22+
type Response = {
23+
label: string;
24+
value: string | boolean | string[] | { value: string; optionValue: string } | Record<string, string>;
25+
isHidden?: boolean | undefined;
26+
};
27+
28+
interface BaseWebhookPayload {
29+
bookingId: number;
30+
title: string;
31+
eventSlug: string | null;
32+
description: string | null;
33+
customInputs: JsonValue | null;
34+
responses: Record<string, Response>;
35+
userFieldsResponses: Record<string, Response>;
36+
startTime: string;
37+
endTime: string;
38+
organizer: Person;
39+
attendees: Person[];
40+
uid: string;
41+
location: string | null;
42+
destinationCalendar: DestinationCalendar | null;
43+
cancellationReason: string | null;
44+
iCalUID: string | null;
45+
smsReminderNumber?: string;
46+
cancelledBy: string | null;
47+
}
48+
49+
interface CancelledEventPayload extends BaseWebhookPayload {
50+
cancelledBy: string;
51+
cancellationReason: string;
52+
}
53+
54+
export class BookingWebhookFactory {
55+
private getType(params: BaseWebhookPayload) {
56+
return params.eventSlug || params.title || "";
57+
}
58+
59+
private getTitle(params: BaseWebhookPayload) {
60+
return params.title || "";
61+
}
62+
63+
private getDestinationCalendar(params: BaseWebhookPayload) {
64+
return params.destinationCalendar ? [params.destinationCalendar] : [];
65+
}
66+
67+
private getCustomInputs(params: BaseWebhookPayload) {
68+
return isObjectButNotArray(params.customInputs) ? params.customInputs : undefined;
69+
}
70+
71+
/**
72+
* Creates base webhook payload with common fields
73+
*/
74+
private createBasePayload(params: BaseWebhookPayload) {
75+
const {
76+
bookingId,
77+
title,
78+
eventSlug,
79+
description,
80+
customInputs,
81+
startTime,
82+
endTime,
83+
uid,
84+
location,
85+
organizer,
86+
attendees,
87+
responses,
88+
userFieldsResponses,
89+
destinationCalendar,
90+
smsReminderNumber,
91+
iCalUID,
92+
} = params;
93+
94+
const basePayload = {
95+
bookingId,
96+
type: this.getType(params),
97+
title: this.getTitle(params),
98+
description,
99+
customInputs: this.getCustomInputs(params),
100+
responses,
101+
userFieldsResponses,
102+
startTime,
103+
endTime,
104+
organizer,
105+
attendees,
106+
uid,
107+
location,
108+
destinationCalendar: this.getDestinationCalendar(params),
109+
iCalUID,
110+
smsReminderNumber,
111+
};
112+
113+
return basePayload;
114+
}
115+
116+
public createCancelledEventPayload(params: CancelledEventPayload) {
117+
const basePayload = this.createBasePayload({
118+
...params,
119+
});
120+
121+
return {
122+
...basePayload,
123+
cancelledBy: params.cancelledBy,
124+
cancellationReason: params.cancellationReason,
125+
};
126+
}
127+
}

0 commit comments

Comments
 (0)