mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
commit
196dfd48f6
137 changed files with 25129 additions and 2501 deletions
20
drizzle.config.ts
Normal file
20
drizzle.config.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import 'dotenv/config';
|
||||
import { defineConfig } from 'drizzle-kit';
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/schema.ts',
|
||||
out: './drizzle',
|
||||
driver: 'pg',
|
||||
dbCredentials: {
|
||||
host: process.env.DATABASE_HOST || 'localhost',
|
||||
port: Number(process.env.DATABASE_PORT) || 5432,
|
||||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE || 'boredgame',
|
||||
ssl: true
|
||||
},
|
||||
// Print all statements
|
||||
verbose: true,
|
||||
// Always as for confirmation
|
||||
strict: true
|
||||
});
|
||||
233
drizzle/0000_oval_wolverine.sql
Normal file
233
drizzle/0000_oval_wolverine.sql
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
CREATE TABLE IF NOT EXISTS "artists" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"external_id" integer,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "artists_to_games" (
|
||||
"artist_id" varchar(255),
|
||||
"game_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "categories" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"external_id" integer,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "categories_to_games" (
|
||||
"category_id" varchar(255),
|
||||
"game_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "collection_items" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"collection_id" varchar(255) NOT NULL,
|
||||
"game_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "collections" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"user_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "designers" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"external_id" integer,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "designers_to_games" (
|
||||
"designer_id" varchar(255),
|
||||
"game_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "expansions" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"base_game_id" varchar(255) NOT NULL,
|
||||
"game_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "games" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"description" text,
|
||||
"year_published" integer,
|
||||
"min_players" integer,
|
||||
"max_players" integer,
|
||||
"playtime" integer,
|
||||
"min_playtime" integer,
|
||||
"max_playtime" integer,
|
||||
"min_age" integer,
|
||||
"image_url" varchar(255),
|
||||
"thumb_url" varchar(255),
|
||||
"url" varchar(255),
|
||||
"external_id" integer,
|
||||
"last_sync_at" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6)),
|
||||
CONSTRAINT "games_external_id_unique" UNIQUE("external_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"external_id" integer,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics_to_games" (
|
||||
"mechanic_id" varchar(255),
|
||||
"game_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
"slug" varchar(255),
|
||||
"external_id" integer,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers_to_games" (
|
||||
"publisher_id" varchar(255),
|
||||
"game_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "roles" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255),
|
||||
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "sessions" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"user_id" varchar(255) NOT NULL,
|
||||
"expires_at" timestamp with time zone NOT NULL,
|
||||
"ip_country" varchar(255),
|
||||
"ip_address" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "user_roles" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"user_id" varchar(255) NOT NULL,
|
||||
"role_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"username" varchar(255),
|
||||
"hashed_password" varchar(255),
|
||||
"email" varchar(255),
|
||||
"first_name" varchar(255),
|
||||
"last_name" varchar(255),
|
||||
"verified" boolean DEFAULT false,
|
||||
"receive_email" boolean DEFAULT false,
|
||||
"theme" varchar(255) DEFAULT 'system',
|
||||
"created_at" timestamp DEFAULT (now(6)),
|
||||
"updated_at" timestamp DEFAULT (now(6)),
|
||||
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "wishlist_items" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"wishlist_id" varchar(255) NOT NULL,
|
||||
"game_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "wishlists" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"user_id" varchar(255) NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT (now(6)),
|
||||
"updated_at" timestamp with time zone DEFAULT (now(6))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_base_game_id_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_wishlist_id_wishlists_id_fk" FOREIGN KEY ("wishlist_id") REFERENCES "wishlists"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "wishlists" ADD CONSTRAINT "wishlists_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
51
drizzle/0001_giant_tomorrow_man.sql
Normal file
51
drizzle/0001_giant_tomorrow_man.sql
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
ALTER TABLE "artists" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "artists" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "artists" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "artists" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "last_sync_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "updated_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "created_at" SET DEFAULT (now());--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "updated_at" SET DEFAULT (now());
|
||||
27
drizzle/0002_sour_silverclaw.sql
Normal file
27
drizzle/0002_sour_silverclaw.sql
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
ALTER TABLE "artists" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "artists" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "categories" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "designers" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "games" ADD COLUMN "text_searchable_index" "tsvector";
|
||||
1
drizzle/0003_thick_tinkerer.sql
Normal file
1
drizzle/0003_thick_tinkerer.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
CREATE INDEX IF NOT EXISTS "text_searchable_idx" ON "games" ("text_searchable_index");
|
||||
30
drizzle/0004_fancy_umar.sql
Normal file
30
drizzle/0004_fancy_umar.sql
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
DO $$ BEGIN
|
||||
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "external_ids" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"type" varchar(255),
|
||||
"external_id" varchar(255)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "game_external_ids" (
|
||||
"game_id" varchar(255) NOT NULL,
|
||||
"external_id" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "games" DROP CONSTRAINT "games_external_id_unique";--> statement-breakpoint
|
||||
ALTER TABLE "games" DROP COLUMN IF EXISTS "external_id";--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "game_external_ids" ADD CONSTRAINT "game_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "game_external_ids" ADD CONSTRAINT "game_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
16
drizzle/0005_uneven_lifeguard.sql
Normal file
16
drizzle/0005_uneven_lifeguard.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
ALTER TABLE "game_external_ids" RENAME TO "games_to_external_ids";--> statement-breakpoint
|
||||
ALTER TABLE "games_to_external_ids" DROP CONSTRAINT "game_external_ids_game_id_games_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "games_to_external_ids" DROP CONSTRAINT "game_external_ids_external_id_external_ids_id_fk";
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
2
drizzle/0006_light_corsair.sql
Normal file
2
drizzle/0006_light_corsair.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "external_ids" ALTER COLUMN "type" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "external_ids" ALTER COLUMN "external_id" SET NOT NULL;
|
||||
71
drizzle/0007_same_valeria_richards.sql
Normal file
71
drizzle/0007_same_valeria_richards.sql
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
CREATE TABLE IF NOT EXISTS "categories_to_external_ids" (
|
||||
"category_id" varchar(255) NOT NULL,
|
||||
"external_id" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "expansions_to_external_ids" (
|
||||
"expansion_id" varchar(255) NOT NULL,
|
||||
"external_id" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics_to_external_ids" (
|
||||
"mechanic_id" varchar(255) NOT NULL,
|
||||
"external_id" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers_to_external_ids" (
|
||||
"publisher_id" varchar(255) NOT NULL,
|
||||
"external_id" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DROP TABLE "artists";--> statement-breakpoint
|
||||
DROP TABLE "artists_to_games";--> statement-breakpoint
|
||||
DROP TABLE "designers";--> statement-breakpoint
|
||||
DROP TABLE "designers_to_games";--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions_to_external_ids" ADD CONSTRAINT "expansions_to_external_ids_expansion_id_expansions_id_fk" FOREIGN KEY ("expansion_id") REFERENCES "expansions"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions_to_external_ids" ADD CONSTRAINT "expansions_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
7
drizzle/0008_complete_manta.sql
Normal file
7
drizzle/0008_complete_manta.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
DO $$ BEGIN
|
||||
CREATE TYPE "type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE type;
|
||||
7
drizzle/0009_equal_christian_walker.sql
Normal file
7
drizzle/0009_equal_christian_walker.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
DO $$ BEGIN
|
||||
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE external_id_type;
|
||||
1
drizzle/0010_flat_mister_sinister.sql
Normal file
1
drizzle/0010_flat_mister_sinister.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "collection_items" ADD COLUMN "times_played" integer DEFAULT 0;
|
||||
97
drizzle/0011_gigantic_mister_sinister.sql
Normal file
97
drizzle/0011_gigantic_mister_sinister.sql
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
ALTER TABLE "categories_to_external_ids" DROP CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "expansions" DROP CONSTRAINT "expansions_base_game_id_games_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "expansions_to_external_ids" DROP CONSTRAINT "expansions_to_external_ids_expansion_id_expansions_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "games_to_external_ids" DROP CONSTRAINT "games_to_external_ids_game_id_games_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "mechanics_to_external_ids" DROP CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "publishers_to_external_ids" DROP CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "categories_to_games" ALTER COLUMN "category_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "categories_to_games" ALTER COLUMN "game_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "mechanics_to_games" ALTER COLUMN "mechanic_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "mechanics_to_games" ALTER COLUMN "game_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "publishers_to_games" ALTER COLUMN "publisher_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "publishers_to_games" ALTER COLUMN "game_id" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_external_id_pk" PRIMARY KEY("category_id","external_id");--> statement-breakpoint
|
||||
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_game_id_pk" PRIMARY KEY("category_id","game_id");--> statement-breakpoint
|
||||
ALTER TABLE "expansions_to_external_ids" ADD CONSTRAINT "expansions_to_external_ids_expansion_id_external_id_pk" PRIMARY KEY("expansion_id","external_id");--> statement-breakpoint
|
||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_external_id_pk" PRIMARY KEY("game_id","external_id");--> statement-breakpoint
|
||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_external_id_pk" PRIMARY KEY("mechanic_id","external_id");--> statement-breakpoint
|
||||
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_game_id_pk" PRIMARY KEY("mechanic_id","game_id");--> statement-breakpoint
|
||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_external_id_pk" PRIMARY KEY("publisher_id","external_id");--> statement-breakpoint
|
||||
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_game_id_pk" PRIMARY KEY("publisher_id","game_id");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_base_game_id_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "expansions_to_external_ids" ADD CONSTRAINT "expansions_to_external_ids_expansion_id_expansions_id_fk" FOREIGN KEY ("expansion_id") REFERENCES "expansions"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
2
drizzle/0012_dizzy_lethal_legion.sql
Normal file
2
drizzle/0012_dizzy_lethal_legion.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "users" ALTER COLUMN "created_at" SET DATA TYPE timestamp (6) with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "updated_at" SET DATA TYPE timestamp (6) with time zone;
|
||||
3
drizzle/0013_clever_monster_badoon.sql
Normal file
3
drizzle/0013_clever_monster_badoon.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "categories" DROP COLUMN IF EXISTS "external_id";--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" DROP COLUMN IF EXISTS "external_id";--> statement-breakpoint
|
||||
ALTER TABLE "publishers" DROP COLUMN IF EXISTS "external_id";
|
||||
1
drizzle/0014_organic_morlocks.sql
Normal file
1
drizzle/0014_organic_morlocks.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE "expansions_to_external_ids";
|
||||
12
drizzle/0015_awesome_gabe_jones.sql
Normal file
12
drizzle/0015_awesome_gabe_jones.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
|
||||
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||
"user_id" varchar(255) NOT NULL,
|
||||
"expires_at" timestamp (6) with time zone,
|
||||
"created_at" timestamp (6) with time zone DEFAULT now()
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
1049
drizzle/meta/0000_snapshot.json
Normal file
1049
drizzle/meta/0000_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1049
drizzle/meta/0001_snapshot.json
Normal file
1049
drizzle/meta/0001_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1055
drizzle/meta/0002_snapshot.json
Normal file
1055
drizzle/meta/0002_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1063
drizzle/meta/0003_snapshot.json
Normal file
1063
drizzle/meta/0003_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1138
drizzle/meta/0004_snapshot.json
Normal file
1138
drizzle/meta/0004_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1138
drizzle/meta/0005_snapshot.json
Normal file
1138
drizzle/meta/0005_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1138
drizzle/meta/0006_snapshot.json
Normal file
1138
drizzle/meta/0006_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1194
drizzle/meta/0007_snapshot.json
Normal file
1194
drizzle/meta/0007_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1194
drizzle/meta/0008_snapshot.json
Normal file
1194
drizzle/meta/0008_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1194
drizzle/meta/0009_snapshot.json
Normal file
1194
drizzle/meta/0009_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1201
drizzle/meta/0010_snapshot.json
Normal file
1201
drizzle/meta/0010_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1346
drizzle/meta/0011_snapshot.json
Normal file
1346
drizzle/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1346
drizzle/meta/0012_snapshot.json
Normal file
1346
drizzle/meta/0012_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1328
drizzle/meta/0013_snapshot.json
Normal file
1328
drizzle/meta/0013_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1271
drizzle/meta/0014_snapshot.json
Normal file
1271
drizzle/meta/0014_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1320
drizzle/meta/0015_snapshot.json
Normal file
1320
drizzle/meta/0015_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
118
drizzle/meta/_journal.json
Normal file
118
drizzle/meta/_journal.json
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1707437865821,
|
||||
"tag": "0000_oval_wolverine",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "5",
|
||||
"when": 1707438055782,
|
||||
"tag": "0001_giant_tomorrow_man",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "5",
|
||||
"when": 1707524139123,
|
||||
"tag": "0002_sour_silverclaw",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "5",
|
||||
"when": 1707526808124,
|
||||
"tag": "0003_thick_tinkerer",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "5",
|
||||
"when": 1707932397672,
|
||||
"tag": "0004_fancy_umar",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "5",
|
||||
"when": 1707932466413,
|
||||
"tag": "0005_uneven_lifeguard",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "5",
|
||||
"when": 1707932522909,
|
||||
"tag": "0006_light_corsair",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "5",
|
||||
"when": 1707951501716,
|
||||
"tag": "0007_same_valeria_richards",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "5",
|
||||
"when": 1708105454143,
|
||||
"tag": "0008_complete_manta",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "5",
|
||||
"when": 1708105890146,
|
||||
"tag": "0009_equal_christian_walker",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "5",
|
||||
"when": 1708243232524,
|
||||
"tag": "0010_flat_mister_sinister",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "5",
|
||||
"when": 1708330668971,
|
||||
"tag": "0011_gigantic_mister_sinister",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"version": "5",
|
||||
"when": 1708330799655,
|
||||
"tag": "0012_dizzy_lethal_legion",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 13,
|
||||
"version": "5",
|
||||
"when": 1708453431550,
|
||||
"tag": "0013_clever_monster_badoon",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"version": "5",
|
||||
"when": 1708479971410,
|
||||
"tag": "0014_organic_morlocks",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 15,
|
||||
"version": "5",
|
||||
"when": 1709344835732,
|
||||
"tag": "0015_awesome_gabe_jones",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
74
package.json
74
package.json
|
|
@ -16,57 +16,61 @@
|
|||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||
"format": "prettier --plugin-search-dir . --write .",
|
||||
"site:update": "pnpm update -i -L",
|
||||
"db:studio": "prisma studio",
|
||||
"db:push": "prisma db push",
|
||||
"db:generate": "prisma generate",
|
||||
"db:seed": "prisma db seed",
|
||||
"i-changed-the-schema": "pnpm run db:push && pnpm run db:generate"
|
||||
"generate": "drizzle-kit generate:pg",
|
||||
"migrate": "tsx ./src/migrate.ts",
|
||||
"seed": "tsx ./src/seed.ts",
|
||||
"push": "drizzle-kit push:pg"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "node --loader ts-node/esm prisma/seed.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@melt-ui/pp": "^0.3.0",
|
||||
"@melt-ui/svelte": "^0.73.0",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"@melt-ui/svelte": "^0.75.2",
|
||||
"@playwright/test": "^1.42.0",
|
||||
"@resvg/resvg-js": "^2.6.0",
|
||||
"@sveltejs/adapter-auto": "^3.1.1",
|
||||
"@sveltejs/enhanced-img": "^0.1.8",
|
||||
"@sveltejs/kit": "^2.5.0",
|
||||
"@sveltejs/kit": "^2.5.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/node": "^20.11.17",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/pg": "^8.11.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"eslint": "^8.56.0",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-kit": "^0.20.14",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"just-clone": "^6.2.0",
|
||||
"just-debounce-it": "^3.2.0",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-import": "^16.0.0",
|
||||
"postcss-import": "^16.0.1",
|
||||
"postcss-load-config": "^5.0.3",
|
||||
"postcss-preset-env": "^9.3.0",
|
||||
"postcss-preset-env": "^9.4.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"prettier-plugin-svelte": "^3.2.2",
|
||||
"prisma": "^5.9.1",
|
||||
"sass": "^1.70.0",
|
||||
"sass": "^1.71.1",
|
||||
"satori": "^0.10.13",
|
||||
"satori-html": "^0.3.2",
|
||||
"svelte": "^4.2.10",
|
||||
"svelte-check": "^3.6.4",
|
||||
"svelte-meta-tags": "^3.1.0",
|
||||
"svelte": "^4.2.12",
|
||||
"svelte-check": "^3.6.6",
|
||||
"svelte-meta-tags": "^3.1.1",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"sveltekit-flash-message": "^2.4.1",
|
||||
"sveltekit-superforms": "^1.13.4",
|
||||
"sveltekit-flash-message": "^2.4.2",
|
||||
"sveltekit-rate-limiter": "^0.4.3",
|
||||
"sveltekit-superforms": "^2.7.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.6.1",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.1",
|
||||
"vitest": "^1.2.2",
|
||||
"vite": "^5.1.5",
|
||||
"vitest": "^1.3.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"type": "module",
|
||||
|
|
@ -75,37 +79,45 @@
|
|||
"pnpm": ">=8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/fira-mono": "^5.0.8",
|
||||
"@fontsource/fira-mono": "^5.0.12",
|
||||
"@iconify-icons/line-md": "^1.2.26",
|
||||
"@iconify-icons/mdi": "^1.2.47",
|
||||
"@lucia-auth/adapter-drizzle": "^1.0.2",
|
||||
"@lucia-auth/adapter-prisma": "4.0.0",
|
||||
"@lukeed/uuid": "^2.0.1",
|
||||
"@neondatabase/serverless": "^0.9.0",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@planetscale/database": "^1.16.0",
|
||||
"@prisma/client": "^5.9.1",
|
||||
"@sentry/sveltekit": "^7.88.0",
|
||||
"@sentry/sveltekit": "^7.100.1",
|
||||
"@sveltejs/adapter-vercel": "^5.1.0",
|
||||
"@types/feather-icons": "^4.29.4",
|
||||
"@vercel/og": "^0.5.20",
|
||||
"bits-ui": "^0.17.0",
|
||||
"bits-ui": "^0.19.3",
|
||||
"boardgamegeekclient": "^1.9.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"cookie": "^0.6.0",
|
||||
"drizzle-orm": "^0.29.4",
|
||||
"feather-icons": "^4.29.1",
|
||||
"formsnap": "^0.4.3",
|
||||
"html-entities": "^2.4.0",
|
||||
"formsnap": "^0.5.1",
|
||||
"html-entities": "^2.5.2",
|
||||
"iconify-icon": "^2.0.0",
|
||||
"just-kebab-case": "^4.2.0",
|
||||
"loader": "^2.1.1",
|
||||
"lucia": "3.0.1",
|
||||
"lucide-svelte": "^0.323.0",
|
||||
"open-props": "^1.6.18",
|
||||
"oslo": "^1.1.0",
|
||||
"lucide-svelte": "^0.344.0",
|
||||
"mysql2": "^3.9.2",
|
||||
"nanoid": "^5.0.6",
|
||||
"open-props": "^1.6.20",
|
||||
"oslo": "^1.1.3",
|
||||
"pg": "^8.11.3",
|
||||
"postgres": "^3.4.3",
|
||||
"radix-svelte": "^0.9.0",
|
||||
"svelte-french-toast": "^1.2.0",
|
||||
"svelte-lazy-loader": "^1.0.0",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwind-variants": "^0.1.20",
|
||||
"tailwind-variants": "^0.2.0",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"zod-to-json-schema": "^3.22.4"
|
||||
}
|
||||
|
|
|
|||
3278
pnpm-lock.yaml
3278
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -158,7 +158,6 @@ model Game {
|
|||
image_url String?
|
||||
thumb_url String?
|
||||
url String?
|
||||
rules_url String?
|
||||
categories Category[]
|
||||
mechanics Mechanic[]
|
||||
designers Designer[]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="Bored? Find a game! Bored Game!" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon-bored.png" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon-bored-game.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<script>
|
||||
// const htmlElement = document.documentElement;
|
||||
|
|
|
|||
1
src/lib/assets/bored-game.svg
Normal file
1
src/lib/assets/bored-game.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -1,12 +1,9 @@
|
|||
<script>
|
||||
import { PUBLIC_SITE_URL } from "$env/static/public";
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
<p>Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a></p>
|
||||
<p>
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://www.flaticon.com/free-icons/board-game"
|
||||
title="board game icons">Board game icons created by Freepik - Flaticon</a
|
||||
>
|
||||
</p>
|
||||
<p>Bored Game © {new Date().getFullYear()} | Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a> | {PUBLIC_SITE_URL}</p>
|
||||
</footer>
|
||||
|
||||
<style lang="postcss">
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
<script lang="ts">
|
||||
import { applyAction, enhance } from '$app/forms';
|
||||
import toast from 'svelte-french-toast';
|
||||
import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte';
|
||||
import * as DropdownMenu from "$components/ui/dropdown-menu";
|
||||
import * as Avatar from "$components/ui/avatar";
|
||||
import Logo from '$components/logo.svelte';
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import toast from 'svelte-french-toast';
|
||||
import Logo from '$components/logo.svelte';
|
||||
|
||||
export let user;
|
||||
export let user: User | null;
|
||||
|
||||
let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div class="corner">
|
||||
<a href="/" class="logo" title="Home">
|
||||
<a href="/" title="Home">
|
||||
<div class="logo-image">
|
||||
<Logo />
|
||||
</div>
|
||||
Bored Game
|
||||
</a>
|
||||
</div>
|
||||
<!-- <TextSearch /> -->
|
||||
|
|
@ -113,23 +114,23 @@
|
|||
}
|
||||
|
||||
.corner {
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.corner a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.logo-image {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
nav {
|
||||
|
|
@ -154,8 +155,4 @@
|
|||
text-decoration: underline;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.separator {
|
||||
@apply m-[5px] h-[1px] bg-black;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
export let kind = 'primary';
|
||||
export let size;
|
||||
export let icon = false;
|
||||
export let disabled = false;
|
||||
</script>
|
||||
|
|
@ -27,18 +26,4 @@
|
|||
min-width: 23.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: var(--warning);
|
||||
}
|
||||
|
||||
.danger:hover {
|
||||
background-color: var(--warning-hover);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, auto);
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
<script lang="ts">
|
||||
import logo from '$lib/assets/bored-game.png';
|
||||
</script>
|
||||
|
||||
<img src={logo} alt="Bored Game Home" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-go-game" viewBox="0 0 24 24"
|
||||
stroke-width="1" stroke="var(--fg)" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M6 18m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M18 18m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M3 12h7m4 0h7" />
|
||||
<path d="M3 6h1m4 0h13" />
|
||||
<path d="M3 18h1m4 0h8m4 0h1" />
|
||||
<path d="M6 3v1m0 4v8m0 4v1" />
|
||||
<path d="M12 3v7m0 4v7" />
|
||||
<path d="M18 3v13m0 4v1" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 671 B |
|
|
@ -1,38 +1,54 @@
|
|||
<script lang="ts">
|
||||
import type { SuperValidated } from 'sveltekit-superforms';
|
||||
import { superForm, type Infer, type SuperValidated } from 'sveltekit-superforms';
|
||||
import { search_schema, type SearchSchema } from '$lib/zodValidation';
|
||||
import * as Form from "$lib/components/ui/form";
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
import Input from '$components/ui/input/input.svelte';
|
||||
import Checkbox from '$components/ui/checkbox/checkbox.svelte';
|
||||
|
||||
export let form: SuperValidated<SearchSchema>;
|
||||
export let data: SuperValidated<Infer<SearchSchema>>;
|
||||
|
||||
const form = superForm(data, {
|
||||
validators: zodClient(search_schema),
|
||||
});
|
||||
|
||||
const { form: formData } = form;
|
||||
</script>
|
||||
|
||||
<search>
|
||||
<Form.Root id="search-form" action="/search" method="GET" data-sveltekit-reload {form} schema={search_schema} let:config>
|
||||
<form id="search-form" action="/search" method="GET" data-sveltekit-reload>
|
||||
<fieldset>
|
||||
<Form.Item>
|
||||
<Form.Field {config} name="q">
|
||||
<Form.Label for="label">Search</Form.Label>
|
||||
<Form.Input />
|
||||
<Form.Validation />
|
||||
</Form.Field>
|
||||
<Form.Field {config} name="skip">
|
||||
<Form.Input type="hidden" />
|
||||
</Form.Field>
|
||||
<Form.Field {config} name="limit">
|
||||
<Form.Input type="hidden" />
|
||||
</Form.Field>
|
||||
</Form.Item>
|
||||
<Form.Field {form} name="q">
|
||||
<Form.Control let:attrs>
|
||||
<Form.Label>Search</Form.Label>
|
||||
<Input {...attrs} bind:value={$formData.q} />
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Field {form} name="skip">
|
||||
<Form.Control let:attrs>
|
||||
<Input type="hidden" />
|
||||
</Form.Control>
|
||||
</Form.Field>
|
||||
<Form.Field {form} name="limit">
|
||||
<Form.Control let:attrs>
|
||||
<Input type="hidden" />
|
||||
</Form.Control>
|
||||
</Form.Field>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Form.Field {config} name="exact">
|
||||
<Form.Label>Exact Search</Form.Label>
|
||||
<Form.Checkbox class="mt-0" />
|
||||
<Form.Field {form} name="exact">
|
||||
<Form.Control let:attrs>
|
||||
<Form.Label>Exact Search</Form.Label>
|
||||
<Checkbox {...attrs} class="mt-0" bind:checked={$formData.exact} />
|
||||
<input name={attrs.name} value={$formData.exact} hidden />
|
||||
</Form.Control>
|
||||
</Form.Field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<Form.Button>Submit</Form.Button>
|
||||
</Form.Root>
|
||||
</form>
|
||||
</search>
|
||||
|
||||
<style lang="postcss">
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
import { ConicGradient } from '@skeletonlabs/skeleton';
|
||||
import type { ConicStop } from '@skeletonlabs/skeleton';
|
||||
import { i } from "@inlang/sdk-js";
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
//import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
|
||||
import { userSchema } from '$lib/config/zod-schemas';
|
||||
import { userSchema } from '$lib/validations/zod-schemas';
|
||||
import { AlertTriangle } from 'lucide-svelte';
|
||||
import { i } from "@inlang/sdk-js";
|
||||
import { signInSchema } from '$lib/validations/auth';
|
||||
export let data;
|
||||
const signInSchema = userSchema.pick({ email: true, password: true });
|
||||
|
||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||
taintedMessage: null,
|
||||
validators: signInSchema,
|
||||
validators: zodClient(signInSchema),
|
||||
delayMs: 0
|
||||
});
|
||||
const conicStops: ConicStop[] = [
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import { userSchema } from '$lib/config/zod-schemas';
|
||||
import { signUpSchema } from '$lib/validations/auth';
|
||||
|
||||
export let data;
|
||||
|
||||
const signUpSchema = userSchema.pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
username: true,
|
||||
email: true,
|
||||
password: true
|
||||
});
|
||||
|
||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||
const { form, errors, enhance } = superForm(data.form, {
|
||||
taintedMessage: null,
|
||||
validators: signUpSchema,
|
||||
validators: zodClient(signUpSchema),
|
||||
delayMs: 0
|
||||
});
|
||||
// $: termsValue = $form.terms as Writable<boolean>;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@
|
|||
</script>
|
||||
|
||||
<AvatarPrimitive.Fallback
|
||||
class={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
)}
|
||||
class={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@
|
|||
|
||||
<AvatarPrimitive.Root
|
||||
{delayMs}
|
||||
class={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
)}
|
||||
class={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ export {
|
|||
//
|
||||
Root as Avatar,
|
||||
Image as AvatarImage,
|
||||
Fallback as AvatarFallback
|
||||
Fallback as AvatarFallback,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,19 +12,19 @@ const buttonVariants = tv({
|
|||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline"
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10"
|
||||
}
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default"
|
||||
}
|
||||
size: "default",
|
||||
},
|
||||
});
|
||||
|
||||
type Variant = VariantProps<typeof buttonVariants>["variant"];
|
||||
|
|
@ -45,5 +45,5 @@ export {
|
|||
Root as Button,
|
||||
type Props as ButtonProps,
|
||||
type Events as ButtonEvents,
|
||||
buttonVariants
|
||||
buttonVariants,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@
|
|||
</script>
|
||||
|
||||
<div
|
||||
class={cn(
|
||||
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
||||
className
|
||||
)}
|
||||
class={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export {
|
|||
Description as CardDescription,
|
||||
Footer as CardFooter,
|
||||
Header as CardHeader,
|
||||
Title as CardTitle
|
||||
Title as CardTitle,
|
||||
};
|
||||
|
||||
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
export let transition: $$Props["transition"] = slide;
|
||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||
duration: 150
|
||||
duration: 150,
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,5 +11,5 @@ export {
|
|||
//
|
||||
Root as Collapsible,
|
||||
Content as CollapsibleContent,
|
||||
Trigger as CollapsibleTrigger
|
||||
Trigger as CollapsibleTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import Check from "lucide-svelte/icons/check";
|
||||
import { cn } from "$lib/utils";
|
||||
import { Check } from "lucide-svelte";
|
||||
|
||||
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
||||
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<DropdownMenuPrimitive.CheckboxItem
|
||||
bind:checked
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||
export let transition: $$Props["transition"] = flyAndScale;
|
||||
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||
export { className as class };
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
<DropdownMenuPrimitive.Content
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
{sideOffset}
|
||||
class={cn(
|
||||
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||
className
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<DropdownMenuPrimitive.Item
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import Circle from "lucide-svelte/icons/circle";
|
||||
import { cn } from "$lib/utils";
|
||||
import { Circle } from "lucide-svelte";
|
||||
|
||||
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
||||
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{value}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@
|
|||
export { className as class };
|
||||
</script>
|
||||
|
||||
<span
|
||||
class={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<span class={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
export let transition: $$Props["transition"] = flyAndScale;
|
||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||
x: -10,
|
||||
y: 0
|
||||
y: 0,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||
import { cn } from "$lib/utils";
|
||||
import { ChevronRight } from "lucide-svelte";
|
||||
|
||||
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
||||
inset?: boolean;
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
class={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent",
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -44,5 +44,5 @@ export {
|
|||
RadioGroup as DropdownMenuRadioGroup,
|
||||
SubContent as DropdownMenuSubContent,
|
||||
SubTrigger as DropdownMenuSubTrigger,
|
||||
CheckboxItem as DropdownMenuCheckboxItem
|
||||
CheckboxItem as DropdownMenuCheckboxItem,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import * as Button from "$lib/components/ui/button";
|
||||
|
||||
type $$Props = Button.Props;
|
||||
type $$Events = Button.Events;
|
||||
</script>
|
||||
|
||||
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
|
||||
<Button.Root type="submit" {...$$restProps}>
|
||||
<slot />
|
||||
</Button.Root>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { Form as FormPrimitive } from "formsnap";
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Description class={cn("text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
<FormPrimitive.Description
|
||||
class={cn("text-sm text-muted-foreground", className)}
|
||||
{...$$restProps}
|
||||
let:descriptionAttrs
|
||||
>
|
||||
<slot {descriptionAttrs} />
|
||||
</FormPrimitive.Description>
|
||||
|
|
|
|||
26
src/lib/components/ui/form/form-element-field.svelte
Normal file
26
src/lib/components/ui/form/form-element-field.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts" context="module">
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import type { FormPathLeaves, SuperForm } from "sveltekit-superforms";
|
||||
type T = Record<string, unknown>;
|
||||
type U = unknown;
|
||||
</script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||
|
||||
export let form: SuperForm<T>;
|
||||
export let name: U;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.ElementField {form} {name} let:constraints let:errors let:tainted let:value>
|
||||
<div class={cn("space-y-2", className)}>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</div>
|
||||
</FormPrimitive.ElementField>
|
||||
26
src/lib/components/ui/form/form-field-errors.svelte
Normal file
26
src/lib/components/ui/form/form-field-errors.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = FormPrimitive.FieldErrorsProps & {
|
||||
errorClasses?: string | undefined | null;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
export let errorClasses: $$Props["class"] = undefined;
|
||||
</script>
|
||||
|
||||
<FormPrimitive.FieldErrors
|
||||
class={cn("text-sm font-medium text-destructive", className)}
|
||||
{...$$restProps}
|
||||
let:errors
|
||||
let:fieldErrorsAttrs
|
||||
let:errorAttrs
|
||||
>
|
||||
<slot {errors} {fieldErrorsAttrs} {errorAttrs}>
|
||||
{#each errors as error}
|
||||
<div {...errorAttrs} class={cn(errorClasses)}>{error}</div>
|
||||
{/each}
|
||||
</slot>
|
||||
</FormPrimitive.FieldErrors>
|
||||
26
src/lib/components/ui/form/form-field.svelte
Normal file
26
src/lib/components/ui/form/form-field.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts" context="module">
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||
type T = Record<string, unknown>;
|
||||
type U = unknown;
|
||||
</script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||
|
||||
export let form: SuperForm<T>;
|
||||
export let name: U;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Field {form} {name} let:constraints let:errors let:tainted let:value>
|
||||
<div class={cn("space-y-2", className)}>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</div>
|
||||
</FormPrimitive.Field>
|
||||
31
src/lib/components/ui/form/form-fieldset.svelte
Normal file
31
src/lib/components/ui/form/form-fieldset.svelte
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<script lang="ts" context="module">
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||
type T = Record<string, unknown>;
|
||||
type U = unknown;
|
||||
</script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = FormPrimitive.FieldsetProps<T, U>;
|
||||
|
||||
export let form: SuperForm<T>;
|
||||
export let name: U;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Fieldset
|
||||
{form}
|
||||
{name}
|
||||
let:constraints
|
||||
let:errors
|
||||
let:tainted
|
||||
let:value
|
||||
class={cn("space-y-2", className)}
|
||||
>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</FormPrimitive.Fieldset>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { Label as LabelPrimitive } from "bits-ui";
|
||||
import { getFormField } from "formsnap";
|
||||
import { getFormControl } from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
|
||||
|
|
@ -9,9 +9,9 @@
|
|||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
|
||||
const { errors, ids } = getFormField();
|
||||
const { labelAttrs } = getFormControl();
|
||||
</script>
|
||||
|
||||
<Label for={$ids.input} class={cn($errors && "text-destructive", className)} {...$$restProps}>
|
||||
<slot />
|
||||
<Label {...$labelAttrs} class={cn("data-[fs-error]:text-destructive", className)} {...$$restProps}>
|
||||
<slot {labelAttrs} />
|
||||
</Label>
|
||||
|
|
|
|||
17
src/lib/components/ui/form/form-legend.svelte
Normal file
17
src/lib/components/ui/form/form-legend.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<script lang="ts">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = FormPrimitive.LegendProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Legend
|
||||
{...$$restProps}
|
||||
class={cn("text-sm font-medium leading-none data-[fs-error]:text-destructive", className)}
|
||||
let:legendAttrs
|
||||
>
|
||||
<slot {legendAttrs} />
|
||||
</FormPrimitive.Legend>
|
||||
|
|
@ -1,82 +1,33 @@
|
|||
import { Form as FormPrimitive, getFormField } from "formsnap";
|
||||
import * as RadioGroupComp from "$lib/components/ui/radio-group";
|
||||
import * as SelectComp from "$lib/components/ui/select";
|
||||
import type { Writable } from "svelte/store";
|
||||
import Item from "./form-item.svelte";
|
||||
import Input from "./form-input.svelte";
|
||||
import Textarea from "./form-textarea.svelte";
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import Description from "./form-description.svelte";
|
||||
import Label from "./form-label.svelte";
|
||||
import Validation from "./form-validation.svelte";
|
||||
import Checkbox from "./form-checkbox.svelte";
|
||||
import Switch from "./form-switch.svelte";
|
||||
import NativeSelect from "./form-native-select.svelte";
|
||||
import RadioGroup from "./form-radio-group.svelte";
|
||||
import Select from "./form-select.svelte";
|
||||
import SelectTrigger from "./form-select-trigger.svelte";
|
||||
import FieldErrors from "./form-field-errors.svelte";
|
||||
import Field from "./form-field.svelte";
|
||||
import Fieldset from "./form-fieldset.svelte";
|
||||
import Legend from "./form-legend.svelte";
|
||||
import ElementField from "./form-element-field.svelte";
|
||||
import Button from "./form-button.svelte";
|
||||
|
||||
const Root = FormPrimitive.Root;
|
||||
const Field = FormPrimitive.Field;
|
||||
const Control = FormPrimitive.Control;
|
||||
const RadioItem = RadioGroupComp.Item;
|
||||
const NativeRadio = FormPrimitive.Radio;
|
||||
const SelectContent = SelectComp.Content;
|
||||
const SelectLabel = SelectComp.Label;
|
||||
const SelectGroup = SelectComp.Group;
|
||||
const SelectItem = SelectComp.Item;
|
||||
const SelectSeparator = SelectComp.Separator;
|
||||
|
||||
export type TextareaGetFormField = Omit<ReturnType<typeof getFormField>, "value"> & {
|
||||
value: Writable<string>;
|
||||
};
|
||||
|
||||
export {
|
||||
Root,
|
||||
Field,
|
||||
Control,
|
||||
Item,
|
||||
Input,
|
||||
Label,
|
||||
Button,
|
||||
Switch,
|
||||
Select,
|
||||
Checkbox,
|
||||
Textarea,
|
||||
Validation,
|
||||
RadioGroup,
|
||||
RadioItem,
|
||||
FieldErrors,
|
||||
Description,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
NativeSelect,
|
||||
NativeRadio,
|
||||
Fieldset,
|
||||
Legend,
|
||||
ElementField,
|
||||
//
|
||||
Root as Form,
|
||||
Field as FormField,
|
||||
Control as FormControl,
|
||||
Item as FormItem,
|
||||
Input as FormInput,
|
||||
Textarea as FormTextarea,
|
||||
Description as FormDescription,
|
||||
Label as FormLabel,
|
||||
Validation as FormValidation,
|
||||
NativeSelect as FormNativeSelect,
|
||||
NativeRadio as FormNativeRadio,
|
||||
Checkbox as FormCheckbox,
|
||||
Switch as FormSwitch,
|
||||
RadioGroup as FormRadioGroup,
|
||||
RadioItem as FormRadioItem,
|
||||
Select as FormSelect,
|
||||
SelectContent as FormSelectContent,
|
||||
SelectLabel as FormSelectLabel,
|
||||
SelectGroup as FormSelectGroup,
|
||||
SelectItem as FormSelectItem,
|
||||
SelectSeparator as FormSelectSeparator,
|
||||
SelectTrigger as FormSelectTrigger,
|
||||
Button as FormButton
|
||||
FieldErrors as FormFieldErrors,
|
||||
Fieldset as FormFieldset,
|
||||
Legend as FormLegend,
|
||||
ElementField as FormElementField,
|
||||
Button as FormButton,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ import Root from "./label.svelte";
|
|||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Label
|
||||
Root as Label,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,5 +20,5 @@ export {
|
|||
Link as PaginationLink,
|
||||
PrevButton as PaginationPrevButton,
|
||||
NextButton as PaginationNextButton,
|
||||
Ellipsis as PaginationEllipsis
|
||||
Ellipsis as PaginationEllipsis,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import MoreHorizontal from "lucide-svelte/icons/more-horizontal";
|
||||
import { cn } from "$lib/utils";
|
||||
import { MoreHorizontal } from "lucide-svelte";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
class={cn(
|
||||
buttonVariants({
|
||||
variant: isActive ? "outline" : "ghost",
|
||||
size
|
||||
size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { cn } from "$lib/utils";
|
||||
import { ChevronRight } from "lucide-svelte";
|
||||
|
||||
type $$Props = PaginationPrimitive.NextButtonProps;
|
||||
type $$Events = PaginationPrimitive.NextButtonEvents;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import ChevronLeft from "lucide-svelte/icons/chevron-left";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { cn } from "$lib/utils";
|
||||
import { ChevronLeft } from "lucide-svelte";
|
||||
|
||||
type $$Props = PaginationPrimitive.PrevButtonProps;
|
||||
type $$Events = PaginationPrimitive.PrevButtonEvents;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
asChild
|
||||
{...$$restProps}
|
||||
>
|
||||
<nav {...builder} class={cn("mx-auto flex flex-col w-full items-center", className)}>
|
||||
<nav {...builder} class={cn("mx-auto flex w-full flex-col items-center", className)}>
|
||||
<slot {pages} {range} {currentPage} />
|
||||
</nav>
|
||||
</PaginationPrimitive.Root>
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export type ListGame = {
|
||||
id: string;
|
||||
game_name: string;
|
||||
game_id: string;
|
||||
collection_id: string;
|
||||
wishlist_id: string;
|
||||
times_played: number;
|
||||
thumb_url: string | null;
|
||||
in_collection: boolean;
|
||||
in_wishlist: boolean;
|
||||
};
|
||||
|
||||
export const modifyListGameSchema = z.object({
|
||||
id: z.string()
|
||||
});
|
||||
|
||||
export type ModifyListGame = typeof modifyListGameSchema;
|
||||
|
||||
export const userSchema = z.object({
|
||||
firstName: z.string().trim().optional(),
|
||||
lastName: z.string().trim().optional(),
|
||||
email: z.string().email({ message: 'Please enter a valid email address' }).optional(),
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(3, { message: 'Username must be at least 3 characters' })
|
||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||
password: z
|
||||
.string({ required_error: 'Password is required' })
|
||||
.trim()
|
||||
.min(8, { message: 'Password must be at least 8 characters' })
|
||||
.max(128, { message: 'Password must be less than 128 characters' }),
|
||||
confirm_password: z
|
||||
.string({ required_error: 'Confirm Password is required' })
|
||||
.trim()
|
||||
.min(8, { message: 'Confirm Password must be at least 8 characters' }),
|
||||
role: z.enum(['USER', 'ADMIN'], { required_error: 'You must have a role' }).default('USER'),
|
||||
verified: z.boolean().default(false),
|
||||
token: z.string().optional(),
|
||||
receiveEmail: z.boolean().default(false),
|
||||
createdAt: z.date().optional(),
|
||||
updatedAt: z.date().optional()
|
||||
});
|
||||
|
||||
export const signUpSchema = userSchema
|
||||
.pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
email: true,
|
||||
username: true,
|
||||
password: true,
|
||||
confirm_password: true,
|
||||
terms: true
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
if (confirm_password !== password) {
|
||||
// ctx.addIssue({
|
||||
// code: 'custom',
|
||||
// message: 'Password and Confirm Password must match',
|
||||
// path: ['password']
|
||||
// });
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: ' Password and Confirm Password must match',
|
||||
path: ['confirm_password']
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const signInSchema = userSchema.pick({
|
||||
username: true,
|
||||
password: true
|
||||
});
|
||||
|
||||
export const updateUserPasswordSchema = userSchema
|
||||
.pick({ password: true, confirm_password: true })
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
if (confirm_password !== password) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['password']
|
||||
});
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['confirm_password']
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const changeUserPasswordSchema = z
|
||||
.object({
|
||||
current_password: z.string({ required_error: 'Current Password is required' }),
|
||||
password: z
|
||||
.string({ required_error: 'Password is required' })
|
||||
.trim()
|
||||
.min(8, { message: 'Password must be at least 8 characters' })
|
||||
.max(128, { message: 'Password must be less than 128 characters' }),
|
||||
confirm_password: z
|
||||
.string({ required_error: 'Confirm Password is required' })
|
||||
.trim()
|
||||
.min(8, { message: 'Confirm Password must be at least 8 characters' })
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
if (confirm_password !== password) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['password']
|
||||
});
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['confirm_password']
|
||||
});
|
||||
}
|
||||
});
|
||||
30
src/lib/drizzle.ts
Normal file
30
src/lib/drizzle.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pg from 'pg';
|
||||
import {
|
||||
DATABASE_USER,
|
||||
DATABASE_PASSWORD,
|
||||
DATABASE_HOST,
|
||||
DATABASE_DB,
|
||||
DATABASE_PORT,
|
||||
} from '$env/static/private';
|
||||
import * as schema from '../schema';
|
||||
|
||||
// create the connection
|
||||
const pool = new pg.Pool({
|
||||
user: DATABASE_USER,
|
||||
password: DATABASE_PASSWORD,
|
||||
host: DATABASE_HOST,
|
||||
port: Number(DATABASE_PORT).valueOf(),
|
||||
database: DATABASE_DB,
|
||||
ssl: true,
|
||||
});
|
||||
|
||||
// user: DATABASE_USER,
|
||||
// password: DATABASE_PASSWORD,
|
||||
// host: DATABASE_HOST,
|
||||
// port: Number(DATABASE_PORT).valueOf(),
|
||||
// database: DATABASE_DB
|
||||
|
||||
const db = drizzle(pool, { schema });
|
||||
|
||||
export default db;
|
||||
1
src/lib/flashMessages.ts
Normal file
1
src/lib/flashMessages.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const notSignedInMessage = { type: 'error', message: 'You are not signed in' } as const;
|
||||
|
|
@ -5,7 +5,7 @@ import { dev } from '$app/environment';
|
|||
import { read } from '$app/server';
|
||||
|
||||
// we use a Vite plugin to turn this import into the result of fs.readFileSync during build
|
||||
import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf';
|
||||
import firaSansSemiBold from '$lib/fonts/FiraSans-Bold.ttf';
|
||||
|
||||
const fontData = read(firaSansSemiBold).arrayBuffer();
|
||||
|
||||
|
|
|
|||
19
src/lib/server/auth-utils.ts
Normal file
19
src/lib/server/auth-utils.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import db from "$lib/drizzle";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { password_reset_tokens } from "../../schema";
|
||||
import { generateId } from "lucia";
|
||||
import { TimeSpan, createDate } from "oslo";
|
||||
|
||||
export async function createPasswordResetToken(userId: string): Promise<string> {
|
||||
// optionally invalidate all existing tokens
|
||||
await db.delete(password_reset_tokens).where(eq(password_reset_tokens.user_id, userId));
|
||||
const tokenId = generateId(40);
|
||||
await db
|
||||
.insert(password_reset_tokens)
|
||||
.values({
|
||||
id: tokenId,
|
||||
user_id: userId,
|
||||
expires_at: createDate(new TimeSpan(2, "h"))
|
||||
});
|
||||
return tokenId;
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
// lib/server/lucia.ts
|
||||
import { Lucia, TimeSpan } from 'lucia';
|
||||
import { PrismaAdapter } from '@lucia-auth/adapter-prisma';
|
||||
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
||||
import { dev } from '$app/environment';
|
||||
import prisma_client from '$lib/prisma';
|
||||
import db from '$lib/drizzle';
|
||||
import { sessions, users } from '../../schema';
|
||||
|
||||
const adapter = new PrismaAdapter(prisma_client.session, prisma_client.user);
|
||||
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
|
||||
|
||||
export const lucia = new Lucia(adapter, {
|
||||
getSessionAttributes: (attributes) => {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
--input: 20 5.9% 90%;
|
||||
--ring: 20 14.3% 4.1%;
|
||||
--radius: 0.5rem;
|
||||
--fg: #2c3e50;
|
||||
}
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 35.5 91.7% 32.9%;
|
||||
--fg: #ffff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
3
src/lib/utils/authUtils.ts
Normal file
3
src/lib/utils/authUtils.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export const normalizeEmail = (email: string): string => {
|
||||
return decodeURIComponent(email).toLowerCase().trim();
|
||||
};
|
||||
77
src/lib/utils/db/categoryUtils.ts
Normal file
77
src/lib/utils/db/categoryUtils.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, type Mechanics, type Categories, categories, categoriesToExternalIds } from '../../../schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function createCategory(locals: App.Locals, category: Categories, externalId: string) {
|
||||
if (!category || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
const foundCategory = await db
|
||||
.select({
|
||||
id: categories.id,
|
||||
name: categories.name,
|
||||
slug: categories.slug
|
||||
})
|
||||
.from(categories)
|
||||
.leftJoin(categoriesToExternalIds, eq(categoriesToExternalIds.externalId, externalId));
|
||||
console.log('Mechanic already exists', foundCategory);
|
||||
if (foundCategory.length > 0) {
|
||||
console.log('Mechanic name', foundCategory[0].name);
|
||||
return new Response('Mechanic already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundCategory[0].id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let dbCategory: Mechanics[] = [];
|
||||
console.log('Creating category', JSON.stringify(category, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbCategory = await transaction
|
||||
.insert(categories)
|
||||
.values({
|
||||
name: category.name,
|
||||
slug: kebabCase(category.name || category.slug || '')
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'category'
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(categoriesToExternalIds).values({
|
||||
categoryId: dbCategory[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
});
|
||||
});
|
||||
|
||||
if (dbCategory.length === 0) {
|
||||
return new Response('Could not create category', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created category', JSON.stringify(dbCategory[0], null, 2));
|
||||
return new Response(JSON.stringify(dbCategory[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Category');
|
||||
}
|
||||
}
|
||||
178
src/lib/utils/db/expansionUtils.ts
Normal file
178
src/lib/utils/db/expansionUtils.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { type Expansions, expansions } from '../../../schema';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function createExpansion(locals: App.Locals, expansion: Expansions) {
|
||||
if (!expansion || expansion?.base_game_id === '' || expansion?.game_id === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const foundExpansion = await db.query.expansions
|
||||
.findFirst({
|
||||
where: and(eq(expansions.base_game_id, expansion.base_game_id), eq(expansions.game_id, expansion.game_id)),
|
||||
columns: {
|
||||
id: true,
|
||||
game_id: true,
|
||||
base_game_id: true
|
||||
}
|
||||
});
|
||||
console.log('Expansion already exists', foundExpansion);
|
||||
if (foundExpansion) {
|
||||
console.log('Expansion Game ID', foundExpansion.game_id);
|
||||
return new Response('Expansion already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundExpansion.game_id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Creating expansion', JSON.stringify(expansion, null, 2));
|
||||
const dbExpansion = await db
|
||||
.insert(expansions)
|
||||
.values({
|
||||
base_game_id: expansion.base_game_id,
|
||||
game_id: expansion.game_id,
|
||||
})
|
||||
.returning();
|
||||
|
||||
if (dbExpansion.length === 0) {
|
||||
return new Response('Could not create expansion', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created expansion', JSON.stringify(dbExpansion[0], null, 2));
|
||||
return new Response(JSON.stringify(dbExpansion[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Expansion');
|
||||
}
|
||||
}
|
||||
|
||||
// export async function createExpansion(
|
||||
// locals: App.Locals,
|
||||
// game: Game,
|
||||
// externalExpansion: BggLinkDto,
|
||||
// gameIsExpansion: boolean,
|
||||
// eventFetch: Function
|
||||
// ) {
|
||||
// try {
|
||||
// let dbExpansionGame = await prisma.game.findUnique({
|
||||
// where: {
|
||||
// external_id: externalExpansion.id
|
||||
// }
|
||||
// });
|
||||
|
||||
// if (!dbExpansionGame) {
|
||||
// const externalGameResponse = await eventFetch(
|
||||
// `/api/external/game/${externalExpansion.id}?simplified=true`
|
||||
// );
|
||||
// if (externalGameResponse.ok) {
|
||||
// const externalGame = await externalGameResponse.json();
|
||||
// console.log('externalGame', externalGame);
|
||||
// const boredGame = mapAPIGameToBoredGame(externalGame);
|
||||
// dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
|
||||
// } else {
|
||||
// throw new Error(
|
||||
// `${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// let dbExpansion;
|
||||
// let baseGameId;
|
||||
// let gameId;
|
||||
// if (gameIsExpansion) {
|
||||
// console.log(
|
||||
// 'External expansion is expansion. Looking for base game',
|
||||
// JSON.stringify(game, null, 2)
|
||||
// );
|
||||
// dbExpansion = await prisma.expansion.findFirst({
|
||||
// where: {
|
||||
// game_id: dbExpansionGame.id
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// base_game_id: true,
|
||||
// game_id: true
|
||||
// }
|
||||
// });
|
||||
// baseGameId = game.id;
|
||||
// gameId = dbExpansionGame.id;
|
||||
// } else {
|
||||
// console.log(
|
||||
// 'External Expansion is base game. Looking for expansion',
|
||||
// JSON.stringify(game, null, 2)
|
||||
// );
|
||||
// dbExpansion = await prisma.expansion.findFirst({
|
||||
// where: {
|
||||
// base_game_id: dbExpansionGame.id
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// base_game_id: true,
|
||||
// game_id: true
|
||||
// }
|
||||
// });
|
||||
// baseGameId = dbExpansionGame.id;
|
||||
// gameId = game.id;
|
||||
// }
|
||||
|
||||
// if (dbExpansion) {
|
||||
// console.log('Expansion already exists', JSON.stringify(dbExpansion, null, 2));
|
||||
// return dbExpansion;
|
||||
// }
|
||||
|
||||
// console.log(`Creating expansion. baseGameId: ${baseGameId}, gameId: ${gameId}`);
|
||||
// const expansion = await prisma.expansion.create({
|
||||
// data: {
|
||||
// base_game_id: baseGameId,
|
||||
// game_id: gameId
|
||||
// }
|
||||
// });
|
||||
|
||||
// console.log('Created expansion', JSON.stringify(expansion, null, 2));
|
||||
|
||||
// if (gameIsExpansion) {
|
||||
// console.log('Connecting current game to expansion');
|
||||
// await prisma.game.update({
|
||||
// where: {
|
||||
// id: gameId
|
||||
// },
|
||||
// data: {
|
||||
// expansions: {
|
||||
// connect: {
|
||||
// id: expansion.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// console.log('Connecting current game to base game');
|
||||
// await prisma.game.update({
|
||||
// where: {
|
||||
// id: baseGameId
|
||||
// },
|
||||
// data: {
|
||||
// expansions: {
|
||||
// connect: {
|
||||
// id: expansion.id
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// return expansion;
|
||||
// } catch (e) {
|
||||
// console.error(e);
|
||||
// throw new Error('Something went wrong creating Expansion');
|
||||
// }
|
||||
// }
|
||||
439
src/lib/utils/db/gameUtils.ts
Normal file
439
src/lib/utils/db/gameUtils.ts
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, gamesToExternalIds, type Games, games } from '../../../schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function getGame(locals: App.Locals, id: string) {
|
||||
if (!id || id === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
return await db.query.games.findFirst({
|
||||
where: eq(games.id, id)
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get games', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function createGame(locals: App.Locals, game: Games, externalId: string) {
|
||||
if (!game || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
const foundGame = await db
|
||||
.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug
|
||||
})
|
||||
.from(games)
|
||||
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
|
||||
console.log('Game already exists', foundGame);
|
||||
if (foundGame.length > 0) {
|
||||
console.log('Game name', foundGame[0].name);
|
||||
return new Response('Game already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let dbGames: Games[] = [];
|
||||
console.log('Creating game', JSON.stringify(game, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbGames = await transaction
|
||||
.insert(games)
|
||||
.values({
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: game.url,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
});
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
|
||||
return new Response(JSON.stringify(dbGames[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Game');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Games, externalId: string) {
|
||||
if (!game || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
|
||||
const externalUrl = `https://boardgamegeek.com/boardgame/${externalId}`;
|
||||
try {
|
||||
let dbGames: Games[] = [];
|
||||
console.log('Creating game', JSON.stringify(game, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbGames = await transaction
|
||||
.insert(games)
|
||||
.values({
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: externalUrl,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: games.id,
|
||||
set: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: externalUrl,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
}
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
}).onConflictDoNothing();
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
|
||||
return new Response(JSON.stringify(dbGames[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Game');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOrUpdateGame(locals: App.Locals, game: Games, externalId: string) {
|
||||
if (!game || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const externalUrl = `https://boardgamegeek.com/boardgame/${externalId}`;
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
const foundGame = await db
|
||||
.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug
|
||||
})
|
||||
.from(games)
|
||||
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
|
||||
console.log('Game already exists', foundGame);
|
||||
if (foundGame.length > 0) {
|
||||
console.log('Game name', foundGame[0].name);
|
||||
return new Response('Game already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let dbGames: Games[] = [];
|
||||
console.log('Creating game', JSON.stringify(game, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbGames = await transaction
|
||||
.insert(games)
|
||||
.values({
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: game.url,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: games.id,
|
||||
set: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: externalUrl,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
}
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
}).onConflictDoNothing();
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
|
||||
return new Response(JSON.stringify(dbGames[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Game');
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateGame(locals: App.Locals, game: Games, id: string) {
|
||||
if (!game || !id || id === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbGame = await db
|
||||
.update(games)
|
||||
.set({
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name || game.slug || ''),
|
||||
description: game.description,
|
||||
year_published: game.year_published,
|
||||
url: game.url,
|
||||
image_url: game.image_url,
|
||||
thumb_url: game.thumb_url,
|
||||
min_age: game.min_age,
|
||||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
})
|
||||
.where(eq(games.id, id))
|
||||
.returning();
|
||||
return new Response(JSON.stringify(dbGame[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get publishers', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('Creating or updating game', JSON.stringify(game, null, 2));
|
||||
// const categoryIds = game.categories;
|
||||
// const mechanicIds = game.mechanics;
|
||||
// const publisherIds = game.publishers;
|
||||
// const designerIds = game.designers;
|
||||
// const artistIds = game.artists;
|
||||
// // const expansionIds = game.expansions;
|
||||
// const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
||||
// console.log('categoryIds', categoryIds);
|
||||
// console.log('mechanicIds', mechanicIds);
|
||||
// await db.transaction(async (transaction) => {
|
||||
// const dbGame = await db.transaction(async (transaction) => {
|
||||
// transaction.insert(games).values({
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name || ''),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }).onConflictDoUpdate({
|
||||
// target: games.id, set: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }
|
||||
// }).returning();
|
||||
// });
|
||||
// // TODO: Connect to everything else
|
||||
// });
|
||||
// await db.insert(games).values({
|
||||
// include: {
|
||||
// mechanics: true,
|
||||
// publishers: true,
|
||||
// designers: true,
|
||||
// artists: true,
|
||||
// expansions: true
|
||||
// },
|
||||
// where: {
|
||||
// external_id: game.external_id
|
||||
// },
|
||||
// create: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// },
|
||||
// update: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
77
src/lib/utils/db/mechanicUtils.ts
Normal file
77
src/lib/utils/db/mechanicUtils.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, mechanics, mechanicsToExternalIds, type Mechanics } from '../../../schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function createMechanic(locals: App.Locals, mechanic: Mechanics, externalId: string) {
|
||||
if (!mechanic || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
const foundMechanic = await db
|
||||
.select({
|
||||
id: mechanics.id,
|
||||
name: mechanics.name,
|
||||
slug: mechanics.slug
|
||||
})
|
||||
.from(mechanics)
|
||||
.leftJoin(mechanicsToExternalIds, eq(mechanicsToExternalIds.externalId, externalId));
|
||||
console.log('Mechanic already exists', foundMechanic);
|
||||
if (foundMechanic.length > 0) {
|
||||
console.log('Mechanic name', foundMechanic[0].name);
|
||||
return new Response('Mechanic already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundMechanic[0].id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let dbMechanics: Mechanics[] = [];
|
||||
console.log('Creating mechanic', JSON.stringify(mechanic, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbMechanics = await transaction
|
||||
.insert(mechanics)
|
||||
.values({
|
||||
name: mechanic.name,
|
||||
slug: kebabCase(mechanic.name || mechanic.slug || '')
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'mechanic'
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(mechanicsToExternalIds).values({
|
||||
mechanicId: dbMechanics[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
});
|
||||
});
|
||||
|
||||
if (dbMechanics.length === 0) {
|
||||
return new Response('Could not create mechanic', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created mechanic', JSON.stringify(dbMechanics[0], null, 2));
|
||||
return new Response(JSON.stringify(dbMechanics[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Mechanic');
|
||||
}
|
||||
}
|
||||
125
src/lib/utils/db/publisherUtils.ts
Normal file
125
src/lib/utils/db/publisherUtils.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import {
|
||||
externalIds,
|
||||
publishersToExternalIds,
|
||||
type Publishers,
|
||||
publishers,
|
||||
} from '../../../schema';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function getPublisher(locals: App.Locals, id: string) {
|
||||
const publisher = await db.select().from(publishers).where(eq(publishers.id, id));
|
||||
if (publisher.length === 0) {
|
||||
error(404, 'not found');
|
||||
}
|
||||
return new Response(JSON.stringify(publisher[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function updatePublisher(locals: App.Locals, publisher: Publishers, id: string) {
|
||||
if (!publisher || publisher.name === '' || !id || id === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbPublisher = await db
|
||||
.update(publishers)
|
||||
.set({
|
||||
name: publisher.name,
|
||||
slug: kebabCase(publisher.name || '')
|
||||
})
|
||||
.where(eq(publishers.id, id))
|
||||
.returning();
|
||||
return new Response(JSON.stringify(dbPublisher[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get publishers', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function createPublisher(
|
||||
locals: App.Locals,
|
||||
publisher: Publishers,
|
||||
externalId: string
|
||||
) {
|
||||
if (!publisher || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
const foundPublisher = await db
|
||||
.select({
|
||||
id: publishers.id,
|
||||
name: publishers.name,
|
||||
slug: publishers.slug
|
||||
})
|
||||
.from(publishers)
|
||||
.leftJoin(publishersToExternalIds, eq(publishersToExternalIds.externalId, externalId));
|
||||
console.log('Publisher already exists', foundPublisher);
|
||||
if (foundPublisher.length > 0) {
|
||||
console.log('Publisher name', foundPublisher[0].name);
|
||||
return new Response('Publisher already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/publisher/${foundPublisher[0].id}`
|
||||
},
|
||||
status: 409
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let dbPublishers: Publishers[] = [];
|
||||
console.log('Creating publisher', JSON.stringify(publisher, null, 2));
|
||||
await db.transaction(async (transaction) => {
|
||||
dbPublishers = await transaction
|
||||
.insert(publishers)
|
||||
.values({
|
||||
name: publisher.name,
|
||||
slug: kebabCase(publisher.name || publisher.slug || '')
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'publisher'
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(publishersToExternalIds).values({
|
||||
publisherId: dbPublishers[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
});
|
||||
});
|
||||
|
||||
if (dbPublishers.length === 0) {
|
||||
return new Response('Could not create publisher', {
|
||||
status: 500
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Created publisher', JSON.stringify(dbPublishers[0], null, 2));
|
||||
return new Response(JSON.stringify(dbPublishers[0]), {
|
||||
status: 201,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Publisher');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,456 +0,0 @@
|
|||
import type { Game } from '@prisma/client';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import type { BggLinkDto } from 'boardgamegeekclient/dist/esm/dto/concrete/subdto';
|
||||
import prisma from '$lib/prisma';
|
||||
import { mapAPIGameToBoredGame } from './gameMapper';
|
||||
|
||||
export async function createArtist(locals: App.Locals, externalArtist: BggLinkDto) {
|
||||
try {
|
||||
let dbArtist = await prisma.artist.findFirst({
|
||||
where: {
|
||||
external_id: externalArtist.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
if (dbArtist) {
|
||||
console.log('Artist already exists', dbArtist.name);
|
||||
return dbArtist;
|
||||
}
|
||||
console.log('Creating artist', JSON.stringify(externalArtist, null, 2));
|
||||
let artist = await prisma.artist.create({
|
||||
data: {
|
||||
name: externalArtist.value,
|
||||
external_id: externalArtist.id,
|
||||
slug: kebabCase(externalArtist.value)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created artist', JSON.stringify(artist, null, 2));
|
||||
return artist;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Artist');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createDesigner(locals: App.Locals, externalDesigner: BggLinkDto) {
|
||||
try {
|
||||
let dbDesigner = await prisma.designer.findFirst({
|
||||
where: {
|
||||
external_id: externalDesigner.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
if (dbDesigner) {
|
||||
console.log('Designer already exists', dbDesigner.name);
|
||||
return dbDesigner;
|
||||
}
|
||||
console.log('Creating designer', JSON.stringify(externalDesigner, null, 2));
|
||||
let designer = await prisma.designer.create({
|
||||
data: {
|
||||
name: externalDesigner.value,
|
||||
external_id: externalDesigner.id,
|
||||
slug: kebabCase(externalDesigner.value)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created designer', JSON.stringify(designer, null, 2));
|
||||
return designer;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Designer');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createPublisher(locals: App.Locals, externalPublisher: BggLinkDto) {
|
||||
try {
|
||||
let dbPublisher = await prisma.publisher.findFirst({
|
||||
where: {
|
||||
external_id: externalPublisher.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
if (dbPublisher) {
|
||||
console.log('Publisher already exists', dbPublisher.name);
|
||||
return dbPublisher;
|
||||
}
|
||||
console.log('Creating publisher', JSON.stringify(externalPublisher, null, 2));
|
||||
let publisher = await prisma.publisher.create({
|
||||
data: {
|
||||
name: externalPublisher.value,
|
||||
external_id: externalPublisher.id,
|
||||
slug: kebabCase(externalPublisher.value)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created publisher', JSON.stringify(publisher, null, 2));
|
||||
return publisher;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Publisher');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createCategory(locals: App.Locals, externalCategory: BggLinkDto) {
|
||||
try {
|
||||
let dbCategory = await prisma.category.findFirst({
|
||||
where: {
|
||||
external_id: externalCategory.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
if (dbCategory) {
|
||||
console.log('Category already exists', dbCategory.name);
|
||||
return dbCategory;
|
||||
}
|
||||
console.log('Creating category', JSON.stringify(externalCategory, null, 2));
|
||||
let category = await prisma.category.create({
|
||||
data: {
|
||||
name: externalCategory.value,
|
||||
external_id: externalCategory.id,
|
||||
slug: kebabCase(externalCategory.value)
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created category', JSON.stringify(category, null, 2));
|
||||
|
||||
return category;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Category');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createMechanic(locals: App.Locals, externalMechanic: BggLinkDto) {
|
||||
try {
|
||||
let dbMechanic = await prisma.mechanic.findFirst({
|
||||
where: {
|
||||
external_id: externalMechanic.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
external_id: true
|
||||
}
|
||||
});
|
||||
if (dbMechanic) {
|
||||
console.log('Mechanic already exists', dbMechanic.name);
|
||||
return dbMechanic;
|
||||
}
|
||||
console.log('Creating mechanic', JSON.stringify(externalMechanic, null, 2));
|
||||
let mechanic = await prisma.mechanic.upsert({
|
||||
where: {
|
||||
external_id: externalMechanic.id
|
||||
},
|
||||
create: {
|
||||
name: externalMechanic.value,
|
||||
external_id: externalMechanic.id,
|
||||
slug: kebabCase(externalMechanic.value)
|
||||
},
|
||||
update: {
|
||||
name: externalMechanic.value,
|
||||
slug: kebabCase(externalMechanic.value)
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created mechanic', JSON.stringify(mechanic, null, 2));
|
||||
|
||||
return mechanic;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Mechanic');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createExpansion(
|
||||
locals: App.Locals,
|
||||
game: Game,
|
||||
externalExpansion: BggLinkDto,
|
||||
gameIsExpansion: boolean,
|
||||
eventFetch: Function
|
||||
) {
|
||||
try {
|
||||
let dbExpansionGame = await prisma.game.findUnique({
|
||||
where: {
|
||||
external_id: externalExpansion.id
|
||||
}
|
||||
});
|
||||
|
||||
if (!dbExpansionGame) {
|
||||
const externalGameResponse = await eventFetch(
|
||||
`/api/external/game/${externalExpansion.id}?simplified=true`
|
||||
);
|
||||
if (externalGameResponse.ok) {
|
||||
const externalGame = await externalGameResponse.json();
|
||||
console.log('externalGame', externalGame);
|
||||
let boredGame = mapAPIGameToBoredGame(externalGame);
|
||||
dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
|
||||
} else {
|
||||
throw new Error(
|
||||
`${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let dbExpansion;
|
||||
let baseGameId;
|
||||
let gameId;
|
||||
if (gameIsExpansion) {
|
||||
console.log(
|
||||
'External expansion is expansion. Looking for base game',
|
||||
JSON.stringify(game, null, 2)
|
||||
);
|
||||
dbExpansion = await prisma.expansion.findFirst({
|
||||
where: {
|
||||
game_id: dbExpansionGame.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
base_game_id: true,
|
||||
game_id: true
|
||||
}
|
||||
});
|
||||
baseGameId = game.id;
|
||||
gameId = dbExpansionGame.id;
|
||||
} else {
|
||||
console.log(
|
||||
'External Expansion is base game. Looking for expansion',
|
||||
JSON.stringify(game, null, 2)
|
||||
);
|
||||
dbExpansion = await prisma.expansion.findFirst({
|
||||
where: {
|
||||
base_game_id: dbExpansionGame.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
base_game_id: true,
|
||||
game_id: true
|
||||
}
|
||||
});
|
||||
baseGameId = dbExpansionGame.id;
|
||||
gameId = game.id;
|
||||
}
|
||||
|
||||
if (dbExpansion) {
|
||||
console.log('Expansion already exists', JSON.stringify(dbExpansion, null, 2));
|
||||
return dbExpansion;
|
||||
}
|
||||
|
||||
console.log(`Creating expansion. baseGameId: ${baseGameId}, gameId: ${gameId}`);
|
||||
let expansion = await prisma.expansion.create({
|
||||
data: {
|
||||
base_game_id: baseGameId,
|
||||
game_id: gameId
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Created expansion', JSON.stringify(expansion, null, 2));
|
||||
|
||||
if (gameIsExpansion) {
|
||||
console.log('Connecting current game to expansion');
|
||||
await prisma.game.update({
|
||||
where: {
|
||||
id: gameId
|
||||
},
|
||||
data: {
|
||||
expansions: {
|
||||
connect: {
|
||||
id: expansion.id
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Connecting current game to base game');
|
||||
await prisma.game.update({
|
||||
where: {
|
||||
id: baseGameId
|
||||
},
|
||||
data: {
|
||||
expansions: {
|
||||
connect: {
|
||||
id: expansion.id
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return expansion;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error('Something went wrong creating Expansion');
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Game) {
|
||||
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
|
||||
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
||||
return await prisma.game.upsert({
|
||||
where: {
|
||||
external_id: game.external_id
|
||||
},
|
||||
create: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name),
|
||||
description: game.description,
|
||||
external_id: game.external_id,
|
||||
url: externalUrl,
|
||||
thumb_url: game.thumb_url,
|
||||
image_url: game.image_url,
|
||||
min_age: game.min_age || 0,
|
||||
min_players: game.min_players || 0,
|
||||
max_players: game.max_players || 0,
|
||||
min_playtime: game.min_playtime || 0,
|
||||
max_playtime: game.max_playtime || 0,
|
||||
year_published: game.year_published || 0
|
||||
},
|
||||
update: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name),
|
||||
description: game.description,
|
||||
external_id: game.external_id,
|
||||
url: externalUrl,
|
||||
thumb_url: game.thumb_url,
|
||||
image_url: game.image_url,
|
||||
min_age: game.min_age || 0,
|
||||
min_players: game.min_players || 0,
|
||||
max_players: game.max_players || 0,
|
||||
min_playtime: game.min_playtime || 0,
|
||||
max_playtime: game.max_playtime || 0,
|
||||
year_published: game.year_published || 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function createOrUpdateGame(locals: App.Locals, game: Game) {
|
||||
console.log('Creating or updating game', JSON.stringify(game, null, 2));
|
||||
const categoryIds = game.categories;
|
||||
const mechanicIds = game.mechanics;
|
||||
const publisherIds = game.publishers;
|
||||
const designerIds = game.designers;
|
||||
const artistIds = game.artists;
|
||||
// const expansionIds = game.expansions;
|
||||
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
||||
console.log('categoryIds', categoryIds);
|
||||
console.log('mechanicIds', mechanicIds);
|
||||
return await prisma.game.upsert({
|
||||
include: {
|
||||
mechanics: true,
|
||||
publishers: true,
|
||||
designers: true,
|
||||
artists: true,
|
||||
expansions: true
|
||||
},
|
||||
where: {
|
||||
external_id: game.external_id
|
||||
},
|
||||
create: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name),
|
||||
description: game.description,
|
||||
external_id: game.external_id,
|
||||
url: externalUrl,
|
||||
thumb_url: game.thumb_url,
|
||||
image_url: game.image_url,
|
||||
min_age: game.min_age || 0,
|
||||
min_players: game.min_players || 0,
|
||||
max_players: game.max_players || 0,
|
||||
min_playtime: game.min_playtime || 0,
|
||||
max_playtime: game.max_playtime || 0,
|
||||
year_published: game.year_published || 0,
|
||||
last_sync_at: new Date(),
|
||||
categories: {
|
||||
connect: categoryIds
|
||||
},
|
||||
mechanics: {
|
||||
connect: mechanicIds
|
||||
},
|
||||
publishers: {
|
||||
connect: publisherIds
|
||||
},
|
||||
designers: {
|
||||
connect: designerIds
|
||||
},
|
||||
artists: {
|
||||
connect: artistIds
|
||||
}
|
||||
},
|
||||
update: {
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name),
|
||||
description: game.description,
|
||||
external_id: game.external_id,
|
||||
url: externalUrl,
|
||||
thumb_url: game.thumb_url,
|
||||
image_url: game.image_url,
|
||||
min_age: game.min_age || 0,
|
||||
min_players: game.min_players || 0,
|
||||
max_players: game.max_players || 0,
|
||||
min_playtime: game.min_playtime || 0,
|
||||
max_playtime: game.max_playtime || 0,
|
||||
year_published: game.year_published || 0,
|
||||
last_sync_at: new Date(),
|
||||
categories: {
|
||||
connect: categoryIds
|
||||
},
|
||||
mechanics: {
|
||||
connect: mechanicIds
|
||||
},
|
||||
publishers: {
|
||||
connect: publisherIds
|
||||
},
|
||||
designers: {
|
||||
connect: designerIds
|
||||
},
|
||||
artists: {
|
||||
connect: artistIds
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
import type { Game } from '@prisma/client';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import type { Games } from '../../schema';
|
||||
|
||||
export function convertToSavedGame(game: GameType | SavedGameType): SavedGameType {
|
||||
return {
|
||||
|
|
@ -43,10 +44,9 @@ export function mapSavedGameToGame(game: SavedGameType): GameType {
|
|||
};
|
||||
}
|
||||
|
||||
export function mapAPIGameToBoredGame(game: GameType): Game {
|
||||
export function mapAPIGameToBoredGame(game: GameType): Games {
|
||||
// TODO: Fix types
|
||||
return {
|
||||
external_id: game.external_id,
|
||||
name: game.name,
|
||||
slug: kebabCase(game.name),
|
||||
thumb_url: game.thumbnail,
|
||||
|
|
@ -57,7 +57,6 @@ export function mapAPIGameToBoredGame(game: GameType): Game {
|
|||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime,
|
||||
min_age: game.min_age,
|
||||
description: game.description,
|
||||
playtime: game.playing_time
|
||||
description: game.description
|
||||
};
|
||||
}
|
||||
|
|
|
|||
106
src/lib/validations/account.ts
Normal file
106
src/lib/validations/account.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import { z } from 'zod';
|
||||
import { userSchema } from './zod-schemas';
|
||||
|
||||
export const profileSchema = userSchema.pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
username: true
|
||||
});
|
||||
|
||||
export const changeEmailSchema = userSchema.pick({
|
||||
email: true,
|
||||
});
|
||||
|
||||
export const changeUserPasswordSchema = z
|
||||
.object({
|
||||
current_password: z.string({ required_error: 'Current Password is required' }),
|
||||
password: z.string({ required_error: 'Password is required' }).trim(),
|
||||
confirm_password: z.string({ required_error: 'Confirm Password is required' }).trim()
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
refinePasswords(confirm_password, password, ctx);
|
||||
});
|
||||
|
||||
export type ChangeUserPasswordSchema = typeof changeUserPasswordSchema;
|
||||
|
||||
export const updateUserPasswordSchema = userSchema
|
||||
.pick({ password: true, confirm_password: true })
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
refinePasswords(confirm_password, password, ctx);
|
||||
});
|
||||
|
||||
export const refinePasswords = async function (
|
||||
confirm_password: string,
|
||||
password: string,
|
||||
ctx: z.RefinementCtx
|
||||
) {
|
||||
comparePasswords(confirm_password, password, ctx);
|
||||
checkPasswordStrength(password, ctx);
|
||||
};
|
||||
|
||||
const comparePasswords = async function (
|
||||
confirm_password: string,
|
||||
password: string,
|
||||
ctx: z.RefinementCtx
|
||||
) {
|
||||
if (confirm_password !== password) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['confirm_password']
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
|
||||
const minimumLength = password.length < 8;
|
||||
const maximumLength = password.length > 128;
|
||||
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
|
||||
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
|
||||
const containsSpecialChar = (ch: string) => /[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
|
||||
let countOfUpperCase = 0,
|
||||
countOfLowerCase = 0,
|
||||
countOfNumbers = 0,
|
||||
countOfSpecialChar = 0;
|
||||
for (let i = 0; i < password.length; i++) {
|
||||
const char = password.charAt(i);
|
||||
if (!isNaN(+char)) {
|
||||
countOfNumbers++;
|
||||
} else if (containsUppercase(char)) {
|
||||
countOfUpperCase++;
|
||||
} else if (containsLowercase(char)) {
|
||||
countOfLowerCase++;
|
||||
} else if (containsSpecialChar(char)) {
|
||||
countOfSpecialChar++;
|
||||
}
|
||||
}
|
||||
|
||||
let errorMessage = 'Your password:';
|
||||
|
||||
if (countOfLowerCase < 1) {
|
||||
errorMessage = ' Must have at least one lowercase letter. ';
|
||||
}
|
||||
if (countOfNumbers < 1) {
|
||||
errorMessage += ' Must have at least one number. ';
|
||||
}
|
||||
if (countOfUpperCase < 1) {
|
||||
errorMessage += ' Must have at least one uppercase letter. ';
|
||||
}
|
||||
if (countOfSpecialChar < 1) {
|
||||
errorMessage += ' Must have at least one special character.';
|
||||
}
|
||||
if (minimumLength) {
|
||||
errorMessage += ' Be at least 8 characters long.';
|
||||
}
|
||||
if (maximumLength) {
|
||||
errorMessage += ' Be less than 128 characters long.';
|
||||
}
|
||||
|
||||
if (errorMessage.length > 'Your password:'.length) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: errorMessage,
|
||||
path: ['password']
|
||||
});
|
||||
}
|
||||
};
|
||||
21
src/lib/validations/auth.ts
Normal file
21
src/lib/validations/auth.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { refinePasswords } from "./account";
|
||||
import { userSchema } from "./zod-schemas";
|
||||
|
||||
export const signUpSchema = userSchema
|
||||
.pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
email: true,
|
||||
username: true,
|
||||
password: true,
|
||||
confirm_password: true,
|
||||
terms: true
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
refinePasswords(confirm_password, password, ctx);
|
||||
});
|
||||
|
||||
export const signInSchema = userSchema.pick({
|
||||
username: true,
|
||||
password: true
|
||||
});
|
||||
44
src/lib/validations/zod-schemas.ts
Normal file
44
src/lib/validations/zod-schemas.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export type ListGame = {
|
||||
id: string;
|
||||
game_name: string;
|
||||
game_id: string;
|
||||
collection_id: string;
|
||||
wishlist_id: string;
|
||||
times_played: number;
|
||||
thumb_url: string | null;
|
||||
in_collection: boolean;
|
||||
in_wishlist: boolean;
|
||||
};
|
||||
|
||||
export const modifyListGameSchema = z.object({
|
||||
id: z.string()
|
||||
});
|
||||
|
||||
export type ModifyListGame = typeof modifyListGameSchema;
|
||||
|
||||
export const userSchema = z.object({
|
||||
firstName: z.string().trim().optional(),
|
||||
lastName: z.string().trim().optional(),
|
||||
email: z.string()
|
||||
.trim()
|
||||
.max(64, { message: 'Email must be less than 64 characters' })
|
||||
.optional(),
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(3, { message: 'Username must be at least 3 characters' })
|
||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||
password: z
|
||||
.string({ required_error: 'Password is required' })
|
||||
.trim(),
|
||||
confirm_password: z
|
||||
.string({ required_error: 'Confirm Password is required' })
|
||||
.trim(),
|
||||
verified: z.boolean().default(false),
|
||||
token: z.string().optional(),
|
||||
receiveEmail: z.boolean().default(false),
|
||||
createdAt: z.date().optional(),
|
||||
updatedAt: z.date().optional()
|
||||
});
|
||||
|
|
@ -117,6 +117,10 @@ export const search_schema = z
|
|||
|
||||
export type SearchSchema = typeof search_schema;
|
||||
|
||||
export const BggForm = z.object({
|
||||
link: z.string().trim().startsWith('https://boardgamegeek.com/boardgame/')
|
||||
})
|
||||
|
||||
export const collection_search_schema = Search.extend({
|
||||
collection_id: z.string()
|
||||
});
|
||||
|
|
@ -222,7 +226,6 @@ const gameSchema = z.object({
|
|||
image_url: z.string().optional(),
|
||||
thumb_url: z.string().optional(),
|
||||
url: z.string().optional(),
|
||||
rules_url: z.string().optional(),
|
||||
weight_amount: z.number().optional(),
|
||||
weight_units: z.enum(['Medium', 'Heavy']).optional(),
|
||||
categories: z.array(category_schema).optional(),
|
||||
|
|
|
|||
25
src/migrate.ts
Normal file
25
src/migrate.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import 'dotenv/config';
|
||||
import postgres from 'postgres';
|
||||
import { drizzle } from 'drizzle-orm/postgres-js';
|
||||
import { migrate } from 'drizzle-orm/postgres-js/migrator';
|
||||
|
||||
const connection = postgres({
|
||||
host: process.env.DATABASE_HOST || 'localhost',
|
||||
port: 5432,
|
||||
user: process.env.DATABASE_USER || 'root',
|
||||
password: process.env.DATABASE_PASSWORD || '',
|
||||
database: process.env.DATABASE_DB || 'boredgame',
|
||||
ssl: 'require',
|
||||
max: 1
|
||||
});
|
||||
const db = drizzle(connection);
|
||||
|
||||
try {
|
||||
await migrate(db, { migrationsFolder: 'drizzle' });
|
||||
console.log('Migrations complete');
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
await connection.end();
|
||||
process.exit();
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerData } from './$types';
|
||||
import { redirect } from 'sveltekit-flash-message/server'
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
|
||||
export const load: PageServerData = async function ({ locals }) {
|
||||
if (!locals?.user?.role?.includes('admin')) redirect(302, '/');
|
||||
export async function load(event) {
|
||||
const { locals } = event;
|
||||
if (!locals?.user?.role?.includes('admin')) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
return {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import { type Actions, error, fail } from '@sveltejs/kit';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import prisma from '$lib/prisma';
|
||||
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { redirect } from 'sveltekit-flash-message/server'
|
||||
import { modifyListGameSchema, type ListGame } from '$lib/validations/zod-schemas';
|
||||
import { search_schema } from '$lib/zodValidation.js';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import db from '$lib/drizzle';
|
||||
import { collection_items, collections, games } from '../../../../schema';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||
export async function load(event) {
|
||||
const { url, locals } = event;
|
||||
const user = locals.user;
|
||||
if (!user) {
|
||||
redirect(302, '/login');
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
// console.log('locals load', locals);
|
||||
|
|
@ -24,14 +29,12 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
|||
skip
|
||||
};
|
||||
|
||||
const searchForm = await superValidate(searchData, search_schema);
|
||||
const listManageForm = await superValidate(modifyListGameSchema);
|
||||
const searchForm = await superValidate(searchData, zod(search_schema));
|
||||
const listManageForm = await superValidate(zod(modifyListGameSchema));
|
||||
|
||||
try {
|
||||
let collection = await prisma.collection.findUnique({
|
||||
where: {
|
||||
user_id: user.id
|
||||
}
|
||||
const collection = await db.query.collections.findFirst({
|
||||
where: eq(collections.user_id, user.id)
|
||||
});
|
||||
console.log('collection', collection);
|
||||
|
||||
|
|
@ -45,27 +48,25 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
|||
// });
|
||||
}
|
||||
|
||||
let collection_items = await prisma.collectionItem.findMany({
|
||||
where: {
|
||||
collection_id: collection.id
|
||||
},
|
||||
include: {
|
||||
const collectionItems = await db.query.collection_items.findMany({
|
||||
where: eq(collection_items.collection_id, collection.id),
|
||||
with: {
|
||||
game: {
|
||||
select: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
thumb_url: true
|
||||
}
|
||||
}
|
||||
},
|
||||
skip,
|
||||
take: limit
|
||||
offset: skip,
|
||||
limit
|
||||
});
|
||||
|
||||
console.log('collection_items', collection_items);
|
||||
console.log('collection_items', collectionItems);
|
||||
|
||||
let collectionItems: ListGame[] = [];
|
||||
for (const item of collection_items) {
|
||||
const items: ListGame[] = [];
|
||||
for (const item of collectionItems) {
|
||||
console.log('item', item);
|
||||
const game = item.game;
|
||||
if (game) {
|
||||
|
|
@ -77,14 +78,14 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
|||
times_played: item.times_played,
|
||||
in_collection: true
|
||||
};
|
||||
collectionItems.push(collectionItem);
|
||||
items.push(collectionItem);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
searchForm,
|
||||
listManageForm,
|
||||
collection: collectionItems
|
||||
collection: items
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
@ -100,18 +101,15 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
|||
export const actions: Actions = {
|
||||
// Add game to a wishlist
|
||||
add: async (event) => {
|
||||
const { params, locals, request } = event;
|
||||
const form = await superValidate(event, modifyListGameSchema);
|
||||
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||
|
||||
if (!event.locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
|
||||
const user = event.locals.user;
|
||||
let game = await prisma.game.findUnique({
|
||||
where: {
|
||||
id: form.data.id
|
||||
}
|
||||
const game = await db.query.games.findFirst({
|
||||
where: eq(games.id, form.data.id)
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
|
|
@ -125,10 +123,8 @@ export const actions: Actions = {
|
|||
}
|
||||
|
||||
try {
|
||||
const collection = await prisma.collection.findUnique({
|
||||
where: {
|
||||
user_id: user.id
|
||||
}
|
||||
const collection = await db.query.collections.findFirst({
|
||||
where: eq(collections.user_id, user.id)
|
||||
});
|
||||
|
||||
if (!collection) {
|
||||
|
|
@ -136,12 +132,10 @@ export const actions: Actions = {
|
|||
return error(404, 'Wishlist not found');
|
||||
}
|
||||
|
||||
await prisma.collectionItem.create({
|
||||
data: {
|
||||
game_id: game.id,
|
||||
collection_id: collection.id,
|
||||
times_played: 0
|
||||
}
|
||||
await db.insert(collection_items).values({
|
||||
game_id: game.id,
|
||||
collection_id: collection.id,
|
||||
times_played: 0
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
@ -153,14 +147,14 @@ export const actions: Actions = {
|
|||
}
|
||||
},
|
||||
// Create new wishlist
|
||||
create: async ({ params, locals, request }) => {
|
||||
create: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
return error(405, 'Method not allowed');
|
||||
},
|
||||
// Delete a wishlist
|
||||
delete: async ({ params, locals, request }) => {
|
||||
delete: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
|
|
@ -168,17 +162,15 @@ export const actions: Actions = {
|
|||
},
|
||||
// Remove game from a wishlist
|
||||
remove: async (event) => {
|
||||
const { params, locals, request } = event;
|
||||
const form = await superValidate(event, modifyListGameSchema);
|
||||
const { locals } = event;
|
||||
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
where: {
|
||||
id: form.data.id
|
||||
}
|
||||
const game = await db.query.games.findFirst({
|
||||
where: eq(games.id, form.data.id)
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
|
|
@ -187,10 +179,8 @@ export const actions: Actions = {
|
|||
}
|
||||
|
||||
try {
|
||||
const collection = await prisma.collection.findUnique({
|
||||
where: {
|
||||
user_id: locals.user.id
|
||||
}
|
||||
const collection = await db.query.collections.findFirst({
|
||||
where: eq(collections.user_id, locals.user.id)
|
||||
});
|
||||
|
||||
if (!collection) {
|
||||
|
|
@ -198,12 +188,10 @@ export const actions: Actions = {
|
|||
return error(404, 'Collection not found');
|
||||
}
|
||||
|
||||
await prisma.collectionItem.delete({
|
||||
where: {
|
||||
collection_id: collection.id,
|
||||
game_id: game.id
|
||||
}
|
||||
});
|
||||
await db.delete(collection_items).where(and(
|
||||
eq(collection_items.collection_id, collection.id),
|
||||
eq(collection_items.game_id, game.id)
|
||||
));
|
||||
|
||||
return {
|
||||
form
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue