From fa14156d820bfcc63a49f5d65ea31643558ba139 Mon Sep 17 00:00:00 2001 From: whidix Date: Sun, 12 Apr 2026 02:01:01 +0200 Subject: [PATCH] feat: remove overrides --- drizzle/0002_old_earthquake.sql | 1 + drizzle/meta/0002_snapshot.json | 1185 +++++++++++++++++ drizzle/meta/_journal.json | 7 + src/lib/server/daily-character.ts | 113 +- src/lib/server/db/schema.ts | 29 - .../(admin)/admin/characters/+page.server.ts | 200 +-- .../(admin)/admin/characters/+page.svelte | 109 +- 7 files changed, 1272 insertions(+), 372 deletions(-) create mode 100644 drizzle/0002_old_earthquake.sql create mode 100644 drizzle/meta/0002_snapshot.json diff --git a/drizzle/0002_old_earthquake.sql b/drizzle/0002_old_earthquake.sql new file mode 100644 index 0000000..282c79f --- /dev/null +++ b/drizzle/0002_old_earthquake.sql @@ -0,0 +1 @@ +DROP TABLE `character_override`; \ No newline at end of file diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..a2a4cb6 --- /dev/null +++ b/drizzle/meta/0002_snapshot.json @@ -0,0 +1,1185 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "f3540f13-a6c4-4c52-ac29-6330ffce33fd", + "prevId": "9a965dd1-d97c-4142-a795-0558214180a4", + "tables": { + "arc": { + "name": "arc", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fr_name": { + "name": "fr_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start_chapter": { + "name": "start_chapter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "end_chapter": { + "name": "end_chapter", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "character": { + "name": "character", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fr_name": { + "name": "fr_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gender": { + "name": "gender", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "age": { + "name": "age", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "affiliations": { + "name": "affiliations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_affiliations": { + "name": "fr_affiliations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "devil_fruit_id": { + "name": "devil_fruit_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haki_observation": { + "name": "haki_observation", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "haki_armament": { + "name": "haki_armament", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "haki_conqueror": { + "name": "haki_conqueror", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "bounty": { + "name": "bounty", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "height": { + "name": "height", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_origin": { + "name": "fr_origin", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_appearance": { + "name": "first_appearance", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "picture_url": { + "name": "picture_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "epithets": { + "name": "epithets", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_epithets": { + "name": "fr_epithets", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "arc_id": { + "name": "arc_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_url": { + "name": "fr_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_in_daily_mode": { + "name": "is_in_daily_mode", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "character_devil_fruit_id_devil_fruit_id_fk": { + "name": "character_devil_fruit_id_devil_fruit_id_fk", + "tableFrom": "character", + "tableTo": "devil_fruit", + "columnsFrom": [ + "devil_fruit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "character_arc_id_arc_id_fk": { + "name": "character_arc_id_arc_id_fk", + "tableFrom": "character", + "tableTo": "arc", + "columnsFrom": [ + "arc_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "character_history": { + "name": "character_history", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "character_id": { + "name": "character_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "won": { + "name": "won", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "character_history_date_unique": { + "name": "character_history_date_unique", + "columns": [ + "date" + ], + "isUnique": true + } + }, + "foreignKeys": { + "character_history_character_id_character_id_fk": { + "name": "character_history_character_id_character_id_fk", + "tableFrom": "character_history", + "tableTo": "character", + "columnsFrom": [ + "character_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "character_scrape_validation": { + "name": "character_scrape_validation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fr_name": { + "name": "fr_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gender": { + "name": "gender", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "age": { + "name": "age", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "affiliations": { + "name": "affiliations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_affiliations": { + "name": "fr_affiliations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "devil_fruit_id": { + "name": "devil_fruit_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "haki_observation": { + "name": "haki_observation", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "haki_armament": { + "name": "haki_armament", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "haki_conqueror": { + "name": "haki_conqueror", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "bounty": { + "name": "bounty", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_origin": { + "name": "fr_origin", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_appearance": { + "name": "first_appearance", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "picture_url": { + "name": "picture_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "epithets": { + "name": "epithets", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_epithets": { + "name": "fr_epithets", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "arc_id": { + "name": "arc_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fr_url": { + "name": "fr_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_deleted": { + "name": "is_deleted", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "character_scrape_validation_devil_fruit_id_devil_fruit_id_fk": { + "name": "character_scrape_validation_devil_fruit_id_devil_fruit_id_fk", + "tableFrom": "character_scrape_validation", + "tableTo": "devil_fruit", + "columnsFrom": [ + "devil_fruit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "character_scrape_validation_arc_id_arc_id_fk": { + "name": "character_scrape_validation_arc_id_arc_id_fk", + "tableFrom": "character_scrape_validation", + "tableTo": "arc", + "columnsFrom": [ + "arc_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "config": { + "name": "config", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "devil_fruit": { + "name": "devil_fruit", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "devil_fruit_name_unique": { + "name": "devil_fruit_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "friendship": { + "name": "friendship", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "requester_id": { + "name": "requester_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "addressee_id": { + "name": "addressee_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "friendship_requester_id_addressee_id_unique": { + "name": "friendship_requester_id_addressee_id_unique", + "columns": [ + "requester_id", + "addressee_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "friendship_requester_id_user_id_fk": { + "name": "friendship_requester_id_user_id_fk", + "tableFrom": "friendship", + "tableTo": "user", + "columnsFrom": [ + "requester_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "friendship_addressee_id_user_id_fk": { + "name": "friendship_addressee_id_user_id_fk", + "tableFrom": "friendship", + "tableTo": "user", + "columnsFrom": [ + "addressee_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_character_history": { + "name": "user_character_history", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "character_history_id": { + "name": "character_history_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "try_count": { + "name": "try_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tried_character_ids": { + "name": "tried_character_ids", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_character_history_user_id_character_history_id_unique": { + "name": "user_character_history_user_id_character_history_id_unique", + "columns": [ + "user_id", + "character_history_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "user_character_history_user_id_user_id_fk": { + "name": "user_character_history_user_id_user_id_fk", + "tableFrom": "user_character_history", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_character_history_character_history_id_character_history_id_fk": { + "name": "user_character_history_character_history_id_character_history_id_fk", + "tableFrom": "user_character_history", + "tableTo": "character_history", + "columnsFrom": [ + "character_history_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_admin": { + "name": "is_admin", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "user_username_unique": { + "name": "user_username_unique", + "columns": [ + "username" + ], + "isUnique": true + }, + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 0a68814..7a27821 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1773697753818, "tag": "0001_fuzzy_talisman", "breakpoints": true + }, + { + "idx": 2, + "version": "6", + "when": 1775950314114, + "tag": "0002_old_earthquake", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/lib/server/daily-character.ts b/src/lib/server/daily-character.ts index 6001ceb..3f7510a 100644 --- a/src/lib/server/daily-character.ts +++ b/src/lib/server/daily-character.ts @@ -1,6 +1,6 @@ import { db } from '$lib/server/db'; -import { arc, character, characterHistory, characterOverride, devilFruit, type Character, type CharacterOverride } from '$lib/server/db/schema'; -import { desc, eq, inArray, and } from 'drizzle-orm'; +import { arc, character, characterHistory, devilFruit, type Character } from '$lib/server/db/schema'; +import { desc, eq, and } from 'drizzle-orm'; // Generate or get random seed for daily character selection const RANDOM_SEED = Math.random(); @@ -51,104 +51,6 @@ function isNotNullish(value: T | null | undefined): value is T { return value !== null && value !== undefined; } -function mergeCharacterWithOverride( - baseCharacter: CharacterWithRelations, - overrideRow?: CharacterOverride, - relationMaps?: RelationMaps -): CharacterWithRelations { - if (!overrideRow) { - return baseCharacter; - } - - const mergedCharacter = { ...baseCharacter } as CharacterWithRelations; - - for (const [key, value] of Object.entries(overrideRow)) { - if (key === 'characterId' || key === 'notes') { - continue; - } - - if (isNotNullish(value)) { - (mergedCharacter as Record)[key] = value; - } - } - - if (relationMaps) { - if (mergedCharacter.arcId) { - mergedCharacter.arcName = relationMaps.arcNameById.get(mergedCharacter.arcId) ?? null; - mergedCharacter.frArcName = relationMaps.arcNameById.get(mergedCharacter.arcId) ?? null; - } else { - mergedCharacter.arcName = null; - mergedCharacter.frArcName = null; - } - - if (mergedCharacter.devilFruitId) { - const devilFruitData = relationMaps.devilFruitById.get(mergedCharacter.devilFruitId); - mergedCharacter.devilFruitName = devilFruitData?.name ?? null; - mergedCharacter.devilFruitType = devilFruitData?.type ?? null; - } else { - mergedCharacter.devilFruitName = null; - mergedCharacter.devilFruitType = null; - } - } - - return mergedCharacter; -} - -async function applyCharacterOverrides( - characters: CharacterWithRelations[] -): Promise { - if (characters.length === 0) { - return characters; - } - - const characterIds = characters.map((currentCharacter) => currentCharacter.id); - const overrideRows = await db - .select() - .from(characterOverride) - .where(inArray(characterOverride.characterId, characterIds)); - - if (overrideRows.length === 0) { - return characters; - } - - const overrideByCharacterId = new Map( - overrideRows.map((overrideRow) => [overrideRow.characterId, overrideRow]) - ); - - const shouldRefreshRelations = overrideRows.some( - (overrideRow) => isNotNullish(overrideRow.arcId) || isNotNullish(overrideRow.devilFruitId) - ); - - let relationMaps: RelationMaps | undefined; - - if (shouldRefreshRelations) { - const [allArcs, allDevilFruits] = await Promise.all([ - db.select({ id: arc.id, name: arc.name }).from(arc), - db - .select({ id: devilFruit.id, name: devilFruit.name, type: devilFruit.type }) - .from(devilFruit) - ]); - - relationMaps = { - arcNameById: new Map(allArcs.map((currentArc) => [currentArc.id, currentArc.name])), - devilFruitById: new Map( - allDevilFruits.map((currentDevilFruit) => [ - currentDevilFruit.id, - { name: currentDevilFruit.name, type: currentDevilFruit.type } - ]) - ) - }; - } - - return characters.map((currentCharacter) => - mergeCharacterWithOverride( - currentCharacter, - overrideByCharacterId.get(currentCharacter.id), - relationMaps - ) - ); -} - export function getDateKey(date: Date): number { return normalizeDay(date).getTime(); } @@ -168,26 +70,22 @@ function pickDailyCharacter(characters: CharacterWithRelations[], date: Date): C } export async function getDailyModeCharacters(): Promise { - const characters = (await db + return (await db .select(characterWithRelationsSelect) .from(character) .leftJoin(arc, eq(character.arcId, arc.id)) .leftJoin(devilFruit, eq(character.devilFruitId, devilFruit.id)) .where(eq(character.isInDailyMode, true)) .all()) as CharacterWithRelations[]; - - return applyCharacterOverrides(characters); } export async function getAllCharacters(): Promise { - const characters = (await db + return (await db .select(characterWithRelationsSelect) .from(character) .leftJoin(arc, eq(character.arcId, arc.id)) .leftJoin(devilFruit, eq(character.devilFruitId, devilFruit.id)) .all()) as CharacterWithRelations[]; - - return applyCharacterOverrides(characters); } export async function getCharacterById(characterId: string): Promise { @@ -203,8 +101,7 @@ export async function getCharacterById(characterId: string): Promise; -// Define the character override table schema -export const characterOverride = sqliteTable('character_override', { - characterId: text('character_id').primaryKey().references(() => character.id, { onDelete: 'cascade' }), - name: text('name'), - gender: text('gender'), - age: integer('age'), - affiliations: text('affiliations', { mode: 'json' }).$type(), - frAffiliations: text('fr_affiliations', { mode: 'json' }).$type(), - devilFruitId: text('devil_fruit_id').references(() => devilFruit.id, { onDelete: 'set null' }), - hakiObservation: integer('haki_observation', { mode: 'boolean' }), - hakiArmament: integer('haki_armament', { mode: 'boolean' }), - hakiConqueror: integer('haki_conqueror', { mode: 'boolean' }), - bounty: integer('bounty'), - height: real('height'), - origin: text('origin'), - frOrigin: text('fr_origin'), - firstAppearance: integer('first_appearance'), - pictureUrl: text('picture_url'), - epithets: text('epithets', { mode: 'json' }).$type(), - frEpithets: text('fr_epithets', { mode: 'json' }).$type(), - status: text('status').$type(), - arcId: text('arc_id').references(() => arc.id, { onDelete: 'set null' }), - url: text('url'), - frUrl: text('fr_url'), - notes: text('notes') -}); - -export type CharacterOverride = InferSelectModel; - // Define the character scrape validation table schema export const characterScrapeValidation = sqliteTable('character_scrape_validation', { id: text('id').primaryKey(), diff --git a/src/routes/(admin)/admin/characters/+page.server.ts b/src/routes/(admin)/admin/characters/+page.server.ts index 039f68a..4de7b78 100644 --- a/src/routes/(admin)/admin/characters/+page.server.ts +++ b/src/routes/(admin)/admin/characters/+page.server.ts @@ -1,22 +1,32 @@ import { db } from '$lib/server/db'; -import { character, devilFruit, arc, characterOverride } from '$lib/server/db/schema'; +import { character, devilFruit, arc, type Status } from '$lib/server/db/schema'; import { eq, sql } from 'drizzle-orm'; import { fail } from '@sveltejs/kit'; import type { PageServerLoad, Actions } from './$types'; -import { writeFile } from 'fs/promises'; -import { join } from 'path'; -import { existsSync, mkdirSync } from 'fs'; -import { env } from '$env/dynamic/private'; + +// Helper function to normalize data (parse JSON arrays) +const normalizeArray = (value: any): any => { + if (!value) return value; + if (Array.isArray(value)) return value; + if (typeof value === 'string' && value.includes('[')) { + try { + return JSON.parse(value); + } catch { + return value; + } + } + return value; +}; export const load: PageServerLoad = async () => { - const [charactersData, devilFruits, arcs, overrides, statusesData, gendersData] = await Promise.all([ + let [characters, devilFruits, arcs, statusesData, gendersData] = await Promise.all([ db .select({ id: character.id, name: character.name, gender: character.gender, age: character.age, - affiliations: character.affiliations, + affiliations: normalizeArray(character.affiliations), devilFruitId: character.devilFruitId, hakiObservation: character.hakiObservation, hakiArmament: character.hakiArmament, @@ -26,7 +36,7 @@ export const load: PageServerLoad = async () => { origin: character.origin, firstAppearance: character.firstAppearance, pictureUrl: character.pictureUrl, - epithets: character.epithets, + epithets: normalizeArray(character.epithets), status: character.status, url: character.url, arcId: character.arcId, @@ -41,7 +51,6 @@ export const load: PageServerLoad = async () => { .orderBy(character.name), db.select().from(devilFruit).orderBy(devilFruit.name), db.select().from(arc).orderBy(arc.name), - db.select().from(characterOverride), db.selectDistinct({ status: character.status }) .from(character) .where(sql`${character.status} IS NOT NULL AND ${character.status} != ''`), @@ -50,76 +59,13 @@ export const load: PageServerLoad = async () => { .where(sql`${character.gender} IS NOT NULL AND ${character.gender} != ''`) ]); - // Create a map of overrides by characterId for easy lookup - const overridesMap = new Map(overrides.map((o) => [o.characterId, o])); - - // Create maps for arcs and devil fruits to lookup names by ID - const arcMap = new Map(arcs.map((a) => [a.id, a.name])); - const devilFruitMap = new Map(devilFruits.map((f) => [f.id, { name: f.name, type: f.type }])); - - // Helper function to normalize data (parse JSON arrays) - const normalizeArray = (value: any): any => { - if (!value) return value; - if (Array.isArray(value)) return value; - if (typeof value === 'string' && value.includes('[')) { - try { - return JSON.parse(value); - } catch { - return value; - } - } - return value; - }; - - // 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]; - } - }); - - // Update arcName if arcId was overridden - if (override.arcId !== null && override.arcId !== undefined) { - displayValues.arcName = arcMap.get(override.arcId) || null; - } - - // Update devilFruitName and devilFruitType if devilFruitId was overridden - if (override.devilFruitId !== null && override.devilFruitId !== undefined) { - const fruit = devilFruitMap.get(override.devilFruitId); - displayValues.devilFruitName = fruit?.name || null; - displayValues.devilFruitType = fruit?.type || null; - } - } - - // Pre-normalize arrays (epithets, affiliations) for performance - displayValues.epithets = normalizeArray(displayValues.epithets); - displayValues.affiliations = normalizeArray(displayValues.affiliations); - - // Create search text for epithets - displayValues.epithetsSearchText = Array.isArray(displayValues.epithets) - ? displayValues.epithets.join(' ').toLowerCase() - : (displayValues.epithets || '').toLowerCase(); - - return { - ...char, - override, - displayValues - }; - }); - return { - characters: charactersWithOverrides, + characters, devilFruits, arcs, availableStatuses: statusesData .map(s => s.status) - .filter((s): s is string => !!s) + .filter((s): s is Status => !!s) .sort((a, b) => a.localeCompare(b)), availableGenders: gendersData .map(g => g.gender) @@ -129,112 +75,6 @@ export const load: PageServerLoad = async () => { }; 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 [originalCharacter] = await db - .select({ - hakiObservation: character.hakiObservation, - hakiArmament: character.hakiArmament, - hakiConqueror: character.hakiConqueror - }) - .from(character) - .where(eq(character.id, id)) - .limit(1); - - if (!originalCharacter) { - return fail(404, { error: 'Character not found' }); - } - - const updates: Record = {}; - - // Handle file upload - const pictureFile = formData.get('pictureFile') as File; - const hasUploadedPicture = !!pictureFile && pictureFile.size > 0; - if (hasUploadedPicture) { - try { - const uploadsDir = env.UPLOADS_DIR || join(process.cwd(),'uploads'); - if (!existsSync(uploadsDir)) { - mkdirSync(uploadsDir, { recursive: true }); - } - - // Get file extension - const extension = pictureFile.name.split('.').pop(); - const filename = `${id}.${extension}`; - const filepath = join(uploadsDir, filename); - - // Convert file to buffer and save - const buffer = Buffer.from(await pictureFile.arrayBuffer()); - await writeFile(filepath, buffer); - - // Update pictureUrl to point to the handler route - updates.pictureUrl = `/uploads/${filename}`; - } catch (error) { - console.error('File upload error:', error); - return fail(500, { error: 'Failed to upload file' }); - } - } - - formData.forEach((value, key) => { - if (key !== 'id' && key !== 'pictureFile') { - if (hasUploadedPicture && key === 'pictureUrl') { - return; - } - // Handle integers (age, bounty, height) - if (key === 'age' || key === 'bounty' || key === 'height') { - const strValue = value as string; - updates[key] = strValue && strValue !== '' ? parseInt(strValue) : null; - } - // Handle text IDs (devilFruitId, arcId) - else if (key === 'devilFruitId' || key === 'arcId') { - const strValue = value as string; - updates[key] = strValue && strValue !== '' ? strValue : null; - } - // Handle checkboxes (haki fields) after parsing all form data - else if (key === 'hakiObservation' || key === 'hakiArmament' || key === 'hakiConqueror') { - return; - } - // Handle strings (name, gender, status, origin, affiliations, epithets, pictureUrl, url, firstAppearance) - else { - updates[key] = value || null; - } - } - }); - - const submittedHakiObservation = formData.has('hakiObservation'); - const submittedHakiArmament = formData.has('hakiArmament'); - const submittedHakiConqueror = formData.has('hakiConqueror'); - - updates.hakiObservation = - submittedHakiObservation === originalCharacter.hakiObservation ? null : submittedHakiObservation; - updates.hakiArmament = - submittedHakiArmament === originalCharacter.hakiArmament ? null : submittedHakiArmament; - updates.hakiConqueror = - submittedHakiConqueror === originalCharacter.hakiConqueror ? null : submittedHakiConqueror; - - // 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' }); diff --git a/src/routes/(admin)/admin/characters/+page.svelte b/src/routes/(admin)/admin/characters/+page.svelte index 85f3565..2abcee6 100644 --- a/src/routes/(admin)/admin/characters/+page.svelte +++ b/src/routes/(admin)/admin/characters/+page.svelte @@ -63,23 +63,22 @@ const matchesSearch = normalizedQuery === '' || - char.displayValues.name.toLowerCase().includes(normalizedQuery) || - char.displayValues.epithetsSearchText.includes(normalizedQuery); + char.name.toLowerCase().includes(normalizedQuery); const matchesDaily = filterDaily === 'all' || - (filterDaily === 'daily' && char.displayValues.isInDailyMode) || - (filterDaily === 'not-daily' && !char.displayValues.isInDailyMode); - const matchesStatus = filterStatus === 'all' || (char.displayValues.status || '') === filterStatus; - const matchesGender = filterGender === 'all' || (char.displayValues.gender || '') === filterGender; + (filterDaily === 'daily' && char.isInDailyMode) || + (filterDaily === 'not-daily' && !char.isInDailyMode); + const matchesStatus = filterStatus === 'all' || (char.status || '') === filterStatus; + const matchesGender = filterGender === 'all' || (char.gender || '') === filterGender; const matchesArc = filterArc === 'all' || - String(char.displayValues.arcId ?? '') === filterArc; + String(char.arcId ?? '') === filterArc; const matchesHaki = filterHaki === 'all' || - (filterHaki === 'observation' && !!char.displayValues.hakiObservation) || - (filterHaki === 'armament' && !!char.displayValues.hakiArmament) || - (filterHaki === 'conqueror' && !!char.displayValues.hakiConqueror) || - (filterHaki === 'none' && !char.displayValues.hakiObservation && !char.displayValues.hakiArmament && !char.displayValues.hakiConqueror); + (filterHaki === 'observation' && !!char.hakiObservation) || + (filterHaki === 'armament' && !!char.hakiArmament) || + (filterHaki === 'conqueror' && !!char.hakiConqueror) || + (filterHaki === 'none' && !char.hakiObservation && !char.hakiArmament && !char.hakiConqueror); return matchesSearch && matchesDaily && matchesStatus && matchesGender && matchesArc && matchesHaki; }); @@ -277,116 +276,116 @@ {#each filteredCharacters as char (char.id)} - +
- {#if char.displayValues.url} + {#if char.url} - {#if char.displayValues.pictureUrl} + {#if char.pictureUrl} {char.displayValues.name} {:else}
- {char.displayValues.name?.charAt(0).toUpperCase() || '?'} + {char.name?.charAt(0).toUpperCase() || '?'}
{/if}
{:else} - {#if char.displayValues.pictureUrl} + {#if char.pictureUrl} {char.displayValues.name} {:else}
- {char.displayValues.name?.charAt(0).toUpperCase() || '?'} + {char.name?.charAt(0).toUpperCase() || '?'}
{/if} {/if}
- {#if char.displayValues.url} + {#if char.url} - {char.displayValues.name} + {char.name} {:else} - {char.displayValues.name} + {char.name} {/if} - {#if char.displayValues.epithets} + {#if char.epithets} - {Array.isArray(char.displayValues.epithets) - ? char.displayValues.epithets.join(', ') - : char.displayValues.epithets} + {Array.isArray(char.epithets) + ? char.epithets.join(', ') + : char.epithets} {/if}
- {char.displayValues.status || '-'} + {char.status || '-'} - {char.displayValues.gender || '-'} + {char.gender || '-'} - - {#if char.displayValues.affiliations} - {#if Array.isArray(char.displayValues.affiliations) && char.displayValues.affiliations.length > 0} - {char.displayValues.affiliations[0]} + + {#if char.affiliations} + {#if Array.isArray(char.affiliations) && char.affiliations.length > 0} + {char.affiliations[0]} {:else} - {char.displayValues.affiliations} + {char.affiliations} {/if} {:else} - {/if} - {char.displayValues.devilFruitName || '-'} + {char.devilFruitName || '-'} - +
- {#if char.displayValues.hakiObservation}👁️{/if} - {#if char.displayValues.hakiArmament}🦾{/if} - {#if char.displayValues.hakiConqueror}👑{/if} - {#if !char.displayValues.hakiObservation && !char.displayValues.hakiArmament && !char.displayValues.hakiConqueror} + {#if char.hakiObservation}👁️{/if} + {#if char.hakiArmament}🦾{/if} + {#if char.hakiConqueror}👑{/if} + {#if !char.hakiObservation && !char.hakiArmament && !char.hakiConqueror} - {/if}
- - {#if char.displayValues.bounty != null} - {formatBounty(char.displayValues.bounty)} ฿ + + {#if char.bounty != null} + {formatBounty(char.bounty)} ฿ {:else} - {/if} - - {#if char.displayValues.height} - {char.displayValues.height} m + + {#if char.height} + {char.height} m {:else} - {/if} - {char.displayValues.origin || '-'} + {char.origin || '-'} - {char.displayValues.arcName || '-'} + {char.arcName || '-'} - +
- +