fix: improve error handling in delegation credential workspace configuration (#26985)
- Changed checkIfSuccessfullyConfiguredInWorkspace to throw detailed errors instead of returning boolean - Updated testDelegationCredentialSetup in Google Calendar and Office365 Calendar services to throw specific errors - Updated assertWorkspaceConfigured to let errors propagate naturally - Updated Calendar interface type to reflect Promise<void> return type - Updated CalendarCacheWrapper and CalendarTelemetryWrapper to match new interface Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -301,20 +301,17 @@ async function _getDelegationCredentialsMapPerUser({
|
||||
return credentialsByUserId;
|
||||
}
|
||||
|
||||
export async function checkIfSuccessfullyConfiguredInWorkspace({
|
||||
export async function assertSuccessfullyConfiguredInWorkspace({
|
||||
delegationCredential,
|
||||
user,
|
||||
}: {
|
||||
delegationCredential: DelegationCredentialWithSensitiveServiceAccountKey;
|
||||
user: User;
|
||||
}) {
|
||||
}): Promise<void> {
|
||||
if (!isValidWorkspaceSlug(delegationCredential.workspacePlatform.slug)) {
|
||||
log.warn(
|
||||
`Only ${WORKSPACE_PLATFORM_SLUGS.toString()} Platforms are supported here, skipping ${
|
||||
delegationCredential.workspacePlatform.slug
|
||||
}`
|
||||
);
|
||||
return false;
|
||||
const errorMessage = `Unsupported workspace platform: ${delegationCredential.workspacePlatform.slug}. Only ${WORKSPACE_PLATFORM_SLUGS.toString()} are supported.`;
|
||||
log.warn(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const credential = _buildDelegatedCalendarCredentialWithServiceAccountKey({
|
||||
@@ -325,9 +322,10 @@ export async function checkIfSuccessfullyConfiguredInWorkspace({
|
||||
const calendar = await getCalendar(credential, "none");
|
||||
|
||||
if (!calendar) {
|
||||
throw new Error("Google Calendar App not found");
|
||||
throw new Error("Calendar App not found for the workspace platform");
|
||||
}
|
||||
return await calendar?.testDelegationCredentialSetup?.();
|
||||
|
||||
await calendar.testDelegationCredentialSetup?.();
|
||||
}
|
||||
|
||||
export async function getAllDelegationCredentialsForUserByAppType({
|
||||
@@ -383,26 +381,29 @@ export const buildAllCredentials = ({
|
||||
...buildNonDelegationCredentials(nonDelegationCredentials),
|
||||
];
|
||||
|
||||
const uniqueAllCredentials = allCredentials.reduce((acc, credential) => {
|
||||
if (!credential.delegatedToId) {
|
||||
// Regular credential go as is
|
||||
acc.push(credential);
|
||||
const uniqueAllCredentials = allCredentials.reduce(
|
||||
(acc, credential) => {
|
||||
if (!credential.delegatedToId) {
|
||||
// Regular credential go as is
|
||||
acc.push(credential);
|
||||
return acc;
|
||||
}
|
||||
const existingDelegationCredential = acc.find(
|
||||
(c) => c.delegatedToId === credential.delegatedToId && c.appId === credential.appId
|
||||
);
|
||||
if (!existingDelegationCredential) {
|
||||
acc.push(credential);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
const existingDelegationCredential = acc.find(
|
||||
(c) => c.delegatedToId === credential.delegatedToId && c.appId === credential.appId
|
||||
);
|
||||
if (!existingDelegationCredential) {
|
||||
acc.push(credential);
|
||||
}
|
||||
return acc;
|
||||
}, [] as typeof allCredentials);
|
||||
},
|
||||
[] as typeof allCredentials
|
||||
);
|
||||
|
||||
return uniqueAllCredentials;
|
||||
};
|
||||
|
||||
export async function enrichUsersWithDelegationCredentials<
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] }
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] },
|
||||
>({ orgId, users }: { orgId: number | null; users: TUser[] }) {
|
||||
const delegationCredentialsMap = await _getDelegationCredentialsMapPerUser({
|
||||
organizationId: orgId,
|
||||
@@ -426,7 +427,7 @@ export async function enrichUsersWithDelegationCredentials<
|
||||
|
||||
export const enrichHostsWithDelegationCredentials = async <
|
||||
THost extends Host<TUser>,
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] }
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] },
|
||||
>({
|
||||
orgId,
|
||||
hosts,
|
||||
@@ -467,7 +468,7 @@ export const enrichHostsWithDelegationCredentials = async <
|
||||
};
|
||||
|
||||
export const enrichUserWithDelegationCredentialsIncludeServiceAccountKey = async <
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] }
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] },
|
||||
>({
|
||||
user,
|
||||
}: {
|
||||
@@ -487,7 +488,7 @@ export const enrichUserWithDelegationCredentialsIncludeServiceAccountKey = async
|
||||
};
|
||||
|
||||
export const enrichUserWithDelegationCredentials = async <
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] }
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] },
|
||||
>({
|
||||
user,
|
||||
}: {
|
||||
@@ -503,7 +504,7 @@ export const enrichUserWithDelegationCredentials = async <
|
||||
};
|
||||
|
||||
export async function enrichUserWithDelegationConferencingCredentialsWithoutOrgId<
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] }
|
||||
TUser extends { id: number; email: string; credentials: CredentialPayload[] },
|
||||
>({ user }: { user: TUser }) {
|
||||
const { credentials, ...restUser } = await enrichUserWithDelegationCredentialsIncludeServiceAccountKey({
|
||||
user,
|
||||
@@ -518,7 +519,7 @@ export async function enrichUserWithDelegationConferencingCredentialsWithoutOrgI
|
||||
* Either get Delegation credential from delegationCredentials or find regular credential from Credential table
|
||||
*/
|
||||
export async function getDelegationCredentialOrFindRegularCredential<
|
||||
TDelegationCredential extends { delegatedToId?: string | null }
|
||||
TDelegationCredential extends { delegatedToId?: string | null },
|
||||
>({
|
||||
id,
|
||||
delegationCredentials,
|
||||
@@ -532,17 +533,17 @@ export async function getDelegationCredentialOrFindRegularCredential<
|
||||
return id.delegationCredentialId
|
||||
? delegationCredentials.find((cred) => cred.delegatedToId === id.delegationCredentialId)
|
||||
: id.credentialId
|
||||
? await CredentialRepository.findCredentialForCalendarServiceById({
|
||||
id: id.credentialId,
|
||||
})
|
||||
: null;
|
||||
? await CredentialRepository.findCredentialForCalendarServiceById({
|
||||
id: id.credentialId,
|
||||
})
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to find a credential from a list of credentials, supporting both regular and DelegationCredential credentials
|
||||
*/
|
||||
export function getDelegationCredentialOrRegularCredential<
|
||||
TCredential extends { delegatedToId?: string | null; id: number }
|
||||
TCredential extends { delegatedToId?: string | null; id: number },
|
||||
>({
|
||||
credentials,
|
||||
id,
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type { calendar_v3 } from "@googleapis/calendar";
|
||||
import type { GaxiosResponse } from "googleapis-common";
|
||||
import { RRule } from "rrule";
|
||||
|
||||
import { MeetLocationType } from "@calcom/app-store/constants";
|
||||
import { getDestinationCalendarRepository } from "@calcom/features/di/containers/DestinationCalendar";
|
||||
import { getLocation, getRichDescription } from "@calcom/lib/CalEventParser";
|
||||
import { ORGANIZER_EMAIL_EXEMPT_DOMAINS } from "@calcom/lib/constants";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { getDestinationCalendarRepository } from "@calcom/features/di/containers/DestinationCalendar";
|
||||
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import type {
|
||||
Calendar,
|
||||
CalendarServiceEvent,
|
||||
CalendarEvent,
|
||||
CalendarServiceEvent,
|
||||
EventBusyDate,
|
||||
GetAvailabilityParams,
|
||||
IntegrationCalendar,
|
||||
@@ -21,6 +19,9 @@ import type {
|
||||
SelectedCalendarEventTypeIds,
|
||||
} from "@calcom/types/Calendar";
|
||||
import type { CredentialForCalendarServiceWithEmail } from "@calcom/types/Credential";
|
||||
import type { calendar_v3 } from "@googleapis/calendar";
|
||||
import type { GaxiosResponse } from "googleapis-common";
|
||||
import { RRule } from "rrule";
|
||||
|
||||
import { AxiosLikeResponseToFetchResponse } from "../../_utils/oauth/AxiosLikeResponseToFetchResponse";
|
||||
import { CalendarAuth } from "./CalendarAuth";
|
||||
@@ -68,7 +69,8 @@ interface GoogleCalError extends Error {
|
||||
code?: number;
|
||||
}
|
||||
|
||||
const isGaxiosResponse= (error: unknown): error is GaxiosResponse<calendar_v3.Schema$Event> =>
|
||||
const isGaxiosResponse = (error: unknown): error is GaxiosResponse<calendar_v3.Schema$Event> =>
|
||||
// biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn not available in all build targets
|
||||
typeof error === "object" && !!error && Object.prototype.hasOwnProperty.call(error, "config");
|
||||
|
||||
class GoogleCalendarService implements Calendar {
|
||||
@@ -497,9 +499,7 @@ class GoogleCalendarService implements Calendar {
|
||||
return apiResponse.json;
|
||||
}
|
||||
|
||||
async getFreeBusyResult(
|
||||
args: FreeBusyArgs,
|
||||
): Promise<calendar_v3.Schema$FreeBusyResponse> {
|
||||
async getFreeBusyResult(args: FreeBusyArgs): Promise<calendar_v3.Schema$FreeBusyResponse> {
|
||||
return await this.fetchAvailability(args);
|
||||
}
|
||||
|
||||
@@ -516,22 +516,23 @@ class GoogleCalendarService implements Calendar {
|
||||
return validCals[0];
|
||||
}
|
||||
|
||||
async getFreeBusyData(
|
||||
args: FreeBusyArgs,
|
||||
): Promise<(EventBusyDate & { id: string })[] | null> {
|
||||
async getFreeBusyData(args: FreeBusyArgs): Promise<(EventBusyDate & { id: string })[] | null> {
|
||||
const freeBusyResult = await this.getFreeBusyResult(args);
|
||||
if (!freeBusyResult.calendars) return null;
|
||||
|
||||
const result = Object.entries(freeBusyResult.calendars).reduce((c, [id, i]) => {
|
||||
i.busy?.forEach((busyTime) => {
|
||||
c.push({
|
||||
id,
|
||||
start: busyTime.start || "",
|
||||
end: busyTime.end || "",
|
||||
const result = Object.entries(freeBusyResult.calendars).reduce(
|
||||
(c, [id, i]) => {
|
||||
i.busy?.forEach((busyTime) => {
|
||||
c.push({
|
||||
id,
|
||||
start: busyTime.start || "",
|
||||
end: busyTime.end || "",
|
||||
});
|
||||
});
|
||||
});
|
||||
return c;
|
||||
}, [] as (EventBusyDate & { id: string })[]);
|
||||
return c;
|
||||
},
|
||||
[] as (EventBusyDate & { id: string })[]
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -646,7 +647,7 @@ class GoogleCalendarService implements Calendar {
|
||||
private async fetchAvailabilityData(
|
||||
calendarIds: string[],
|
||||
dateFrom: string,
|
||||
dateTo: string,
|
||||
dateTo: string
|
||||
): Promise<EventBusyDate[]> {
|
||||
// More efficient date difference calculation using native Date objects
|
||||
// Use Math.floor to match dayjs diff behavior (truncates, doesn't round up)
|
||||
@@ -657,13 +658,11 @@ class GoogleCalendarService implements Calendar {
|
||||
|
||||
// Google API only allows a date range of 90 days for /freebusy
|
||||
if (diff <= 90) {
|
||||
const freeBusyData = await this.getFreeBusyData(
|
||||
{
|
||||
timeMin: dateFrom,
|
||||
timeMax: dateTo,
|
||||
items: calendarIds.map((id) => ({ id })),
|
||||
}
|
||||
);
|
||||
const freeBusyData = await this.getFreeBusyData({
|
||||
timeMin: dateFrom,
|
||||
timeMax: dateTo,
|
||||
items: calendarIds.map((id) => ({ id })),
|
||||
});
|
||||
|
||||
if (!freeBusyData) throw new Error("No response from google calendar");
|
||||
return freeBusyData.map((freeBusy) => ({ start: freeBusy.start, end: freeBusy.end }));
|
||||
@@ -685,13 +684,11 @@ class GoogleCalendarService implements Calendar {
|
||||
currentEndTime = originalEndTime;
|
||||
}
|
||||
|
||||
const chunkData = await this.getFreeBusyData(
|
||||
{
|
||||
timeMin: new Date(currentStartTime).toISOString(),
|
||||
timeMax: new Date(currentEndTime).toISOString(),
|
||||
items: calendarIds.map((id) => ({ id })),
|
||||
}
|
||||
);
|
||||
const chunkData = await this.getFreeBusyData({
|
||||
timeMin: new Date(currentStartTime).toISOString(),
|
||||
timeMax: new Date(currentEndTime).toISOString(),
|
||||
items: calendarIds.map((id) => ({ id })),
|
||||
});
|
||||
|
||||
if (chunkData) {
|
||||
busyData.push(...chunkData.map((freeBusy) => ({ start: freeBusy.start, end: freeBusy.end })));
|
||||
@@ -757,7 +754,7 @@ class GoogleCalendarService implements Calendar {
|
||||
primary: cal.primary ?? false,
|
||||
readOnly: !(cal.accessRole === "writer" || cal.accessRole === "owner") && true,
|
||||
email: cal.id ?? "",
|
||||
} satisfies IntegrationCalendar)
|
||||
}) satisfies IntegrationCalendar
|
||||
);
|
||||
} catch (error) {
|
||||
this.log.error("There was an error getting calendars: ", safeStringify(error));
|
||||
@@ -765,12 +762,28 @@ class GoogleCalendarService implements Calendar {
|
||||
}
|
||||
}
|
||||
|
||||
// It would error if the delegation credential is not set up correctly
|
||||
async testDelegationCredentialSetup() {
|
||||
async testDelegationCredentialSetup(): Promise<void> {
|
||||
log.debug("Testing delegation credential setup");
|
||||
const calendar = await this.authedCalendar();
|
||||
const cals = await calendar.calendarList.list({ fields: "items(id)" });
|
||||
return !!cals.data.items;
|
||||
try {
|
||||
const calendar = await this.authedCalendar();
|
||||
const cals = await calendar.calendarList.list({ fields: "items(id)" });
|
||||
if (!cals.data.items) {
|
||||
throw new Error("No calendars found - delegation credential may not have proper access");
|
||||
}
|
||||
} catch (error) {
|
||||
const googleError = error as { code?: number; message?: string };
|
||||
if (googleError.code === 401) {
|
||||
throw new Error(
|
||||
`Google API authentication failed: ${googleError.message || "Invalid credentials or insufficient permissions"}`
|
||||
);
|
||||
}
|
||||
if (googleError.code === 403) {
|
||||
throw new Error(
|
||||
`Google API access denied: ${googleError.message || "The service account may not have domain-wide delegation enabled or the required scopes"}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async createSelectedCalendar(
|
||||
@@ -885,9 +898,7 @@ class GoogleCalendarService implements Calendar {
|
||||
* from leaking into the emitted .d.ts file, which would cause TypeScript to load
|
||||
* all Google API SDK declaration files when type-checking dependent packages.
|
||||
*/
|
||||
export default function BuildCalendarService(
|
||||
credential: CredentialForCalendarServiceWithEmail
|
||||
): Calendar {
|
||||
export default function BuildCalendarService(credential: CredentialForCalendarServiceWithEmail): Calendar {
|
||||
return new GoogleCalendarService(credential);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { Calendar as OfficeCalendar, User, Event } from "@microsoft/microsoft-graph-types-beta";
|
||||
import type { DefaultBodyType } from "msw";
|
||||
import { findIana } from "windows-iana";
|
||||
|
||||
import { MSTeamsLocationType } from "@calcom/app-store/constants";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { triggerDelegationCredentialErrorWebhook } from "@calcom/features/webhooks/lib/triggerDelegationCredentialErrorWebhook";
|
||||
import { getLocation, getRichDescriptionHTML } from "@calcom/lib/CalEventParser";
|
||||
import {
|
||||
CalendarAppDelegationCredentialInvalidGrantError,
|
||||
CalendarAppDelegationCredentialConfigurationError,
|
||||
CalendarAppDelegationCredentialInvalidGrantError,
|
||||
} from "@calcom/lib/CalendarAppError";
|
||||
import { handleErrorsJson, handleErrorsRaw } from "@calcom/lib/errors";
|
||||
import logger from "@calcom/lib/logger";
|
||||
@@ -22,9 +18,11 @@ import type {
|
||||
NewCalendarEventType,
|
||||
} from "@calcom/types/Calendar";
|
||||
import type { CredentialForCalendarServiceWithTenantId } from "@calcom/types/Credential";
|
||||
|
||||
import { OAuthManager } from "../../_utils/oauth/OAuthManager";
|
||||
import type { Event, Calendar as OfficeCalendar, User } from "@microsoft/microsoft-graph-types-beta";
|
||||
import type { DefaultBodyType } from "msw";
|
||||
import { findIana } from "windows-iana";
|
||||
import { getTokenObjectFromCredential } from "../../_utils/oauth/getTokenObjectFromCredential";
|
||||
import { OAuthManager } from "../../_utils/oauth/OAuthManager";
|
||||
import { oAuthManagerHelper } from "../../_utils/oauth/oAuthManagerHelper";
|
||||
import metadata from "../_metadata";
|
||||
import { getOfficeAppKeys } from "./getOfficeAppKeys";
|
||||
@@ -102,12 +100,12 @@ class Office365CalendarService implements Calendar {
|
||||
body: new URLSearchParams(bodyParams),
|
||||
});
|
||||
},
|
||||
isTokenObjectUnusable: async function () {
|
||||
isTokenObjectUnusable: async () => {
|
||||
// TODO: Implement this. As current implementation of CalendarService doesn't handle it. It hasn't been handled in the OAuthManager implementation as well.
|
||||
// This is a placeholder for future implementation.
|
||||
return null;
|
||||
},
|
||||
isAccessTokenUnusable: async function () {
|
||||
isAccessTokenUnusable: async () => {
|
||||
// TODO: Implement this
|
||||
return null;
|
||||
},
|
||||
@@ -251,8 +249,7 @@ class Office365CalendarService implements Calendar {
|
||||
return this.azureUserId;
|
||||
}
|
||||
|
||||
// It would error if the delegation credential is not set up correctly
|
||||
async testDelegationCredentialSetup(): Promise<boolean> {
|
||||
async testDelegationCredentialSetup(): Promise<void> {
|
||||
const delegationCredentialClientId = this.credential.delegatedTo?.serviceAccountKey?.client_id;
|
||||
const delegationCredentialClientSecret = this.credential.delegatedTo?.serviceAccountKey?.private_key;
|
||||
const url = await this.getAuthUrl(
|
||||
@@ -261,7 +258,9 @@ class Office365CalendarService implements Calendar {
|
||||
);
|
||||
|
||||
if (!delegationCredentialClientId || !delegationCredentialClientSecret) {
|
||||
return false;
|
||||
throw new CalendarAppDelegationCredentialConfigurationError(
|
||||
"Delegation credential is missing client_id or client_secret"
|
||||
);
|
||||
}
|
||||
const loginResponse = await fetch(url, {
|
||||
method: "POST",
|
||||
@@ -274,7 +273,13 @@ class Office365CalendarService implements Calendar {
|
||||
}),
|
||||
});
|
||||
const parsedLoginResponse = await loginResponse.json();
|
||||
return Boolean(parsedLoginResponse?.access_token);
|
||||
if (!parsedLoginResponse?.access_token) {
|
||||
const errorDescription =
|
||||
parsedLoginResponse?.error_description || parsedLoginResponse?.error || "Unknown error";
|
||||
throw new CalendarAppDelegationCredentialInvalidGrantError(
|
||||
`Failed to obtain access token from Microsoft: ${errorDescription}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getUserEndpoint(): Promise<string> {
|
||||
@@ -284,8 +289,8 @@ class Office365CalendarService implements Calendar {
|
||||
|
||||
async createEvent(event: CalendarServiceEvent, credentialId: number): Promise<NewCalendarEventType> {
|
||||
const mainHostDestinationCalendar = event.destinationCalendar
|
||||
? event.destinationCalendar.find((cal) => cal.credentialId === credentialId) ??
|
||||
event.destinationCalendar[0]
|
||||
? (event.destinationCalendar.find((cal) => cal.credentialId === credentialId) ??
|
||||
event.destinationCalendar[0])
|
||||
: undefined;
|
||||
try {
|
||||
const eventsUrl = mainHostDestinationCalendar?.externalId
|
||||
@@ -502,8 +507,8 @@ class Office365CalendarService implements Calendar {
|
||||
organizer: {
|
||||
emailAddress: {
|
||||
address: event.destinationCalendar
|
||||
? event.destinationCalendar.find((cal) => cal.userId === event.organizer.id)?.externalId ??
|
||||
event.organizer.email
|
||||
? (event.destinationCalendar.find((cal) => cal.userId === event.organizer.id)?.externalId ??
|
||||
event.organizer.email)
|
||||
: event.organizer.email,
|
||||
name: event.organizer.name,
|
||||
},
|
||||
@@ -794,8 +799,6 @@ class Office365CalendarService implements Calendar {
|
||||
* from leaking into the emitted .d.ts file, which would cause TypeScript to load
|
||||
* all Microsoft Graph SDK declaration files when type-checking dependent packages.
|
||||
*/
|
||||
export default function BuildCalendarService(
|
||||
credential: CredentialForCalendarServiceWithTenantId
|
||||
): Calendar {
|
||||
export default function BuildCalendarService(credential: CredentialForCalendarServiceWithTenantId): Calendar {
|
||||
return new Office365CalendarService(credential);
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ export class CalendarCacheWrapper implements Calendar {
|
||||
return this.deps.originalCalendar.listCalendars(event);
|
||||
}
|
||||
|
||||
testDelegationCredentialSetup?(): Promise<boolean> {
|
||||
return this.deps.originalCalendar.testDelegationCredentialSetup?.() || Promise.resolve(false);
|
||||
testDelegationCredentialSetup?(): Promise<void> {
|
||||
return this.deps.originalCalendar.testDelegationCredentialSetup?.() || Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ export class CalendarTelemetryWrapper implements Calendar {
|
||||
return this.deps.originalCalendar.listCalendars(event);
|
||||
}
|
||||
|
||||
testDelegationCredentialSetup?(): Promise<boolean> {
|
||||
return this.deps.originalCalendar.testDelegationCredentialSetup?.() || Promise.resolve(false);
|
||||
testDelegationCredentialSetup?(): Promise<void> {
|
||||
return this.deps.originalCalendar.testDelegationCredentialSetup?.() || Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { z } from "zod";
|
||||
|
||||
import { checkIfSuccessfullyConfiguredInWorkspace } from "@calcom/app-store/delegationCredential";
|
||||
import { assertSuccessfullyConfiguredInWorkspace } from "@calcom/app-store/delegationCredential";
|
||||
import { sendDelegationCredentialDisabledEmail } from "@calcom/emails/integration-email-service";
|
||||
import { DelegationCredentialRepository } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository";
|
||||
import type { ServiceAccountKey } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository";
|
||||
import { DelegationCredentialRepository } from "@calcom/features/delegation-credentials/repositories/DelegationCredentialRepository";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { getAffectedMembersForDisable } from "./getAffectedMembersForDisable.handler";
|
||||
import type { DelegationCredentialToggleEnabledSchema } from "./schema";
|
||||
@@ -142,14 +141,10 @@ const assertWorkspaceConfigured = async ({
|
||||
throw new Error("Domain wide delegation doesn't have service account key");
|
||||
}
|
||||
|
||||
const isSuccessfullyConfigured = await checkIfSuccessfullyConfiguredInWorkspace({
|
||||
await assertSuccessfullyConfiguredInWorkspace({
|
||||
delegationCredential,
|
||||
user,
|
||||
});
|
||||
|
||||
if (!isSuccessfullyConfigured) {
|
||||
throw new Error("Workspace not successfully configured");
|
||||
}
|
||||
};
|
||||
|
||||
function hasServiceAccountKey<T extends { serviceAccountKey: ServiceAccountKey | null }>(
|
||||
|
||||
Vendored
+1
-1
@@ -316,7 +316,7 @@ export interface Calendar {
|
||||
|
||||
listCalendars(event?: CalendarEvent): Promise<IntegrationCalendar[]>;
|
||||
|
||||
testDelegationCredentialSetup?(): Promise<boolean>;
|
||||
testDelegationCredentialSetup?(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user