
* refactor: emails (WIP) * wip * wip * refactor: calendarClient * chore: remove comment * feat: new templates * feat: more templates (wip) * feat: email templates wip * feat: email templates wip * feat: prepare for testing * For testing stripe integration * Uses imported BASE_URL * Fixes types * use BASE_URL Co-authored-by: Omar López <zomars@me.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
255 lines
8.3 KiB
TypeScript
255 lines
8.3 KiB
TypeScript
import { Credential, Prisma } from "@prisma/client";
|
|
import { GetTokenResponse } from "google-auth-library/build/src/auth/oauth2client";
|
|
import { Auth, calendar_v3, google } from "googleapis";
|
|
|
|
import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "@lib/calendarClient";
|
|
import prisma from "@lib/prisma";
|
|
|
|
export interface ConferenceData {
|
|
createRequest: calendar_v3.Schema$CreateConferenceRequest;
|
|
}
|
|
|
|
const googleAuth = (credential: Credential) => {
|
|
const { client_secret, client_id, redirect_uris } = JSON.parse(process.env.GOOGLE_API_CREDENTIALS!).web;
|
|
const myGoogleAuth = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
|
|
const googleCredentials = credential.key as Auth.Credentials;
|
|
myGoogleAuth.setCredentials(googleCredentials);
|
|
|
|
// FIXME - type errors IDK Why this is a protected method ¯\_(ツ)_/¯
|
|
const isExpired = () => myGoogleAuth.isTokenExpiring();
|
|
|
|
const refreshAccessToken = () =>
|
|
myGoogleAuth
|
|
// FIXME - type errors IDK Why this is a protected method ¯\_(ツ)_/¯
|
|
.refreshToken(googleCredentials.refresh_token)
|
|
.then((res: GetTokenResponse) => {
|
|
const token = res.res?.data;
|
|
googleCredentials.access_token = token.access_token;
|
|
googleCredentials.expiry_date = token.expiry_date;
|
|
return prisma.credential
|
|
.update({
|
|
where: {
|
|
id: credential.id,
|
|
},
|
|
data: {
|
|
key: googleCredentials as Prisma.InputJsonValue,
|
|
},
|
|
})
|
|
.then(() => {
|
|
myGoogleAuth.setCredentials(googleCredentials);
|
|
return myGoogleAuth;
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
console.error("Error refreshing google token", err);
|
|
return myGoogleAuth;
|
|
});
|
|
|
|
return {
|
|
getToken: () => (!isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken()),
|
|
};
|
|
};
|
|
|
|
export const GoogleCalendarApiAdapter = (credential: Credential): CalendarApiAdapter => {
|
|
const auth = googleAuth(credential);
|
|
const integrationType = "google_calendar";
|
|
|
|
return {
|
|
getAvailability: (dateFrom, dateTo, selectedCalendars) =>
|
|
new Promise((resolve, reject) =>
|
|
auth.getToken().then((myGoogleAuth) => {
|
|
const calendar = google.calendar({
|
|
version: "v3",
|
|
auth: myGoogleAuth,
|
|
});
|
|
const selectedCalendarIds = selectedCalendars
|
|
.filter((e) => e.integration === integrationType)
|
|
.map((e) => e.externalId);
|
|
if (selectedCalendarIds.length === 0 && selectedCalendars.length > 0) {
|
|
// Only calendars of other integrations selected
|
|
resolve([]);
|
|
return;
|
|
}
|
|
|
|
(selectedCalendarIds.length === 0
|
|
? calendar.calendarList
|
|
.list()
|
|
.then((cals) => cals.data.items?.map((cal) => cal.id).filter(Boolean) || [])
|
|
: Promise.resolve(selectedCalendarIds)
|
|
)
|
|
.then((calsIds) => {
|
|
calendar.freebusy.query(
|
|
{
|
|
requestBody: {
|
|
timeMin: dateFrom,
|
|
timeMax: dateTo,
|
|
items: calsIds.map((id) => ({ id: id })),
|
|
},
|
|
},
|
|
(err, apires) => {
|
|
if (err) {
|
|
reject(err);
|
|
}
|
|
resolve(Object.values(apires.data.calendars).flatMap((item) => item["busy"]));
|
|
}
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
console.error("There was an error contacting google calendar service: ", err);
|
|
reject(err);
|
|
});
|
|
})
|
|
),
|
|
createEvent: (event: CalendarEvent) =>
|
|
new Promise((resolve, reject) =>
|
|
auth.getToken().then((myGoogleAuth) => {
|
|
const payload: calendar_v3.Schema$Event = {
|
|
summary: event.title,
|
|
description: event.description,
|
|
start: {
|
|
dateTime: event.startTime,
|
|
timeZone: event.organizer.timeZone,
|
|
},
|
|
end: {
|
|
dateTime: event.endTime,
|
|
timeZone: event.organizer.timeZone,
|
|
},
|
|
attendees: event.attendees,
|
|
reminders: {
|
|
useDefault: false,
|
|
overrides: [{ method: "email", minutes: 10 }],
|
|
},
|
|
};
|
|
|
|
if (event.location) {
|
|
payload["location"] = event.location;
|
|
}
|
|
|
|
if (event.conferenceData && event.location === "integrations:google:meet") {
|
|
payload["conferenceData"] = event.conferenceData;
|
|
}
|
|
|
|
const calendar = google.calendar({
|
|
version: "v3",
|
|
auth: myGoogleAuth,
|
|
});
|
|
calendar.events.insert(
|
|
{
|
|
auth: myGoogleAuth,
|
|
calendarId: "primary",
|
|
requestBody: payload,
|
|
conferenceDataVersion: 1,
|
|
},
|
|
function (err, event) {
|
|
if (err || !event?.data) {
|
|
console.error("There was an error contacting google calendar service: ", err);
|
|
return reject(err);
|
|
}
|
|
return resolve(event.data);
|
|
}
|
|
);
|
|
})
|
|
),
|
|
updateEvent: (uid: string, event: CalendarEvent) =>
|
|
new Promise((resolve, reject) =>
|
|
auth.getToken().then((myGoogleAuth) => {
|
|
const payload: calendar_v3.Schema$Event = {
|
|
summary: event.title,
|
|
description: event.description,
|
|
start: {
|
|
dateTime: event.startTime,
|
|
timeZone: event.organizer.timeZone,
|
|
},
|
|
end: {
|
|
dateTime: event.endTime,
|
|
timeZone: event.organizer.timeZone,
|
|
},
|
|
attendees: event.attendees,
|
|
reminders: {
|
|
useDefault: false,
|
|
overrides: [{ method: "email", minutes: 10 }],
|
|
},
|
|
};
|
|
|
|
if (event.location) {
|
|
payload["location"] = event.location;
|
|
}
|
|
|
|
const calendar = google.calendar({
|
|
version: "v3",
|
|
auth: myGoogleAuth,
|
|
});
|
|
calendar.events.update(
|
|
{
|
|
auth: myGoogleAuth,
|
|
calendarId: "primary",
|
|
eventId: uid,
|
|
sendNotifications: true,
|
|
sendUpdates: "all",
|
|
requestBody: payload,
|
|
},
|
|
function (err, event) {
|
|
if (err) {
|
|
console.error("There was an error contacting google calendar service: ", err);
|
|
return reject(err);
|
|
}
|
|
return resolve(event?.data);
|
|
}
|
|
);
|
|
})
|
|
),
|
|
deleteEvent: (uid: string) =>
|
|
new Promise((resolve, reject) =>
|
|
auth.getToken().then((myGoogleAuth) => {
|
|
const calendar = google.calendar({
|
|
version: "v3",
|
|
auth: myGoogleAuth,
|
|
});
|
|
calendar.events.delete(
|
|
{
|
|
auth: myGoogleAuth,
|
|
calendarId: "primary",
|
|
eventId: uid,
|
|
sendNotifications: true,
|
|
sendUpdates: "all",
|
|
},
|
|
function (err, event) {
|
|
if (err) {
|
|
console.error("There was an error contacting google calendar service: ", err);
|
|
return reject(err);
|
|
}
|
|
return resolve(event?.data);
|
|
}
|
|
);
|
|
})
|
|
),
|
|
listCalendars: () =>
|
|
new Promise((resolve, reject) =>
|
|
auth.getToken().then((myGoogleAuth) => {
|
|
const calendar = google.calendar({
|
|
version: "v3",
|
|
auth: myGoogleAuth,
|
|
});
|
|
calendar.calendarList
|
|
.list()
|
|
.then((cals) => {
|
|
resolve(
|
|
cals.data.items?.map((cal) => {
|
|
const calendar: IntegrationCalendar = {
|
|
externalId: cal.id ?? "No id",
|
|
integration: integrationType,
|
|
name: cal.summary ?? "No name",
|
|
primary: cal.primary ?? false,
|
|
};
|
|
return calendar;
|
|
}) || []
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
console.error("There was an error contacting google calendar service: ", err);
|
|
reject(err);
|
|
});
|
|
})
|
|
),
|
|
};
|
|
};
|