diff --git a/app/composables/useDatabase.ts b/app/composables/useDatabase.ts index d4fb931..622aa6a 100644 --- a/app/composables/useDatabase.ts +++ b/app/composables/useDatabase.ts @@ -1,7 +1,6 @@ import { Database } from "bun:sqlite"; import { BunSQLiteDatabase, drizzle } from "drizzle-orm/bun-sqlite"; import * as schema from '../db/schema'; -import { eq, or, sql } from "drizzle-orm"; let instance: BunSQLiteDatabase & { $client: Database; diff --git a/db.sqlite b/db.sqlite index 6f3c060..64617a4 100644 Binary files a/db.sqlite and b/db.sqlite differ diff --git a/server/api/auth/register.post.ts b/server/api/auth/register.post.ts index 4b95569..e800780 100644 --- a/server/api/auth/register.post.ts +++ b/server/api/auth/register.post.ts @@ -74,7 +74,7 @@ export default defineEventHandler(async (e): Promise => { logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [], lastTimestamp: new Date() } }) as UserSessionRequired); - const emailId = Bun.hash('register' + id.id + hash, Date.now()); + const emailId = Bun.hash('register' + id.id + hash, Date.now()).toString(10); const timestamp = Date.now() + 1000 * 60 * 60; await runTask('validation', { diff --git a/server/api/auth/request-reset.post.ts b/server/api/auth/request-reset.post.ts index 63a0a1b..08f5721 100644 --- a/server/api/auth/request-reset.post.ts +++ b/server/api/auth/request-reset.post.ts @@ -24,7 +24,7 @@ export default defineEventHandler(async (e) => { if(result && result.id) { - const id = hash('reset' + result.id + result.hash, Date.now()); + const id = hash('reset' + result.id + result.hash, Date.now()).toString(10); const timestamp = Date.now() + 1000 * 60 * 60; await runTask('validation', { payload: { diff --git a/server/api/users/[id]/revalidate.post.ts b/server/api/users/[id]/revalidate.post.ts index 51586fb..21a0fa3 100644 --- a/server/api/users/[id]/revalidate.post.ts +++ b/server/api/users/[id]/revalidate.post.ts @@ -47,7 +47,7 @@ export default defineEventHandler(async (e) => { return; } - const emailId = hash('register' + data.id + data.hash, Date.now()); + const emailId = hash('register' + data.id + data.hash, Date.now()).toString(10); const timestamp = Date.now() + 1000 * 60 * 60; await runTask('validation', { diff --git a/server/components/mail/reset-password.ts b/server/components/mail/reset-password.ts index d1fe15a..d194101 100644 --- a/server/components/mail/reset-password.ts +++ b/server/components/mail/reset-password.ts @@ -1,4 +1,5 @@ import { dom, text } from "#shared/dom.virtual.util"; +import { format } from "#shared/general.util"; export default function(data: any) { diff --git a/server/routes/user/mailvalidation.get.ts b/server/routes/user/mailvalidation.get.ts index ed31af8..4c4a353 100644 --- a/server/routes/user/mailvalidation.get.ts +++ b/server/routes/user/mailvalidation.get.ts @@ -16,6 +16,8 @@ export default defineEventHandler(async (e) => { if(!query.success) throw query.error; + const date = new Date(); + if(Bun.hash('1' + query.data.u.toString(), query.data.t).toString() !== query.data.h) { return createError({ @@ -23,7 +25,7 @@ export default defineEventHandler(async (e) => { message: 'Lien incorrect', }); } - if(Date.now() > query.data.t + (60 * 60 * 1000)) + if(date.getTime() > query.data.t + (60 * 60 * 1000)) { return createError({ statusCode: 400, @@ -34,7 +36,7 @@ export default defineEventHandler(async (e) => { const db = useDatabase(); const validate = db.select(getTableColumns(emailValidationTable)).from(emailValidationTable).where(eq(emailValidationTable.id, query.data.i)).get(); - if(!validate || validate.timestamp <= new Date()) + if(!validate || validate.timestamp <= date) { return createError({ statusCode: 400, @@ -42,7 +44,7 @@ export default defineEventHandler(async (e) => { }); } - db.delete(emailValidationTable).where(lte(emailValidationTable.timestamp, new Date())).run(); + db.delete(emailValidationTable).where(lte(emailValidationTable.timestamp, date)).run(); const result = db.select({ state: usersTable.state }).from(usersTable).where(eq(usersTable.id, query.data.u)).get(); if(result === undefined) diff --git a/server/tasks/validation.ts b/server/tasks/validation.ts index 8945182..27e0998 100644 --- a/server/tasks/validation.ts +++ b/server/tasks/validation.ts @@ -14,18 +14,18 @@ export default defineTask({ name: 'validation', description: 'Add email ID to DB', }, - run(e) { + run({ payload, context }) { try { - if(e.payload.type !== 'validation') + if(payload.type !== 'validation') { throw new Error(`Données inconnues`); } - const payload = e.payload as ValidationPayload; + const _payload = payload as ValidationPayload; const db = useDatabase(); db.delete(emailValidationTable).where(lt(emailValidationTable.timestamp, new Date())).run(); - db.insert(emailValidationTable).values({ id: payload.id, timestamp: new Date(payload.timestamp) }).run(); + db.insert(emailValidationTable).values({ id: _payload.id, timestamp: new Date(_payload.timestamp) }).run(); return { result: true }; } diff --git a/shared/character.util.ts b/shared/character.util.ts index ed5599f..e250745 100644 --- a/shared/character.util.ts +++ b/shared/character.util.ts @@ -1,9 +1,9 @@ -import type { Ability, Alignment, ArmorConfig, Character, CharacterConfig, CharacterVariables, CompiledCharacter, DamageType, FeatureItem, ItemConfig, ItemState, Level, MainStat, Resistance, SpellConfig, SpellElement, SpellType, TrainingLevel, WeaponConfig, WeaponType } from "~/types/character"; -import { keyof, z } from "zod/v4"; +import type { Ability, Alignment, ArmorConfig, Character, CharacterConfig, CharacterVariables, CompiledCharacter, DamageType, FeatureItem, ItemConfig, ItemState, Level, MainStat, Resistance, SpellElement, SpellType, TrainingLevel, WeaponConfig, WeaponType } from "~/types/character"; +import { z } from "zod/v4"; import characterConfig from '#shared/character-config.json'; import proses, { preview } from "#shared/proses"; import { button, buttongroup, checkbox, floater, foldable, input, loading, multiselect, numberpicker, select, tabgroup, Toaster, toggle } from "#shared/components.util"; -import { div, dom, icon, span, text, type DOMList, type RedrawableHTML } from "#shared/dom.util"; +import { div, dom, icon, span, text, reactive, type DOMList, type RedrawableHTML } from "#shared/dom.util"; import { followermenu, fullblocker, tooltip } from "#shared/floating.util"; import { clamp, deepEquals } from "#shared/general.util"; import markdown from "#shared/markdown.util"; @@ -1006,11 +1006,11 @@ class TrainingPicker extends BuilderTab ]), div("flex justify-center items-center gap-2 my-2 md:text-base text-sm", [ dom("span", { text: "Vie" }), - text(this._builder, '{{compiled.health}}'), + text(() => this._builder.compiled.health), ]), div("flex justify-center items-center gap-2 my-2 md:text-base text-sm", [ dom("span", { text: "Mana" }), - text(this._builder, '{{compiled.mana}}'), + text(() => this._builder.compiled.mana), ]), button(text('Suivant'), () => this._builder.display(3), 'h-[35px] px-[15px]'), ]), dom('span') @@ -1311,7 +1311,7 @@ export class CharacterSheet useRequestFetch()(`/api/character/${id}`).then(character => { if(character) { - this.character = new CharacterCompiler(character); + this.character = new CharacterCompiler(reactive(character)); if(character.campaign) { @@ -1321,7 +1321,7 @@ export class CharacterSheet useRequestFetch()(`/api/character/${id}`).then(character => { if(character) { - this.character!.character = character; + this.character!.character = reactive(character); this.character!.values; 'update' in this.container! && this.container!.update!(true); } @@ -1458,12 +1458,12 @@ export class CharacterSheet dom("span", { class: "flex flex-row items-center gap-2 text-3xl font-light" }, [ text("PV: "), health.readonly, - text(character, `/ {{health}}`), + text(() => character.health), ]), dom("span", { class: "flex flex-row items-center gap-2 text-3xl font-light" }, [ text("Mana: "), mana.readonly, - text(character, `/ {{mana}}`), + text(() => character.mana), ]), ]), ]), @@ -1478,31 +1478,31 @@ export class CharacterSheet div("flex flex-row justify-center 2xl:gap-4 gap-2 p-4 border-b border-light-35 dark:border-dark-35", [ div("flex 2xl:gap-4 gap-2 flex-row items-center justify-between", [ div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.strength}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.strength}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Force" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.dexterity}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.dexterity}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Dextérité" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.constitution}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.constitution}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Constitution" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.intelligence}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.intelligence}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Intelligence" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.curiosity}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.curiosity}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Curiosité" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.charisma}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.charisma}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Charisme" }) ]), div("flex flex-col items-center px-2", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{modifier.psyche}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.modifier.psyche}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Psyché" }) ]) ]), @@ -1511,11 +1511,11 @@ export class CharacterSheet div("flex 2xl:gap-4 gap-2 flex-row items-center justify-between", [ div("flex flex-col px-2 items-center", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `+{{initiative}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => `+${character.initiative}`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Initiative" }) ]), div("flex flex-col px-2 items-center", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, () => character.speed === false ? "Aucun déplacement" : `{{speed}} cases`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => character.speed === false ? "Aucun déplacement" : `${character.speed} cases`) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Course" }) ]) ]), @@ -1525,15 +1525,15 @@ export class CharacterSheet div("flex 2xl:gap-4 gap-2 flex-row items-center justify-between", [ icon("game-icons:checked-shield", { width: 32, height: 32 }), div("flex flex-col px-2 items-center", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `{{defense.passive}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => clamp(character.defense.static + character.defense.passiveparry + character.defense.passivedodge, 0, character.defense.hardcap)) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Passive" }) ]), div("flex flex-col px-2 items-center", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `{{defense.parry}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => clamp(character.defense.static + character.defense.activeparry + character.defense.passivedodge, 0, character.defense.hardcap)) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Blocage" }) ]), div("flex flex-col px-2 items-center", [ - dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(character, `{{defense.dodge}}`) ]), + dom("span", { class: "2xl:text-2xl text-xl font-bold" }, [ text(() => clamp(character.defense.static + character.defense.passiveparry + character.defense.activedodge, 0, character.defense.hardcap)) ]), dom("span", { class: "text-sm 2xl:text-base", text: "Esquive" }) ]) ]), @@ -1551,7 +1551,7 @@ export class CharacterSheet Object.keys(character.abilities).map((ability) => div("flex flex-row px-1 justify-between items-center", [ span("text-sm text-light-70 dark:text-dark-70 max-w-20 truncate", abilityTexts[ability as Ability] || ability), - span("font-bold text-base text-light-100 dark:text-dark-100", text(character.abilities, `+{{${ability}}}`)), + span("font-bold text-base text-light-100 dark:text-dark-100", text(() => `+${character.abilities[ability as Ability] ?? 0}`)), ]) ) ), @@ -1583,10 +1583,10 @@ export class CharacterSheet ]) : undefined, div("grid grid-cols-2 gap-x-3 gap-y-1 text-sm", [ - div('flex flex-row items-center gap-2', [ text('Précision'), span('font-bold', text(character.spellranks, "{{precision}}")) ]), - div('flex flex-row items-center gap-2', [ text('Savoir'), span('font-bold', text(character.spellranks, "{{knowledge}}")) ]), - div('flex flex-row items-center gap-2', [ text('Instinct'), span('font-bold', text(character.spellranks, "{{instinct}}")) ]), - div('flex flex-row items-center gap-2', [ text('Oeuvres'), span('font-bold', text(character.spellranks, "{{arts}}")) ]), + div('flex flex-row items-center gap-2', [ text('Précision'), span('font-bold', text(() => character.spellranks.precision)) ]), + div('flex flex-row items-center gap-2', [ text('Savoir'), span('font-bold', text(() => character.spellranks.knowledge)) ]), + div('flex flex-row items-center gap-2', [ text('Instinct'), span('font-bold', text(() => character.spellranks.instinct)) ]), + div('flex flex-row items-center gap-2', [ text('Oeuvres'), span('font-bold', text(() => character.spellranks.arts)) ]), ]) ]) ]),