Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions packages/features/ee/teams/lib/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,16 +396,6 @@ export async function isTeamOwner(userId: number, teamId: number) {
}));
}

export async function isTeamMember(userId: number, teamId: number) {
return !!(await prisma.membership.findFirst({
where: {
userId,
teamId,
accepted: true,
},
}));
}

export function generateNewChildEventTypeDataForDB({
eventType,
userId,
Expand Down
11 changes: 10 additions & 1 deletion packages/lib/server/repository/membership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,22 @@ export class MembershipRepository {
});
}

static async findUniqueByUserIdAndTeamId({ userId, teamId }: { userId: number; teamId: number }) {
static async findUniqueByUserIdAndTeamId({
userId,
teamId,
accepted,
}: {
userId: number;
teamId: number;
accepted?: boolean;
}) {
return await prisma.membership.findUnique({
where: {
userId_teamId: {
userId,
teamId,
},
accepted,
},
});
Comment on lines +306 to 323
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix the Prisma findUnique misuse with the accepted filter.

prisma.membership.findUnique only accepts a unique selector; adding accepted alongside the userId_teamId composite key makes the query invalid (MembershipWhereUniqueInput rejects non-unique fields). With the current change, any call passing accepted: true will throw an Unknown arg 'accepted' error at runtime. Please switch to a findFirst (or split the check) so the optional accepted predicate is respected.

-    return await prisma.membership.findUnique({
-      where: {
-        userId_teamId: {
-          userId,
-          teamId,
-        },
-        accepted,
-      },
-    });
+    return await prisma.membership.findFirst({
+      where: {
+        userId,
+        teamId,
+        ...(accepted !== undefined ? { accepted } : {}),
+      },
+    });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static async findUniqueByUserIdAndTeamId({
userId,
teamId,
accepted,
}: {
userId: number;
teamId: number;
accepted?: boolean;
}) {
return await prisma.membership.findUnique({
where: {
userId_teamId: {
userId,
teamId,
},
accepted,
},
});
static async findUniqueByUserIdAndTeamId({
userId,
teamId,
accepted,
}: {
userId: number;
teamId: number;
accepted?: boolean;
}) {
return await prisma.membership.findFirst({
where: {
userId,
teamId,
...(accepted !== undefined ? { accepted } : {}),
},
});
🤖 Prompt for AI Agents
In packages/lib/server/repository/membership.ts around lines 306 to 323, the
code misuses prisma.membership.findUnique by passing a non-unique field
(accepted) alongside the composite unique userId_teamId key which causes an
"Unknown arg 'accepted'" runtime error; change the call to
prisma.membership.findFirst (or equivalent) and move the selector into a where
object that includes userId, teamId, and the optional accepted predicate so the
optional accepted filter is honored without violating the unique-input contract.

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isTeamMember } from "@calcom/features/ee/teams/lib/queries";
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/types";

Expand All @@ -14,8 +14,14 @@ type UpdateMembershipOptions = {
};

export const getInternalNotesPresetsHandler = async ({ ctx, input }: UpdateMembershipOptions) => {
if (!(await isTeamMember(ctx.user?.id, input.teamId))) {
throw new TRPCError({ code: "UNAUTHORIZED" });
const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
userId: ctx.user.id,
teamId: input.teamId,
accepted: true,
});

if (!membership) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "User is not a member of this team" });
}

return await prisma.internalNotePreset.findMany({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/lib/delegationCredential/server";
import { getUserAvailabilityService } from "@calcom/lib/di/containers/GetUserAvailability";
import { isTeamMember } from "@calcom/features/ee/teams/lib/queries";
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
import type { TrpcSessionUser } from "@calcom/trpc/server/types";

Expand All @@ -17,8 +16,16 @@ type GetMemberAvailabilityOptions = {

export const getMemberAvailabilityHandler = async ({ ctx, input }: GetMemberAvailabilityOptions) => {
const userAvailabilityService = getUserAvailabilityService();
const team = await isTeamMember(ctx.user?.id, input.teamId);
if (!team) throw new TRPCError({ code: "UNAUTHORIZED" });

const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
userId: ctx.user.id,
teamId: input.teamId,
accepted: true,
});

if (!membership) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "User is not a member of this team" });
}
Comment on lines +20 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix membership lookup: accepted filter breaks findUnique.

MembershipRepository.findUniqueByUserIdAndTeamId currently forwards accepted to prisma.membership.findUnique. Prisma only allows unique fields inside findUnique, so the extra accepted immediately triggers Unknown arg 'accepted' in where.accepted for type MembershipWhereUniqueInput. As a result this guard will now throw for every request, blocking the handler.

Please switch the repository helper to use findFirst (or otherwise add a proper composite unique) before adding the accepted criterion. For example:

-    return await prisma.membership.findUnique({
-      where: {
-        userId_teamId: {
-          userId,
-          teamId,
-        },
-        accepted,
-      },
-    });
+    return await prisma.membership.findFirst({
+      where: {
+        userId,
+        teamId,
+        ...(accepted !== undefined ? { accepted } : {}),
+      },
+    });

Until that happens this handler will remain unusable.

Committable suggestion skipped: line range outside the PR's diff.


// verify member is in team
const members = await MembershipRepository.findByTeamIdForAvailability({ teamId: input.teamId });
Expand Down
Loading