habits.andr33v.ru/server/api/auth/register.post.ts

94 lines
3.0 KiB
TypeScript

import { hashPassword } from '~/server/utils/password';
import { generateVillageForUser } from '~/server/services/villageService';
import { useSession } from 'h3';
const ANONYMOUS_COOKIE_NAME = 'smurf-anonymous-session';
/**
* Handles user registration.
*
* This endpoint has two main flows:
* 1. Anonymous User Conversion: If an anonymous session cookie is present,
* it finds the anonymous user, updates their details, makes them permanent,
* and logs them in, preserving their progress.
* 2. Standard Registration: If no anonymous session is found, it creates a
* brand new user and a new village for them.
*
* In both cases, it automatically logs the user in upon successful registration.
*/
export default defineEventHandler(async (event) => {
const { email, password, nickname } = await readBody(event);
// --- 1. Input Validation ---
if (!email || !password) {
throw createError({ statusCode: 400, statusMessage: 'Email and password are required' });
}
if (password.length < 8) {
throw createError({ statusCode: 400, statusMessage: 'Password must be at least 8 characters long' });
}
const normalizedEmail = email.toLowerCase();
// Check if email is already in use by a permanent account
const existingPermanentUser = await prisma.user.findFirst({
where: { email: normalizedEmail, isAnonymous: false },
});
if (existingPermanentUser) {
throw createError({ statusCode: 409, statusMessage: 'Email already in use' });
}
const hashedPassword = await hashPassword(password);
let user;
// --- 2. Identify User Flow (Anonymous Conversion vs. Standard) ---
const anonymousSessionId = getCookie(event, ANONYMOUS_COOKIE_NAME);
const anonymousUser = anonymousSessionId
? await prisma.user.findUnique({ where: { anonymousSessionId } })
: null;
if (anonymousUser) {
// --- Flow A: Convert Anonymous User ---
user = await prisma.user.update({
where: { id: anonymousUser.id },
data: {
email: normalizedEmail,
password: hashedPassword,
nickname: nickname || 'New Smurf',
isAnonymous: false, // Make the user permanent
anonymousSessionId: null, // Invalidate the anonymous session ID
},
});
// The village and progress are already associated with this user.
// Invalidate the anonymous cookie
setCookie(event, ANONYMOUS_COOKIE_NAME, '', { maxAge: -1 });
} else {
// --- Flow B: Create New User ---
user = await prisma.user.create({
data: {
email: normalizedEmail,
password: hashedPassword,
nickname: nickname || 'New Smurf',
isAnonymous: false,
},
});
// Generate a new village for the brand new user
await generateVillageForUser(user);
}
// --- 3. Automatically log the user in ---
const session = await useSession(event, { password: process.env.SESSION_PASSWORD! });
await session.update({ user: { id: user.id } });
// --- 4. Return DTO ---
return {
user: {
id: user.id,
email: user.email,
nickname: user.nickname,
}
};
});