diff --git a/packages/features/eventtypes/lib/getPublicEvent.ts b/packages/features/eventtypes/lib/getPublicEvent.ts index 78b491de4d..4de2cba600 100644 --- a/packages/features/eventtypes/lib/getPublicEvent.ts +++ b/packages/features/eventtypes/lib/getPublicEvent.ts @@ -356,15 +356,16 @@ export const getPublicEvent = async ( const eventMetaData = EventTypeMetaDataSchema.parse(event.metadata || {}); const teamMetadata = teamMetadataSchema.parse(event.team?.metadata || {}); - const hosts = []; - for (const host of event.hosts) { - hosts.push({ - ...host, - user: await UserRepository.enrichUserWithItsProfile({ - user: host.user, - }), - }); - } + const usersAsHosts = event.hosts.map((host) => host.user); + + // Enrich users in a single batch call + const enrichedUsers = await UserRepository.enrichUsersWithTheirProfiles(usersAsHosts); + + // Map enriched users back to the hosts + const hosts = event.hosts.map((host, index) => ({ + ...host, + user: enrichedUsers[index], + })); const eventWithUserProfiles = { ...event, @@ -558,18 +559,18 @@ async function getOwnerFromUsersArray(prisma: PrismaClient, eventTypeId: number) }, }); if (!users.length) return null; - const usersWithUserProfile = []; - for (const user of users) { - const { profile } = await UserRepository.enrichUserWithItsProfile({ - user: user, - }); - usersWithUserProfile.push({ - ...user, - organizationId: profile?.organization?.id ?? null, - organization: profile?.organization, - profile, - }); - } + + // Batch enrich users in a single call + const enrichedUsers = await UserRepository.enrichUsersWithTheirProfiles(users); + + // Map the enriched users back to include the organization info + const usersWithUserProfile = enrichedUsers.map((user) => ({ + ...user, + organizationId: user.profile?.organization?.id ?? null, + organization: user.profile?.organization, + profile: user.profile, + })); + return [ { ...usersWithUserProfile[0], diff --git a/packages/lib/server/repository/profile.ts b/packages/lib/server/repository/profile.ts index 5a3dcb1478..3e730511dd 100644 --- a/packages/lib/server/repository/profile.ts +++ b/packages/lib/server/repository/profile.ts @@ -437,6 +437,39 @@ export class ProfileRepository { return profiles; } + static async findManyForUsers(userIds: number[]) { + const profiles = await prisma.profile.findMany({ + where: { + userId: { + in: userIds, + }, + }, + include: { + organization: { + select: organizationSelect, + }, + }, + }); + + return profiles.map((profile) => { + const parsedOrganization = getParsedTeam(profile.organization); + + return normalizeProfile({ + username: profile.username, + id: profile.id, + userId: profile.userId, + uid: profile.uid, + name: parsedOrganization.name, + organizationId: profile.organizationId, + organization: { + ...parsedOrganization, + requestedSlug: parsedOrganization.metadata?.requestedSlug ?? null, + metadata: parsedOrganization.metadata, + }, + }); + }); + } + static async findManyForUser(user: { id: number }) { const profiles = ( await prisma.profile.findMany({ diff --git a/packages/lib/server/repository/user.ts b/packages/lib/server/repository/user.ts index 2ff73c763a..d370d7e247 100644 --- a/packages/lib/server/repository/user.ts +++ b/packages/lib/server/repository/user.ts @@ -380,6 +380,65 @@ export class UserRepository { }; } + static async enrichUsersWithTheirProfiles( + users: T[] + ): Promise< + Array< + T & { + nonProfileUsername: string | null; + profile: UserProfile; + } + > + > { + if (users.length === 0) return []; + + const userIds = users.map((user) => user.id); + const profiles = await ProfileRepository.findManyForUsers(userIds); + + // Create a Map for faster lookups, preserving arrays of profiles per user + const profileMap = new Map(); + profiles.forEach((profile) => { + if (!profileMap.has(profile.userId)) { + profileMap.set(profile.userId, []); + } + profileMap.get(profile.userId)!.push(profile); + }); + + // Precompute personal profiles for all users + const personalProfileMap = new Map(); + users.forEach((user) => { + personalProfileMap.set(user.id, ProfileRepository.buildPersonalProfileFromUser({ user })); + }); + + return users.map((user) => { + const userProfiles = profileMap.get(user.id) || []; + if (userProfiles.length > 0) { + const profile = userProfiles[0]; + if (profile?.organization?.isPlatform) { + return { + ...user, + nonProfileUsername: user.username, + profile: personalProfileMap.get(user.id)!, + }; + } + + return { + ...user, + username: profile.username, + nonProfileUsername: user.username, + profile, + }; + } + + // If no organization profile exists, use the precomputed personal profile + return { + ...user, + nonProfileUsername: user.username, + profile: personalProfileMap.get(user.id)!, + }; + }); + } + static enrichUserWithItsProfileBuiltFromUser({ user, }: {