From 04d7a280ef74a7f7fcdc80833a6f33428ebf311c Mon Sep 17 00:00:00 2001 From: Jan Vereecken Date: Sat, 31 Jul 2021 15:00:27 +0200 Subject: [PATCH 1/3] Use calendarView instead of events When calling Microsoft Graph use calendars/calendarView instead of calendars/events to allow occurences to be returned. --- lib/calendarClient.ts | 111 ++++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/lib/calendarClient.ts b/lib/calendarClient.ts index 9d3964b0d1..09668fa403 100644 --- a/lib/calendarClient.ts +++ b/lib/calendarClient.ts @@ -10,8 +10,14 @@ import CalEventParser from "./CalEventParser"; const { google } = require("googleapis"); const googleAuth = (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 { 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] + ); myGoogleAuth.setCredentials(credential.key); const isExpired = () => myGoogleAuth.isTokenExpiring(); @@ -43,7 +49,8 @@ const googleAuth = (credential) => { }); return { - getToken: () => (!isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken()), + getToken: () => + !isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken(), }; }; @@ -81,7 +88,9 @@ const o365Auth = (credential) => { .then(handleErrorsJson) .then((responseBody) => { credential.key.access_token = responseBody.access_token; - credential.key.expiry_date = Math.round(+new Date() / 1000 + responseBody.expires_in); + credential.key.expiry_date = Math.round( + +new Date() / 1000 + responseBody.expires_in + ); return prisma.credential .update({ where: { @@ -139,7 +148,11 @@ export interface CalendarApiAdapter { deleteEvent(uid: string); - getAvailability(dateFrom, dateTo, selectedCalendars: IntegrationCalendar[]): Promise; + getAvailability( + dateFrom, + dateTo, + selectedCalendars: IntegrationCalendar[] + ): Promise; listCalendars(): Promise; } @@ -206,7 +219,7 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => { return { getAvailability: (dateFrom, dateTo, selectedCalendars) => { - const filter = "?$filter=start/dateTime ge '" + dateFrom + "' and end/dateTime le '" + dateTo + "'"; + const filter = "?startdatetime=" + dateFrom + "&enddatetime=" + dateTo; return auth .getToken() .then((accessToken) => { @@ -229,7 +242,7 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => { headers: { Prefer: 'outlook.timezone="Etc/GMT"', }, - url: `/me/calendars/${calendarId}/events${filter}`, + url: `/me/calendars/${calendarId}/calendarView${filter}`, })); return fetch("https://graph.microsoft.com/v1.0/$batch", { @@ -309,7 +322,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { getAvailability: (dateFrom, dateTo, selectedCalendars) => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); const selectedCalendarIds = selectedCalendars .filter((e) => e.integration === integrationType) .map((e) => e.externalId); @@ -320,7 +336,9 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { } (selectedCalendarIds.length == 0 - ? calendar.calendarList.list().then((cals) => cals.data.items.map((cal) => cal.id)) + ? calendar.calendarList + .list() + .then((cals) => cals.data.items.map((cal) => cal.id)) : Promise.resolve(selectedCalendarIds) ) .then((calsIds) => { @@ -336,12 +354,19 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { if (err) { reject(err); } - resolve(Object.values(apires.data.calendars).flatMap((item) => item["busy"])); + resolve( + Object.values(apires.data.calendars).flatMap( + (item) => item["busy"] + ) + ); } ); }) .catch((err) => { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); reject(err); }); }) @@ -375,7 +400,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { payload["conferenceData"] = event.conferenceData; } - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.insert( { auth: myGoogleAuth, @@ -385,7 +413,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -418,7 +449,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { payload["location"] = event.location; } - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.update( { auth: myGoogleAuth, @@ -430,7 +464,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -441,7 +478,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { deleteEvent: (uid: string) => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.delete( { auth: myGoogleAuth, @@ -452,7 +492,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -463,7 +506,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { listCalendars: () => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.calendarList .list() .then((cals) => { @@ -480,7 +526,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { ); }) .catch((err) => { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); reject(err); }); }) @@ -503,19 +552,29 @@ const calendars = (withCredentials): CalendarApiAdapter[] => }) .filter(Boolean); -const getBusyCalendarTimes = (withCredentials, dateFrom, dateTo, selectedCalendars) => +const getBusyCalendarTimes = ( + withCredentials, + dateFrom, + dateTo, + selectedCalendars +) => Promise.all( - calendars(withCredentials).map((c) => c.getAvailability(dateFrom, dateTo, selectedCalendars)) + calendars(withCredentials).map((c) => + c.getAvailability(dateFrom, dateTo, selectedCalendars) + ) ).then((results) => { return results.reduce((acc, availability) => acc.concat(availability), []); }); const listCalendars = (withCredentials) => - Promise.all(calendars(withCredentials).map((c) => c.listCalendars())).then((results) => - results.reduce((acc, calendars) => acc.concat(calendars), []) + Promise.all(calendars(withCredentials).map((c) => c.listCalendars())).then( + (results) => results.reduce((acc, calendars) => acc.concat(calendars), []) ); -const createEvent = async (credential: Credential, calEvent: CalendarEvent): Promise => { +const createEvent = async ( + credential: Credential, + calEvent: CalendarEvent +): Promise => { const parser: CalEventParser = new CalEventParser(calEvent); const uid: string = parser.getUid(); /* @@ -525,7 +584,9 @@ const createEvent = async (credential: Credential, calEvent: CalendarEvent): Pro */ const richEvent: CalendarEvent = parser.asRichEventPlain(); - const creationResult = credential ? await calendars([credential])[0].createEvent(richEvent) : null; + const creationResult = credential + ? await calendars([credential])[0].createEvent(richEvent) + : null; const maybeHangoutLink = creationResult?.hangoutLink; const maybeEntryPoints = creationResult?.entryPoints; From bd07a93f066dd5758701e6a34c750c857ef3fcc0 Mon Sep 17 00:00:00 2001 From: nicolas Date: Thu, 5 Aug 2021 21:49:32 +0200 Subject: [PATCH 2/3] Removed full stop --- lib/CalEventParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CalEventParser.ts b/lib/CalEventParser.ts index ef1ff3151c..e6bd5dfdab 100644 --- a/lib/CalEventParser.ts +++ b/lib/CalEventParser.ts @@ -37,7 +37,7 @@ export default class CalEventParser { * Returns a footer section with links to change the event (as HTML). */ public getChangeEventFooterHtml(): string { - return `

Need to make a change? Cancel or reschedule.

`; + return `

Need to make a change? Cancel or reschedule

`; } /** From a764b960b2114231739481808cfbd48b139cb18e Mon Sep 17 00:00:00 2001 From: joshsny Date: Fri, 6 Aug 2021 07:30:17 +0200 Subject: [PATCH 3/3] changed preview link to open in new tab --- pages/event-types/index.tsx | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pages/event-types/index.tsx b/pages/event-types/index.tsx index 52380cf101..ee77b4c2e7 100644 --- a/pages/event-types/index.tsx +++ b/pages/event-types/index.tsx @@ -1,12 +1,6 @@ -import Head from "next/head"; -import Link from "next/link"; -import prisma from "../../lib/prisma"; -import Shell from "../../components/Shell"; -import { useRouter } from "next/router"; -import { getSession, useSession } from "next-auth/client"; -import React, { Fragment, useRef } from "react"; +import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@components/Dialog"; +import Loader from "@components/Loader"; import { Menu, Transition } from "@headlessui/react"; - import { ClockIcon, DotsHorizontalIcon, @@ -16,9 +10,14 @@ import { PlusIcon, UserIcon, } from "@heroicons/react/solid"; -import Loader from "@components/Loader"; import classNames from "@lib/classNames"; -import { Dialog, DialogContent, DialogTrigger, DialogClose } from "@components/Dialog"; +import { getSession, useSession } from "next-auth/client"; +import Head from "next/head"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import React, { Fragment, useRef } from "react"; +import Shell from "../../components/Shell"; +import prisma from "../../lib/prisma"; export default function Availability({ user, types }) { const [session, loading] = useSession(); @@ -225,7 +224,10 @@ export default function Availability({ user, types }) {