fix(webapp): match org invite emails case-insensitively

This commit is contained in:
isshaddad
2026-06-05 16:50:34 -04:00
parent 707bf1adb4
commit 36485affc2
4 changed files with 19 additions and 7 deletions
@@ -0,0 +1,12 @@
---
area: webapp
type: fix
---
Org member invites now match emails case-insensitively. Previously an invite
created with different casing than the invitee's account email (e.g.
"Andreas@example.com" vs "andreas@example.com") could never be accepted —
the accept route compared emails strictly and the pending-invite lookups
were exact-match. Invite emails are now lowercased on creation, and all
invite-by-email lookups (accept, decline, pending list) match
case-insensitively so existing mixed-case invite rows still work.
+5 -5
View File
@@ -156,7 +156,7 @@ export async function getInviteFromToken({ token }: { token: string }) {
export async function getUsersInvites({ email }: { email: string }) {
return await prisma.orgMemberInvite.findMany({
where: {
email,
email: { equals: email, mode: "insensitive" },
organization: {
deletedAt: null,
},
@@ -180,7 +180,7 @@ export async function acceptInvite({
const invite = await tx.orgMemberInvite.delete({
where: {
id: inviteId,
email: user.email,
email: { equals: user.email, mode: "insensitive" },
},
include: {
organization: {
@@ -215,7 +215,7 @@ export async function acceptInvite({
// 4. Check for other invites
const remainingInvites = await tx.orgMemberInvite.findMany({
where: {
email: user.email,
email: { equals: user.email, mode: "insensitive" },
},
});
@@ -259,7 +259,7 @@ export async function declineInvite({
const declinedInvite = await prisma.orgMemberInvite.delete({
where: {
id: inviteId,
email: user.email,
email: { equals: user.email, mode: "insensitive" },
},
include: {
organization: true,
@@ -269,7 +269,7 @@ export async function declineInvite({
//2. check for other invites
const remainingInvites = await prisma.orgMemberInvite.findMany({
where: {
email: user.email,
email: { equals: user.email, mode: "insensitive" },
},
});
@@ -149,7 +149,7 @@ const schema = z.object({
}
return [""];
}, z.string().email().array().nonempty("At least one email is required")),
}, z.string().trim().toLowerCase().email().array().nonempty("At least one email is required")),
rbacRoleId: z.string().optional(),
});
+1 -1
View File
@@ -34,7 +34,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
);
}
if (invite.email !== user.email) {
if (invite.email.toLowerCase() !== user.email.toLowerCase()) {
return redirectWithErrorMessage(
"/",
request,