import useDatabase from '~/composables/useDatabase'; import { campaignCharactersTable, campaignMembersTable, campaignTable, characterAbilitiesTable, characterChoicesTable, characterLevelingTable, characterTable, characterTrainingTable, usersTable } from '~/db/schema'; import { group } from '#shared/general.util'; import type { Character, MainStat, TrainingLevel } from '~/types/character'; import { and, eq, exists, getTableColumns, isNotNull, or, sql } from 'drizzle-orm'; export default defineEventHandler(async (e) => { const id = getRouterParam(e, "id"); if(!id) { setResponseStatus(e, 400); return; } const session = await getUserSession(e); if(!session.user) { setResponseStatus(e, 401); return; } const db = useDatabase(); const character = db.query.characterTable.findFirst({ with: { abilities: true, levels: true, training: true, choices: true, user: { columns: { username: true } }, campaign: { columns: { character: false, id: true, }, with: { campaign: { columns: { owner: true, }, with: { members: { columns: { user: true } } } } } } }, where: and(eq(characterTable.id, parseInt(id, 10)), or(eq(characterTable.visibility, 'public'), eq(characterTable.owner, session.user!.id), exists(db.select({ id: sql`NULL` }).from(campaignCharactersTable) .leftJoin(campaignTable, eq(campaignCharactersTable.id, campaignTable.id)) .leftJoin(campaignMembersTable, and(eq(campaignMembersTable.id, campaignTable.id), eq(campaignMembersTable.user, session.user.id))) .where(and(eq(campaignCharactersTable.character, parseInt(id, 10)), or(eq(campaignTable.owner, session.user.id), isNotNull(campaignMembersTable.user))))))), }).sync(); if(character !== undefined) { return { id: character.id, name: character.name, people: character.people, level: character.level, aspect: character.aspect, notes: { public: character.public_notes, private: session.user?.id === character.owner ? character.private_notes : undefined }, variables: character.variables, training: character.training.reduce((p, v) => { p[v.stat] ??= {}; p[v.stat][v.level as TrainingLevel] = v.choice; return p; }, {} as Record>>), leveling: group(character.levels, "level", "choice"), abilities: group(character.abilities, "ability", "value"), choices: character.choices.reduce((p, v) => { p[v.id] ??= []; p[v.id]?.push(v.choice); return p; }, {} as Record), owner: character.owner, username: character.user.username, visibility: character.visibility, campaign: character.campaign?.id, } as Character; } setResponseStatus(e, 404); return; });