habits.andr33v.ru/server/api/onboarding/initiate.post.ts

97 lines
3.0 KiB
TypeScript

import { randomUUID } from 'crypto';
import prisma from '~/server/utils/prisma';
import { generateVillageForUser } from '~/server/services/villageService';
const ANONYMOUS_COOKIE_NAME = 'smurf-anonymous-session';
/**
* Initiates an anonymous user session.
* 1. Checks for an existing session cookie.
* 2. If found, verifies it corresponds to an existing anonymous user.
* 3. If not found or invalid, creates a new anonymous user and a corresponding village.
* 4. Sets the session ID in a long-lived cookie.
* 5. Returns the session ID and basic user info.
*/
export default defineEventHandler(async (event) => {
const existingSessionId = getCookie(event, ANONYMOUS_COOKIE_NAME);
if (existingSessionId) {
const user = await prisma.user.findUnique({
where: {
anonymousSessionId: existingSessionId,
isAnonymous: true
},
select: {
id: true,
anonymousSessionId: true,
village: { select: { id: true } } // Include village ID for deletion
}
});
// If a valid anonymous user is found for this session, reset their progress.
if (user) {
const villageId = user.village?.id;
// Use a transaction to atomically delete all progress.
await prisma.$transaction([
// 1. Delete all habits (HabitCompletion records will cascade)
prisma.habit.deleteMany({ where: { userId: user.id } }),
// 2. Delete all village objects to break the dependency on tiles before deleting the village
...(villageId ? [prisma.villageObject.deleteMany({ where: { villageId } })] : []),
// 3. Delete the village if it exists (all related records will cascade)
...(villageId ? [prisma.village.delete({ where: { id: villageId } })] : []),
]);
// Re-create the village from scratch. This service will also set initial coins.
await generateVillageForUser(user);
// Fetch the final, reset state of the user to return
const resetUser = await prisma.user.findUnique({
where: { id: user.id },
select: {
id: true,
anonymousSessionId: true,
nickname: true,
coins: true,
exp: true,
isAnonymous: true
}
});
return resetUser;
}
}
// No valid session found, create a new anonymous user.
const newSessionId = randomUUID();
const newUser = await prisma.user.create({
data: {
isAnonymous: true,
anonymousSessionId: newSessionId,
},
select: {
id: true, // Also return ID
anonymousSessionId: true,
nickname: true,
coins: true,
exp: true,
isAnonymous: true // Ensure this flag is returned
}
});
// Now, generate the village with default tiles for the new anonymous user
await generateVillageForUser(newUser);
// Set a long-lived cookie (e.g., 1 year)
setCookie(event, ANONYMOUS_COOKIE_NAME, newSessionId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 365 * 24 * 60 * 60 // 1 year in seconds
});
return newUser;
});