mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-10 22:01:16 +00:00
Some checks failed
continuous-integration/drone/push Build is failing
- Add InviteCode model with code, maxUses, expiry, usage tracking - Registration now requires a valid invite code - New users get USER role instead of ADMIN - Admin-only /invites page to create, manage, and share invite codes - Invite links auto-fill code via ?code= URL param - Drone pipeline now builds app, worker, and bot images separately - Add NEXT_PUBLIC_APP_URL build arg to fix URL redirects
70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
"use server";
|
|
|
|
import bcrypt from "bcryptjs";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { registerSchema } from "@/schemas/auth.schema";
|
|
import type { ActionResult } from "@/types/api.types";
|
|
|
|
export async function registerUser(input: unknown): Promise<ActionResult<{ id: string }>> {
|
|
const parsed = registerSchema.safeParse(input);
|
|
if (!parsed.success) {
|
|
return { success: false, error: "Validation failed" };
|
|
}
|
|
|
|
// Validate invite code
|
|
const invite = await prisma.inviteCode.findUnique({
|
|
where: { code: parsed.data.inviteCode },
|
|
});
|
|
|
|
if (!invite) {
|
|
return { success: false, error: "Invalid invite code" };
|
|
}
|
|
|
|
if (invite.uses >= invite.maxUses) {
|
|
return { success: false, error: "This invite code has already been used" };
|
|
}
|
|
|
|
if (invite.expiresAt && invite.expiresAt < new Date()) {
|
|
return { success: false, error: "This invite code has expired" };
|
|
}
|
|
|
|
const existing = await prisma.user.findUnique({
|
|
where: { email: parsed.data.email },
|
|
});
|
|
|
|
if (existing) {
|
|
return { success: false, error: "An account with this email already exists" };
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(parsed.data.password, 10);
|
|
|
|
// Create user and increment invite usage in a transaction
|
|
const user = await prisma.$transaction(async (tx) => {
|
|
const newUser = await tx.user.create({
|
|
data: {
|
|
name: parsed.data.name,
|
|
email: parsed.data.email,
|
|
hashedPassword,
|
|
role: "USER",
|
|
settings: {
|
|
create: {
|
|
lowStockThreshold: 10,
|
|
currency: "USD",
|
|
theme: "dark",
|
|
units: "metric",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
await tx.inviteCode.update({
|
|
where: { id: invite.id },
|
|
data: { uses: { increment: 1 } },
|
|
});
|
|
|
|
return newUser;
|
|
});
|
|
|
|
return { success: true, data: { id: user.id } };
|
|
}
|