* Base UI work * Bulk invite users * WIP workspace oauth implementation * Seperate components - add existing gcal check * Move callback session to getServerSession * Implementation of state redirect back to teams on login * Add callback to populate text field * Change error message * Redirect from callback and open modal * Fix bulk translations * Fix translations for google button * Delete Query * Feature flag this * Update packages/trpc/server/routers/viewer/teams/inviteMember.handler.ts * Check if Gcal in installed globally * Add new router * Add missing [trpc] route * Feedback * Update packages/trpc/server/routers/viewer/googleWorkspace/googleWorkspace.handler.ts * Typefixes * More typefixes --------- Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: zomars <zomars@me.com>
80 lines
2.7 KiB
TypeScript
80 lines
2.7 KiB
TypeScript
import { google } from "googleapis";
|
|
import { z } from "zod";
|
|
|
|
import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug";
|
|
import { prisma } from "@calcom/prisma";
|
|
|
|
import type { TrpcSessionUser } from "../../../trpc";
|
|
|
|
type CheckForGCalOptions = {
|
|
ctx: {
|
|
user: NonNullable<TrpcSessionUser>;
|
|
};
|
|
};
|
|
|
|
const credentialsSchema = z.object({
|
|
refresh_token: z.string().optional(),
|
|
expiry_date: z.number().optional(),
|
|
access_token: z.string().optional(),
|
|
token_type: z.string().optional(),
|
|
id_token: z.string().optional(),
|
|
scope: z.string().optional(),
|
|
});
|
|
|
|
export const checkForGWorkspace = async ({ ctx }: CheckForGCalOptions) => {
|
|
const gWorkspacePresent = await prisma.credential.findFirst({
|
|
where: {
|
|
type: "google_workspace_directory",
|
|
userId: ctx.user.id,
|
|
},
|
|
});
|
|
|
|
return { id: gWorkspacePresent?.id };
|
|
};
|
|
|
|
export const getUsersFromGWorkspace = async ({ ctx }: CheckForGCalOptions) => {
|
|
const { client_id, client_secret } = await getAppKeysFromSlug("google-calendar");
|
|
if (!client_id || typeof client_id !== "string") throw new Error("Google client_id missing.");
|
|
if (!client_secret || typeof client_secret !== "string") throw new Error("Google client_secret missing.");
|
|
|
|
const hasExistingCredentials = await prisma.credential.findFirst({
|
|
where: {
|
|
type: "google_workspace_directory",
|
|
},
|
|
});
|
|
if (!hasExistingCredentials) {
|
|
throw new Error("No workspace credentials found");
|
|
}
|
|
|
|
const credentials = credentialsSchema.parse(hasExistingCredentials.key);
|
|
|
|
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret);
|
|
|
|
// Set users credentials instead of our app credentials - allowing us to make requests on their behalf
|
|
oAuth2Client.setCredentials(credentials);
|
|
|
|
// Create a new instance of the Admin SDK directory API
|
|
const directory = google.admin({ version: "directory_v1", auth: oAuth2Client });
|
|
|
|
const { data } = await directory.users.list({
|
|
maxResults: 200, // Up this if we ever need to get more than 200 users
|
|
customer: "my_customer", // This only works for single domain setups - we'll need to change this if we ever support multi-domain setups (unlikely we'll ever need to)
|
|
});
|
|
|
|
// We only want their email addresses
|
|
const emails = data.users?.map((user) => user.primaryEmail as string) ?? ([] as string[]);
|
|
return emails;
|
|
};
|
|
|
|
export const removeCurrentGoogleWorkspaceConnection = async ({ ctx }: CheckForGCalOptions) => {
|
|
// There should only ever be one google_workspace_directory credential per user but we delete many as we can't make type unique
|
|
const gWorkspacePresent = await prisma.credential.deleteMany({
|
|
where: {
|
|
type: "google_workspace_directory",
|
|
userId: ctx.user.id,
|
|
},
|
|
});
|
|
|
|
return { deleted: gWorkspacePresent?.count };
|
|
};
|