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 `
Hi ${this.calEvent.organizer.name},

A new event has been scheduled.

Event Type:
${this.calEvent.type}

Invitee Email:
${this.calEvent.attendees[0].email}

` + this.getAdditionalBody() + ( this.calEvent.location ? ` Location:
${this.calEvent.location}

` : '' ) + `Invitee Time Zone:
${this.calEvent.attendees[0].timeZone}

Additional notes:
${this.calEvent.description}
`; } /** * 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('
', "\n") .replace(/<[^>]+>/g, ''); } /** * Sends the email to the event attendant and returns a Promise. */ public sendEmail(): Promise { const options = this.getMailerOptions(); const {transport, from} = options; const organizerStart: 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 ""; } }