Files
calendar/packages/features/users/lib/getRoutedUsers.ts
Benny JooGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

182 lines
5.2 KiB
TypeScript

import { enrichHostsWithDelegationCredentials } from "@calcom/app-store/delegationCredential";
import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import type { RRResetInterval } from "@calcom/prisma/client";
import type { RRTimestampBasis } from "@calcom/prisma/enums";
import { SchedulingType } from "@calcom/prisma/enums";
import type { CredentialPayload } from "@calcom/types/Credential";
const log = logger.getSubLogger({ prefix: ["[getRoutedUsers]"] });
export const getRoutedUsersWithContactOwnerAndFixedUsers = <
T extends { id: number; isFixed?: boolean; email: string },
>({
routedTeamMemberIds,
users,
contactOwnerEmail,
}: {
routedTeamMemberIds: number[] | null;
users: T[];
contactOwnerEmail: string | null;
}) => {
// We don't want to enter a scenario where we have no team members to be booked
// So, let's just fallback to regular flow if no routedTeamMemberIds are provided
if (!routedTeamMemberIds || !routedTeamMemberIds.length) {
return users;
}
log.debug(
"filtering users as per routedTeamMemberIds",
safeStringify({ routedTeamMemberIds, contactOwnerEmail })
);
return users.filter(
(user) => routedTeamMemberIds.includes(user.id) || user.isFixed || user.email === contactOwnerEmail
);
};
type BaseUser = {
id: number;
uuid: string;
email: string;
};
type BaseHost<User extends BaseUser> = {
isFixed: boolean;
createdAt: Date;
priority?: number | null;
weight?: number | null;
weightAdjustment?: number | null;
user: User;
groupId: string | null;
};
export type EventType = {
assignAllTeamMembers: boolean;
assignRRMembersUsingSegment: boolean;
rrSegmentQueryValue: Record<string, unknown> | null | undefined;
team: {
id: number;
parentId: number | null;
rrResetInterval: RRResetInterval | null;
rrTimestampBasis: RRTimestampBasis;
} | null;
};
export function getNormalizedHosts<User extends BaseUser, Host extends BaseHost<User>>({
eventType,
}: {
eventType: {
schedulingType: SchedulingType | null;
hosts?: Host[];
users: User[];
};
}) {
if (eventType.hosts?.length && eventType.schedulingType) {
return {
hosts: eventType.hosts.map((host) => ({
isFixed: host.isFixed,
user: host.user,
priority: host.priority,
weight: host.weight,
createdAt: host.createdAt,
groupId: host.groupId,
})),
fallbackHosts: null,
};
} else {
return {
hosts: null,
fallbackHosts: eventType.users.map((user) => {
return {
isFixed: !eventType.schedulingType || eventType.schedulingType === SchedulingType.COLLECTIVE,
email: user.email,
user: user,
createdAt: null,
groupId: null,
};
}),
};
}
}
type BaseUserWithCredentialPayload = BaseUser & { credentials: CredentialPayload[] };
export async function getNormalizedHostsWithDelegationCredentials<
User extends BaseUserWithCredentialPayload,
Host extends BaseHost<User>,
>({
eventType,
}: {
eventType: {
schedulingType: SchedulingType | null;
hosts?: Host[];
users: User[];
teamId?: number;
};
}) {
if (eventType.hosts?.length && eventType.schedulingType) {
const hostsWithoutDelegationCredential = eventType.hosts.map((host) => ({
isFixed: host.isFixed,
user: host.user,
priority: host.priority,
weight: host.weight,
createdAt: host.createdAt,
groupId: host.groupId,
}));
const firstHost = hostsWithoutDelegationCredential[0];
const firstUserOrgId = await getOrgIdFromMemberOrTeamId({
memberId: firstHost?.user?.id ?? null,
teamId: eventType.teamId,
});
const hostsEnrichedWithDelegationCredential = await enrichHostsWithDelegationCredentials({
orgId: firstUserOrgId ?? null,
hosts: hostsWithoutDelegationCredential ?? null,
});
return {
hosts: hostsEnrichedWithDelegationCredential,
fallbackHosts: null,
};
} else {
const hostsWithoutDelegationCredential = eventType.users.map((user) => {
return {
isFixed: !eventType.schedulingType || eventType.schedulingType === SchedulingType.COLLECTIVE,
email: user.email,
user: user,
createdAt: null,
};
});
const firstHost = hostsWithoutDelegationCredential[0];
const firstUserOrgId = await getOrgIdFromMemberOrTeamId({
memberId: firstHost?.user?.id ?? null,
teamId: eventType.teamId,
});
const hostsEnrichedWithDelegationCredential = await enrichHostsWithDelegationCredentials({
orgId: firstUserOrgId ?? null,
hosts: hostsWithoutDelegationCredential ?? null,
});
return {
hosts: null,
fallbackHosts: hostsEnrichedWithDelegationCredential,
};
}
}
// Routing forms feature removed - segment matching always returns all hosts
export async function findMatchingHostsWithEventSegment<User extends BaseUser>({
eventType,
hosts,
}: {
eventType: EventType;
hosts: {
isFixed: boolean;
user: User;
priority?: number | null;
weight?: number | null;
createdAt: Date | null;
groupId: string | null;
}[];
}) {
return hosts;
}