diff --git a/apps/api/pages/api/event-types/[id]/_get.ts b/apps/api/pages/api/event-types/[id]/_get.ts index 83119feb20..539a894775 100644 --- a/apps/api/pages/api/event-types/[id]/_get.ts +++ b/apps/api/pages/api/event-types/[id]/_get.ts @@ -51,7 +51,6 @@ export async function getHandler(req: NextApiRequest) { include: { customInputs: true, team: { select: { slug: true } }, - users: true, hosts: { select: { userId: true, isFixed: true } }, owner: { select: { username: true, id: true } }, children: { select: { id: true, userId: true } }, diff --git a/apps/api/pages/api/event-types/_get.ts b/apps/api/pages/api/event-types/_get.ts index 5b014f603d..c36aea118b 100644 --- a/apps/api/pages/api/event-types/_get.ts +++ b/apps/api/pages/api/event-types/_get.ts @@ -56,7 +56,6 @@ async function getHandler(req: NextApiRequest) { include: { customInputs: true, team: { select: { slug: true } }, - users: true, hosts: { select: { userId: true, isFixed: true } }, owner: { select: { username: true, id: true } }, children: { select: { id: true, userId: true } }, diff --git a/apps/api/pages/api/teams/[teamId]/event-types/_get.ts b/apps/api/pages/api/teams/[teamId]/event-types/_get.ts index b8c177a820..977b4c28dd 100644 --- a/apps/api/pages/api/teams/[teamId]/event-types/_get.ts +++ b/apps/api/pages/api/teams/[teamId]/event-types/_get.ts @@ -59,7 +59,6 @@ async function getHandler(req: NextApiRequest) { include: { customInputs: true, team: { select: { slug: true } }, - users: true, hosts: { select: { userId: true, isFixed: true } }, owner: { select: { username: true, id: true } }, children: { select: { id: true, userId: true } }, diff --git a/packages/app-store/routing-forms/trpc/response.handler.ts b/packages/app-store/routing-forms/trpc/response.handler.ts index 3d588753ba..488e29da7e 100644 --- a/packages/app-store/routing-forms/trpc/response.handler.ts +++ b/packages/app-store/routing-forms/trpc/response.handler.ts @@ -24,7 +24,12 @@ export const responseHandler = async ({ ctx, input }: ResponseHandlerOptions) => id: formId, }, include: { - user: true, + user: { + select: { + id: true, + email: true, + }, + }, }, }); if (!form) { diff --git a/packages/app-store/routing-forms/trpc/utils.ts b/packages/app-store/routing-forms/trpc/utils.ts index c1c926ba72..e349ceb592 100644 --- a/packages/app-store/routing-forms/trpc/utils.ts +++ b/packages/app-store/routing-forms/trpc/utils.ts @@ -10,7 +10,7 @@ import type { OrderedResponses } from "../types/types"; import type { Response, SerializableForm } from "../types/types"; export async function onFormSubmission( - form: Ensure & { user: User }, "fields">, + form: Ensure & { user: Pick }, "fields">, response: Response ) { const fieldResponsesByName: Record< diff --git a/packages/app-store/vital/lib/reschedule.ts b/packages/app-store/vital/lib/reschedule.ts index 53f91ccd32..c800597dcb 100644 --- a/packages/app-store/vital/lib/reschedule.ts +++ b/packages/app-store/vital/lib/reschedule.ts @@ -57,8 +57,6 @@ const Reschedule = async (bookingUid: string, cancellationReason: string) => { const event = await prisma.eventType.findFirstOrThrow({ select: { title: true, - users: true, - schedulingType: true, }, where: { id: bookingToReschedule.eventTypeId, diff --git a/packages/app-store/wipemycalother/lib/reschedule.ts b/packages/app-store/wipemycalother/lib/reschedule.ts index a9134ffb53..ff8d2afe28 100644 --- a/packages/app-store/wipemycalother/lib/reschedule.ts +++ b/packages/app-store/wipemycalother/lib/reschedule.ts @@ -57,7 +57,6 @@ const Reschedule = async (bookingUid: string, cancellationReason: string) => { const event = await prisma.eventType.findFirstOrThrow({ select: { title: true, - users: true, schedulingType: true, }, where: { diff --git a/packages/features/auth/lib/next-auth-options.ts b/packages/features/auth/lib/next-auth-options.ts index 9af77b1804..706e000b72 100644 --- a/packages/features/auth/lib/next-auth-options.ts +++ b/packages/features/auth/lib/next-auth-options.ts @@ -47,7 +47,7 @@ const loginWithTotp = async (user: { email: string }) => type UserTeams = { teams: (Membership & { - team: Team; + team: Pick; })[]; }; @@ -106,7 +106,9 @@ const providers: Provider[] = [ throw new Error(ErrorCode.InternalServerError); } - const user = await UserRepository.findByEmailAndIncludeProfiles({ email: credentials.email }); + const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({ + email: credentials.email, + }); // Don't leak information about it being username or password that is invalid if (!user) { throw new Error(ErrorCode.IncorrectEmailPassword); @@ -273,7 +275,9 @@ if (isSAMLLoginEnabled) { email?: string; locale?: string; }) => { - const user = await UserRepository.findByEmailAndIncludeProfiles({ email: profile.email || "" }); + const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({ + email: profile.email || "", + }); if (!user) { throw new Error(ErrorCode.UserNotFound); } @@ -339,7 +343,7 @@ if (isSAMLLoginEnabled) { } const { id, firstName, lastName, email } = userInfo; - const user = await UserRepository.findByEmailAndIncludeProfiles({ email }); + const user = await UserRepository.findByEmailAndIncludeProfilesAndPassword({ email }); if (!user) { throw new Error(ErrorCode.UserNotFound); } diff --git a/packages/lib/server/repository/eventType.ts b/packages/lib/server/repository/eventType.ts index 8a561ff05a..bfa48b3f5b 100644 --- a/packages/lib/server/repository/eventType.ts +++ b/packages/lib/server/repository/eventType.ts @@ -1,4 +1,5 @@ -import type { Prisma, EventType as PrismaEventType } from "@prisma/client"; +import type { EventType as PrismaEventType } from "@prisma/client"; +import { Prisma } from "@prisma/client"; import logger from "@calcom/lib/logger"; import { prisma } from "@calcom/prisma"; @@ -22,6 +23,16 @@ type IEventType = Ensure< "title" | "slug" | "length" >; +const userSelect = Prisma.validator()({ + name: true, + avatarUrl: true, + username: true, + id: true, + email: true, + locale: true, + defaultScheduleId: true, +}); + export class EventTypeRepository { static async create(data: IEventType) { const { @@ -92,19 +103,23 @@ export class EventTypeRepository { // TODO: As required by getByViewHandler - Make it configurable team: { include: { - eventTypes: true, + eventTypes: { + include: { + users: { select: userSelect }, + }, + }, }, }, hashedLink: true, - users: true, + users: { select: userSelect }, children: { include: { - users: true, + users: { select: userSelect }, }, }, hosts: { include: { - user: true, + user: { select: userSelect }, }, }, }; diff --git a/packages/lib/server/repository/membership.ts b/packages/lib/server/repository/membership.ts index 5123199875..a607552ea4 100644 --- a/packages/lib/server/repository/membership.ts +++ b/packages/lib/server/repository/membership.ts @@ -1,5 +1,6 @@ import { prisma } from "@calcom/prisma"; -import type { Prisma, MembershipRole } from "@calcom/prisma/client"; +import type { MembershipRole } from "@calcom/prisma/client"; +import { Prisma } from "@calcom/prisma/client"; import logger from "../../logger"; import { safeStringify } from "../../safeStringify"; @@ -14,6 +15,33 @@ type IMembership = { role: MembershipRole; }; +const membershipSelect = Prisma.validator()({ + id: true, + teamId: true, + userId: true, + accepted: true, + role: true, + disableImpersonation: true, +}); + +const teamParentSelect = Prisma.validator()({ + id: true, + name: true, + slug: true, + logoUrl: true, + parentId: true, +}); + +const userSelect = Prisma.validator()({ + name: true, + avatarUrl: true, + username: true, + id: true, + email: true, + locale: true, + defaultScheduleId: true, +}); + export class MembershipRepository { static async create(data: IMembership) { return await prisma.membership.create({ @@ -68,25 +96,33 @@ export class MembershipRepository { include: { team: { include: { - members: true, - parent: true, + members: { + select: membershipSelect, + }, + parent: { + select: teamParentSelect, + }, eventTypes: { include: { team: { include: { - eventTypes: true, + eventTypes: { + include: { + users: { select: userSelect }, + }, + }, }, }, hashedLink: true, - users: true, - hosts: { - include: { - user: true, - }, - }, + users: { select: userSelect }, children: { include: { - users: true, + users: { select: userSelect }, + }, + }, + hosts: { + include: { + user: { select: userSelect }, }, }, }, diff --git a/packages/lib/server/repository/profile.ts b/packages/lib/server/repository/profile.ts index 2387ba56ba..8fbfc9f036 100644 --- a/packages/lib/server/repository/profile.ts +++ b/packages/lib/server/repository/profile.ts @@ -4,6 +4,7 @@ import { v4 as uuidv4 } from "uuid"; import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains"; import { safeStringify } from "@calcom/lib/safeStringify"; import prisma from "@calcom/prisma"; +import { Prisma } from "@calcom/prisma/client"; import type { Team } from "@calcom/prisma/client"; import type { UpId, UserAsPersonalProfile, UserProfile } from "@calcom/types/UserProfile"; @@ -11,6 +12,28 @@ import logger from "../../logger"; import { getParsedTeam } from "./teamUtils"; import { UserRepository } from "./user"; +const userSelect = Prisma.validator()({ + name: true, + avatarUrl: true, + username: true, + id: true, + email: true, + locale: true, + defaultScheduleId: true, + startTime: true, + endTime: true, + bufferTime: true, +}); + +const membershipSelect = Prisma.validator()({ + id: true, + teamId: true, + userId: true, + accepted: true, + role: true, + disableImpersonation: true, +}); + const log = logger.getSubLogger({ prefix: ["repository/profile"] }); const organizationSelect = { id: true, @@ -30,14 +53,17 @@ export class ProfileRepository { return uuidv4(); } - private static getInheritedDataFromUser({ user }: { user: PrismaUser }) { + private static getInheritedDataFromUser({ + user, + }: { + user: Pick; + }) { return { name: user.name, avatarUrl: user.avatarUrl, startTime: user.startTime, endTime: user.endTime, bufferTime: user.bufferTime, - avatar: user.avatar, }; } @@ -233,7 +259,9 @@ export class ProfileRepository { organization: { select: organizationSelect, }, - user: true, + user: { + select: userSelect, + }, }, }); @@ -268,7 +296,9 @@ export class ProfileRepository { organization: { select: organizationSelect, }, - user: true, + user: { + select: userSelect, + }, }, }); return profile; @@ -313,11 +343,15 @@ export class ProfileRepository { id, }, include: { - user: true, + user: { + select: userSelect, + }, movedFromUser: true, organization: { include: { - members: true, + members: { + select: membershipSelect, + }, }, }, }, @@ -346,7 +380,9 @@ export class ProfileRepository { organization: whereClauseForOrgWithSlugOrRequestedSlug(orgSlug), }, include: { - user: true, + user: { + select: userSelect, + }, organization: { select: organizationSelect, }, @@ -416,7 +452,9 @@ export class ProfileRepository { organizationId, }, include: { - user: true, + user: { + select: userSelect, + }, organization: { select: organizationSelect, }, @@ -434,7 +472,9 @@ export class ProfileRepository { organization: { select: organizationSelect, }, - user: true, + user: { + select: userSelect, + }, }, }); if (!profile) { diff --git a/packages/lib/server/repository/team.ts b/packages/lib/server/repository/team.ts index 0d71bce1ed..715ef7564f 100644 --- a/packages/lib/server/repository/team.ts +++ b/packages/lib/server/repository/team.ts @@ -1,4 +1,4 @@ -import type { Prisma } from "@prisma/client"; +import { Prisma } from "@prisma/client"; import type { z } from "zod"; import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains"; @@ -148,12 +148,23 @@ export async function getOrg({ teamSelect, }); } + +const teamSelect = Prisma.validator()({ + id: true, + name: true, + slug: true, + logoUrl: true, + parentId: true, + metadata: true, +}); + export class TeamRepository { static async findById({ id }: { id: number }) { const team = await prisma.team.findUnique({ where: { id, }, + select: teamSelect, }); if (!team) { return null; diff --git a/packages/lib/server/repository/user.ts b/packages/lib/server/repository/user.ts index aaf3255376..9b7195e8fa 100644 --- a/packages/lib/server/repository/user.ts +++ b/packages/lib/server/repository/user.ts @@ -1,6 +1,7 @@ import { whereClauseForOrgWithSlugOrRequestedSlug } from "@calcom/ee/organizations/lib/orgDomains"; import prisma from "@calcom/prisma"; -import type { User as UserType, Prisma } from "@calcom/prisma/client"; +import { Prisma } from "@calcom/prisma/client"; +import type { User as UserType } from "@calcom/prisma/client"; import type { UpId, UserProfile } from "@calcom/types/UserProfile"; import { isOrganization } from "../../entityPermissionUtils"; @@ -12,6 +13,54 @@ import { getParsedTeam } from "./teamUtils"; const log = logger.getSubLogger({ prefix: ["[repository/user]"] }); export const ORGANIZATION_ID_UNKNOWN = "ORGANIZATION_ID_UNKNOWN"; + +const teamSelect = Prisma.validator()({ + id: true, + name: true, + slug: true, + metadata: true, + logoUrl: true, +}); + +const userSelect = Prisma.validator()({ + id: true, + username: true, + name: true, + email: true, + emailVerified: true, + bio: true, + avatar: true, + avatarUrl: true, + timeZone: true, + startTime: true, + endTime: true, + weekStart: true, + bufferTime: true, + hideBranding: true, + theme: true, + createdDate: true, + trialEndsAt: true, + completedOnboarding: true, + locale: true, + timeFormat: true, + twoFactorSecret: true, + twoFactorEnabled: true, + backupCodes: true, + identityProviderId: true, + invitedTo: true, + brandColor: true, + darkBrandColor: true, + away: true, + allowDynamicBooking: true, + allowSEOIndexing: true, + receiveMonthlyDigestEmail: true, + verified: true, + disableImpersonation: true, + locked: true, + movedToProfileId: true, + metadata: true, +}); + export class UserRepository { static async findTeamsByUserId({ userId }: { userId: UserType["id"] }) { const teamMemberships = await prisma.membership.findMany({ @@ -19,7 +68,9 @@ export class UserRepository { userId: userId, }, include: { - team: true, + team: { + select: teamSelect, + }, }, }); @@ -69,6 +120,7 @@ export class UserRepository { return ( await prisma.user.findMany({ + select: userSelect, where, }) ).map((user) => { @@ -136,7 +188,7 @@ export class UserRepository { return { where, profiles }; } - static async findByEmailAndIncludeProfiles({ email }: { email: string }) { + static async findByEmailAndIncludeProfilesAndPassword({ email }: { email: string }) { const user = await prisma.user.findUnique({ where: { email: email.toLowerCase(), @@ -157,7 +209,9 @@ export class UserRepository { locale: true, teams: { include: { - team: true, + team: { + select: teamSelect, + }, }, }, }, @@ -179,6 +233,7 @@ export class UserRepository { where: { id, }, + select: userSelect, }); if (!user) { diff --git a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts index a1a1351ee7..e53cc02553 100644 --- a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @@ -100,7 +100,11 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { schedulingType: SchedulingType.COLLECTIVE, }, select: { - users: true, + users: { + select: { + id: true, + }, + }, }, }); diff --git a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts index 43cbc8aa63..9b1c35fadb 100644 --- a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts @@ -127,7 +127,6 @@ export const requestRescheduleHandler = async ({ ctx, input }: RequestReschedule event = await prisma.eventType.findFirstOrThrow({ select: { title: true, - users: true, schedulingType: true, recurringEvent: true, }, diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts index 52e1a121c5..a080b773f4 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts @@ -32,7 +32,11 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { include: { customInputs: true, schedule: true, - users: true, + users: { + select: { + id: true, + }, + }, team: true, workflows: true, webhooks: true, diff --git a/packages/trpc/server/routers/viewer/eventTypes/util.ts b/packages/trpc/server/routers/viewer/eventTypes/util.ts index 7443863406..857311622c 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/util.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/util.ts @@ -20,7 +20,11 @@ export const eventOwnerProcedure = authedProcedure const event = await ctx.prisma.eventType.findUnique({ where: { id: input.id }, include: { - users: true, + users: { + select: { + id: true, + }, + }, team: { select: { members: { diff --git a/packages/trpc/server/routers/viewer/payments.tsx b/packages/trpc/server/routers/viewer/payments.tsx index 282dcad5af..d065aadf06 100644 --- a/packages/trpc/server/routers/viewer/payments.tsx +++ b/packages/trpc/server/routers/viewer/payments.tsx @@ -29,7 +29,14 @@ export const paymentsRouter = router({ }, include: { payment: true, - user: true, + user: { + select: { + email: true, + locale: true, + name: true, + timeZone: true, + }, + }, attendees: true, eventType: true, }, diff --git a/packages/trpc/server/routers/viewer/workflows/update.handler.ts b/packages/trpc/server/routers/viewer/workflows/update.handler.ts index 6e26e13194..19296d8cc7 100644 --- a/packages/trpc/server/routers/viewer/workflows/update.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/update.handler.ts @@ -147,7 +147,11 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => { id: newEventTypeId, }, include: { - users: true, + users: { + select: { + id: true, + }, + }, team: { include: { members: true,