From 5d0ba3dafcbb481bf6579da81cc02152c486b428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 10 Feb 2022 03:44:46 -0700 Subject: [PATCH] The road to zero TypeScript errors (#1756) * Type fixes * Type fixes * Type fixes * Type fixes Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- components/integrations/IntegrationList.tsx | 0 environment.d.ts | 2 +- lib/crypto.ts | 2 +- lib/events/EventManager.ts | 9 +++--- .../calendar/interfaces/Calendar.ts | 3 +- .../calendar/services/BaseCalendarService.ts | 12 +++++-- lib/parseZone.ts | 8 ++--- lib/serverConfig.ts | 7 +++-- pages/api/availability/week.ts | 31 ------------------- pages/api/book/event.ts | 11 +++++-- pages/api/user/profile.ts | 7 +++-- pages/index.tsx | 3 +- server/routers/viewer/webhook.tsx | 8 +++++ test/lib/team-event-types.test.ts | 4 +++ 14 files changed, 54 insertions(+), 53 deletions(-) delete mode 100644 components/integrations/IntegrationList.tsx delete mode 100644 pages/api/availability/week.ts diff --git a/components/integrations/IntegrationList.tsx b/components/integrations/IntegrationList.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/environment.d.ts b/environment.d.ts index f0d36bee..dd2b2fca 100644 --- a/environment.d.ts +++ b/environment.d.ts @@ -14,7 +14,7 @@ declare namespace NodeJS { readonly ZOOM_CLIENT_SECRET: string | undefined; readonly EMAIL_FROM: string | undefined; readonly EMAIL_SERVER_HOST: string | undefined; - readonly EMAIL_SERVER_PORT: number | undefined; + readonly EMAIL_SERVER_PORT: string | undefined; readonly EMAIL_SERVER_USER: string | undefined; readonly EMAIL_SERVER_PASSWORD: string | undefined; readonly CRON_API_KEY: string | undefined; diff --git a/lib/crypto.ts b/lib/crypto.ts index dde42b62..d33f0c8f 100644 --- a/lib/crypto.ts +++ b/lib/crypto.ts @@ -33,7 +33,7 @@ export const symmetricDecrypt = function (text: string, key: string) { const _key = Buffer.from(key, "latin1"); const components = text.split(":"); - const iv_from_ciphertext = Buffer.from(components.shift(), OUTPUT_ENCODING); + const iv_from_ciphertext = Buffer.from(components.shift() || "", OUTPUT_ENCODING); const decipher = crypto.createDecipheriv(ALGORITHM, _key, iv_from_ciphertext); let deciphered = decipher.update(components.join(":"), OUTPUT_ENCODING, INPUT_ENCODING); deciphered += decipher.final(INPUT_ENCODING); diff --git a/lib/events/EventManager.ts b/lib/events/EventManager.ts index 199418b2..e318b217 100644 --- a/lib/events/EventManager.ts +++ b/lib/events/EventManager.ts @@ -18,7 +18,7 @@ export interface EventResult { success: boolean; uid: string; createdEvent?: Event; - updatedEvent?: Event; + updatedEvent?: Event | Event[]; originalEvent: CalendarEvent; } @@ -207,9 +207,10 @@ export default class EventManager { // If and only if event type is a dedicated meeting, update the dedicated video meeting. if (isDedicated) { const result = await this.updateVideoEvent(evt, booking); - if (result.updatedEvent) { - evt.videoCallData = result.updatedEvent; - evt.location = result.updatedEvent.url; + const [updatedEvent] = Array.isArray(result.updatedEvent) ? result.updatedEvent : [result.updatedEvent]; + if (updatedEvent) { + evt.videoCallData = updatedEvent; + evt.location = updatedEvent.url; } results.push(result); } diff --git a/lib/integrations/calendar/interfaces/Calendar.ts b/lib/integrations/calendar/interfaces/Calendar.ts index c63ade15..9bb21237 100644 --- a/lib/integrations/calendar/interfaces/Calendar.ts +++ b/lib/integrations/calendar/interfaces/Calendar.ts @@ -8,6 +8,7 @@ import { VideoCallData } from "@lib/videoClient"; import { NewCalendarEventType } from "../constants/types"; import { ConferenceData } from "./GoogleCalendar"; +import type { Event } from "@lib/events/EventManager"; export type Person = { name: string; @@ -66,7 +67,7 @@ type EventBusyDate = Record<"start" | "end", Date | string>; export interface Calendar { createEvent(event: CalendarEvent): Promise; - updateEvent(uid: string, event: CalendarEvent): Promise; + updateEvent(uid: string, event: CalendarEvent): Promise; deleteEvent(uid: string, event: CalendarEvent): Promise; diff --git a/lib/integrations/calendar/services/BaseCalendarService.ts b/lib/integrations/calendar/services/BaseCalendarService.ts index 2583e5b0..8a3d18f4 100644 --- a/lib/integrations/calendar/services/BaseCalendarService.ts +++ b/lib/integrations/calendar/services/BaseCalendarService.ts @@ -25,6 +25,7 @@ import { CALDAV_CALENDAR_TYPE } from "../constants/generals"; import { CalendarEventType, EventBusyDate, NewCalendarEventType } from "../constants/types"; import { Calendar, CalendarEvent, IntegrationCalendar } from "../interfaces/Calendar"; import { convertDate, getAttendees, getDuration } from "../utils/CalendarUtils"; +import type { Event } from "@lib/events/EventManager"; dayjs.extend(utc); dayjs.extend(timezone); @@ -121,7 +122,7 @@ export default abstract class BaseCalendarService implements Calendar { } } - async updateEvent(uid: string, event: CalendarEvent): Promise { + async updateEvent(uid: string, event: CalendarEvent) { try { const events = await this.getEventsByUID(uid); @@ -141,7 +142,12 @@ export default abstract class BaseCalendarService implements Calendar { if (error) { this.log.debug("Error creating iCalString"); - return {}; + return { + type: event.type, + id: typeof event.uid === "string" ? event.uid : "-1", + password: "", + url: typeof event.location === "string" ? event.location : "-1", + }; } const eventsToUpdate = events.filter((e) => e.uid === uid); @@ -157,7 +163,7 @@ export default abstract class BaseCalendarService implements Calendar { headers: this.headers, }); }) - ); + ).then((p) => p.map((r) => r.json() as unknown as Event)); } catch (reason) { this.log.error(reason); diff --git a/lib/parseZone.ts b/lib/parseZone.ts index 999c82f2..10a93746 100644 --- a/lib/parseZone.ts +++ b/lib/parseZone.ts @@ -23,22 +23,22 @@ export function parseZone( date, { utc: true, - ...format, + ...(typeof format === "string" ? { format } : { ...format }), }, locale, strict ); } const [, dateTime, sign, tzHour, tzMinute] = match; - const uOffset: number = tzHour * 60 + parseInt(tzMinute, 10); + const uOffset: number = parseInt(tzHour) * 60 + parseInt(tzMinute, 10); const offset = sign === "+" ? uOffset : -uOffset; return dayjs( dateTime, { $offset: offset, - ...format, - } as dayjs.OptionType, + ...(typeof format === "string" ? { format } : { ...format }), + } as dayjs.OptionType & { $offset: number }, locale, strict ); diff --git a/lib/serverConfig.ts b/lib/serverConfig.ts index 9b3a0286..a51d0c7e 100644 --- a/lib/serverConfig.ts +++ b/lib/serverConfig.ts @@ -1,10 +1,13 @@ -function detectTransport(): string | any { +import SendmailTransport from "nodemailer/lib/sendmail-transport"; +import SMTPConnection from "nodemailer/lib/smtp-connection"; + +function detectTransport(): SendmailTransport.Options | SMTPConnection.Options | string { if (process.env.EMAIL_SERVER) { return process.env.EMAIL_SERVER; } if (process.env.EMAIL_SERVER_HOST) { - const port = parseInt(process.env.EMAIL_SERVER_PORT); + const port = parseInt(process.env.EMAIL_SERVER_PORT!); const transport = { host: process.env.EMAIL_SERVER_HOST, port, diff --git a/pages/api/availability/week.ts b/pages/api/availability/week.ts deleted file mode 100644 index a8e6bdc4..00000000 --- a/pages/api/availability/week.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { getSession } from "@lib/auth"; - -import prisma from "../../../lib/prisma"; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - const session = await getSession({ req: req }); - - if (!session) { - res.status(401).json({ message: "Not authenticated" }); - return; - } - - if (req.method == "PATCH") { - const startMins = req.body.start; - const endMins = req.body.end; - - await prisma.schedule.update({ - where: { - id: session.user.id, - }, - data: { - startTime: startMins, - endTime: endMins, - }, - }); - - res.status(200).json({ message: "Start and end times updated successfully" }); - } -} diff --git a/pages/api/book/event.ts b/pages/api/book/event.ts index bdc287fb..85c30b90 100644 --- a/pages/api/book/event.ts +++ b/pages/api/book/event.ts @@ -533,9 +533,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (results.length) { // TODO: Handle created event metadata more elegantly - metadata.hangoutLink = results[0].updatedEvent?.hangoutLink; - metadata.conferenceData = results[0].updatedEvent?.conferenceData; - metadata.entryPoints = results[0].updatedEvent?.entryPoints; + const [updatedEvent] = Array.isArray(results[0].updatedEvent) + ? results[0].updatedEvent + : [results[0].updatedEvent]; + if (updatedEvent) { + metadata.hangoutLink = updatedEvent.hangoutLink; + metadata.conferenceData = updatedEvent.conferenceData; + metadata.entryPoints = updatedEvent.entryPoints; + } } await sendRescheduledEmails({ ...evt, additionInformation: metadata }); diff --git a/pages/api/user/profile.ts b/pages/api/user/profile.ts index 95593f01..084d2bf9 100644 --- a/pages/api/user/profile.ts +++ b/pages/api/user/profile.ts @@ -5,6 +5,7 @@ import { getSession } from "@lib/auth"; import prisma from "@lib/prisma"; import { resizeBase64Image } from "@server/lib/resizeBase64Image"; +import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const session = await getSession({ req: req }); @@ -36,8 +37,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, }); } catch (e) { - if (e.code === "P2002") { - return res.status(409).json({ message: "Username already taken" }); + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2002") { + return res.status(409).json({ message: "Username already taken" }); + } } throw e; } diff --git a/pages/index.tsx b/pages/index.tsx index b80cf67b..36899d44 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,10 +1,11 @@ import { getSession } from "@lib/auth"; +import { NextPageContext } from "next"; function RedirectPage() { return; } -export async function getServerSideProps(context) { +export async function getServerSideProps(context: NextPageContext) { const session = await getSession(context); if (!session?.user?.id) { return { redirect: { permanent: false, destination: "/auth/login" } }; diff --git a/server/routers/viewer/webhook.tsx b/server/routers/viewer/webhook.tsx index 8e31f948..5afa7c37 100644 --- a/server/routers/viewer/webhook.tsx +++ b/server/routers/viewer/webhook.tsx @@ -6,6 +6,7 @@ import { WEBHOOK_TRIGGER_EVENTS } from "@lib/webhooks/constants"; import sendPayload from "@lib/webhooks/sendPayload"; import { createProtectedRouter } from "@server/createRouter"; +import { getTranslation } from "@server/lib/i18n"; export const webhookRouter = createProtectedRouter() .query("list", { @@ -94,6 +95,11 @@ export const webhookRouter = createProtectedRouter() }), async resolve({ input }) { const { url, type, payloadTemplate } = input; + const translation = await getTranslation("en", "common"); + const language = { + locale: "en", + translate: translation, + }; const data = { type: "Test", @@ -106,12 +112,14 @@ export const webhookRouter = createProtectedRouter() email: "jdoe@example.com", name: "John Doe", timeZone: "Europe/London", + language, }, ], organizer: { name: "Cal", email: "", timeZone: "Europe/London", + language, }, }; diff --git a/test/lib/team-event-types.test.ts b/test/lib/team-event-types.test.ts index 4e2fdff2..90f60002 100644 --- a/test/lib/team-event-types.test.ts +++ b/test/lib/team-event-types.test.ts @@ -10,6 +10,8 @@ it("can find lucky users", async () => { timeZone: "GMT", bufferTime: 0, email: "test@example.com", + destinationCalendar: null, + locale: "en", }, { id: 2, @@ -19,6 +21,8 @@ it("can find lucky users", async () => { timeZone: "GMT", bufferTime: 0, email: "test2@example.com", + destinationCalendar: null, + locale: "en", }, ]; expect(