Introduced CalEventParser to acquire rich descriptions for events in integrations

This commit is contained in:
nicolas 2021-06-29 23:43:18 +02:00
parent 3aa1e1716d
commit 098b95ef55
8 changed files with 268 additions and 115 deletions

108
lib/CalEventParser.ts Normal file
View file

@ -0,0 +1,108 @@
import { CalendarEvent } from "./calendarClient";
import { v5 as uuidv5 } from "uuid";
import short from "short-uuid";
import { stripHtml } from "./emails/helpers";
const translator = short();
export default class CalEventParser {
calEvent: CalendarEvent;
constructor(calEvent: CalendarEvent) {
this.calEvent = calEvent;
}
/**
* Returns a link to reschedule the given booking.
*/
public getRescheduleLink(): string {
return process.env.BASE_URL + "/reschedule/" + this.getUid();
}
/**
* Returns a link to cancel the given booking.
*/
public getCancelLink(): string {
return process.env.BASE_URL + "/cancel/" + this.getUid();
}
/**
* Returns a unique identifier for the given calendar event.
*/
public getUid(): string {
return translator.fromUUID(uuidv5(JSON.stringify(this.calEvent), uuidv5.URL));
}
/**
* Returns a footer section with links to change the event (as HTML).
*/
public getChangeEventFooterHtml(): string {
return `
<br/>
<br/>
<strong>Need to change this event?</strong><br />
Cancel: <a href="${this.getCancelLink()}">${this.getCancelLink()}</a><br />
Reschedule: <a href="${this.getRescheduleLink()}">${this.getRescheduleLink()}</a>
`;
}
/**
* Returns a footer section with links to change the event (as plain text).
*/
public getChangeEventFooter(): string {
return stripHtml(this.getChangeEventFooterHtml());
}
/**
* Returns an extended description with all important information (as HTML).
*
* @protected
*/
public getRichDescriptionHtml(): string {
return (
`
<div>
<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.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}
` +
this.getChangeEventFooterHtml() +
`
</div>
`
);
}
/**
* Returns an extended description with all important information (as plain text).
*
* @protected
*/
public getRichDescription(): string {
return stripHtml(this.getRichDescriptionHtml());
}
/**
* Returns a calendar event with rich description.
*/
public asRichEvent(): CalendarEvent {
const eventCopy: CalendarEvent = { ...this.calEvent };
eventCopy.description = this.getRichDescription();
return eventCopy;
}
}

View file

@ -1,15 +1,12 @@
import EventOrganizerMail from "./emails/EventOrganizerMail"; import EventOrganizerMail from "./emails/EventOrganizerMail";
import EventAttendeeMail from "./emails/EventAttendeeMail"; import EventAttendeeMail from "./emails/EventAttendeeMail";
import { v5 as uuidv5 } from "uuid";
import short from "short-uuid";
import EventOrganizerRescheduledMail from "./emails/EventOrganizerRescheduledMail"; import EventOrganizerRescheduledMail from "./emails/EventOrganizerRescheduledMail";
import EventAttendeeRescheduledMail from "./emails/EventAttendeeRescheduledMail"; import EventAttendeeRescheduledMail from "./emails/EventAttendeeRescheduledMail";
import prisma from "./prisma";
const translator = short(); import CalEventParser from "./CalEventParser";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const { google } = require("googleapis"); const { google } = require("googleapis");
import prisma from "./prisma";
const googleAuth = (credential) => { const googleAuth = (credential) => {
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;
@ -105,12 +102,14 @@ const o365Auth = (credential) => {
}; };
}; };
// eslint-disable-next-line
interface Person { interface Person {
name?: string; name?: string;
email: string; email: string;
timeZone: string; timeZone: string;
} }
// eslint-disable-next-line
interface CalendarEvent { interface CalendarEvent {
type: string; type: string;
title: string; title: string;
@ -123,10 +122,12 @@ interface CalendarEvent {
conferenceData?: ConferenceData; conferenceData?: ConferenceData;
} }
// eslint-disable-next-line
interface ConferenceData { interface ConferenceData {
createRequest: any; createRequest: any;
} }
// eslint-disable-next-line
interface IntegrationCalendar { interface IntegrationCalendar {
integration: string; integration: string;
primary: boolean; primary: boolean;
@ -134,6 +135,7 @@ interface IntegrationCalendar {
name: string; name: string;
} }
// eslint-disable-next-line
interface CalendarApiAdapter { interface CalendarApiAdapter {
createEvent(event: CalendarEvent): Promise<any>; createEvent(event: CalendarEvent): Promise<any>;
@ -507,9 +509,11 @@ const listCalendars = (withCredentials) =>
); );
const createEvent = async (credential, calEvent: CalendarEvent): Promise<any> => { const createEvent = async (credential, calEvent: CalendarEvent): Promise<any> => {
const uid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL)); const parser: CalEventParser = new CalEventParser(calEvent);
const uid: string = parser.getUid();
const richEvent: CalendarEvent = parser.asRichEvent();
const creationResult = credential ? await calendars([credential])[0].createEvent(calEvent) : null; const creationResult = credential ? await calendars([credential])[0].createEvent(richEvent) : null;
const organizerMail = new EventOrganizerMail(calEvent, uid); const organizerMail = new EventOrganizerMail(calEvent, uid);
const attendeeMail = new EventAttendeeMail(calEvent, uid); const attendeeMail = new EventAttendeeMail(calEvent, uid);
@ -534,10 +538,12 @@ const createEvent = async (credential, calEvent: CalendarEvent): Promise<any> =>
}; };
const updateEvent = async (credential, uidToUpdate: string, calEvent: CalendarEvent): Promise<any> => { const updateEvent = async (credential, uidToUpdate: string, calEvent: CalendarEvent): Promise<any> => {
const newUid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL)); const parser: CalEventParser = new CalEventParser(calEvent);
const newUid: string = parser.getUid();
const richEvent: CalendarEvent = parser.asRichEvent();
const updateResult = credential const updateResult = credential
? await calendars([credential])[0].updateEvent(uidToUpdate, calEvent) ? await calendars([credential])[0].updateEvent(uidToUpdate, richEvent)
: null; : null;
const organizerMail = new EventOrganizerRescheduledMail(calEvent, newUid); const organizerMail = new EventOrganizerRescheduledMail(calEvent, newUid);

View file

@ -1,9 +1,9 @@
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import EventMail from "./EventMail"; import EventMail from "./EventMail";
import utc from 'dayjs/plugin/utc'; import utc from "dayjs/plugin/utc";
import timezone from 'dayjs/plugin/timezone'; import timezone from "dayjs/plugin/timezone";
import localizedFormat from 'dayjs/plugin/localizedFormat'; import localizedFormat from "dayjs/plugin/localizedFormat";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);
@ -15,20 +15,28 @@ export default class EventAttendeeMail extends EventMail {
* @protected * @protected
*/ */
protected getHtmlRepresentation(): string { protected getHtmlRepresentation(): string {
return ` return (
`
<div> <div>
Hi ${this.calEvent.attendees[0].name},<br /> Hi ${this.calEvent.attendees[0].name},<br />
<br /> <br />
Your ${this.calEvent.type} with ${this.calEvent.organizer.name} at ${this.getInviteeStart().format('h:mma')} Your ${this.calEvent.type} with ${this.calEvent.organizer.name} at ${this.getInviteeStart().format(
(${this.calEvent.attendees[0].timeZone}) on ${this.getInviteeStart().format('dddd, LL')} is scheduled.<br /> "h:mma"
<br />` + this.getAdditionalBody() + ( )}
this.calEvent.location ? `<strong>Location:</strong> ${this.calEvent.location}<br /><br />` : '' (${this.calEvent.attendees[0].timeZone}) on ${this.getInviteeStart().format(
) + "dddd, LL"
)} is scheduled.<br />
<br />` +
this.getAdditionalBody() +
(this.calEvent.location ? `<strong>Location:</strong> ${this.calEvent.location}<br /><br />` : "") +
`<strong>Additional notes:</strong><br /> `<strong>Additional notes:</strong><br />
${this.calEvent.description}<br /> ${this.calEvent.description}<br />
` + this.getAdditionalFooter() + ` ` +
this.getAdditionalFooter() +
`
</div> </div>
`; `
);
} }
/** /**
@ -36,12 +44,14 @@ export default class EventAttendeeMail extends EventMail {
* *
* @protected * @protected
*/ */
protected getNodeMailerPayload(): Object { protected getNodeMailerPayload(): Record<string, unknown> {
return { return {
to: `${this.calEvent.attendees[0].name} <${this.calEvent.attendees[0].email}>`, to: `${this.calEvent.attendees[0].name} <${this.calEvent.attendees[0].email}>`,
from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`,
replyTo: this.calEvent.organizer.email, replyTo: this.calEvent.organizer.email,
subject: `Confirmed: ${this.calEvent.type} with ${this.calEvent.organizer.name} on ${this.getInviteeStart().format('dddd, LL')}`, subject: `Confirmed: ${this.calEvent.type} with ${
this.calEvent.organizer.name
} on ${this.getInviteeStart().format("dddd, LL")}`,
html: this.getHtmlRepresentation(), html: this.getHtmlRepresentation(),
text: this.getPlainTextRepresentation(), text: this.getPlainTextRepresentation(),
}; };

View file

@ -7,15 +7,21 @@ export default class EventAttendeeRescheduledMail extends EventAttendeeMail {
* @protected * @protected
*/ */
protected getHtmlRepresentation(): string { protected getHtmlRepresentation(): string {
return ` return (
`
<div> <div>
Hi ${this.calEvent.attendees[0].name},<br /> Hi ${this.calEvent.attendees[0].name},<br />
<br /> <br />
Your ${this.calEvent.type} with ${this.calEvent.organizer.name} has been rescheduled to ${this.getInviteeStart().format('h:mma')} Your ${this.calEvent.type} with ${
(${this.calEvent.attendees[0].timeZone}) on ${this.getInviteeStart().format('dddd, LL')}.<br /> this.calEvent.organizer.name
` + this.getAdditionalFooter() + ` } has been rescheduled to ${this.getInviteeStart().format("h:mma")}
(${this.calEvent.attendees[0].timeZone}) on ${this.getInviteeStart().format("dddd, LL")}.<br />
` +
this.getAdditionalFooter() +
`
</div> </div>
`; `
);
} }
/** /**
@ -23,12 +29,14 @@ export default class EventAttendeeRescheduledMail extends EventAttendeeMail {
* *
* @protected * @protected
*/ */
protected getNodeMailerPayload(): Object { protected getNodeMailerPayload(): Record<string, unknown> {
return { return {
to: `${this.calEvent.attendees[0].name} <${this.calEvent.attendees[0].email}>`, to: `${this.calEvent.attendees[0].name} <${this.calEvent.attendees[0].email}>`,
from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`,
replyTo: this.calEvent.organizer.email, replyTo: this.calEvent.organizer.email,
subject: `Rescheduled: ${this.calEvent.type} with ${this.calEvent.organizer.name} on ${this.getInviteeStart().format('dddd, LL')}`, subject: `Rescheduled: ${this.calEvent.type} with ${
this.calEvent.organizer.name
} on ${this.getInviteeStart().format("dddd, LL")}`,
html: this.getHtmlRepresentation(), html: this.getHtmlRepresentation(),
text: this.getPlainTextRepresentation(), text: this.getPlainTextRepresentation(),
}; };

View file

@ -1,9 +1,12 @@
import { CalendarEvent } from "../calendarClient"; import { CalendarEvent } from "../calendarClient";
import { serverConfig } from "../serverConfig"; import { serverConfig } from "../serverConfig";
import nodemailer from 'nodemailer'; import nodemailer from "nodemailer";
import CalEventParser from "../CalEventParser";
import { stripHtml } from "./helpers";
export default abstract class EventMail { export default abstract class EventMail {
calEvent: CalendarEvent; calEvent: CalendarEvent;
parser: CalEventParser;
uid: string; uid: string;
/** /**
@ -17,6 +20,7 @@ export default abstract class EventMail {
constructor(calEvent: CalendarEvent, uid: string) { constructor(calEvent: CalendarEvent, uid: string) {
this.calEvent = calEvent; this.calEvent = calEvent;
this.uid = uid; this.uid = uid;
this.parser = new CalEventParser(calEvent);
} }
/** /**
@ -33,34 +37,23 @@ export default abstract class EventMail {
* @protected * @protected
*/ */
protected getPlainTextRepresentation(): string { protected getPlainTextRepresentation(): string {
return this.stripHtml(this.getHtmlRepresentation()); return 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, '');
} }
/** /**
* Returns the payload object for the nodemailer. * Returns the payload object for the nodemailer.
* @protected * @protected
*/ */
protected abstract getNodeMailerPayload(): Object; protected abstract getNodeMailerPayload(): Record<string, unknown>;
/** /**
* Sends the email to the event attendant and returns a Promise. * Sends the email to the event attendant and returns a Promise.
*/ */
public sendEmail(): Promise<any> { public sendEmail(): Promise<any> {
new Promise((resolve, reject) => nodemailer.createTransport(this.getMailerOptions().transport).sendMail( new Promise((resolve, reject) =>
this.getNodeMailerPayload(), nodemailer
(error, info) => { .createTransport(this.getMailerOptions().transport)
.sendMail(this.getNodeMailerPayload(), (error, info) => {
if (error) { if (error) {
this.printNodeMailerError(error); this.printNodeMailerError(error);
reject(new Error(error)); reject(new Error(error));
@ -109,7 +102,7 @@ export default abstract class EventMail {
* @protected * @protected
*/ */
protected getRescheduleLink(): string { protected getRescheduleLink(): string {
return process.env.BASE_URL + '/reschedule/' + this.uid; return this.parser.getRescheduleLink();
} }
/** /**
@ -118,21 +111,14 @@ export default abstract class EventMail {
* @protected * @protected
*/ */
protected getCancelLink(): string { protected getCancelLink(): string {
return process.env.BASE_URL + '/cancel/' + this.uid; return this.parser.getCancelLink();
} }
/** /**
* Defines a footer that will be appended to the email. * Defines a footer that will be appended to the email.
* @protected * @protected
*/ */
protected getAdditionalFooter(): string { protected getAdditionalFooter(): string {
return ` return this.parser.getChangeEventFooterHtml();
<br/>
<br/>
<strong>Need to change this event?</strong><br />
Cancel: <a href="${this.getCancelLink()}">${this.getCancelLink()}</a><br />
Reschedule: <a href="${this.getRescheduleLink()}">${this.getRescheduleLink()}</a>
`;
} }
} }

View file

@ -2,10 +2,12 @@ import {createEvent} from "ics";
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import EventMail from "./EventMail"; import EventMail from "./EventMail";
import utc from 'dayjs/plugin/utc'; import utc from "dayjs/plugin/utc";
import timezone from 'dayjs/plugin/timezone'; import timezone from "dayjs/plugin/timezone";
import toArray from 'dayjs/plugin/toArray'; import toArray from "dayjs/plugin/toArray";
import localizedFormat from 'dayjs/plugin/localizedFormat'; import localizedFormat from "dayjs/plugin/localizedFormat";
import { stripHtml } from "./helpers";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
dayjs.extend(toArray); dayjs.extend(toArray);
@ -18,14 +20,24 @@ export default class EventOrganizerMail extends EventMail {
*/ */
protected getiCalEventAsString(): string { protected getiCalEventAsString(): string {
const icsEvent = createEvent({ const icsEvent = createEvent({
start: dayjs(this.calEvent.startTime).utc().toArray().slice(0, 6).map((v, i) => i === 1 ? v + 1 : v), start: dayjs(this.calEvent.startTime)
startInputType: 'utc', .utc()
productId: 'calendso/ics', .toArray()
.slice(0, 6)
.map((v, i) => (i === 1 ? v + 1 : v)),
startInputType: "utc",
productId: "calendso/ics",
title: `${this.calEvent.type} with ${this.calEvent.attendees[0].name}`, title: `${this.calEvent.type} with ${this.calEvent.attendees[0].name}`,
description: this.calEvent.description + this.stripHtml(this.getAdditionalBody()) + this.stripHtml(this.getAdditionalFooter()), description:
duration: { minutes: dayjs(this.calEvent.endTime).diff(dayjs(this.calEvent.startTime), 'minute') }, this.calEvent.description +
stripHtml(this.getAdditionalBody()) +
stripHtml(this.getAdditionalFooter()),
duration: { minutes: dayjs(this.calEvent.endTime).diff(dayjs(this.calEvent.startTime), "minute") },
organizer: { name: this.calEvent.organizer.name, email: this.calEvent.organizer.email }, organizer: { name: this.calEvent.organizer.name, email: this.calEvent.organizer.email },
attendees: this.calEvent.attendees.map( (attendee: any) => ({ name: attendee.name, email: attendee.email }) ), attendees: this.calEvent.attendees.map((attendee: any) => ({
name: attendee.name,
email: attendee.email,
})),
status: "CONFIRMED", status: "CONFIRMED",
}); });
if (icsEvent.error) { if (icsEvent.error) {
@ -40,7 +52,8 @@ export default class EventOrganizerMail extends EventMail {
* @protected * @protected
*/ */
protected getHtmlRepresentation(): string { protected getHtmlRepresentation(): string {
return ` return (
`
<div> <div>
Hi ${this.calEvent.organizer.name},<br /> Hi ${this.calEvent.organizer.name},<br />
<br /> <br />
@ -51,22 +64,26 @@ export default class EventOrganizerMail extends EventMail {
<br /> <br />
<strong>Invitee Email:</strong><br /> <strong>Invitee Email:</strong><br />
<a href="mailto:${this.calEvent.attendees[0].email}">${this.calEvent.attendees[0].email}</a><br /> <a href="mailto:${this.calEvent.attendees[0].email}">${this.calEvent.attendees[0].email}</a><br />
<br />` + this.getAdditionalBody() + <br />` +
( this.getAdditionalBody() +
this.calEvent.location ? ` (this.calEvent.location
? `
<strong>Location:</strong><br /> <strong>Location:</strong><br />
${this.calEvent.location}<br /> ${this.calEvent.location}<br />
<br /> <br />
` : '' `
) + : "") +
`<strong>Invitee Time Zone:</strong><br /> `<strong>Invitee Time Zone:</strong><br />
${this.calEvent.attendees[0].timeZone}<br /> ${this.calEvent.attendees[0].timeZone}<br />
<br /> <br />
<strong>Additional notes:</strong><br /> <strong>Additional notes:</strong><br />
${this.calEvent.description} ${this.calEvent.description}
` + this.getAdditionalFooter() + ` ` +
this.getAdditionalFooter() +
`
</div> </div>
`; `
);
} }
/** /**
@ -74,17 +91,19 @@ export default class EventOrganizerMail extends EventMail {
* *
* @protected * @protected
*/ */
protected getNodeMailerPayload(): Object { protected getNodeMailerPayload(): Record<string, unknown> {
const organizerStart: Dayjs = <Dayjs>dayjs(this.calEvent.startTime).tz(this.calEvent.organizer.timeZone); const organizerStart: Dayjs = <Dayjs>dayjs(this.calEvent.startTime).tz(this.calEvent.organizer.timeZone);
return { return {
icalEvent: { icalEvent: {
filename: 'event.ics', filename: "event.ics",
content: this.getiCalEventAsString(), content: this.getiCalEventAsString(),
}, },
from: `Calendso <${this.getMailerOptions().from}>`, from: `Calendso <${this.getMailerOptions().from}>`,
to: this.calEvent.organizer.email, to: this.calEvent.organizer.email,
subject: `New event: ${this.calEvent.attendees[0].name} - ${organizerStart.format('LT dddd, LL')} - ${this.calEvent.type}`, subject: `New event: ${this.calEvent.attendees[0].name} - ${organizerStart.format("LT dddd, LL")} - ${
this.calEvent.type
}`,
html: this.getHtmlRepresentation(), html: this.getHtmlRepresentation(),
text: this.getPlainTextRepresentation(), text: this.getPlainTextRepresentation(),
}; };

View file

@ -8,7 +8,8 @@ export default class EventOrganizerRescheduledMail extends EventOrganizerMail {
* @protected * @protected
*/ */
protected getHtmlRepresentation(): string { protected getHtmlRepresentation(): string {
return ` return (
`
<div> <div>
Hi ${this.calEvent.organizer.name},<br /> Hi ${this.calEvent.organizer.name},<br />
<br /> <br />
@ -19,22 +20,26 @@ export default class EventOrganizerRescheduledMail extends EventOrganizerMail {
<br /> <br />
<strong>Invitee Email:</strong><br /> <strong>Invitee Email:</strong><br />
<a href="mailto:${this.calEvent.attendees[0].email}">${this.calEvent.attendees[0].email}</a><br /> <a href="mailto:${this.calEvent.attendees[0].email}">${this.calEvent.attendees[0].email}</a><br />
<br />` + this.getAdditionalBody() + <br />` +
( this.getAdditionalBody() +
this.calEvent.location ? ` (this.calEvent.location
? `
<strong>Location:</strong><br /> <strong>Location:</strong><br />
${this.calEvent.location}<br /> ${this.calEvent.location}<br />
<br /> <br />
` : '' `
) + : "") +
`<strong>Invitee Time Zone:</strong><br /> `<strong>Invitee Time Zone:</strong><br />
${this.calEvent.attendees[0].timeZone}<br /> ${this.calEvent.attendees[0].timeZone}<br />
<br /> <br />
<strong>Additional notes:</strong><br /> <strong>Additional notes:</strong><br />
${this.calEvent.description} ${this.calEvent.description}
` + this.getAdditionalFooter() + ` ` +
this.getAdditionalFooter() +
`
</div> </div>
`; `
);
} }
/** /**
@ -42,17 +47,19 @@ export default class EventOrganizerRescheduledMail extends EventOrganizerMail {
* *
* @protected * @protected
*/ */
protected getNodeMailerPayload(): Object { protected getNodeMailerPayload(): Record<string, unknown> {
const organizerStart: Dayjs = <Dayjs>dayjs(this.calEvent.startTime).tz(this.calEvent.organizer.timeZone); const organizerStart: Dayjs = <Dayjs>dayjs(this.calEvent.startTime).tz(this.calEvent.organizer.timeZone);
return { return {
icalEvent: { icalEvent: {
filename: 'event.ics', filename: "event.ics",
content: this.getiCalEventAsString(), content: this.getiCalEventAsString(),
}, },
from: `Calendso <${this.getMailerOptions().from}>`, from: `Calendso <${this.getMailerOptions().from}>`,
to: this.calEvent.organizer.email, to: this.calEvent.organizer.email,
subject: `Rescheduled event: ${this.calEvent.attendees[0].name} - ${organizerStart.format('LT dddd, LL')} - ${this.calEvent.type}`, subject: `Rescheduled event: ${this.calEvent.attendees[0].name} - ${organizerStart.format(
"LT dddd, LL"
)} - ${this.calEvent.type}`,
html: this.getHtmlRepresentation(), html: this.getHtmlRepresentation(),
text: this.getPlainTextRepresentation(), text: this.getPlainTextRepresentation(),
}; };

View file

@ -6,15 +6,24 @@ export function getIntegrationName(videoCallData: VideoCallData): string {
return nameProto.charAt(0).toUpperCase() + nameProto.slice(1); return nameProto.charAt(0).toUpperCase() + nameProto.slice(1);
} }
export function getFormattedMeetingId(videoCallData: VideoCallData): string { function extractZoom(videoCallData: VideoCallData): string {
switch(videoCallData.type) {
case 'zoom_video':
const strId = videoCallData.id.toString(); const strId = videoCallData.id.toString();
const part1 = strId.slice(0, 3); const part1 = strId.slice(0, 3);
const part2 = strId.slice(3, 7); const part2 = strId.slice(3, 7);
const part3 = strId.slice(7, 11); const part3 = strId.slice(7, 11);
return part1 + " " + part2 + " " + part3; return part1 + " " + part2 + " " + part3;
}
export function getFormattedMeetingId(videoCallData: VideoCallData): string {
switch (videoCallData.type) {
case "zoom_video":
return extractZoom(videoCallData);
default: default:
return videoCallData.id.toString(); return videoCallData.id.toString();
} }
} }
export function stripHtml(html: string): string {
return html.replace("<br />", "\n").replace(/<[^>]+>/g, "");
}