Add Discord verification option for users without email

This commit is contained in:
openhands committed 2026-07-07 20:37:42 +02:00
1 parent eb01b14379
commit 43c0ba6614
6 files changed
+257 -56

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
"use server";
import { prisma } from "@/lib/prisma";
import { auth } from "@/lib/auth";
export async function linkDiscordId(discordId: string): Promise<string | null> {
const session = await auth();
if (!session?.user?.id) return "Niet ingelogd";
const userId = Number(session.user.id);
if (!discordId || !/^\d{17,20}$/.test(discordId.trim())) {
return "Ongeldig Discord ID";
}
const discordIdClean = discordId.trim();
// Check if this Discord ID is already linked to another account.
try {
const existing = await prisma.socialAccounts.findUnique({
where: { provider_providerId: { provider: "discord", providerId: discordIdClean } },
select: { userId: true },
});
if (existing && Number(existing.userId) !== userId) {
return "Dit Discord ID is al gekoppeld aan een ander account";
}
} catch {
return "Fout bij controleren Discord ID";
}
try {
// Upsert: create or update the social_accounts entry.
await prisma.socialAccounts.upsert({
where: { provider_providerId: { provider: "discord", providerId: discordIdClean } },
create: {
userId: BigInt(userId),
provider: "discord",
providerId: discordIdClean,
createdAt: new Date(),
updatedAt: new Date(),
},
update: { userId: BigInt(userId), updatedAt: new Date() },
});
// Mark user as verified.
await prisma.user.update({
where: { id: userId },
data: { mailVerified: "1" },
});
return null; // success
} catch (e) {
console.error("[link-discord] Failed:", (e as Error).message);
return "Fout bij koppelen van Discord account";
}
}
+16 -7
View File
@@ -16,7 +16,7 @@ const registerSchema = z.object({
.min(3, "Username must be at least 3 characters")
.max(25, "Username must be at most 25 characters")
.regex(/^[A-Za-z0-9_\-=?!@:.,]+$/, "Username contains invalid characters"),
mail: z.string().email("Enter a valid email address"),
mail: z.string().email("Enter a valid email address").optional().or(z.literal("")),
password: z
.string()
.min(8, "Password must be at least 8 characters")
@@ -43,6 +43,7 @@ export async function register(prevState: string | null, formData: FormData): Pr
}
const { username, mail, password, look } = parsed.data;
const hasEmail = !!mail;
const ip = await clientIp();
// Throttle sign-ups per IP (5 per 10 minutes) to curb account spam.
@@ -88,7 +89,7 @@ export async function register(prevState: string | null, formData: FormData): Pr
data: {
username,
password: await hashPassword(password),
mail,
mail: hasEmail ? mail : null,
accountCreated: now,
ipRegister: ip,
ipCurrent: ip,
@@ -97,14 +98,22 @@ export async function register(prevState: string | null, formData: FormData): Pr
select: { id: true },
});
try {
await sendVerification(created.id, mail);
} catch {
// No-op: account is created; user can request a new link later.
if (hasEmail) {
try {
await sendVerification(created.id, mail);
} catch {
// No-op: account is created; user can request a new link later.
}
}
} catch {
return "Could not create the account (is the username unique?)";
}
redirect("/login?registered=1");
if (hasEmail) {
redirect("/login?registered=1");
} else {
const { signIn } = await import("@/lib/auth");
await signIn("credentials", { username, password, redirect: false });
redirect("/verify?method=discord");
}
}