Les comptes déjà créés ne sont pas inscrits. Le choix est facultatif à l’inscription et dans les paramètres. Un lien public demande confirmation avant d’arrêter les actualités, sans toucher aux messages de compte.
104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
'use server';
|
|
|
|
import bcrypt from 'bcryptjs';
|
|
import prisma from '@/lib/prisma';
|
|
import { z } from 'zod';
|
|
import { redirect } from 'next/navigation';
|
|
import { getSystemConfig } from '@/lib/config';
|
|
import { sendVerificationEmail } from '@/lib/auth/email-verification';
|
|
|
|
const RegisterSchema = z.object({
|
|
email: z.string().email(),
|
|
password: z.string().min(6),
|
|
confirmPassword: z.string().min(6),
|
|
name: z.string().min(2),
|
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
message: 'Passwords do not match',
|
|
path: ['confirmPassword'],
|
|
});
|
|
|
|
export async function register(prevState: string | undefined, formData: FormData) {
|
|
const config = await getSystemConfig();
|
|
const allowRegister = config.ALLOW_REGISTRATION !== 'false' && process.env.ALLOW_REGISTRATION !== 'false';
|
|
|
|
if (!allowRegister) {
|
|
return 'Registration is currently disabled by the administrator.';
|
|
}
|
|
|
|
const validatedFields = RegisterSchema.safeParse({
|
|
email: formData.get('email'),
|
|
password: formData.get('password'),
|
|
confirmPassword: formData.get('confirmPassword'),
|
|
name: formData.get('name'),
|
|
});
|
|
|
|
if (!validatedFields.success) {
|
|
return 'Invalid fields. Failed to register.';
|
|
}
|
|
|
|
const { email, password, name } = validatedFields.data;
|
|
const normalizedEmail = email.toLowerCase();
|
|
const adminEmail = process.env.ADMIN_EMAIL?.toLowerCase();
|
|
const isAdmin = Boolean(adminEmail && normalizedEmail === adminEmail);
|
|
|
|
try {
|
|
const existingUser = await prisma.user.findUnique({ where: { email: normalizedEmail } });
|
|
if (existingUser) {
|
|
return 'User already exists.';
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
const role = isAdmin ? 'ADMIN' : 'USER';
|
|
|
|
const created = await prisma.user.create({
|
|
data: {
|
|
email: normalizedEmail,
|
|
password: hashedPassword,
|
|
name,
|
|
role,
|
|
// Admin bootstrap + Google OAuth are trusted; everyone else must verify.
|
|
emailVerified: isAdmin ? new Date() : null,
|
|
},
|
|
});
|
|
|
|
if (formData.get('marketingConsent') === '1') {
|
|
try {
|
|
const { setMarketingOptIn } = await import('@/lib/marketing/preference')
|
|
const { marketingRequestMeta } = await import('@/lib/marketing/request-meta')
|
|
const meta = await marketingRequestMeta()
|
|
await setMarketingOptIn({
|
|
userId: created.id,
|
|
optedIn: true,
|
|
source: 'register',
|
|
language: typeof formData.get('marketingLanguage') === 'string'
|
|
? String(formData.get('marketingLanguage'))
|
|
: null,
|
|
meta,
|
|
})
|
|
} catch (err) {
|
|
console.error('[register] marketing consent save failed:', err)
|
|
}
|
|
}
|
|
|
|
if (!isAdmin) {
|
|
const mailResult = await sendVerificationEmail({
|
|
email: normalizedEmail,
|
|
name,
|
|
});
|
|
|
|
if (!mailResult.success) {
|
|
console.error('[register] verification email failed:', mailResult.error);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Registration Error:', error);
|
|
return 'Database Error: Failed to create user.';
|
|
}
|
|
|
|
if (isAdmin) {
|
|
redirect('/login?verified=1');
|
|
}
|
|
|
|
redirect(`/check-email?email=${encodeURIComponent(normalizedEmail)}`);
|
|
}
|