Files
calendar/packages/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials.ts
T
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>hbjORbj
79a09362c9 refactor: remove circular dependency between prisma and app-store packages (#23475)
* refactor: remove circular dependency between prisma and app-store packages

- Replace EventTypeAppMetadataSchema with z.record(z.any()).optional() pattern
- Remove appDataSchemas import from packages/prisma/zod-utils.ts
- Add null checks in consuming packages for flexible validation
- Fix test file that no longer needs @ts-expect-error directive

This breaks the circular dependency while maintaining all functionality
by moving strict validation to the business logic layer where operations
actually happen, following existing patterns in the codebase.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: remove EventTypeAppMetadataSchema exports from prisma package

- Remove EventTypeAppMetadataSchema and eventTypeAppMetadataOptionalSchema exports from prisma/zod-utils.ts
- Update all importing files to use local z.record(z.any()).optional() schemas
- Replace type annotations with Record<string, any> where appropriate
- Maintain validation functionality while breaking circular dependency
- All TypeScript compilation now passes without errors

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: complete removal of EventTypeAppMetadataSchema from remaining files

- Update handleSeats/createNewSeat.ts to use local schema
- Update payment handlers to use local schemas
- Update eventTypes update handler to use local schema
- All files now define their own validation instead of importing from prisma
- Circular dependency completely eliminated

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: resolve TypeScript compilation errors

- Remove duplicate z import from handleConfirmation.ts
- Remove duplicate appDataSchemas import from update.handler.ts
- Fix index signature errors in handlePayment.ts by using appData variable consistently
- All type checks now pass successfully

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add type casting for appSlug in eventTypeService

- Cast appSlug as keyof typeof apps to resolve index signature error
- Maintains type safety while allowing dynamic property access

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix

* remove

* make zod-utils.ts in app-store

* update imports

* fix

* fix

* fix

* revert unrelated change

* update imports

* fix

* fix

* revert

* fix

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: hbjORbj <sldisek783@gmail.com>
2025-09-12 05:57:09 -03:00

129 lines
4.3 KiB
TypeScript

import type { z } from "zod";
import { eventTypeAppMetadataOptionalSchema } from "@calcom/app-store/zod-utils";
import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/lib/delegationCredential/server";
import { UserRepository } from "@calcom/lib/server/repository/user";
import prisma from "@calcom/prisma";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { CredentialPayload } from "@calcom/types/Credential";
export type EventType = {
userId?: number | null;
team?: { id: number | null; parentId: number | null } | null;
parentId?: number | null;
metadata: z.infer<typeof EventTypeMetaDataSchema>;
} | null;
/**
* Gets credentials from the user, team, and org if applicable
*
*/
export const getAllCredentialsIncludeServiceAccountKey = async (
user: { id: number; username: string | null; email: string; credentials: CredentialPayload[] },
eventType: EventType
) => {
let allCredentials = user.credentials;
// If it's a team event type query for team credentials
if (eventType?.team?.id) {
const teamCredentialsQuery = await prisma.credential.findMany({
where: {
teamId: eventType.team.id,
},
select: credentialForCalendarServiceSelect,
});
allCredentials.push(...teamCredentialsQuery);
}
// If it's a managed event type, query for the parent team's credentials
if (eventType?.parentId) {
const teamCredentialsQuery = await prisma.team.findFirst({
where: {
eventTypes: {
some: {
id: eventType.parentId,
},
},
},
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
},
});
if (teamCredentialsQuery?.credentials) {
allCredentials.push(...teamCredentialsQuery?.credentials);
}
}
const { profile } = await new UserRepository(prisma).enrichUserWithItsProfile({
user: user,
});
// If the user is a part of an organization, query for the organization's credentials
if (profile?.organizationId) {
const org = await prisma.team.findUnique({
where: {
id: profile.organizationId,
},
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
},
});
if (org?.credentials) {
allCredentials.push(...org.credentials);
}
}
// Only return CRM credentials that are enabled on the event type
const eventTypeAppMetadata = eventTypeAppMetadataOptionalSchema.parse(eventType?.metadata?.apps);
// Will be [credentialId]: { enabled: boolean }]
const eventTypeCrmCredentials: Record<number, { enabled: boolean }> = {};
for (const appKey in eventTypeAppMetadata) {
const app = eventTypeAppMetadata[appKey as keyof typeof eventTypeAppMetadata];
if (app.appCategories && app.appCategories.some((category: string) => category === "crm")) {
eventTypeCrmCredentials[app.credentialId] = {
enabled: app.enabled,
};
}
}
allCredentials = allCredentials.filter((credential) => {
if (!credential.type.includes("_crm") && !credential.type.includes("_other_calendar")) {
return credential;
}
// Backwards compatibility: All CRM apps are triggered for every event type. Unless disabled on the event type
// Check if the CRM app exists on the event type
if (eventTypeCrmCredentials[credential.id]) {
if (eventTypeCrmCredentials[credential.id].enabled) {
return credential;
}
} else {
// If the CRM app doesn't exist on the event type metadata, check that the credential belongs to the user/team/org and is an old CRM credential
if (
credential.type.includes("_other_calendar") &&
(credential.userId === eventType?.userId ||
credential.teamId === eventType?.team?.id ||
credential.teamId === eventType?.team?.parentId ||
credential.teamId === profile?.organizationId)
) {
// If the CRM app doesn't exist on the event type metadata, assume it's an older CRM credential
return credential;
}
}
});
const userWithDelegationCredentials = await enrichUserWithDelegationCredentialsIncludeServiceAccountKey({
user: { ...user, credentials: allCredentials },
});
return userWithDelegationCredentials.credentials;
};