Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions .server-changes/invite-email-case-insensitive.md
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 5 additions & 5 deletions apps/webapp/app/models/member.server.ts
Comment thread
isshaddad marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -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: {
Expand Down Expand Up @@ -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" },
},
});

Expand Down Expand Up @@ -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,
Expand All @@ -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" },
},
});
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
});

Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/routes/invite-accept.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down