From bcc1a8e2793409bf19e88b95e3ff4458474b11c7 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Fri, 1 Nov 2024 19:22:57 -0400 Subject: [PATCH] fix: create a wrapper for google calendar fetching (#17440) * fix: create a wrapper for google cal fetching * improve log --- .../app-store/googlecalendar/api/callback.ts | 25 ++------------ .../googlecalendar/lib/CalendarService.ts | 17 ++++++---- .../app-store/googlecalendar/lib/utils.ts | 34 +++++++++++++++++++ 3 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 packages/app-store/googlecalendar/lib/utils.ts diff --git a/packages/app-store/googlecalendar/api/callback.ts b/packages/app-store/googlecalendar/api/callback.ts index 020f26fc65..dfd1b24edc 100644 --- a/packages/app-store/googlecalendar/api/callback.ts +++ b/packages/app-store/googlecalendar/api/callback.ts @@ -15,6 +15,7 @@ import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import { decodeOAuthState } from "../../_utils/oauth/decodeOAuthState"; import { REQUIRED_SCOPES, SCOPE_USERINFO_PROFILE } from "../lib/constants"; import { getGoogleAppKeys } from "../lib/getGoogleAppKeys"; +import { getAllCalendars } from "../lib/utils"; async function getHandler(req: NextApiRequest, res: NextApiResponse) { const { code } = req.query; @@ -74,11 +75,7 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) { const cals = await getAllCalendars(calendar); - let primaryCal = cals.find((cal) => cal.primary); - if (!primaryCal?.id) { - // If the primary calendar is not set, set it to the first calendar - primaryCal = cals[0]; - } + const primaryCal = cals.find((cal) => cal.primary) ?? cals[0]; // Only attempt to update the user's profile photo if the user has granted the required scope if (grantedScopes.includes(SCOPE_USERINFO_PROFILE)) { @@ -210,24 +207,6 @@ async function updateProfilePhoto(oAuth2Client: Auth.OAuth2Client, userId: numbe } } -async function getAllCalendars(calendar: calendar_v3.Calendar) { - let allCalendars: calendar_v3.Schema$CalendarListEntry[] = []; - let pageToken = null; - - do { - const response: any = await calendar.calendarList.list({ - fields: "items(id,summary,primary,accessRole),nextPageToken", - pageToken: pageToken, - maxResults: 250, // 250 is max - }); - - allCalendars = [...allCalendars, ...(response.data.items ?? [])]; - pageToken = response.data.nextPageToken; - } while (pageToken); - - return allCalendars; -} - export default defaultHandler({ GET: Promise.resolve({ default: defaultResponder(getHandler) }), }); diff --git a/packages/app-store/googlecalendar/lib/CalendarService.ts b/packages/app-store/googlecalendar/lib/CalendarService.ts index 20ed7ce00f..42ac3771cc 100644 --- a/packages/app-store/googlecalendar/lib/CalendarService.ts +++ b/packages/app-store/googlecalendar/lib/CalendarService.ts @@ -36,6 +36,7 @@ import { markTokenAsExpired } from "../../_utils/oauth/markTokenAsExpired"; import { OAuth2UniversalSchema } from "../../_utils/oauth/universalSchema"; import { metadata } from "../_metadata"; import { getGoogleAppKeys } from "./getGoogleAppKeys"; +import { getAllCalendars } from "./utils"; const log = logger.getSubLogger({ prefix: ["app-store/googlecalendar/lib/CalendarService"] }); interface GoogleCalError extends Error { @@ -609,9 +610,9 @@ export default class GoogleCalendarService implements Calendar { } async function getCalIds() { if (selectedCalendarIds.length !== 0) return selectedCalendarIds; - const cals = await calendar.calendarList.list({ fields: "items(id)" }); - if (!cals.data.items) return []; - return cals.data.items.reduce((c, cal) => (cal.id ? [...c, cal.id] : c), [] as string[]); + const cals = await getAllCalendars(calendar, ["id"]); + if (!cals.length) return []; + return cals.reduce((c, cal) => (cal.id ? [...c, cal.id] : c), [] as string[]); } try { @@ -669,9 +670,13 @@ export default class GoogleCalendarService implements Calendar { try { const { json: cals } = await this.oAuthManagerInstance.request( async () => - new AxiosLikeResponseToFetchResponse( - await calendar.calendarList.list({ fields: "items(id,summary,primary,accessRole)" }) - ) + new AxiosLikeResponseToFetchResponse({ + status: 200, + statusText: "OK", + data: { + items: await getAllCalendars(calendar), + }, + }) ); if (!cals.items) return []; diff --git a/packages/app-store/googlecalendar/lib/utils.ts b/packages/app-store/googlecalendar/lib/utils.ts new file mode 100644 index 0000000000..d4487150f2 --- /dev/null +++ b/packages/app-store/googlecalendar/lib/utils.ts @@ -0,0 +1,34 @@ +import type { calendar_v3 } from "googleapis"; + +import logger from "@calcom/lib/logger"; + +export async function getAllCalendars( + calendar: calendar_v3.Calendar, + fields: string[] = ["id", "summary", "primary", "accessRole"] +): Promise { + let allCalendars: calendar_v3.Schema$CalendarListEntry[] = []; + let pageToken: string | undefined; + + try { + do { + const response: any = await calendar.calendarList.list({ + fields: `items(${fields.join(",")}),nextPageToken`, + pageToken, + maxResults: 250, // 250 is max + }); + + allCalendars = [...allCalendars, ...(response.data.items ?? [])]; + pageToken = response.data.nextPageToken; + + logger.error("Google Calendar pagination failed in the middle", { + totalSoFar: allCalendars.length, + hasMorePages: !!pageToken, + }); + } while (pageToken); + + return allCalendars; + } catch (error) { + logger.error("Error fetching all Google Calendars", { error }); + throw error; + } +}