feat: add daily win recording endpoint, user authentication, and profile management
- Implemented a POST endpoint for recording daily wins in the game. - Created login and signup functionality with email and password. - Developed a profile page allowing users to update their profile information, change passwords, and manage active sessions. - Added a toggle feature for switching between login and signup forms. - Enhanced the layout by removing the profile button and adjusting the header structure.
This commit is contained in:
171
src/routes/(admin)/admin/characters/+page.server.ts
Normal file
171
src/routes/(admin)/admin/characters/+page.server.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { db } from '$lib/server/db';
|
||||
import { character, devilFruit, arc, characterOverride } from '$lib/server/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const [charactersData, devilFruits, arcs, overrides] = await Promise.all([
|
||||
db
|
||||
.select({
|
||||
id: character.id,
|
||||
name: character.name,
|
||||
gender: character.gender,
|
||||
age: character.age,
|
||||
affiliations: character.affiliations,
|
||||
devilFruitId: character.devilFruitId,
|
||||
hakiObservation: character.hakiObservation,
|
||||
hakiArmament: character.hakiArmament,
|
||||
hakiConqueror: character.hakiConqueror,
|
||||
bounty: character.bounty,
|
||||
height: character.height,
|
||||
origin: character.origin,
|
||||
firstAppearance: character.firstAppearance,
|
||||
pictureUrl: character.pictureUrl,
|
||||
epithets: character.epithets,
|
||||
status: character.status,
|
||||
url: character.url,
|
||||
arcId: character.arcId,
|
||||
isInDailyMode: character.isInDailyMode,
|
||||
arcName: arc.name,
|
||||
devilFruitName: devilFruit.name,
|
||||
devilFruitType: devilFruit.type
|
||||
})
|
||||
.from(character)
|
||||
.leftJoin(arc, eq(character.arcId, arc.id))
|
||||
.leftJoin(devilFruit, eq(character.devilFruitId, devilFruit.id))
|
||||
.orderBy(character.name),
|
||||
db.select().from(devilFruit).orderBy(devilFruit.name),
|
||||
db.select().from(arc).orderBy(arc.name),
|
||||
db.select().from(characterOverride)
|
||||
]);
|
||||
|
||||
// Create a map of overrides by characterId for easy lookup
|
||||
const overridesMap = new Map(overrides.map((o) => [o.characterId, o]));
|
||||
|
||||
// Merge character data with overrides
|
||||
const charactersWithOverrides = charactersData.map((char) => {
|
||||
const override = overridesMap.get(char.id);
|
||||
|
||||
// Build displayValues by only applying non-null override fields
|
||||
const displayValues = { ...char } as any;
|
||||
if (override) {
|
||||
Object.keys(override).forEach((key) => {
|
||||
if (override[key as keyof typeof override] !== null && key !== 'characterId') {
|
||||
displayValues[key as keyof typeof displayValues] = override[key as keyof typeof override];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...char,
|
||||
override,
|
||||
displayValues
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
characters: charactersWithOverrides,
|
||||
devilFruits,
|
||||
arcs
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
update: async ({ request, locals }) => {
|
||||
if (!locals.user?.isAdmin) {
|
||||
return fail(401, { error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
const id = formData.get('id') as string;
|
||||
|
||||
if (!id) {
|
||||
return fail(400, { error: 'Character ID is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const updates: Record<string, any> = {
|
||||
// Initialize boolean fields to false (they'll be set to true if present in formData)
|
||||
hakiObservation: false,
|
||||
hakiArmament: false,
|
||||
hakiConqueror: false
|
||||
};
|
||||
|
||||
formData.forEach((value, key) => {
|
||||
if (key !== 'id') {
|
||||
// Handle checkboxes (haki fields)
|
||||
if (key === 'hakiObservation' || key === 'hakiArmament' || key === 'hakiConqueror') {
|
||||
updates[key] = value === 'on';
|
||||
}
|
||||
// Handle integers (age, bounty, height, devilFruitId, arcId)
|
||||
else if (key === 'age' || key === 'bounty' || key === 'height' || key === 'devilFruitId' || key === 'arcId') {
|
||||
const strValue = value as string;
|
||||
updates[key] = strValue && strValue !== '' ? parseInt(strValue) : null;
|
||||
}
|
||||
// Handle strings (name, gender, status, origin, affiliations, epithets, pictureUrl, url, firstAppearance)
|
||||
else {
|
||||
updates[key] = value || null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update or insert into characterOverride table
|
||||
await db
|
||||
.insert(characterOverride)
|
||||
.values({ characterId: id, ...updates })
|
||||
.onConflictDoUpdate({ target: characterOverride.characterId, set: updates });
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Character update error:', error);
|
||||
return fail(500, { error: 'Failed to update character' });
|
||||
}
|
||||
},
|
||||
|
||||
delete: async ({ request, locals }) => {
|
||||
if (!locals.user?.isAdmin) {
|
||||
return fail(401, { error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
const id = formData.get('id') as string;
|
||||
|
||||
if (!id) {
|
||||
return fail(400, { error: 'Character ID is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.delete(character).where(eq(character.id, id));
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Character delete error:', error);
|
||||
return fail(500, { error: 'Failed to delete character' });
|
||||
}
|
||||
},
|
||||
|
||||
toggleDailyMode: async ({ request, locals }) => {
|
||||
if (!locals.user?.isAdmin) {
|
||||
return fail(401, { error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
const id = formData.get('id') as string;
|
||||
const isInDailyMode = formData.get('isInDailyMode') === 'true';
|
||||
|
||||
if (!id) {
|
||||
return fail(400, { error: 'Character ID is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.update(character)
|
||||
.set({ isInDailyMode })
|
||||
.where(eq(character.id, id));
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Toggle daily mode error:', error);
|
||||
return fail(500, { error: 'Failed to toggle daily mode' });
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user