Introduced EventOwnerMail and VideoEventOwnerMail as class based implementations
This commit is contained in:
parent
51a8bafaa7
commit
e37dd017c8
5 changed files with 231 additions and 81 deletions
|
@ -1,5 +1,6 @@
|
||||||
|
import EventOwnerMail from "./emails/EventOwnerMail";
|
||||||
|
|
||||||
const {google} = require('googleapis');
|
const {google} = require('googleapis');
|
||||||
import createNewEventEmail from "./emails/new-event";
|
|
||||||
|
|
||||||
const googleAuth = () => {
|
const googleAuth = () => {
|
||||||
const {client_secret, client_id, redirect_uris} = JSON.parse(process.env.GOOGLE_API_CREDENTIALS).web;
|
const {client_secret, client_id, redirect_uris} = JSON.parse(process.env.GOOGLE_API_CREDENTIALS).web;
|
||||||
|
@ -323,17 +324,16 @@ const getBusyTimes = (withCredentials, dateFrom, dateTo) => Promise.all(
|
||||||
(results) => results.reduce((acc, availability) => acc.concat(availability), [])
|
(results) => results.reduce((acc, availability) => acc.concat(availability), [])
|
||||||
);
|
);
|
||||||
|
|
||||||
const createEvent = (credential, calEvent: CalendarEvent): Promise<any> => {
|
const createEvent = async (credential, calEvent: CalendarEvent): Promise<any> => {
|
||||||
|
const mail = new EventOwnerMail(calEvent);
|
||||||
|
const sentMail = await mail.sendEmail();
|
||||||
|
|
||||||
createNewEventEmail(
|
const creationResult = credential ? await calendars([credential])[0].createEvent(calEvent) : null;
|
||||||
calEvent,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (credential) {
|
return {
|
||||||
return calendars([credential])[0].createEvent(calEvent);
|
createdEvent: creationResult,
|
||||||
}
|
sentMail: sentMail
|
||||||
|
};
|
||||||
return Promise.resolve({});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateEvent = (credential, uid: String, calEvent: CalendarEvent): Promise<any> => {
|
const updateEvent = (credential, uid: String, calEvent: CalendarEvent): Promise<any> => {
|
||||||
|
|
150
lib/emails/EventOwnerMail.ts
Normal file
150
lib/emails/EventOwnerMail.ts
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import {CalendarEvent} from "../calendarClient";
|
||||||
|
import {createEvent} from "ics";
|
||||||
|
import dayjs, {Dayjs} from "dayjs";
|
||||||
|
import {serverConfig} from "../serverConfig";
|
||||||
|
import nodemailer from 'nodemailer';
|
||||||
|
|
||||||
|
export default class EventOwnerMail {
|
||||||
|
calEvent: CalendarEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An EventOwnerMail always consists of a CalendarEvent
|
||||||
|
* that stores the very basic data of the event (like date, title etc).
|
||||||
|
*
|
||||||
|
* @param calEvent
|
||||||
|
*/
|
||||||
|
constructor(calEvent: CalendarEvent) {
|
||||||
|
this.calEvent = calEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the instance's event as an iCal event in string representation.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getiCalEventAsString(): string {
|
||||||
|
const icsEvent = createEvent({
|
||||||
|
start: dayjs(this.calEvent.startTime).utc().toArray().slice(0, 6),
|
||||||
|
startInputType: 'utc',
|
||||||
|
productId: 'calendso/ics',
|
||||||
|
title: `${this.calEvent.type} with ${this.calEvent.attendees[0].name}`,
|
||||||
|
description: this.calEvent.description + this.stripHtml(this.getAdditionalBody()),
|
||||||
|
duration: {minutes: dayjs(this.calEvent.endTime).diff(dayjs(this.calEvent.startTime), 'minute')},
|
||||||
|
organizer: {name: this.calEvent.organizer.name, email: this.calEvent.organizer.email},
|
||||||
|
attendees: this.calEvent.attendees.map((attendee: any) => ({name: attendee.name, email: attendee.email})),
|
||||||
|
status: "CONFIRMED",
|
||||||
|
});
|
||||||
|
if (icsEvent.error) {
|
||||||
|
throw icsEvent.error;
|
||||||
|
}
|
||||||
|
return icsEvent.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the email text as HTML representation.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getHtmlRepresentation(): string {
|
||||||
|
return `
|
||||||
|
<div>
|
||||||
|
Hi ${this.calEvent.organizer.name},<br />
|
||||||
|
<br />
|
||||||
|
A new event has been scheduled.<br />
|
||||||
|
<br />
|
||||||
|
<strong>Event Type:</strong><br />
|
||||||
|
${this.calEvent.type}<br />
|
||||||
|
<br />
|
||||||
|
<strong>Invitee Email:</strong><br />
|
||||||
|
<a href="mailto:${this.calEvent.attendees[0].email}">${this.calEvent.attendees[0].email}</a><br />
|
||||||
|
<br />` + this.getAdditionalBody() +
|
||||||
|
(
|
||||||
|
this.calEvent.location ? `
|
||||||
|
<strong>Location:</strong><br />
|
||||||
|
${this.calEvent.location}<br />
|
||||||
|
<br />
|
||||||
|
` : ''
|
||||||
|
) +
|
||||||
|
`<strong>Invitee Time Zone:</strong><br />
|
||||||
|
${this.calEvent.attendees[0].timeZone}<br />
|
||||||
|
<br />
|
||||||
|
<strong>Additional notes:</strong><br />
|
||||||
|
${this.calEvent.description}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the email text in a plain text representation
|
||||||
|
* by stripping off the HTML tags.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getPlainTextRepresentation(): string {
|
||||||
|
return this.stripHtml(this.getHtmlRepresentation());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips off all HTML tags and leaves plain text.
|
||||||
|
*
|
||||||
|
* @param html
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected stripHtml(html: string): string {
|
||||||
|
return html
|
||||||
|
.replace('<br />', "\n")
|
||||||
|
.replace(/<[^>]+>/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the email to the event attendant and returns a Promise.
|
||||||
|
*/
|
||||||
|
public sendEmail(): Promise<any> {
|
||||||
|
const options = this.getMailerOptions();
|
||||||
|
const {transport, from} = options;
|
||||||
|
const organizerStart: Dayjs = <Dayjs>dayjs(this.calEvent.startTime).tz(this.calEvent.organizer.timeZone);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => nodemailer.createTransport(transport).sendMail(
|
||||||
|
{
|
||||||
|
icalEvent: {
|
||||||
|
filename: 'event.ics',
|
||||||
|
content: this.getiCalEventAsString(),
|
||||||
|
},
|
||||||
|
from: `Calendso <${from}>`,
|
||||||
|
to: this.calEvent.organizer.email,
|
||||||
|
subject: `New event: ${this.calEvent.attendees[0].name} - ${organizerStart.format('LT dddd, LL')} - ${this.calEvent.type}`,
|
||||||
|
html: this.getHtmlRepresentation(),
|
||||||
|
text: this.getPlainTextRepresentation(),
|
||||||
|
},
|
||||||
|
(error, info) => {
|
||||||
|
if (error) {
|
||||||
|
console.error("SEND_NEW_EVENT_NOTIFICATION_ERROR", this.calEvent.organizer.email, error);
|
||||||
|
reject(new Error(error));
|
||||||
|
} else {
|
||||||
|
resolve(info);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers the required provider information from the config.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getMailerOptions(): any {
|
||||||
|
return {
|
||||||
|
transport: serverConfig.transport,
|
||||||
|
from: serverConfig.from,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to include additional HTML or plain text
|
||||||
|
* content into the mail body and calendar event description.
|
||||||
|
* Leave it to an empty string if not desired.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getAdditionalBody(): string {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
27
lib/emails/VideoEventOwnerMail.ts
Normal file
27
lib/emails/VideoEventOwnerMail.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {CalendarEvent} from "../calendarClient";
|
||||||
|
import EventOwnerMail from "./EventOwnerMail";
|
||||||
|
import {formattedId, integrationTypeToName, VideoCallData} from "./confirm-booked";
|
||||||
|
|
||||||
|
export default class VideoEventOwnerMail extends EventOwnerMail {
|
||||||
|
videoCallData: VideoCallData;
|
||||||
|
|
||||||
|
constructor(calEvent: CalendarEvent, videoCallData: VideoCallData) {
|
||||||
|
super(calEvent);
|
||||||
|
this.videoCallData = videoCallData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the video call information to the mail body
|
||||||
|
* and calendar event description.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected getAdditionalBody(): string {
|
||||||
|
return `
|
||||||
|
<strong>Video call provider:</strong> ${integrationTypeToName(this.videoCallData.type)}<br />
|
||||||
|
<strong>Meeting ID:</strong> ${formattedId(this.videoCallData)}<br />
|
||||||
|
<strong>Meeting Password:</strong> ${this.videoCallData.password}<br />
|
||||||
|
<strong>Meeting URL:</strong> <a href="${this.videoCallData.url}">${this.videoCallData.url}</a><br />
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
import prisma from "./prisma";
|
import prisma from "./prisma";
|
||||||
|
import {VideoCallData} from "./emails/confirm-booked";
|
||||||
|
import {CalendarEvent} from "./calendarClient";
|
||||||
|
import VideoEventOwnerMail from "./emails/VideoEventOwnerMail";
|
||||||
|
|
||||||
function handleErrorsJson(response) {
|
function handleErrorsJson(response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
@ -53,26 +56,10 @@ const zoomAuth = (credential) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Person {
|
|
||||||
name?: string,
|
|
||||||
email: string,
|
|
||||||
timeZone: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VideoMeeting {
|
|
||||||
title: string;
|
|
||||||
startTime: string;
|
|
||||||
endTime: string;
|
|
||||||
description?: string;
|
|
||||||
timezone: string;
|
|
||||||
organizer: Person;
|
|
||||||
attendees: Person[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VideoApiAdapter {
|
interface VideoApiAdapter {
|
||||||
createMeeting(meeting: VideoMeeting): Promise<any>;
|
createMeeting(event: CalendarEvent): Promise<any>;
|
||||||
|
|
||||||
updateMeeting(uid: String, meeting: VideoMeeting);
|
updateMeeting(uid: String, event: CalendarEvent);
|
||||||
|
|
||||||
deleteMeeting(uid: String);
|
deleteMeeting(uid: String);
|
||||||
|
|
||||||
|
@ -83,17 +70,17 @@ const ZoomVideo = (credential): VideoApiAdapter => {
|
||||||
|
|
||||||
const auth = zoomAuth(credential);
|
const auth = zoomAuth(credential);
|
||||||
|
|
||||||
const translateMeeting = (meeting: VideoMeeting) => {
|
const translateEvent = (event: CalendarEvent) => {
|
||||||
// Documentation at: https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate
|
// Documentation at: https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate
|
||||||
const meet = {
|
return {
|
||||||
topic: meeting.title,
|
topic: event.title,
|
||||||
type: 2, // Means that this is a scheduled meeting
|
type: 2, // Means that this is a scheduled meeting
|
||||||
start_time: meeting.startTime,
|
start_time: event.startTime,
|
||||||
duration: ((new Date(meeting.endTime)).getTime() - (new Date(meeting.startTime)).getTime()) / 60000,
|
duration: ((new Date(event.endTime)).getTime() - (new Date(event.startTime)).getTime()) / 60000,
|
||||||
//schedule_for: "string", TODO: Used when scheduling the meeting for someone else (needed?)
|
//schedule_for: "string", TODO: Used when scheduling the meeting for someone else (needed?)
|
||||||
timezone: meeting.timezone,
|
timezone: event.attendees[0].timeZone,
|
||||||
//password: "string", TODO: Should we use a password? Maybe generate a random one?
|
//password: "string", TODO: Should we use a password? Maybe generate a random one?
|
||||||
agenda: meeting.description,
|
agenda: event.description,
|
||||||
settings: {
|
settings: {
|
||||||
host_video: true,
|
host_video: true,
|
||||||
participant_video: true,
|
participant_video: true,
|
||||||
|
@ -110,8 +97,6 @@ const ZoomVideo = (credential): VideoApiAdapter => {
|
||||||
registrants_email_notification: true
|
registrants_email_notification: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return meet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -149,13 +134,13 @@ const ZoomVideo = (credential): VideoApiAdapter => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
});*/
|
});*/
|
||||||
},
|
},
|
||||||
createMeeting: (meeting: VideoMeeting) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/users/me/meetings', {
|
createMeeting: (event: CalendarEvent) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/users/me/meetings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ' + accessToken,
|
'Authorization': 'Bearer ' + accessToken,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(translateMeeting(meeting))
|
body: JSON.stringify(translateEvent(event))
|
||||||
}).then(handleErrorsJson)),
|
}).then(handleErrorsJson)),
|
||||||
deleteMeeting: (uid: String) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/meetings/' + uid, {
|
deleteMeeting: (uid: String) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/meetings/' + uid, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
@ -163,13 +148,13 @@ const ZoomVideo = (credential): VideoApiAdapter => {
|
||||||
'Authorization': 'Bearer ' + accessToken
|
'Authorization': 'Bearer ' + accessToken
|
||||||
}
|
}
|
||||||
}).then(handleErrorsRaw)),
|
}).then(handleErrorsRaw)),
|
||||||
updateMeeting: (uid: String, meeting: VideoMeeting) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/meetings/' + uid, {
|
updateMeeting: (uid: String, event: CalendarEvent) => auth.getToken().then(accessToken => fetch('https://api.zoom.us/v2/meetings/' + uid, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ' + accessToken,
|
'Authorization': 'Bearer ' + accessToken,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(translateMeeting(meeting))
|
body: JSON.stringify(translateEvent(event))
|
||||||
}).then(handleErrorsRaw)),
|
}).then(handleErrorsRaw)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -191,23 +176,32 @@ const getBusyTimes = (withCredentials, dateFrom, dateTo) => Promise.all(
|
||||||
(results) => results.reduce((acc, availability) => acc.concat(availability), [])
|
(results) => results.reduce((acc, availability) => acc.concat(availability), [])
|
||||||
);
|
);
|
||||||
|
|
||||||
const createMeeting = (credential, meeting: VideoMeeting): Promise<any> => {
|
const createMeeting = async (credential, calEvent: CalendarEvent): Promise<any> => {
|
||||||
|
if(!credential) {
|
||||||
//TODO Send email to event host
|
throw new Error("Credentials must be set! Video platforms are optional, so this method shouldn't even be called.");
|
||||||
/*createNewMeetingEmail(
|
|
||||||
meeting,
|
|
||||||
);*/
|
|
||||||
|
|
||||||
if (credential) {
|
|
||||||
return videoIntegrations([credential])[0].createMeeting(meeting);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve({});
|
const creationResult = await videoIntegrations([credential])[0].createMeeting(calEvent);
|
||||||
|
|
||||||
|
const videoCallData: VideoCallData = {
|
||||||
|
type: credential.type,
|
||||||
|
id: creationResult.id,
|
||||||
|
password: creationResult.password,
|
||||||
|
url: creationResult.join_url,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mail = new VideoEventOwnerMail(calEvent, videoCallData);
|
||||||
|
const sentMail = await mail.sendEmail();
|
||||||
|
|
||||||
|
return {
|
||||||
|
createdEvent: creationResult,
|
||||||
|
sentMail: sentMail
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMeeting = (credential, uid: String, meeting: VideoMeeting): Promise<any> => {
|
const updateMeeting = (credential, uid: String, event: CalendarEvent): Promise<any> => {
|
||||||
if (credential) {
|
if (credential) {
|
||||||
return videoIntegrations([credential])[0].updateMeeting(uid, meeting);
|
return videoIntegrations([credential])[0].updateMeeting(uid, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
|
@ -221,4 +215,4 @@ const deleteMeeting = (credential, uid: String): Promise<any> => {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
};
|
};
|
||||||
|
|
||||||
export {getBusyTimes, createMeeting, updateMeeting, deleteMeeting, VideoMeeting};
|
export {getBusyTimes, createMeeting, updateMeeting, deleteMeeting};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import type {NextApiRequest, NextApiResponse} from 'next';
|
import type {NextApiRequest, NextApiResponse} from 'next';
|
||||||
import prisma from '../../../lib/prisma';
|
import prisma from '../../../lib/prisma';
|
||||||
import {CalendarEvent, createEvent, updateEvent} from '../../../lib/calendarClient';
|
import {CalendarEvent, createEvent, updateEvent} from '../../../lib/calendarClient';
|
||||||
import createConfirmBookedEmail, {VideoCallData} from "../../../lib/emails/confirm-booked";
|
|
||||||
import async from 'async';
|
import async from 'async';
|
||||||
import {v5 as uuidv5} from 'uuid';
|
import {v5 as uuidv5} from 'uuid';
|
||||||
import short from 'short-uuid';
|
import short from 'short-uuid';
|
||||||
import {createMeeting, updateMeeting, VideoMeeting} from "../../../lib/videoClient";
|
import {createMeeting, updateMeeting} from "../../../lib/videoClient";
|
||||||
|
|
||||||
const translator = short();
|
const translator = short();
|
||||||
|
|
||||||
|
@ -44,18 +43,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO Only create meeting if integration exists.
|
|
||||||
const meeting: VideoMeeting = {
|
|
||||||
attendees: [
|
|
||||||
{email: req.body.email, name: req.body.name, timeZone: req.body.timeZone}
|
|
||||||
],
|
|
||||||
endTime: req.body.end,
|
|
||||||
organizer: {email: currentUser.email, name: currentUser.name, timeZone: currentUser.timeZone},
|
|
||||||
startTime: req.body.start,
|
|
||||||
timezone: currentUser.timeZone,
|
|
||||||
title: req.body.eventName + ' with ' + req.body.name,
|
|
||||||
};
|
|
||||||
|
|
||||||
const hashUID: string = translator.fromUUID(uuidv5(JSON.stringify(evt), uuidv5.URL));
|
const hashUID: string = translator.fromUUID(uuidv5(JSON.stringify(evt), uuidv5.URL));
|
||||||
const cancelLink: string = process.env.BASE_URL + '/cancel/' + hashUID;
|
const cancelLink: string = process.env.BASE_URL + '/cancel/' + hashUID;
|
||||||
const rescheduleLink:string = process.env.BASE_URL + '/reschedule/' + hashUID;
|
const rescheduleLink:string = process.env.BASE_URL + '/reschedule/' + hashUID;
|
||||||
|
@ -108,7 +95,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
|
|
||||||
results = results.concat(await async.mapLimit(videoCredentials, 5, async (credential) => {
|
results = results.concat(await async.mapLimit(videoCredentials, 5, async (credential) => {
|
||||||
const bookingRefUid = booking.references.filter((ref) => ref.type === credential.type)[0].uid;
|
const bookingRefUid = booking.references.filter((ref) => ref.type === credential.type)[0].uid;
|
||||||
return await updateMeeting(credential, bookingRefUid, meeting) // TODO Maybe append links?
|
return await updateMeeting(credential, bookingRefUid, evt) // TODO Maybe append links?
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Clone elements
|
// Clone elements
|
||||||
|
@ -147,7 +134,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
results = results.concat(await async.mapLimit(videoCredentials, 5, async (credential) => {
|
results = results.concat(await async.mapLimit(videoCredentials, 5, async (credential) => {
|
||||||
const response = await createMeeting(credential, meeting);
|
const response = await createMeeting(credential, evt);
|
||||||
return {
|
return {
|
||||||
type: credential.type,
|
type: credential.type,
|
||||||
response
|
response
|
||||||
|
@ -157,7 +144,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
referencesToCreate = results.map((result => {
|
referencesToCreate = results.map((result => {
|
||||||
return {
|
return {
|
||||||
type: result.type,
|
type: result.type,
|
||||||
uid: result.response.id.toString()
|
uid: result.response.createdEvent.id.toString()
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -182,20 +169,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const videoResults = results.filter((res) => res.type.endsWith('_video'));
|
|
||||||
const videoCallData: VideoCallData = videoResults.length === 0 ? undefined : {
|
|
||||||
type: videoResults[0].type,
|
|
||||||
id: videoResults[0].response.id,
|
|
||||||
password: videoResults[0].response.password,
|
|
||||||
url: videoResults[0].response.join_url,
|
|
||||||
};
|
|
||||||
|
|
||||||
// If one of the integrations allows email confirmations or no integrations are added, send it.
|
// If one of the integrations allows email confirmations or no integrations are added, send it.
|
||||||
if (currentUser.credentials.length === 0 || !results.every((result) => result.disableConfirmationEmail)) {
|
/*if (currentUser.credentials.length === 0 || !results.every((result) => result.disableConfirmationEmail)) {
|
||||||
await createConfirmBookedEmail(
|
await createConfirmBookedEmail(
|
||||||
evt, cancelLink, rescheduleLink, {}, videoCallData
|
evt, cancelLink, rescheduleLink, {}, videoCallData
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
res.status(200).json(results);
|
res.status(200).json(results);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue