fix: calendar event fixes (#1260)

* fix: calendar event fixes

* update after code review
This commit is contained in:
Mihai C 2021-12-06 21:34:31 +02:00 committed by GitHub
parent c109ab1e30
commit dd446abeec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 120 additions and 23 deletions

View file

@ -1,15 +1,104 @@
import dayjs from "dayjs";
import short from "short-uuid"; import short from "short-uuid";
import { v5 as uuidv5 } from "uuid"; import { v5 as uuidv5 } from "uuid";
import { getIntegrationName } from "@lib/integrations";
import { CalendarEvent } from "./calendarClient"; import { CalendarEvent } from "./calendarClient";
import { BASE_URL } from "./config/constants"; import { BASE_URL } from "./config/constants";
const translator = short(); const translator = short();
export const getUid = (calEvent: CalendarEvent) => { export const getWhat = (calEvent: CalendarEvent) => {
return `
${calEvent.language("what")}
${calEvent.type}
`;
};
export const getWhen = (calEvent: CalendarEvent) => {
const inviteeStart = dayjs(calEvent.startTime).tz(calEvent.attendees[0].timeZone);
const inviteeEnd = dayjs(calEvent.endTime).tz(calEvent.attendees[0].timeZone);
return `
${calEvent.language("when")}
${calEvent.language(inviteeStart.format("dddd").toLowerCase())}, ${calEvent.language(
inviteeStart.format("MMMM").toLowerCase()
)} ${inviteeStart.format("D")}, ${inviteeStart.format("YYYY")} | ${inviteeStart.format(
"h:mma"
)} - ${inviteeEnd.format("h:mma")} (${calEvent.attendees[0].timeZone})
`;
};
export const getWho = (calEvent: CalendarEvent) => {
const attendees = calEvent.attendees
.map((attendee) => {
return `
${attendee?.name || calEvent.language("guest")}
${attendee.email}
`;
})
.join("");
const organizer = `
${calEvent.organizer.name} - ${calEvent.language("organizer")}
${calEvent.organizer.email}
`;
return `
${calEvent.language("who")}
${organizer + attendees}
`;
};
export const getAdditionalNotes = (calEvent: CalendarEvent) => {
return `
${calEvent.language("additional_notes")}
${calEvent.description}
`;
};
export const getLocation = (calEvent: CalendarEvent) => {
let providerName = calEvent.location ? getIntegrationName(calEvent.location) : "";
if (calEvent.location && calEvent.location.includes("integrations:")) {
const location = calEvent.location.split(":")[1];
providerName = location[0].toUpperCase() + location.slice(1);
}
if (calEvent.videoCallData) {
return calEvent.videoCallData.url;
}
if (calEvent.additionInformation?.hangoutLink) {
return calEvent.additionInformation.hangoutLink;
}
return providerName || calEvent.location;
};
export const getManageLink = (calEvent: CalendarEvent) => {
return `
${calEvent.language("need_to_reschedule_or_cancel")}
${getCancelLink(calEvent)}
`;
};
export const getUid = (calEvent: CalendarEvent): string => {
return calEvent.uid ?? translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL)); return calEvent.uid ?? translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL));
}; };
export const getCancelLink = (calEvent: CalendarEvent) => { export const getCancelLink = (calEvent: CalendarEvent): string => {
return BASE_URL + "/cancel/" + getUid(calEvent); return BASE_URL + "/cancel/" + getUid(calEvent);
}; };
export const getRichDescription = (calEvent: CalendarEvent) => {
return `
${getWhat(calEvent)}
${getWhen(calEvent)}
${getWho(calEvent)}
${getLocation(calEvent)}
${getAdditionalNotes(calEvent)}
${getManageLink(calEvent)}
`;
};

View file

@ -181,7 +181,7 @@ const updateEvent = async (
const uid = getUid(calEvent); const uid = getUid(calEvent);
let success = true; let success = true;
const updationResult = const updatedResult =
credential && bookingRefUid credential && bookingRefUid
? await calendars([credential])[0] ? await calendars([credential])[0]
.updateEvent(bookingRefUid, calEvent) .updateEvent(bookingRefUid, calEvent)
@ -192,7 +192,7 @@ const updateEvent = async (
}) })
: undefined; : undefined;
if (!updationResult) { if (!updatedResult) {
return { return {
type: credential.type, type: credential.type,
success, success,
@ -205,7 +205,7 @@ const updateEvent = async (
type: credential.type, type: credential.type,
success, success,
uid, uid,
updatedEvent: updationResult, updatedEvent: updatedResult,
originalEvent: calEvent, originalEvent: calEvent,
}; };
}; };

View file

@ -121,6 +121,7 @@ export default class AttendeeScheduledEmail {
${this.calEvent.language("emailed_you_and_any_other_attendees")} ${this.calEvent.language("emailed_you_and_any_other_attendees")}
${this.getWhat()} ${this.getWhat()}
${this.getWhen()} ${this.getWhen()}
${this.getWho()}
${this.getLocation()} ${this.getLocation()}
${this.getAdditionalNotes()} ${this.getAdditionalNotes()}
${this.calEvent.language("need_to_reschedule_or_cancel")} ${this.calEvent.language("need_to_reschedule_or_cancel")}
@ -380,7 +381,9 @@ ${this.getAdditionalNotes()}
<p style="height: 6px"></p> <p style="height: 6px"></p>
<div style="line-height: 6px;"> <div style="line-height: 6px;">
<p style="color: #494949;">${this.calEvent.language("where")}</p> <p style="color: #494949;">${this.calEvent.language("where")}</p>
<p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName}</p> <p style="color: #494949; font-weight: 400; line-height: 24px;">${
providerName || this.calEvent.location
}</p>
</div> </div>
`; `;
} }

View file

@ -125,6 +125,7 @@ ${this.calEvent.language("new_event_scheduled")}
${this.calEvent.language("emailed_you_and_any_other_attendees")} ${this.calEvent.language("emailed_you_and_any_other_attendees")}
${this.getWhat()} ${this.getWhat()}
${this.getWhen()} ${this.getWhen()}
${this.getWho()}
${this.getLocation()} ${this.getLocation()}
${this.getAdditionalNotes()} ${this.getAdditionalNotes()}
${this.calEvent.language("need_to_reschedule_or_cancel")} ${this.calEvent.language("need_to_reschedule_or_cancel")}
@ -368,7 +369,9 @@ ${getCancelLink(this.calEvent)}
<p style="height: 6px"></p> <p style="height: 6px"></p>
<div style="line-height: 6px;"> <div style="line-height: 6px;">
<p style="color: #494949;">${this.calEvent.language("where")}</p> <p style="color: #494949;">${this.calEvent.language("where")}</p>
<p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName}</p> <p style="color: #494949; font-weight: 400; line-height: 24px;">${
providerName || this.calEvent.location
}</p>
</div> </div>
`; `;
} }

View file

@ -123,7 +123,6 @@ export default class EventManager {
const result = await this.createVideoEvent(evt); const result = await this.createVideoEvent(evt);
if (result.createdEvent) { if (result.createdEvent) {
evt.videoCallData = result.createdEvent; evt.videoCallData = result.createdEvent;
evt.location = result.createdEvent.url;
} }
results.push(result); results.push(result);
@ -195,7 +194,6 @@ export default class EventManager {
const result = await this.updateVideoEvent(evt, booking); const result = await this.updateVideoEvent(evt, booking);
if (result.updatedEvent) { if (result.updatedEvent) {
evt.videoCallData = result.updatedEvent; evt.videoCallData = result.updatedEvent;
evt.location = result.updatedEvent.url;
} }
results.push(result); results.push(result);
} }

View file

@ -14,6 +14,7 @@ import {
} from "tsdav"; } from "tsdav";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { symmetricDecrypt } from "@lib/crypto"; import { symmetricDecrypt } from "@lib/crypto";
import logger from "@lib/logger"; import logger from "@lib/logger";
@ -79,8 +80,8 @@ export class AppleCalendar implements CalendarApiAdapter {
start: this.convertDate(event.startTime), start: this.convertDate(event.startTime),
duration: this.getDuration(event.startTime, event.endTime), duration: this.getDuration(event.startTime, event.endTime),
title: event.title, title: event.title,
description: event.description ?? "", description: getRichDescription(event),
location: event.location, location: getLocation(event),
organizer: { email: event.organizer.email, name: event.organizer.name }, organizer: { email: event.organizer.email, name: event.organizer.name },
attendees: this.getAttendees(event.attendees), attendees: this.getAttendees(event.attendees),
}); });
@ -137,8 +138,8 @@ export class AppleCalendar implements CalendarApiAdapter {
start: this.convertDate(event.startTime), start: this.convertDate(event.startTime),
duration: this.getDuration(event.startTime, event.endTime), duration: this.getDuration(event.startTime, event.endTime),
title: event.title, title: event.title,
description: event.description ?? "", description: getRichDescription(event),
location: event.location, location: getLocation(event),
organizer: { email: event.organizer.email, name: event.organizer.name }, organizer: { email: event.organizer.email, name: event.organizer.name },
attendees: this.getAttendees(event.attendees), attendees: this.getAttendees(event.attendees),
}); });

View file

@ -14,6 +14,7 @@ import {
} from "tsdav"; } from "tsdav";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { symmetricDecrypt } from "@lib/crypto"; import { symmetricDecrypt } from "@lib/crypto";
import logger from "@lib/logger"; import logger from "@lib/logger";
@ -82,8 +83,8 @@ export class CalDavCalendar implements CalendarApiAdapter {
start: this.convertDate(event.startTime), start: this.convertDate(event.startTime),
duration: this.getDuration(event.startTime, event.endTime), duration: this.getDuration(event.startTime, event.endTime),
title: event.title, title: event.title,
description: event.description ?? "", description: getRichDescription(event),
location: event.location, location: getLocation(event),
organizer: { email: event.organizer.email, name: event.organizer.name }, organizer: { email: event.organizer.email, name: event.organizer.name },
attendees: this.getAttendees(event.attendees), attendees: this.getAttendees(event.attendees),
}); });
@ -141,8 +142,8 @@ export class CalDavCalendar implements CalendarApiAdapter {
start: this.convertDate(event.startTime), start: this.convertDate(event.startTime),
duration: this.getDuration(event.startTime, event.endTime), duration: this.getDuration(event.startTime, event.endTime),
title: event.title, title: event.title,
description: event.description ?? "", description: getRichDescription(event),
location: event.location, location: getLocation(event),
organizer: { email: event.organizer.email, name: event.organizer.name }, organizer: { email: event.organizer.email, name: event.organizer.name },
attendees: this.getAttendees(event.attendees), attendees: this.getAttendees(event.attendees),
}); });

View file

@ -2,6 +2,7 @@ import { Credential, Prisma } from "@prisma/client";
import { GetTokenResponse } from "google-auth-library/build/src/auth/oauth2client"; import { GetTokenResponse } from "google-auth-library/build/src/auth/oauth2client";
import { Auth, calendar_v3, google } from "googleapis"; import { Auth, calendar_v3, google } from "googleapis";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "@lib/calendarClient"; import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "@lib/calendarClient";
import prisma from "@lib/prisma"; import prisma from "@lib/prisma";
@ -105,7 +106,7 @@ export const GoogleCalendarApiAdapter = (credential: Credential): CalendarApiAda
auth.getToken().then((myGoogleAuth) => { auth.getToken().then((myGoogleAuth) => {
const payload: calendar_v3.Schema$Event = { const payload: calendar_v3.Schema$Event = {
summary: event.title, summary: event.title,
description: event.description, description: getRichDescription(event),
start: { start: {
dateTime: event.startTime, dateTime: event.startTime,
timeZone: event.organizer.timeZone, timeZone: event.organizer.timeZone,
@ -122,7 +123,7 @@ export const GoogleCalendarApiAdapter = (credential: Credential): CalendarApiAda
}; };
if (event.location) { if (event.location) {
payload["location"] = event.location; payload["location"] = getLocation(event);
} }
if (event.conferenceData && event.location === "integrations:google:meet") { if (event.conferenceData && event.location === "integrations:google:meet") {
@ -155,7 +156,7 @@ export const GoogleCalendarApiAdapter = (credential: Credential): CalendarApiAda
auth.getToken().then((myGoogleAuth) => { auth.getToken().then((myGoogleAuth) => {
const payload: calendar_v3.Schema$Event = { const payload: calendar_v3.Schema$Event = {
summary: event.title, summary: event.title,
description: event.description, description: getRichDescription(event),
start: { start: {
dateTime: event.startTime, dateTime: event.startTime,
timeZone: event.organizer.timeZone, timeZone: event.organizer.timeZone,
@ -171,7 +172,7 @@ export const GoogleCalendarApiAdapter = (credential: Credential): CalendarApiAda
}; };
if (event.location) { if (event.location) {
payload["location"] = event.location; payload["location"] = getLocation(event);
} }
const calendar = google.calendar({ const calendar = google.calendar({

View file

@ -1,6 +1,7 @@
import { Calendar as OfficeCalendar } from "@microsoft/microsoft-graph-types-beta"; import { Calendar as OfficeCalendar } from "@microsoft/microsoft-graph-types-beta";
import { Credential } from "@prisma/client"; import { Credential } from "@prisma/client";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "@lib/calendarClient"; import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "@lib/calendarClient";
import { handleErrorsJson, handleErrorsRaw } from "@lib/errors"; import { handleErrorsJson, handleErrorsRaw } from "@lib/errors";
import prisma from "@lib/prisma"; import prisma from "@lib/prisma";
@ -65,7 +66,7 @@ export const Office365CalendarApiAdapter = (credential: Credential): CalendarApi
subject: event.title, subject: event.title,
body: { body: {
contentType: "HTML", contentType: "HTML",
content: event.description, content: getRichDescription(event),
}, },
start: { start: {
dateTime: event.startTime, dateTime: event.startTime,
@ -82,7 +83,7 @@ export const Office365CalendarApiAdapter = (credential: Credential): CalendarApi
}, },
type: "required", type: "required",
})), })),
location: event.location ? { displayName: event.location } : undefined, location: event.location ? { displayName: getLocation(event) } : undefined,
}; };
}; };