import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-user.input"; import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input"; import { Injectable, NotFoundException } from "@nestjs/common"; import { CreationSource } from "@calcom/platform-libraries"; import type { Profile, User, Team, Prisma } from "@calcom/prisma/client"; export type UserWithProfile = User & { movedToProfile?: (Profile & { organization: Pick }) | null; profiles?: (Profile & { organization: Pick })[]; }; @Injectable() export class UsersRepository { constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {} async create( user: CreateManagedUserInput, username: string, oAuthClientId: string, isPlatformManaged: boolean ) { this.formatInput(user); return this.dbWrite.prisma.user.create({ data: { ...user, username, platformOAuthClients: { connect: { id: oAuthClientId }, }, isPlatformManaged, creationSource: CreationSource.API_V2, }, }); } async addToOAuthClient(userId: number, oAuthClientId: string) { return this.dbWrite.prisma.user.update({ data: { platformOAuthClients: { connect: { id: oAuthClientId }, }, }, where: { id: userId }, }); } async findById(userId: number) { return this.dbRead.prisma.user.findUnique({ where: { id: userId, }, }); } async findByIdWithinPlatformScope(userId: number, clientId: string) { return this.dbRead.prisma.user.findFirst({ where: { id: userId, isPlatformManaged: true, platformOAuthClients: { some: { id: clientId, }, }, }, }); } async findByIdWithProfile(userId: number): Promise { return this.dbRead.prisma.user.findUnique({ where: { id: userId, }, include: { movedToProfile: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, profiles: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, }, }); } async findOwnerByTeamIdWithProfile(teamId: number): Promise { return this.dbRead.prisma.user.findFirst({ where: { teams: { some: { teamId, role: "OWNER", }, }, }, include: { movedToProfile: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, profiles: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, }, }); } async findByIdsWithEventTypes(userIds: number[]) { return this.dbRead.prisma.user.findMany({ where: { id: { in: userIds, }, }, include: { eventTypes: true, }, }); } async findByIds(userIds: number[]) { return this.dbRead.prisma.user.findMany({ where: { id: { in: userIds, }, }, }); } async findByIdWithCalendars(userId: number) { return this.dbRead.prisma.user.findUnique({ where: { id: userId, }, include: { selectedCalendars: true, destinationCalendar: true, }, }); } async findByEmail(email: string) { return this.dbRead.prisma.user.findUnique({ where: { email, }, }); } async findByEmailWithProfile(email: string) { return this.dbRead.prisma.user.findUnique({ where: { email, }, include: { movedToProfile: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, profiles: { include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } }, }, }, }); } async findByUsername(username: string, orgSlug?: string, orgId?: number) { return this.dbRead.prisma.user.findFirst({ where: orgId || orgSlug ? { profiles: { some: { organization: orgSlug ? { slug: orgSlug } : { id: orgId }, username: username, }, }, } : { username, }, }); } async findManagedUsersByOAuthClientId(oauthClientId: string, cursor: number, limit: number) { return this.dbRead.prisma.user.findMany({ where: { platformOAuthClients: { some: { id: oauthClientId, }, }, isPlatformManaged: true, }, take: limit, skip: cursor, }); } async findManagedUsersByOAuthClientIdAndEmails( oauthClientId: string, cursor: number, limit: number, oAuthEmails?: string[] ) { return this.dbRead.prisma.user.findMany({ where: { platformOAuthClients: { some: { id: oauthClientId, }, }, isPlatformManaged: true, ...(oAuthEmails && oAuthEmails.length > 0 ? { email: { in: oAuthEmails, }, } : {}), }, take: limit, skip: cursor, }); } async update(userId: number, updateData: UpdateManagedUserInput) { this.formatInput(updateData); return this.dbWrite.prisma.user.update({ where: { id: userId }, data: updateData, }); } async updateByEmail(email: string, updateData: Prisma.UserUpdateInput) { return this.dbWrite.prisma.user.update({ where: { email }, data: updateData, }); } async updateUsername(userId: number, newUsername: string) { return this.dbWrite.prisma.user.update({ where: { id: userId }, data: { username: newUsername, }, }); } async delete(userId: number): Promise { return this.dbWrite.prisma.user.delete({ where: { id: userId }, }); } formatInput(userInput: CreateManagedUserInput | UpdateManagedUserInput) { if (userInput.weekStart) { userInput.weekStart = userInput.weekStart; } } setDefaultSchedule(userId: number, scheduleId: number) { return this.dbWrite.prisma.user.update({ where: { id: userId }, data: { defaultScheduleId: scheduleId, }, }); } async getUserScheduleDefaultId(userId: number) { const user = await this.findById(userId); if (!user?.defaultScheduleId) return null; return user?.defaultScheduleId; } async getOrganizationUsers(organizationId: number) { const profiles = await this.dbRead.prisma.profile.findMany({ where: { organizationId, }, include: { user: true, }, }); return profiles.map((profile) => profile.user); } async setDefaultConferencingApp(userId: number, appSlug?: string, appLink?: string) { const user = await this.findById(userId); if (!user) { throw new NotFoundException("user not found"); } return await this.dbWrite.prisma.user.update({ data: { metadata: typeof user.metadata === "object" ? { ...user.metadata, defaultConferencingApp: { appSlug: appSlug, appLink: appLink, }, } : {}, }, where: { id: userId }, }); } async findUserOOORedirectEligible(userId: number, toTeamUserId: number) { return await this.dbRead.prisma.user.findUnique({ where: { id: toTeamUserId, teams: { some: { team: { members: { some: { userId: userId, accepted: true, }, }, }, }, }, }, select: { id: true, }, }); } async getOrgsManagedUserEmailsBySubscriptionId(subscriptionId: string) { return await this.dbRead.prisma.user.findMany({ distinct: ["email"], where: { isPlatformManaged: true, profiles: { some: { organization: { platformBilling: { subscriptionId, }, }, }, }, }, select: { email: true, }, }); } async getActiveManagedUsersAsHost(subscriptionId: string, startTime: Date, endTime: Date) { return await this.dbRead.prisma.user.findMany({ distinct: ["email"], where: { isPlatformManaged: true, profiles: { some: { organization: { platformBilling: { subscriptionId, }, }, }, }, bookings: { some: { userId: { not: null }, startTime: { gte: startTime, lte: endTime, }, }, }, }, select: { email: true, }, }); } async getActiveManagedUsersAsAttendee(managedUsersEmails: string[], startTime: Date, endTime: Date) { return await this.dbRead.prisma.attendee.findMany({ distinct: ["email"], where: { email: { in: managedUsersEmails }, booking: { startTime: { gte: startTime, lte: endTime, }, }, }, select: { email: true, }, }); } async getUserEmailsVerifiedForTeam(teamId: number) { return this.dbRead.prisma.user.findMany({ where: { teams: { some: { teamId, }, }, }, select: { id: true, email: true, secondaryEmails: { where: { emailVerified: { not: null, }, }, select: { email: true, }, }, }, }); } }