mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
commit
f9123eea53
130 changed files with 11120 additions and 13479 deletions
|
|
@ -2,7 +2,8 @@
|
|||
"useTabs": true,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"pluginSearchDirs": ["."],
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ export default defineConfig({
|
|||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE || 'boredgame',
|
||||
ssl: true
|
||||
ssl: process.env.DATABASE_HOST !== 'localhost'
|
||||
},
|
||||
// Print all statements
|
||||
verbose: true,
|
||||
// Always as for confirmation
|
||||
strict: true
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,233 +0,0 @@
|
|||
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 $$;
|
||||
365
drizzle/0000_tricky_hitman.sql
Normal file
365
drizzle/0000_tricky_hitman.sql
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
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 "categories" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"name" text,
|
||||
"slug" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "categories_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "categories_to_external_ids" (
|
||||
"category_id" uuid NOT NULL,
|
||||
"external_id" uuid NOT NULL,
|
||||
CONSTRAINT "categories_to_external_ids_category_id_external_id_pk" PRIMARY KEY("category_id","external_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "categories_to_games" (
|
||||
"category_id" uuid NOT NULL,
|
||||
"game_id" uuid NOT NULL,
|
||||
CONSTRAINT "categories_to_games_category_id_game_id_pk" PRIMARY KEY("category_id","game_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "collection_items" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"collection_id" text NOT NULL,
|
||||
"game_id" text NOT NULL,
|
||||
"times_played" integer DEFAULT 0,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "collection_items_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "collections" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"user_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "expansions" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"base_game_id" text NOT NULL,
|
||||
"game_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "expansions_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "external_ids" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"type" "external_id_type" NOT NULL,
|
||||
"external_id" text NOT NULL,
|
||||
CONSTRAINT "external_ids_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "games" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"name" text,
|
||||
"slug" text,
|
||||
"description" text,
|
||||
"year_published" integer,
|
||||
"min_players" integer,
|
||||
"max_players" integer,
|
||||
"playtime" integer,
|
||||
"min_playtime" integer,
|
||||
"max_playtime" integer,
|
||||
"min_age" integer,
|
||||
"image_url" text,
|
||||
"thumb_url" text,
|
||||
"url" text,
|
||||
"text_searchable_index" "tsvector",
|
||||
"last_sync_at" timestamp (6) with time zone,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "games_to_external_ids" (
|
||||
"game_id" uuid NOT NULL,
|
||||
"external_id" uuid NOT NULL,
|
||||
CONSTRAINT "games_to_external_ids_game_id_external_id_pk" PRIMARY KEY("game_id","external_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"name" text,
|
||||
"slug" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "mechanics_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics_to_external_ids" (
|
||||
"mechanic_id" uuid NOT NULL,
|
||||
"external_id" uuid NOT NULL,
|
||||
CONSTRAINT "mechanics_to_external_ids_mechanic_id_external_id_pk" PRIMARY KEY("mechanic_id","external_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "mechanics_to_games" (
|
||||
"mechanic_id" uuid NOT NULL,
|
||||
"game_id" uuid NOT NULL,
|
||||
CONSTRAINT "mechanics_to_games_mechanic_id_game_id_pk" PRIMARY KEY("mechanic_id","game_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"expires_at" timestamp (6) with time zone,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"name" text,
|
||||
"slug" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "publishers_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers_to_external_ids" (
|
||||
"publisher_id" uuid NOT NULL,
|
||||
"external_id" uuid NOT NULL,
|
||||
CONSTRAINT "publishers_to_external_ids_publisher_id_external_id_pk" PRIMARY KEY("publisher_id","external_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "publishers_to_games" (
|
||||
"publisher_id" uuid NOT NULL,
|
||||
"game_id" uuid NOT NULL,
|
||||
CONSTRAINT "publishers_to_games_publisher_id_game_id_pk" PRIMARY KEY("publisher_id","game_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "roles" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"name" text,
|
||||
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
|
||||
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "sessions" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"expires_at" timestamp with time zone NOT NULL,
|
||||
"ip_country" text,
|
||||
"ip_address" text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "user_roles" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"user_id" text NOT NULL,
|
||||
"role_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"username" text,
|
||||
"hashed_password" text,
|
||||
"email" text,
|
||||
"first_name" text,
|
||||
"last_name" text,
|
||||
"verified" boolean DEFAULT false,
|
||||
"receive_email" boolean DEFAULT false,
|
||||
"theme" text DEFAULT 'system',
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
|
||||
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "wishlist_items" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"wishlist_id" text NOT NULL,
|
||||
"game_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "wishlists" (
|
||||
"id" uuid PRIMARY KEY NOT NULL,
|
||||
"cuid" text,
|
||||
"user_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "text_searchable_idx" ON "games" ("text_searchable_index");--> 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_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("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 "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 restrict ON UPDATE cascade;
|
||||
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 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 "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 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_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("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 "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 $$;
|
||||
--> 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_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("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 $$;
|
||||
--> 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 $$;
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
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());
|
||||
6
drizzle/0001_numerous_dragon_man.sql
Normal file
6
drizzle/0001_numerous_dragon_man.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE "collection_items" ALTER COLUMN "collection_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "base_game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "wishlist_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
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";
|
||||
5
drizzle/0002_thick_lyja.sql
Normal file
5
drizzle/0002_thick_lyja.sql
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE "collections" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "password_reset_tokens" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "sessions" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "user_id" SET DATA TYPE uuid;
|
||||
1
drizzle/0003_mushy_madame_masque.sql
Normal file
1
drizzle/0003_mushy_madame_masque.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "user_roles" ALTER COLUMN "role_id" SET DATA TYPE uuid;
|
||||
|
|
@ -1 +0,0 @@
|
|||
CREATE INDEX IF NOT EXISTS "text_searchable_idx" ON "games" ("text_searchable_index");
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
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 $$;
|
||||
13
drizzle/0004_glossy_enchantress.sql
Normal file
13
drizzle/0004_glossy_enchantress.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
ALTER TABLE "categories" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "collections" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "expansions" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "external_ids" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "games" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "mechanics" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "publishers" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "user_roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "wishlist_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
||||
ALTER TABLE "wishlists" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();
|
||||
2
drizzle/0005_light_captain_marvel.sql
Normal file
2
drizzle/0005_light_captain_marvel.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "roles" ALTER COLUMN "cuid" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "roles" ALTER COLUMN "name" SET NOT NULL;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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 $$;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
ALTER TABLE "external_ids" ALTER COLUMN "type" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "external_ids" ALTER COLUMN "external_id" SET NOT NULL;
|
||||
1
drizzle/0006_wild_stone_men.sql
Normal file
1
drizzle/0006_wild_stone_men.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "user_roles" ADD COLUMN "default" boolean DEFAULT false;
|
||||
1
drizzle/0007_large_miss_america.sql
Normal file
1
drizzle/0007_large_miss_america.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "user_roles" RENAME COLUMN "default" TO "primary";
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
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 $$;
|
||||
1
drizzle/0008_amusing_franklin_richards.sql
Normal file
1
drizzle/0008_amusing_franklin_richards.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "users" ADD COLUMN "two_factor_secret" text;
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
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;
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
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;
|
||||
2
drizzle/0009_gray_carlie_cooper.sql
Normal file
2
drizzle/0009_gray_carlie_cooper.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "users" ALTER COLUMN "two_factor_secret" SET DEFAULT '';--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "two_factor_enabled" boolean DEFAULT false;
|
||||
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE "collection_items" ADD COLUMN "times_played" integer DEFAULT 0;
|
||||
14
drizzle/0010_wakeful_metal_master.sql
Normal file
14
drizzle/0010_wakeful_metal_master.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE IF NOT EXISTS "recovery_codes" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"code" text NOT NULL,
|
||||
"used" boolean DEFAULT false,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "recovery_codes" ADD CONSTRAINT "recovery_codes_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 $$;
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
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 $$;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
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;
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
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 +0,0 @@
|
|||
DROP TABLE "expansions_to_external_ids";
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
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 $$;
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -5,113 +5,78 @@
|
|||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1707437865821,
|
||||
"tag": "0000_oval_wolverine",
|
||||
"when": 1710268038944,
|
||||
"tag": "0000_tricky_hitman",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "5",
|
||||
"when": 1707438055782,
|
||||
"tag": "0001_giant_tomorrow_man",
|
||||
"when": 1710268191378,
|
||||
"tag": "0001_numerous_dragon_man",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "5",
|
||||
"when": 1707524139123,
|
||||
"tag": "0002_sour_silverclaw",
|
||||
"when": 1710268300740,
|
||||
"tag": "0002_thick_lyja",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "5",
|
||||
"when": 1707526808124,
|
||||
"tag": "0003_thick_tinkerer",
|
||||
"when": 1710268371021,
|
||||
"tag": "0003_mushy_madame_masque",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "5",
|
||||
"when": 1707932397672,
|
||||
"tag": "0004_fancy_umar",
|
||||
"when": 1710277583673,
|
||||
"tag": "0004_glossy_enchantress",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "5",
|
||||
"when": 1707932466413,
|
||||
"tag": "0005_uneven_lifeguard",
|
||||
"when": 1710366724519,
|
||||
"tag": "0005_light_captain_marvel",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "5",
|
||||
"when": 1707932522909,
|
||||
"tag": "0006_light_corsair",
|
||||
"when": 1710905422967,
|
||||
"tag": "0006_wild_stone_men",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "5",
|
||||
"when": 1707951501716,
|
||||
"tag": "0007_same_valeria_richards",
|
||||
"when": 1710905572670,
|
||||
"tag": "0007_large_miss_america",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "5",
|
||||
"when": 1708105454143,
|
||||
"tag": "0008_complete_manta",
|
||||
"when": 1711757183163,
|
||||
"tag": "0008_amusing_franklin_richards",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "5",
|
||||
"when": 1708105890146,
|
||||
"tag": "0009_equal_christian_walker",
|
||||
"when": 1711868447607,
|
||||
"tag": "0009_gray_carlie_cooper",
|
||||
"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",
|
||||
"when": 1712271520175,
|
||||
"tag": "0010_wakeful_metal_master",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
86
package.json
86
package.json
|
|
@ -4,12 +4,11 @@
|
|||
"private": "true",
|
||||
"scripts": {
|
||||
"dev": "NODE_OPTIONS=\"--inspect\" vite dev --host",
|
||||
"build": "prisma generate && vite build",
|
||||
"build": "vite build",
|
||||
"package": "svelte-kit package",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"test:ui": "svelte-kit sync && playwright test --ui",
|
||||
"postinstall": "prisma generate",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"test:unit": "vitest",
|
||||
|
|
@ -21,56 +20,53 @@
|
|||
"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.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.2",
|
||||
"@melt-ui/svelte": "^0.76.3",
|
||||
"@playwright/test": "^1.43.0",
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"@sveltejs/adapter-auto": "^3.2.0",
|
||||
"@sveltejs/enhanced-img": "^0.1.9",
|
||||
"@sveltejs/kit": "^2.5.5",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/pg": "^8.11.2",
|
||||
"@types/node": "^20.12.6",
|
||||
"@types/pg": "^8.11.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"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",
|
||||
"eslint-plugin-svelte": "^2.36.0",
|
||||
"just-clone": "^6.2.0",
|
||||
"just-debounce-it": "^3.2.0",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-import": "^16.0.1",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-load-config": "^5.0.3",
|
||||
"postcss-preset-env": "^9.4.0",
|
||||
"postcss-preset-env": "^9.5.4",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-svelte": "^3.2.2",
|
||||
"prisma": "^5.9.1",
|
||||
"sass": "^1.71.1",
|
||||
"sass": "^1.74.1",
|
||||
"satori": "^0.10.13",
|
||||
"satori-html": "^0.3.2",
|
||||
"svelte": "^4.2.12",
|
||||
"svelte-check": "^3.6.6",
|
||||
"svelte-meta-tags": "^3.1.1",
|
||||
"svelte-check": "^3.6.9",
|
||||
"svelte-headless-table": "^0.18.2",
|
||||
"svelte-meta-tags": "^3.1.2",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"sveltekit-flash-message": "^2.4.2",
|
||||
"sveltekit-flash-message": "^2.4.4",
|
||||
"sveltekit-rate-limiter": "^0.4.3",
|
||||
"sveltekit-superforms": "^2.7.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"sveltekit-superforms": "^2.12.4",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.6.1",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.5",
|
||||
"vitest": "^1.3.1",
|
||||
"tsx": "^4.7.2",
|
||||
"typescript": "^5.4.4",
|
||||
"vite": "^5.2.8",
|
||||
"vitest": "^1.4.0",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"type": "module",
|
||||
|
|
@ -82,43 +78,41 @@
|
|||
"@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",
|
||||
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
||||
"@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.100.1",
|
||||
"@sveltejs/adapter-vercel": "^5.1.0",
|
||||
"@sveltejs/adapter-vercel": "^5.2.0",
|
||||
"@types/feather-icons": "^4.29.4",
|
||||
"@vercel/og": "^0.5.20",
|
||||
"bits-ui": "^0.19.3",
|
||||
"bits-ui": "^0.19.7",
|
||||
"boardgamegeekclient": "^1.9.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"cookie": "^0.6.0",
|
||||
"drizzle-orm": "^0.29.4",
|
||||
"drizzle-orm": "^0.30.7",
|
||||
"feather-icons": "^4.29.1",
|
||||
"formsnap": "^0.5.1",
|
||||
"html-entities": "^2.5.2",
|
||||
"iconify-icon": "^2.0.0",
|
||||
"just-capitalize": "^3.2.0",
|
||||
"just-kebab-case": "^4.2.0",
|
||||
"loader": "^2.1.1",
|
||||
"lucia": "3.0.1",
|
||||
"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",
|
||||
"lucia": "3.1.1",
|
||||
"lucide-svelte": "^0.358.0",
|
||||
"open-props": "^1.7.2",
|
||||
"oslo": "^1.2.0",
|
||||
"pg": "^8.11.5",
|
||||
"postgres": "^3.4.4",
|
||||
"qrcode": "^1.5.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.2.0",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
"tailwind-variants": "^0.2.1",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"zod-to-json-schema": "^3.22.4"
|
||||
"zod-to-json-schema": "^3.22.5"
|
||||
}
|
||||
}
|
||||
2197
pnpm-lock.yaml
2197
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,256 +0,0 @@
|
|||
{
|
||||
"categories": [
|
||||
{
|
||||
"name": "Abstract Strategy"
|
||||
},
|
||||
{
|
||||
"name": "Action / Dexterity"
|
||||
},
|
||||
{
|
||||
"name": "Adventure"
|
||||
},
|
||||
{
|
||||
"name": "Age of Reason"
|
||||
},
|
||||
{
|
||||
"name": "American Civil War"
|
||||
},
|
||||
{
|
||||
"name": "American Indian Wars"
|
||||
},
|
||||
{
|
||||
"name": "American Revolutionary War"
|
||||
},
|
||||
{
|
||||
"name": "American West"
|
||||
},
|
||||
{
|
||||
"name": "Ancient"
|
||||
},
|
||||
{
|
||||
"name": "Animals"
|
||||
},
|
||||
{
|
||||
"name": "Arabian"
|
||||
},
|
||||
{
|
||||
"name": "Aviation / Flight"
|
||||
},
|
||||
{
|
||||
"name": "Bluffing"
|
||||
},
|
||||
{
|
||||
"name": "Book"
|
||||
},
|
||||
{
|
||||
"name": "Card Game"
|
||||
},
|
||||
{
|
||||
"name": "Children's Game"
|
||||
},
|
||||
{
|
||||
"name": "City Building"
|
||||
},
|
||||
{
|
||||
"name": "Civil War"
|
||||
},
|
||||
{
|
||||
"name": "Civilization"
|
||||
},
|
||||
{
|
||||
"name": "Collectible Components"
|
||||
},
|
||||
{
|
||||
"name": "Comic Book / Strip"
|
||||
},
|
||||
{
|
||||
"name": "Deduction"
|
||||
},
|
||||
{
|
||||
"name": "Dice"
|
||||
},
|
||||
{
|
||||
"name": "Economic"
|
||||
},
|
||||
{
|
||||
"name": "Educational"
|
||||
},
|
||||
{
|
||||
"name": "Electronic"
|
||||
},
|
||||
{
|
||||
"name": "Environmental"
|
||||
},
|
||||
{
|
||||
"name": "Expansion for Base-game"
|
||||
},
|
||||
{
|
||||
"name": "Exploration"
|
||||
},
|
||||
{
|
||||
"name": "Fan Expansion"
|
||||
},
|
||||
{
|
||||
"name": "Fantasy"
|
||||
},
|
||||
{
|
||||
"name": "Farming"
|
||||
},
|
||||
{
|
||||
"name": "Fighting"
|
||||
},
|
||||
{
|
||||
"name": "Game System"
|
||||
},
|
||||
{
|
||||
"name": "Horror"
|
||||
},
|
||||
{
|
||||
"name": "Humor"
|
||||
},
|
||||
{
|
||||
"name": "Industry / Manufacturing"
|
||||
},
|
||||
{
|
||||
"name": "Korean War"
|
||||
},
|
||||
{
|
||||
"name": "Mafia"
|
||||
},
|
||||
{
|
||||
"name": "Math"
|
||||
},
|
||||
{
|
||||
"name": "Mature / Adult"
|
||||
},
|
||||
{
|
||||
"name": "Maze"
|
||||
},
|
||||
{
|
||||
"name": "Medical"
|
||||
},
|
||||
{
|
||||
"name": "Medieval"
|
||||
},
|
||||
{
|
||||
"name": "Memory"
|
||||
},
|
||||
{
|
||||
"name": "Miniatures"
|
||||
},
|
||||
{
|
||||
"name": "Modern Warefare"
|
||||
},
|
||||
{
|
||||
"name": "Movies / TV / Radio Theme"
|
||||
},
|
||||
{
|
||||
"name": "Murder/Mystery"
|
||||
},
|
||||
{
|
||||
"name": "Music"
|
||||
},
|
||||
{
|
||||
"name": "Mythology"
|
||||
},
|
||||
{
|
||||
"name": "Napoleonic"
|
||||
},
|
||||
{
|
||||
"name": "Nautical"
|
||||
},
|
||||
{
|
||||
"name": "Negotiation"
|
||||
},
|
||||
{
|
||||
"name": "Novel-based"
|
||||
},
|
||||
{
|
||||
"name": "Number"
|
||||
},
|
||||
{
|
||||
"name": "Party Game"
|
||||
},
|
||||
{
|
||||
"name": "Pike and Shot"
|
||||
},
|
||||
{
|
||||
"name": "Pirates"
|
||||
},
|
||||
{
|
||||
"name": "Political"
|
||||
},
|
||||
{
|
||||
"name": "Post-Napoleonic"
|
||||
},
|
||||
{
|
||||
"name": "Prehistoric"
|
||||
},
|
||||
{
|
||||
"name": "Print & Play"
|
||||
},
|
||||
{
|
||||
"name": "Puzzle"
|
||||
},
|
||||
{
|
||||
"name": "Racing"
|
||||
},
|
||||
{
|
||||
"name": "Real-time"
|
||||
},
|
||||
{
|
||||
"name": "Religious"
|
||||
},
|
||||
{
|
||||
"name": "Renaissance"
|
||||
},
|
||||
{
|
||||
"name": "Science Fiction"
|
||||
},
|
||||
{
|
||||
"name": "Space Exploration"
|
||||
},
|
||||
{
|
||||
"name": "Spies/Secret Agents"
|
||||
},
|
||||
{
|
||||
"name": "Sports"
|
||||
},
|
||||
{
|
||||
"name": "Territory Building"
|
||||
},
|
||||
{
|
||||
"name": "Trains"
|
||||
},
|
||||
{
|
||||
"name": "Transportation"
|
||||
},
|
||||
{
|
||||
"name": "Travel"
|
||||
},
|
||||
{
|
||||
"name": "Trivia"
|
||||
},
|
||||
{
|
||||
"name": "Video Game Theme"
|
||||
},
|
||||
{
|
||||
"name": "Vietnam War"
|
||||
},
|
||||
{
|
||||
"name": "Wargame"
|
||||
},
|
||||
{
|
||||
"name": "Word Game"
|
||||
},
|
||||
{
|
||||
"name": "World War I"
|
||||
},
|
||||
{
|
||||
"name": "World War II"
|
||||
},
|
||||
{
|
||||
"name": "Zombies"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,577 +0,0 @@
|
|||
{
|
||||
"mechanics": [
|
||||
{
|
||||
"name": "Acting"
|
||||
},
|
||||
{
|
||||
"name": "Action Drafting"
|
||||
},
|
||||
{
|
||||
"name": "Action Points"
|
||||
},
|
||||
{
|
||||
"name": "Action Queue"
|
||||
},
|
||||
{
|
||||
"name": "Action Retrieval"
|
||||
},
|
||||
{
|
||||
"name": "Action Timer"
|
||||
},
|
||||
{
|
||||
"name": "Action/Event"
|
||||
},
|
||||
{
|
||||
"name": "Advantage Token"
|
||||
},
|
||||
{
|
||||
"name": "Alliances"
|
||||
},
|
||||
{
|
||||
"name": "Area Majority / Influence"
|
||||
},
|
||||
{
|
||||
"name": "Area Movement"
|
||||
},
|
||||
{
|
||||
"name": "Area-Impulse"
|
||||
},
|
||||
{
|
||||
"name": "Auction Compensation"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Dexterity"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Dutch"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Dutch Priority"
|
||||
},
|
||||
{
|
||||
"name": "Auction: English"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Fixed Placement"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Multiple Lot"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Once Around"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Sealed Bid"
|
||||
},
|
||||
{
|
||||
"name": "Auction: Turn Order Until Pass"
|
||||
},
|
||||
{
|
||||
"name": "Auction/Bidding"
|
||||
},
|
||||
{
|
||||
"name": "Automatic Resource Growth"
|
||||
},
|
||||
{
|
||||
"name": "Betting and Bluffing"
|
||||
},
|
||||
{
|
||||
"name": "Bias"
|
||||
},
|
||||
{
|
||||
"name": "Bids As Wagers"
|
||||
},
|
||||
{
|
||||
"name": "Bingo"
|
||||
},
|
||||
{
|
||||
"name": "Bribery"
|
||||
},
|
||||
{
|
||||
"name": "Campaign / Battle Card Driven"
|
||||
},
|
||||
{
|
||||
"name": "Card Play Conflict Resolution"
|
||||
},
|
||||
{
|
||||
"name": "Catch the Leader"
|
||||
},
|
||||
{
|
||||
"name": "Chaining"
|
||||
},
|
||||
{
|
||||
"name": "Chit-Pull System"
|
||||
},
|
||||
{
|
||||
"name": "Closed Drafting"
|
||||
},
|
||||
{
|
||||
"name": "Closed Economy Auction"
|
||||
},
|
||||
{
|
||||
"name": "Command Cards"
|
||||
},
|
||||
{
|
||||
"name": "Commodity Speculation"
|
||||
},
|
||||
{
|
||||
"name": "Communication Limits"
|
||||
},
|
||||
{
|
||||
"name": "Connections"
|
||||
},
|
||||
{
|
||||
"name": "Constrained Bidding"
|
||||
},
|
||||
{
|
||||
"name": "Contracts"
|
||||
},
|
||||
{
|
||||
"name": "Cooperative Game"
|
||||
},
|
||||
{
|
||||
"name": "Crayon Rail System"
|
||||
},
|
||||
{
|
||||
"name": "Critical Hits and Failures"
|
||||
},
|
||||
{
|
||||
"name": "Cube Tower"
|
||||
},
|
||||
{
|
||||
"name": "Deck Construction"
|
||||
},
|
||||
{
|
||||
"name": "Deck, Bag, and Pool Building"
|
||||
},
|
||||
{
|
||||
"name": "Deduction"
|
||||
},
|
||||
{
|
||||
"name": "Delayed Purchase"
|
||||
},
|
||||
{
|
||||
"name": "Dice Rolling"
|
||||
},
|
||||
{
|
||||
"name": "Die Icon Resolution"
|
||||
},
|
||||
{
|
||||
"name": "Different Dice Movement"
|
||||
},
|
||||
{
|
||||
"name": "Drawing"
|
||||
},
|
||||
{
|
||||
"name": "Elapsed Real Time Ending"
|
||||
},
|
||||
{
|
||||
"name": "Enclosure"
|
||||
},
|
||||
{
|
||||
"name": "End Game Bonuses"
|
||||
},
|
||||
{
|
||||
"name": "Events"
|
||||
},
|
||||
{
|
||||
"name": "Finale Ending"
|
||||
},
|
||||
{
|
||||
"name": "Flicking"
|
||||
},
|
||||
{
|
||||
"name": "Follow"
|
||||
},
|
||||
{
|
||||
"name": "Force Commitment"
|
||||
},
|
||||
{
|
||||
"name": "Grid Coverage"
|
||||
},
|
||||
{
|
||||
"name": "Grid Movement"
|
||||
},
|
||||
{
|
||||
"name": "Hand Management"
|
||||
},
|
||||
{
|
||||
"name": "Hexagon Grid"
|
||||
},
|
||||
{
|
||||
"name": "Hidden Movement"
|
||||
},
|
||||
{
|
||||
"name": "Hidden Roles"
|
||||
},
|
||||
{
|
||||
"name": "Hidden Victory Points"
|
||||
},
|
||||
{
|
||||
"name": "Highest-Lowest Scoring"
|
||||
},
|
||||
{
|
||||
"name": "Hot Potato"
|
||||
},
|
||||
{
|
||||
"name": "I Cut, You Choose"
|
||||
},
|
||||
{
|
||||
"name": "Impulse Movement"
|
||||
},
|
||||
{
|
||||
"name": "Income"
|
||||
},
|
||||
{
|
||||
"name": "Increase Value of Unchosen Resources"
|
||||
},
|
||||
{
|
||||
"name": "Induction"
|
||||
},
|
||||
{
|
||||
"name": "Interrupts"
|
||||
},
|
||||
{
|
||||
"name": "Investment"
|
||||
},
|
||||
{
|
||||
"name": "Kill Steal"
|
||||
},
|
||||
{
|
||||
"name": "King of the Hill"
|
||||
},
|
||||
{
|
||||
"name": "Ladder Climbing"
|
||||
},
|
||||
{
|
||||
"name": "Layering"
|
||||
},
|
||||
{
|
||||
"name": "Legacy Game"
|
||||
},
|
||||
{
|
||||
"name": "Line Drawing"
|
||||
},
|
||||
{
|
||||
"name": "Line of Sight"
|
||||
},
|
||||
{
|
||||
"name": "Loans"
|
||||
},
|
||||
{
|
||||
"name": "Lose a Turn"
|
||||
},
|
||||
{
|
||||
"name": "Mancala"
|
||||
},
|
||||
{
|
||||
"name": "Map Addition"
|
||||
},
|
||||
{
|
||||
"name": "Map Deformation"
|
||||
},
|
||||
{
|
||||
"name": "Map Reduction"
|
||||
},
|
||||
{
|
||||
"name": "Market"
|
||||
},
|
||||
{
|
||||
"name": "Matching"
|
||||
},
|
||||
{
|
||||
"name": "Measurement Movement"
|
||||
},
|
||||
{
|
||||
"name": "Melding and Splaying"
|
||||
},
|
||||
{
|
||||
"name": "Memory"
|
||||
},
|
||||
{
|
||||
"name": "Minimap Resolution"
|
||||
},
|
||||
{
|
||||
"name": "Modular Board"
|
||||
},
|
||||
{
|
||||
"name": "Move Through Deck"
|
||||
},
|
||||
{
|
||||
"name": "Movement Points"
|
||||
},
|
||||
{
|
||||
"name": "Movement Template"
|
||||
},
|
||||
{
|
||||
"name": "Moving Multiple Units"
|
||||
},
|
||||
{
|
||||
"name": "Multi-Use Cards"
|
||||
},
|
||||
{
|
||||
"name": "Multiple Maps"
|
||||
},
|
||||
{
|
||||
"name": "Narrative Choice / Paragraph"
|
||||
},
|
||||
{
|
||||
"name": "Negotiation"
|
||||
},
|
||||
{
|
||||
"name": "Neighbor Scope"
|
||||
},
|
||||
{
|
||||
"name": "Network and Route Building"
|
||||
},
|
||||
{
|
||||
"name": "Once-Per-Game Abilities"
|
||||
},
|
||||
{
|
||||
"name": "Open Drafting"
|
||||
},
|
||||
{
|
||||
"name": "Order Counters"
|
||||
},
|
||||
{
|
||||
"name": "Ordering"
|
||||
},
|
||||
{
|
||||
"name": "Ownership"
|
||||
},
|
||||
{
|
||||
"name": "Paper-and-Pencil"
|
||||
},
|
||||
{
|
||||
"name": "Passed Action Token"
|
||||
},
|
||||
{
|
||||
"name": "Pattern Building"
|
||||
},
|
||||
{
|
||||
"name": "Pattern Movement"
|
||||
},
|
||||
{
|
||||
"name": "Pattern Recognition"
|
||||
},
|
||||
{
|
||||
"name": "Physical Removal"
|
||||
},
|
||||
{
|
||||
"name": "Pick-up and Deliver"
|
||||
},
|
||||
{
|
||||
"name": "Pieces as Map"
|
||||
},
|
||||
{
|
||||
"name": "Player Elimination"
|
||||
},
|
||||
{
|
||||
"name": "Player Judge"
|
||||
},
|
||||
{
|
||||
"name": "Point to Point Movement"
|
||||
},
|
||||
{
|
||||
"name": "Predictive Bid"
|
||||
},
|
||||
{
|
||||
"name": "Prisoner's Dilemma"
|
||||
},
|
||||
{
|
||||
"name": "Programmed Movement"
|
||||
},
|
||||
{
|
||||
"name": "Push Your Luck"
|
||||
},
|
||||
{
|
||||
"name": "Questions and Answers"
|
||||
},
|
||||
{
|
||||
"name": "Race"
|
||||
},
|
||||
{
|
||||
"name": "Random Production"
|
||||
},
|
||||
{
|
||||
"name": "Ratio / Combat Results Table"
|
||||
},
|
||||
{
|
||||
"name": "Re-rolling and Locking"
|
||||
},
|
||||
{
|
||||
"name": "Real-Time"
|
||||
},
|
||||
{
|
||||
"name": "Relative Movement"
|
||||
},
|
||||
{
|
||||
"name": "Resource Queue"
|
||||
},
|
||||
{
|
||||
"name": "Resource to Move"
|
||||
},
|
||||
{
|
||||
"name": "Rock-Paper-Scissors"
|
||||
},
|
||||
{
|
||||
"name": "Role Playing"
|
||||
},
|
||||
{
|
||||
"name": "Roles with Asymmetric Information"
|
||||
},
|
||||
{
|
||||
"name": "Roll / Spin and Move"
|
||||
},
|
||||
{
|
||||
"name": "Rondel"
|
||||
},
|
||||
{
|
||||
"name": "Scenario / Mission / Campaign Game"
|
||||
},
|
||||
{
|
||||
"name": "Score-and-Reset Game"
|
||||
},
|
||||
{
|
||||
"name": "Secret Unit Deployment"
|
||||
},
|
||||
{
|
||||
"name": "Selection Order Bid"
|
||||
},
|
||||
{
|
||||
"name": "Semi-Cooperative Game"
|
||||
},
|
||||
{
|
||||
"name": "Set Collection"
|
||||
},
|
||||
{
|
||||
"name": "Simulation"
|
||||
},
|
||||
{
|
||||
"name": "Simultaneous Action Selection"
|
||||
},
|
||||
{
|
||||
"name": "Singing"
|
||||
},
|
||||
{
|
||||
"name": "Single Loser Game"
|
||||
},
|
||||
{
|
||||
"name": "Slide/Push"
|
||||
},
|
||||
{
|
||||
"name": "Solo / Solitaire Game"
|
||||
},
|
||||
{
|
||||
"name": "Speed Matching"
|
||||
},
|
||||
{
|
||||
"name": "Square Grid"
|
||||
},
|
||||
{
|
||||
"name": "Stacking and Balancing"
|
||||
},
|
||||
{
|
||||
"name": "Stat Check Resolution"
|
||||
},
|
||||
{
|
||||
"name": "Static Capture"
|
||||
},
|
||||
{
|
||||
"name": "Stock Holding"
|
||||
},
|
||||
{
|
||||
"name": "Storytelling"
|
||||
},
|
||||
{
|
||||
"name": "Sudden Death Ending"
|
||||
},
|
||||
{
|
||||
"name": "Tags"
|
||||
},
|
||||
{
|
||||
"name": "Take That"
|
||||
},
|
||||
{
|
||||
"name": "Targeted Clues"
|
||||
},
|
||||
{
|
||||
"name": "Team-Based Game"
|
||||
},
|
||||
{
|
||||
"name": "Tech Trees / Tech Tracks"
|
||||
},
|
||||
{
|
||||
"name": "Three Dimensional Movement"
|
||||
},
|
||||
{
|
||||
"name": "Tile Placement"
|
||||
},
|
||||
{
|
||||
"name": "Track Movement"
|
||||
},
|
||||
{
|
||||
"name": "Trading"
|
||||
},
|
||||
{
|
||||
"name": "Traitor Game"
|
||||
},
|
||||
{
|
||||
"name": "Trick-taking"
|
||||
},
|
||||
{
|
||||
"name": "Tug of War"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Auction"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Claim Action"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Pass Order"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Progressive"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Random"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Role Order"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Stat-Based"
|
||||
},
|
||||
{
|
||||
"name": "Turn Order: Time Track"
|
||||
},
|
||||
{
|
||||
"name": "Variable Phase Order"
|
||||
},
|
||||
{
|
||||
"name": "Variable Player Powers"
|
||||
},
|
||||
{
|
||||
"name": "Variable Set-up"
|
||||
},
|
||||
{
|
||||
"name": "Victory Points as a Resource"
|
||||
},
|
||||
{
|
||||
"name": "Voting"
|
||||
},
|
||||
{
|
||||
"name": "Worker Placement"
|
||||
},
|
||||
{
|
||||
"name": "Worker Placement with Dice Workers"
|
||||
},
|
||||
{
|
||||
"name": "Worker Placement, Different Worker Types"
|
||||
},
|
||||
{
|
||||
"name": "Zone of Control"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["fullTextSearch", "fullTextIndex", "relationJoins"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
relationMode = "prisma"
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
userRoles UserRole[]
|
||||
|
||||
@@map("roles")
|
||||
}
|
||||
|
||||
model UserRole {
|
||||
id String @id @default(cuid())
|
||||
user User @relation(fields: [user_id], references: [id])
|
||||
user_id String
|
||||
role Role @relation(fields: [role_id], references: [id])
|
||||
role_id String
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@unique([user_id, role_id])
|
||||
@@index([user_id])
|
||||
@@index([role_id])
|
||||
@@map("user_roles")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
username String @unique
|
||||
hashed_password String?
|
||||
email String? @unique
|
||||
firstName String?
|
||||
lastName String?
|
||||
roles UserRole[]
|
||||
verified Boolean @default(false)
|
||||
receiveEmail Boolean @default(false)
|
||||
collection Collection?
|
||||
wishlist Wishlist?
|
||||
list List[]
|
||||
theme String @default("system")
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
sessions Session[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @unique
|
||||
userId String
|
||||
ip_country String
|
||||
ip_address String
|
||||
expiresAt DateTime
|
||||
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@map("sessions")
|
||||
}
|
||||
|
||||
model Collection {
|
||||
id String @id @default(cuid())
|
||||
user_id String @unique
|
||||
user User @relation(references: [id], fields: [user_id])
|
||||
items CollectionItem[]
|
||||
|
||||
@@index([user_id])
|
||||
@@map("collections")
|
||||
}
|
||||
|
||||
model CollectionItem {
|
||||
id String @id @default(cuid())
|
||||
collection_id String
|
||||
collection Collection @relation(references: [id], fields: [collection_id], onDelete: Cascade)
|
||||
game_id String @unique
|
||||
game Game @relation(references: [id], fields: [game_id])
|
||||
times_played Int
|
||||
|
||||
@@index([game_id, collection_id])
|
||||
@@index([game_id])
|
||||
@@index([collection_id])
|
||||
@@map("collection_items")
|
||||
}
|
||||
|
||||
model Wishlist {
|
||||
id String @id @default(cuid())
|
||||
user_id String @unique
|
||||
user User @relation(references: [id], fields: [user_id])
|
||||
items WishlistItem[]
|
||||
|
||||
@@index([user_id])
|
||||
@@map("wishlists")
|
||||
}
|
||||
|
||||
model WishlistItem {
|
||||
id String @id @default(cuid())
|
||||
wishlist_id String
|
||||
wishlist Wishlist @relation(references: [id], fields: [wishlist_id], onDelete: Cascade)
|
||||
game_id String @unique
|
||||
game Game @relation(references: [id], fields: [game_id])
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@index([game_id, wishlist_id])
|
||||
@@index([game_id])
|
||||
@@index([wishlist_id])
|
||||
@@map("wishlist_items")
|
||||
}
|
||||
|
||||
model List {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
user_id String @unique
|
||||
user User @relation(references: [id], fields: [user_id])
|
||||
items ListItem[]
|
||||
|
||||
@@index([user_id])
|
||||
@@map("lists")
|
||||
}
|
||||
|
||||
model ListItem {
|
||||
id String @id @default(cuid())
|
||||
list_id String
|
||||
list List @relation(references: [id], fields: [list_id], onDelete: Cascade)
|
||||
game_id String @unique
|
||||
game Game @relation(references: [id], fields: [game_id])
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@index([game_id, list_id])
|
||||
@@index([game_id])
|
||||
@@index([list_id])
|
||||
@@map("list_items")
|
||||
}
|
||||
|
||||
model Game {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
description String? @db.LongText
|
||||
year_published Int? @db.Year
|
||||
min_players Int?
|
||||
max_players Int?
|
||||
playtime Int?
|
||||
min_playtime Int?
|
||||
max_playtime Int?
|
||||
min_age Int?
|
||||
image_url String?
|
||||
thumb_url String?
|
||||
url String?
|
||||
categories Category[]
|
||||
mechanics Mechanic[]
|
||||
designers Designer[]
|
||||
publishers Publisher[]
|
||||
artists Artist[]
|
||||
names GameName[]
|
||||
expansions Expansion[] @relation("BaseToExpansion")
|
||||
expansion_of Expansion[] @relation("ExpansionToBase")
|
||||
collection_items CollectionItem[]
|
||||
wishlist_items WishlistItem[]
|
||||
list_items ListItem[]
|
||||
external_id Int @unique
|
||||
last_sync_at DateTime? @db.Timestamp(6)
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@fulltext([slug])
|
||||
@@map("games")
|
||||
}
|
||||
|
||||
model GameName {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
game_id String
|
||||
game Game @relation(references: [id], fields: [game_id])
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@index([game_id])
|
||||
@@map("game_names")
|
||||
}
|
||||
|
||||
model Publisher {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
external_id Int @unique
|
||||
games Game[]
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@map("publishers")
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
games Game[]
|
||||
external_id Int @unique
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Mechanic {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
games Game[]
|
||||
external_id Int @unique
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@map("mechanics")
|
||||
}
|
||||
|
||||
model Designer {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String
|
||||
external_id Int @unique
|
||||
games Game[]
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@map("designers")
|
||||
}
|
||||
|
||||
model Artist {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String @unique
|
||||
external_id Int @unique
|
||||
games Game[]
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@fulltext([name])
|
||||
@@map("artists")
|
||||
}
|
||||
|
||||
model Expansion {
|
||||
id String @id @default(cuid())
|
||||
base_game Game @relation(name: "BaseToExpansion", fields: [base_game_id], references: [id])
|
||||
base_game_id String
|
||||
game Game @relation(name: "ExpansionToBase", fields: [game_id], references: [id])
|
||||
game_id String
|
||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||
|
||||
@@index([base_game_id])
|
||||
@@index([game_id])
|
||||
@@map("expansions")
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log(`Start seeding ...`);
|
||||
|
||||
console.log('Creating roles ...');
|
||||
const existingRoles = await prisma.role.findMany();
|
||||
if (existingRoles.length === 0) {
|
||||
await prisma.role.createMany({
|
||||
data: [{ name: 'admin' }, { name: 'user' }]
|
||||
});
|
||||
console.log('Roles created.');
|
||||
} else {
|
||||
console.log('Roles already exist. No action taken.');
|
||||
}
|
||||
|
||||
if (!await prisma.publisher.findFirst({
|
||||
where: {
|
||||
external_id: 9999
|
||||
}
|
||||
})) {
|
||||
console.log('Publisher does not exist. Creating...');
|
||||
await prisma.publisher.create({
|
||||
data: {
|
||||
name: 'Unknown',
|
||||
slug: 'unknown',
|
||||
external_id: 9999
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!await prisma.designer.findFirst({
|
||||
where: {
|
||||
external_id: 9999
|
||||
}
|
||||
})) {
|
||||
console.log('Designer does not exist. Creating...');
|
||||
await prisma.designer.create({
|
||||
data: {
|
||||
name: 'Unknown',
|
||||
slug: 'unknown',
|
||||
external_id: 9999
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!await prisma.artist.findFirst({
|
||||
where: {
|
||||
external_id: 9999
|
||||
}
|
||||
})) {
|
||||
console.log('Artist does not exist. Creating...');
|
||||
await prisma.artist.create({
|
||||
data: {
|
||||
name: 'Unknown',
|
||||
slug: 'unknown',
|
||||
external_id: 9999
|
||||
}
|
||||
});
|
||||
}
|
||||
// for (const p of userData) {
|
||||
// const user = await prisma.user.create({
|
||||
// data: {
|
||||
// firstName: p.user.firstName,
|
||||
// lastName: p.user.lastName,
|
||||
// email: p.user.email,
|
||||
// username: p.user.username
|
||||
// }
|
||||
// });
|
||||
// console.log(`Created user with id: ${user.id}`);
|
||||
// }
|
||||
console.log(`Seeding finished.`);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
11
src/app.d.ts
vendored
11
src/app.d.ts
vendored
|
|
@ -2,21 +2,20 @@
|
|||
// for information about these interfaces
|
||||
// and what to do when importing types
|
||||
|
||||
import type { PrismaClient, User } from '@prisma/client';
|
||||
|
||||
type User = Omit<User, 'created_at' | 'updated_at'>;
|
||||
|
||||
// src/app.d.ts
|
||||
declare global {
|
||||
namespace App {
|
||||
interface PageData {
|
||||
flash?: { type: 'success' | 'error' | 'info'; message: string };
|
||||
flash?: {
|
||||
type: 'success' | 'error' | 'info';
|
||||
message: string;
|
||||
data?: Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
interface Locals {
|
||||
auth: import('lucia').AuthRequest;
|
||||
user: import('lucia').User | null;
|
||||
session: import('lucia').Session | null;
|
||||
prisma: PrismaClient;
|
||||
startTimer: number;
|
||||
ip: string;
|
||||
country: string;
|
||||
|
|
|
|||
|
|
@ -39,11 +39,12 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
|||
...sessionCookie.attributes
|
||||
});
|
||||
}
|
||||
console.log('session from hooks', JSON.stringify(session, null, 2));
|
||||
if (!session) {
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: ".",
|
||||
path: '.',
|
||||
...sessionCookie.attributes
|
||||
});
|
||||
}
|
||||
|
|
@ -57,4 +58,4 @@ export const handle: Handle = sequence(
|
|||
// Sentry.sentryHandle(),
|
||||
authentication
|
||||
);
|
||||
// export const handleError = Sentry.handleErrorWithSentry();
|
||||
// export const handleError = Sentry.handleErrorWithSentry();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from "$app/forms";
|
||||
import { fly } from "svelte/transition";
|
||||
import { createSelect, melt } from "@melt-ui/svelte";
|
||||
import { Check, ChevronDown, MinusCircle, PlusCircle } from "lucide-svelte";
|
||||
import { MinusCircle, PlusCircle } from "lucide-svelte";
|
||||
import { Button } from '$components/ui/button';
|
||||
import type { Collection, Wishlist } from "@prisma/client";
|
||||
import type { CollectionItems, Wishlists } from "../../schema";
|
||||
|
||||
export let game_id: string;
|
||||
export let collection: Collection;
|
||||
export let wishlist: Wishlist;
|
||||
export let collection: CollectionItems;
|
||||
export let wishlist: Wishlists;
|
||||
export let in_wishlist = false;
|
||||
export let in_collection = false;
|
||||
export let lists = [];
|
||||
|
|
|
|||
|
|
@ -1,25 +1,28 @@
|
|||
<script>
|
||||
import { PUBLIC_SITE_URL } from "$env/static/public";
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
<p>Bored Game © {new Date().getFullYear()} | Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a> | {PUBLIC_SITE_URL}</p>
|
||||
<p>Bored Game © {new Date().getFullYear()}</p>
|
||||
<p>Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a>
|
||||
</p>
|
||||
<p>{PUBLIC_SITE_URL}</p>
|
||||
</footer>
|
||||
|
||||
<style lang="postcss">
|
||||
footer {
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
footer a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
@media (width < 640px) {
|
||||
footer {
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import type { CollectionItem } from '@prisma/client';
|
||||
import type { CollectionItems } from '../../schema';
|
||||
|
||||
export let game: GameType | CollectionItem;
|
||||
export let game: GameType | CollectionItems;
|
||||
export let detailed: boolean = false;
|
||||
export let variant: 'default' | 'compact' = 'default';
|
||||
|
||||
|
|
@ -18,10 +18,10 @@
|
|||
<Card.Header>
|
||||
<Card.Title class="game-card-header">
|
||||
<span style:--transition-name="game-name-{game.slug}">
|
||||
{game.name}
|
||||
<!-- {game.name}
|
||||
{#if game?.year_published}
|
||||
({game?.year_published})
|
||||
{/if}
|
||||
{/if} -->
|
||||
</span>
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
title={`View ${game.name}`}
|
||||
data-sveltekit-preload-data
|
||||
>
|
||||
<img src={game.thumb_url} alt={`Image of ${game.name}`} loading="lazy" decoding="async" />
|
||||
<!-- <img src={game.thumb_url} alt={`Image of ${game.name}`} loading="lazy" decoding="async" />
|
||||
<div class="game-details">
|
||||
{#if game?.players}
|
||||
<p>Players: {game.players}</p>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
<div class="description">{@html game.description}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div> -->
|
||||
</a>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
|
|
|||
|
|
@ -6,10 +6,17 @@
|
|||
import * as Avatar from "$components/ui/avatar";
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import Logo from '$components/logo.svelte';
|
||||
import type { Users } from "../../schema";
|
||||
|
||||
export let user: User | null;
|
||||
export let user: Users | null = null;
|
||||
|
||||
let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
|
||||
console.log('header user', user);
|
||||
|
||||
let avatar: string;
|
||||
|
||||
$: if (user) {
|
||||
avatar = user.username?.slice(0, 1).toUpperCase() || ':)';
|
||||
}
|
||||
</script>
|
||||
|
||||
<header>
|
||||
|
|
@ -18,14 +25,12 @@
|
|||
<div class="logo-image">
|
||||
<Logo />
|
||||
</div>
|
||||
Bored Game
|
||||
<span class="logo-text">Bored Game</span>
|
||||
</a>
|
||||
</div>
|
||||
<!-- <TextSearch /> -->
|
||||
<nav>
|
||||
{#if user}
|
||||
<a href="/collection" title="Go to your collection" data-sveltekit-preload-data>Collection</a>
|
||||
<a href="/wishlist" title="Go to your wishlist" data-sveltekit-preload-data>Wishlist</a>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Avatar.Root asChild>
|
||||
|
|
@ -88,8 +93,7 @@
|
|||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
{/if}
|
||||
{#if !user}
|
||||
{:else}
|
||||
<a href="/login">
|
||||
<span class="flex-auto">Login</span></a
|
||||
>
|
||||
|
|
@ -131,6 +135,17 @@
|
|||
.logo-image {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
@media (width < 640px) {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
@media (width < 640px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Button as ButtonPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
import { buttonVariants, type Props, type Events } from ".";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { buttonVariants, type Props, type Events } from "./index.js";
|
||||
|
||||
type $$Props = Props;
|
||||
type $$Events = Events;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLUListElement>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import MoreHorizontal from "lucide-svelte/icons/more-horizontal";
|
||||
import { cn } from "$lib/utils";
|
||||
import Ellipsis from "lucide-svelte/icons/ellipsis";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||
|
|
@ -14,6 +14,6 @@
|
|||
class={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<MoreHorizontal class="h-4 w-4" />
|
||||
<Ellipsis class="h-4 w-4" />
|
||||
<span class="sr-only">More pages</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLLIElement>;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
import { buttonVariants, type Props } from "$lib/components/ui/button";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { buttonVariants, type Props } from "$lib/components/ui/button/index.js";
|
||||
|
||||
type $$Props = PaginationPrimitive.PageProps &
|
||||
Props & {
|
||||
|
|
|
|||
|
|
@ -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 { Button } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
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 { Button } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = PaginationPrimitive.PrevButtonProps;
|
||||
type $$Events = PaginationPrimitive.PrevButtonEvents;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
|
||||
import { cn } from "$lib/utils";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = PaginationPrimitive.Props;
|
||||
type $$Events = PaginationPrimitive.Events;
|
||||
|
|
|
|||
28
src/lib/components/ui/table/index.ts
Normal file
28
src/lib/components/ui/table/index.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import Root from "./table.svelte";
|
||||
import Body from "./table-body.svelte";
|
||||
import Caption from "./table-caption.svelte";
|
||||
import Cell from "./table-cell.svelte";
|
||||
import Footer from "./table-footer.svelte";
|
||||
import Head from "./table-head.svelte";
|
||||
import Header from "./table-header.svelte";
|
||||
import Row from "./table-row.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Body,
|
||||
Caption,
|
||||
Cell,
|
||||
Footer,
|
||||
Head,
|
||||
Header,
|
||||
Row,
|
||||
//
|
||||
Root as Table,
|
||||
Body as TableBody,
|
||||
Caption as TableCaption,
|
||||
Cell as TableCell,
|
||||
Footer as TableFooter,
|
||||
Head as TableHead,
|
||||
Header as TableHeader,
|
||||
Row as TableRow,
|
||||
};
|
||||
13
src/lib/components/ui/table/table-body.svelte
Normal file
13
src/lib/components/ui/table/table-body.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tbody class={cn("[&_tr:last-child]:border-0", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</tbody>
|
||||
13
src/lib/components/ui/table/table-caption.svelte
Normal file
13
src/lib/components/ui/table/table-caption.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLTableCaptionElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<caption class={cn("mt-4 text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</caption>
|
||||
18
src/lib/components/ui/table/table-cell.svelte
Normal file
18
src/lib/components/ui/table/table-cell.svelte
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLTdAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLTdAttributes;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<td
|
||||
class={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</td>
|
||||
13
src/lib/components/ui/table/table-footer.svelte
Normal file
13
src/lib/components/ui/table/table-footer.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tfoot class={cn("bg-primary font-medium text-primary-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</tfoot>
|
||||
19
src/lib/components/ui/table/table-head.svelte
Normal file
19
src/lib/components/ui/table/table-head.svelte
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLThAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLThAttributes;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<th
|
||||
class={cn(
|
||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</th>
|
||||
14
src/lib/components/ui/table/table-header.svelte
Normal file
14
src/lib/components/ui/table/table-header.svelte
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<thead class={cn("[&_tr]:border-b", className)} {...$$restProps} on:click on:keydown>
|
||||
<slot />
|
||||
</thead>
|
||||
23
src/lib/components/ui/table/table-row.svelte
Normal file
23
src/lib/components/ui/table/table-row.svelte
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLTableRowElement> & {
|
||||
"data-state"?: unknown;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tr
|
||||
class={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</tr>
|
||||
15
src/lib/components/ui/table/table.svelte
Normal file
15
src/lib/components/ui/table/table.svelte
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLTableAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLTableAttributes;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class="w-full overflow-auto">
|
||||
<table class={cn("w-full caption-bottom text-sm", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,7 @@ import {
|
|||
DATABASE_PASSWORD,
|
||||
DATABASE_HOST,
|
||||
DATABASE_DB,
|
||||
DATABASE_PORT,
|
||||
DATABASE_PORT
|
||||
} from '$env/static/private';
|
||||
import * as schema from '../schema';
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ const pool = new pg.Pool({
|
|||
host: DATABASE_HOST,
|
||||
port: Number(DATABASE_PORT).valueOf(),
|
||||
database: DATABASE_DB,
|
||||
ssl: true,
|
||||
ssl: DATABASE_HOST !== 'localhost'
|
||||
});
|
||||
|
||||
// user: DATABASE_USER,
|
||||
|
|
|
|||
|
|
@ -1 +1,5 @@
|
|||
export const notSignedInMessage = { type: 'error', message: 'You are not signed in' } as const;
|
||||
export const notSignedInMessage = { type: 'error', message: 'You are not signed in' } as const;
|
||||
export const forbiddenMessage = {
|
||||
type: 'error',
|
||||
message: 'You are not allowed to access this'
|
||||
} as const;
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
export default prisma
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
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";
|
||||
import { password_reset_tokens } from "../../schema";
|
||||
|
||||
export async function createPasswordResetToken(userId: string): Promise<string> {
|
||||
// optionally invalidate all existing tokens
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
// lib/server/lucia.ts
|
||||
import { Lucia, TimeSpan } from 'lucia';
|
||||
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
||||
import { dev } from '$app/environment';
|
||||
import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';
|
||||
import db from '$lib/drizzle';
|
||||
import { sessions, users } from '../../schema';
|
||||
|
||||
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
|
||||
|
||||
let domain;
|
||||
if (process.env.NODE_ENV === 'production' || process.env.VERCEL_ENV === 'production') {
|
||||
domain = 'boredgame.vercel.app';
|
||||
} else if (process.env.VERCEL_ENV === 'preview' || process.env.VERCEL_ENV === 'development') {
|
||||
domain = process.env.VERCEL_BRANCH_URL;
|
||||
} else {
|
||||
domain = 'localhost';
|
||||
}
|
||||
|
||||
export const lucia = new Lucia(adapter, {
|
||||
getSessionAttributes: (attributes) => {
|
||||
return {
|
||||
|
|
@ -23,23 +31,24 @@ export const lucia = new Lucia(adapter, {
|
|||
theme: attributes.theme
|
||||
};
|
||||
},
|
||||
sessionExpiresIn: new TimeSpan(30, "d"), // 30 days
|
||||
sessionExpiresIn: new TimeSpan(30, 'd'), // 30 days
|
||||
sessionCookie: {
|
||||
name: 'session',
|
||||
expires: false, // session cookies have very long lifespan (2 years)
|
||||
attributes: {
|
||||
// set to `true` when using HTTPS
|
||||
secure: !dev,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
domain: dev ? 'localhost' : 'boredgame.vercel.app',
|
||||
domain
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
declare module "lucia" {
|
||||
declare module 'lucia' {
|
||||
interface Register {
|
||||
Lucia: typeof lucia;
|
||||
DatabaseUserAttributes: DatabaseUserAttributes;
|
||||
DatabaseSessionAttributes: DatabaseSessionAttributes;
|
||||
}
|
||||
interface DatabaseSessionAttributes {
|
||||
ip_country: string;
|
||||
|
|
@ -51,5 +60,6 @@ declare module "lucia" {
|
|||
firstName: string;
|
||||
lastName: string;
|
||||
theme: string;
|
||||
two_factor_secret: string | null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
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 === '') {
|
||||
|
|
@ -44,7 +44,7 @@ export async function createCategory(locals: App.Locals, category: Categories, e
|
|||
.insert(categories)
|
||||
.values({
|
||||
name: category.name,
|
||||
slug: kebabCase(category.name || category.slug || '')
|
||||
slug: kebabCase(category.name ?? category.slug ?? '')
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
import type { Game } from '@prisma/client';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import type { Games } from '../../schema';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { userSchema } from './zod-schemas';
|
|||
export const profileSchema = userSchema.pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
username: true
|
||||
username: true,
|
||||
});
|
||||
|
||||
export const changeEmailSchema = userSchema.pick({
|
||||
|
|
@ -15,7 +15,7 @@ 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()
|
||||
confirm_password: z.string({ required_error: 'Confirm Password is required' }).trim(),
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
refinePasswords(confirm_password, password, ctx);
|
||||
|
|
@ -23,6 +23,19 @@ export const changeUserPasswordSchema = z
|
|||
|
||||
export type ChangeUserPasswordSchema = typeof changeUserPasswordSchema;
|
||||
|
||||
export const addTwoFactorSchema = z.object({
|
||||
current_password: z.string({ required_error: 'Current Password is required' }),
|
||||
two_factor_code: z.string({ required_error: 'Two Factor Code is required' }).trim(),
|
||||
});
|
||||
|
||||
export type AddTwoFactorSchema = typeof addTwoFactorSchema;
|
||||
|
||||
export const removeTwoFactorSchema = addTwoFactorSchema.pick({
|
||||
current_password: true,
|
||||
});
|
||||
|
||||
export type RemoveTwoFactorSchema = typeof removeTwoFactorSchema;
|
||||
|
||||
export const updateUserPasswordSchema = userSchema
|
||||
.pick({ password: true, confirm_password: true })
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
|
|
@ -32,7 +45,7 @@ export const updateUserPasswordSchema = userSchema
|
|||
export const refinePasswords = async function (
|
||||
confirm_password: string,
|
||||
password: string,
|
||||
ctx: z.RefinementCtx
|
||||
ctx: z.RefinementCtx,
|
||||
) {
|
||||
comparePasswords(confirm_password, password, ctx);
|
||||
checkPasswordStrength(password, ctx);
|
||||
|
|
@ -41,13 +54,13 @@ export const refinePasswords = async function (
|
|||
const comparePasswords = async function (
|
||||
confirm_password: string,
|
||||
password: string,
|
||||
ctx: z.RefinementCtx
|
||||
ctx: z.RefinementCtx,
|
||||
) {
|
||||
if (confirm_password !== password) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: 'Password and Confirm Password must match',
|
||||
path: ['confirm_password']
|
||||
path: ['confirm_password'],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -100,7 +113,15 @@ const checkPasswordStrength = async function (password: string, ctx: z.Refinemen
|
|||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: errorMessage,
|
||||
path: ['password']
|
||||
path: ['password'],
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const addRoleSchema = z.object({
|
||||
roles: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: 'You have to select at least one item.',
|
||||
}),
|
||||
});
|
||||
|
||||
export type AddRoleSchema = typeof addRoleSchema;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { refinePasswords } from "./account";
|
||||
import { userSchema } from "./zod-schemas";
|
||||
import { refinePasswords } from './account';
|
||||
import { userSchema } from './zod-schemas';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const signUpSchema = userSchema
|
||||
.pick({
|
||||
|
|
@ -9,13 +10,18 @@ export const signUpSchema = userSchema
|
|||
username: true,
|
||||
password: true,
|
||||
confirm_password: true,
|
||||
terms: true
|
||||
terms: true,
|
||||
})
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
refinePasswords(confirm_password, password, ctx);
|
||||
});
|
||||
|
||||
export const signInSchema = userSchema.pick({
|
||||
username: true,
|
||||
password: true
|
||||
});
|
||||
export const signInSchema = z.object({
|
||||
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(),
|
||||
totpToken: z.string().trim().min(6).max(10).optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import { migrate } from 'drizzle-orm/postgres-js/migrator';
|
|||
|
||||
const connection = postgres({
|
||||
host: process.env.DATABASE_HOST || 'localhost',
|
||||
port: 5432,
|
||||
port: process.env.DATABASE_PORT,
|
||||
user: process.env.DATABASE_USER || 'root',
|
||||
password: process.env.DATABASE_PASSWORD || '',
|
||||
database: process.env.DATABASE_DB || 'boredgame',
|
||||
ssl: 'require',
|
||||
ssl: process.env.NODE_ENV === 'development' ? false : 'require',
|
||||
max: 1
|
||||
});
|
||||
const db = drizzle(connection);
|
||||
|
|
@ -21,5 +21,5 @@ try {
|
|||
console.error(e);
|
||||
}
|
||||
|
||||
await connection.end();
|
||||
// await connection.end();
|
||||
process.exit();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,32 @@
|
|||
import { redirect } from 'sveltekit-flash-message/server'
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import { redirect, loadFlash } from 'sveltekit-flash-message/server';
|
||||
import { forbiddenMessage, notSignedInMessage } from '$lib/flashMessages';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { user_roles } from '../../../../schema';
|
||||
|
||||
export async function load(event) {
|
||||
export const load = loadFlash(async (event) => {
|
||||
const { locals } = event;
|
||||
if (!locals?.user?.role?.includes('admin')) {
|
||||
if (!locals?.user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
return {}
|
||||
};
|
||||
const { user } = locals;
|
||||
const userRoles = await db.query.user_roles.findMany({
|
||||
where: eq(user_roles.user_id, user.id),
|
||||
with: {
|
||||
role: {
|
||||
columns: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const containsAdminRole = userRoles.some((user_role) => user_role?.role?.name === 'admin');
|
||||
if (!userRoles?.length || !containsAdminRole) {
|
||||
console.log('Not an admin');
|
||||
redirect(302, '/', forbiddenMessage, event);
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1 +1,50 @@
|
|||
<slot />
|
||||
<script lang="ts">
|
||||
import { getFlash } from 'sveltekit-flash-message';
|
||||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { theme } from '$state/theme';
|
||||
import toast, { Toaster } from 'svelte-french-toast';
|
||||
|
||||
export let data;
|
||||
$: ({ user } = data);
|
||||
|
||||
const flash = getFlash(page, {
|
||||
clearOnNavigate: true,
|
||||
clearAfterMs: 3000,
|
||||
clearArray: true
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
// set the theme to the user's active theme
|
||||
$theme = user?.theme || 'system';
|
||||
document.querySelector('html')?.setAttribute('data-theme', $theme);
|
||||
});
|
||||
|
||||
|
||||
$: if ($flash) {
|
||||
if ($flash.type === 'success') {
|
||||
toast.success($flash.message);
|
||||
} else {
|
||||
toast.error($flash.message, {
|
||||
duration: 5000
|
||||
});
|
||||
}
|
||||
|
||||
// Clearing the flash message could sometimes
|
||||
// be required here to avoid double-toasting.
|
||||
flash.set(undefined);
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1>Do the admin stuff</h1>
|
||||
|
||||
<slot />
|
||||
|
||||
<Toaster />
|
||||
|
||||
<style lang="postcss">
|
||||
:global(main) {
|
||||
margin: 0;
|
||||
max-width: 100vw;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Button } from '$components/ui/button';
|
||||
</script>
|
||||
|
||||
<h1>At the admin page yo!</h1>
|
||||
|
||||
<Button href="/admin/users">Search for users</Button>
|
||||
23
src/routes/(app)/(protected)/admin/users/+page.server.ts
Normal file
23
src/routes/(app)/(protected)/admin/users/+page.server.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { redirect } from "sveltekit-flash-message/server";
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { notSignedInMessage } from "$lib/flashMessages";
|
||||
import db from "$lib/drizzle";
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
|
||||
// TODO: Ensure admin user
|
||||
if (!event.locals.user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const users = await db.query
|
||||
.users
|
||||
.findMany({
|
||||
limit: 10,
|
||||
offset: 0
|
||||
});
|
||||
|
||||
return {
|
||||
users
|
||||
};
|
||||
};
|
||||
10
src/routes/(app)/(protected)/admin/users/+page.svelte
Normal file
10
src/routes/(app)/(protected)/admin/users/+page.svelte
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import DataTable from './user-table.svelte';
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<h1>Users</h1>
|
||||
|
||||
<div class="container mx-auto py-10">
|
||||
<DataTable users={data?.users ?? []}/>
|
||||
</div>
|
||||
143
src/routes/(app)/(protected)/admin/users/[id]/+page.server.ts
Normal file
143
src/routes/(app)/(protected)/admin/users/[id]/+page.server.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import { and, eq, inArray, not } from 'drizzle-orm';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { forbiddenMessage, notSignedInMessage } from '$lib/flashMessages';
|
||||
import db from '$lib/drizzle';
|
||||
import { roles, user_roles, users } from '../../../../../../schema';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const { params } = event;
|
||||
const { id } = params;
|
||||
|
||||
// TODO: Ensure admin user
|
||||
if (!event.locals.user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const foundUser = await db.query.users.findFirst({
|
||||
where: eq(users.cuid, id),
|
||||
with: {
|
||||
user_roles: {
|
||||
with: {
|
||||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const containsAdminRole = foundUser?.user_roles?.some(
|
||||
(user_role) => user_role?.role?.name === 'admin'
|
||||
);
|
||||
if (!containsAdminRole) {
|
||||
console.log('Not an admin');
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const currentRoleIds = foundUser?.user_roles?.map((user_role) => user_role?.role.cuid) || [];
|
||||
let availableRoles: { name: string; cuid: string }[] = [];
|
||||
if (currentRoleIds?.length > 0) {
|
||||
availableRoles = await db.query.roles.findMany({
|
||||
where: not(inArray(roles.cuid, currentRoleIds)),
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
user: foundUser,
|
||||
availableRoles
|
||||
};
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
addRole: async (event) => {
|
||||
const { request, locals } = event;
|
||||
const { user } = locals;
|
||||
|
||||
if (!user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const userRoles = await db.query.user_roles.findMany({
|
||||
where: eq(user_roles.user_id, user.id),
|
||||
with: {
|
||||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('userRoles', userRoles);
|
||||
|
||||
const containsAdminRole = userRoles.some((user_role) => user_role?.role?.name === 'admin');
|
||||
console.log('containsAdminRole', containsAdminRole);
|
||||
if (!containsAdminRole) {
|
||||
redirect(302, '/', forbiddenMessage, event);
|
||||
}
|
||||
|
||||
const data = await request.formData();
|
||||
const role = data.get('role');
|
||||
const dbRole = await db.query.roles.findFirst({
|
||||
where: eq(roles.cuid, role?.toString() ?? '')
|
||||
});
|
||||
console.log('dbRole', dbRole);
|
||||
if (dbRole) {
|
||||
await db.insert(user_roles).values({
|
||||
user_id: user.id,
|
||||
role_id: dbRole.id
|
||||
});
|
||||
redirect({ type: 'success', message: `Successfully added role ${dbRole.name}!` }, event);
|
||||
} else {
|
||||
redirect({ type: 'error', message: `Failed to add role ${dbRole.name}!` }, event);
|
||||
}
|
||||
},
|
||||
removeRole: async (event) => {
|
||||
const { request, locals } = event;
|
||||
const { user } = locals;
|
||||
if (!user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const userRoles = await db.query.user_roles.findMany({
|
||||
where: eq(user_roles.user_id, user.id),
|
||||
with: {
|
||||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const containsAdminRole = userRoles.some((user_role) => user_role?.role?.name === 'admin');
|
||||
if (!containsAdminRole) {
|
||||
redirect(302, '/', forbiddenMessage, event);
|
||||
}
|
||||
|
||||
const data = await request.formData();
|
||||
const role = data.get('role');
|
||||
const dbRole = await db.query.roles.findFirst({
|
||||
where: eq(roles.cuid, role?.toString() ?? '')
|
||||
});
|
||||
console.log('dbRole', dbRole);
|
||||
if (dbRole) {
|
||||
await db
|
||||
.delete(user_roles)
|
||||
.where(and(eq(user_roles.user_id, user.id), eq(user_roles.role_id, dbRole.id)));
|
||||
redirect({ type: 'success', message: `Successfully removed role ${dbRole.name}!` }, event);
|
||||
} else {
|
||||
redirect({ type: 'error', message: `Failed to remove role ${dbRole.name} !` }, event);
|
||||
}
|
||||
}
|
||||
};
|
||||
44
src/routes/(app)/(protected)/admin/users/[id]/+page.svelte
Normal file
44
src/routes/(app)/(protected)/admin/users/[id]/+page.svelte
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import capitalize from 'just-capitalize';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
// import AddRolesForm from './add-roles-form.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
const { user, availableRoles } = data;
|
||||
const { user_roles }: { user_roles: { role: { name: string, cuid: string } }[] } = user;
|
||||
</script>
|
||||
|
||||
<h1>User Details</h1>
|
||||
<p>Username {user?.username}</p>
|
||||
<p>Email Address: {user?.email || 'N/A'}</p>
|
||||
<p>First Name: {user?.first_name || 'N/A'}</p>
|
||||
<p>Last Name: {user?.last_name || 'N/A'}</p>
|
||||
|
||||
<h2>User Roles</h2>
|
||||
{#each user_roles as user_role}
|
||||
{#if user_role?.role?.name !== 'user'}
|
||||
<form action="?/removeRole" method="POST" use:enhance data-sveltekit-replacestate>
|
||||
<div class="flex flex-row space-x-3 place-items-center mt-2">
|
||||
<input id="role" type="hidden" name="role" value={user_role?.role?.cuid} />
|
||||
<Button type="submit">Remove</Button>
|
||||
<p>{capitalize(user_role?.role?.name)}</p>
|
||||
</div>
|
||||
</form>
|
||||
{:else}
|
||||
<p>{capitalize(user_role?.role?.name)}</p>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<h2>Roles Available to Assign</h2>
|
||||
<!--<AddRolesForm {availableRoles} />-->
|
||||
{#each availableRoles as role}
|
||||
<form action="?/addRole" method="POST" use:enhance data-sveltekit-replacestate>
|
||||
<div class="flex flex-row space-x-3 place-items-center mt-2">
|
||||
<input id="role" type="hidden" name="role" value={role?.cuid} />
|
||||
<Button type="submit">Add</Button>
|
||||
<p>{capitalize(role?.name)}</p>
|
||||
</div>
|
||||
</form>
|
||||
{/each}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<script lang="ts">
|
||||
import * as Form from '$lib/components/ui/form';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox/index.js';
|
||||
import { addRoleSchema, type AddRoleSchema } from '$lib/validations/account';
|
||||
import {
|
||||
type SuperValidated,
|
||||
type Infer,
|
||||
superForm
|
||||
} from 'sveltekit-superforms';
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
|
||||
export let availableRoles: { name: string; cuid: string }[] = [];
|
||||
const data: SuperValidated<Infer<AddRoleSchema>> = availableRoles;
|
||||
|
||||
const form = superForm(data, {
|
||||
validators: zodClient(addRoleSchema)
|
||||
// onUpdated: ({ form: f }) => {
|
||||
// if (f.valid) {
|
||||
// toast.success("You submitted" + JSON.stringify(f.data, null, 2));
|
||||
// } else {
|
||||
// toast.error("Please fix the errors in the form.");
|
||||
// }
|
||||
// }
|
||||
});
|
||||
|
||||
const { form: formData, enhance } = form;
|
||||
|
||||
function addRole(id: string) {
|
||||
$formData.roles = [...$formData.roles, id];
|
||||
}
|
||||
|
||||
function removeRole(id: string) {
|
||||
$formData.roles = $formData.roles.filter((i) => i !== id);
|
||||
}
|
||||
</script>
|
||||
|
||||
<form action="/?/addMultipleRoles" method="POST" use:enhance>
|
||||
<Form.Fieldset {form} name="roles" class="space-y-0">
|
||||
<div class="mb-4">
|
||||
<Form.Legend class="text-base">Roles</Form.Legend>
|
||||
<Form.Description>
|
||||
Select the roles you want to add to the user.
|
||||
</Form.Description>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
{#each roles as item}
|
||||
{@const checked = $formData.roles.includes(item.cuid)}
|
||||
<div class="flex flex-row items-start space-x-3">
|
||||
<Form.Control let:attrs>
|
||||
<Checkbox
|
||||
{...attrs}
|
||||
{checked}
|
||||
onCheckedChange={(v) => {
|
||||
if (v) {
|
||||
addItem(item.id);
|
||||
} else {
|
||||
removeItem(item.id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Form.Label class="text-sm font-normal">
|
||||
{item.label}
|
||||
</Form.Label>
|
||||
<input
|
||||
hidden
|
||||
type="checkbox"
|
||||
name={attrs.name}
|
||||
value={item.id}
|
||||
{checked}
|
||||
/>
|
||||
</Form.Control>
|
||||
</div>
|
||||
{/each}
|
||||
<Form.FieldErrors />
|
||||
</div>
|
||||
</Form.Fieldset>
|
||||
<Form.Button>Update display</Form.Button>
|
||||
{#if browser}
|
||||
<SuperDebug data={$formData} />
|
||||
{/if}
|
||||
</form>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script lang="ts">
|
||||
import Ellipsis from 'lucide-svelte/icons/ellipsis';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { User } from 'lucide-svelte';
|
||||
|
||||
export let cuid: string;
|
||||
</script>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button
|
||||
variant="ghost"
|
||||
builders={[builder]}
|
||||
size="icon"
|
||||
class="relative h-8 w-8 p-0"
|
||||
>
|
||||
<span class="sr-only">Open menu</span>
|
||||
<Ellipsis class="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Label>Actions</DropdownMenu.Label>
|
||||
<DropdownMenu.Item on:click={() => navigator.clipboard.writeText(cuid)}>
|
||||
Copy User ID
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Separator />
|
||||
<a href={`/admin/users/${cuid}`}>
|
||||
<DropdownMenu.Item>
|
||||
<User class="mr-2 h-4 w-4" />
|
||||
<span>View user</span>
|
||||
</DropdownMenu.Item>
|
||||
</a>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
export let checked: Writable<boolean>;
|
||||
</script>
|
||||
|
||||
<Checkbox bind:checked={$checked} />
|
||||
232
src/routes/(app)/(protected)/admin/users/user-table.svelte
Normal file
232
src/routes/(app)/(protected)/admin/users/user-table.svelte
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
createTable,
|
||||
Render,
|
||||
Subscribe,
|
||||
createRender,
|
||||
} from "svelte-headless-table";
|
||||
import {
|
||||
addPagination,
|
||||
addSortBy,
|
||||
addTableFilter,
|
||||
addHiddenColumns,
|
||||
addSelectedRows,
|
||||
} from "svelte-headless-table/plugins";
|
||||
import { readable } from "svelte/store";
|
||||
import ArrowUpDown from "lucide-svelte/icons/arrow-up-down";
|
||||
import ChevronDown from "lucide-svelte/icons/chevron-down";
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import DataTableActions from "./user-table-actions.svelte";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import DataTableCheckbox from "./user-table-checkbox.svelte";
|
||||
import type { Users } from '../../../../../schema';
|
||||
|
||||
export let users: Users[] = [];
|
||||
|
||||
const table = createTable(readable(users), {
|
||||
page: addPagination(),
|
||||
sort: addSortBy({ disableMultiSort: true }),
|
||||
filter: addTableFilter({
|
||||
fn: ({ filterValue, value }) => value.includes(filterValue),
|
||||
}),
|
||||
hide: addHiddenColumns(),
|
||||
select: addSelectedRows(),
|
||||
});
|
||||
|
||||
const columns = table.createColumns([
|
||||
table.column({
|
||||
accessor: "cuid",
|
||||
header: (_, { pluginStates }) => {
|
||||
const { allPageRowsSelected } = pluginStates.select;
|
||||
return createRender(DataTableCheckbox, {
|
||||
checked: allPageRowsSelected,
|
||||
});
|
||||
},
|
||||
cell: ({ row }, { pluginStates }) => {
|
||||
const { getRowState } = pluginStates.select;
|
||||
const { isSelected } = getRowState(row);
|
||||
|
||||
return createRender(DataTableCheckbox, {
|
||||
checked: isSelected,
|
||||
});
|
||||
},
|
||||
plugins: {
|
||||
filter: {
|
||||
exclude: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
table.column({
|
||||
accessor: "username",
|
||||
header: "Username",
|
||||
}),
|
||||
table.column({
|
||||
accessor: "email",
|
||||
header: "Email",
|
||||
cell: ({ value }) => {
|
||||
return value ?? "N/A";
|
||||
}
|
||||
}),
|
||||
table.column({
|
||||
accessor: "first_name",
|
||||
header: "First Name",
|
||||
cell: ({ value }) => {
|
||||
return value && value.length > 0 ? value : "N/A";
|
||||
},
|
||||
plugins: {
|
||||
filter: {
|
||||
exclude: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
table.column({
|
||||
accessor: "last_name",
|
||||
header: "Last Name",
|
||||
cell: ({ value }) => {
|
||||
return value && value.length > 0 ? value : "N/A";
|
||||
},
|
||||
plugins: {
|
||||
filter: {
|
||||
exclude: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
table.column({
|
||||
accessor: ({ cuid }) => cuid,
|
||||
header: "",
|
||||
cell: ({ value }) => {
|
||||
return createRender(DataTableActions, { cuid: value });
|
||||
},
|
||||
plugins: {
|
||||
sort: {
|
||||
disable: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const {
|
||||
headerRows,
|
||||
pageRows,
|
||||
tableAttrs,
|
||||
tableBodyAttrs,
|
||||
pluginStates,
|
||||
flatColumns,
|
||||
rows,
|
||||
} = table.createViewModel(columns);
|
||||
|
||||
const { pageIndex, hasNextPage, hasPreviousPage } = pluginStates.page;
|
||||
const { filterValue } = pluginStates.filter;
|
||||
const { hiddenColumnIds } = pluginStates.hide;
|
||||
const { selectedDataIds } = pluginStates.select;
|
||||
|
||||
const ids = flatColumns.map((col) => col.id);
|
||||
let hideForId = Object.fromEntries(ids.map((id) => [id, true]));
|
||||
|
||||
$: $hiddenColumnIds = Object.entries(hideForId)
|
||||
.filter(([, hide]) => !hide)
|
||||
.map(([id]) => id);
|
||||
|
||||
const columnsToHide: string[] = [];
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center py-4">
|
||||
<Input
|
||||
class="max-w-sm"
|
||||
placeholder="Filter emails..."
|
||||
type="text"
|
||||
bind:value={$filterValue}
|
||||
/>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button variant="outline" class="ml-auto" builders={[builder]}>
|
||||
Columns <ChevronDown class="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
{#each flatColumns as col}
|
||||
{#if columnsToHide.includes(col.id)}
|
||||
<DropdownMenu.CheckboxItem bind:checked={hideForId[col.id]}>
|
||||
{col.header}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
{/if}
|
||||
{/each}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<div class="rounded-md border">
|
||||
<Table.Root {...$tableAttrs}>
|
||||
<Table.Header>
|
||||
{#each $headerRows as headerRow}
|
||||
<Subscribe rowAttrs={headerRow.attrs()}>
|
||||
<Table.Row>
|
||||
{#each headerRow.cells as cell (cell.id)}
|
||||
<Subscribe
|
||||
attrs={cell.attrs()}
|
||||
let:attrs
|
||||
props={cell.props()}
|
||||
let:props
|
||||
>
|
||||
<Table.Head {...attrs} class="[&:has([role=checkbox])]:pl-3">
|
||||
{#if cell.id === "email"}
|
||||
<Button variant="ghost" on:click={props.sort.toggle}>
|
||||
<Render of={cell.render()} />
|
||||
<ArrowUpDown class={"ml-2 h-4 w-4"} />
|
||||
</Button>
|
||||
{:else if cell.id === "username"}
|
||||
<Button variant="ghost" on:click={props.sort.toggle}>
|
||||
<Render of={cell.render()} />
|
||||
<ArrowUpDown class={"ml-2 h-4 w-4"} />
|
||||
</Button>
|
||||
{:else}
|
||||
<Render of={cell.render()} />
|
||||
{/if}
|
||||
</Table.Head>
|
||||
</Subscribe>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
</Subscribe>
|
||||
{/each}
|
||||
</Table.Header>
|
||||
<Table.Body {...$tableBodyAttrs}>
|
||||
{#each $pageRows as row (row.id)}
|
||||
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
|
||||
<Table.Row
|
||||
{...rowAttrs}
|
||||
data-state={$selectedDataIds[row.id] && "selected"}
|
||||
>
|
||||
{#each row.cells as cell (cell.id)}
|
||||
<Subscribe attrs={cell.attrs()} let:attrs>
|
||||
<Table.Cell {...attrs} class="[&:has([role=checkbox])]:pl-3">
|
||||
<Render of={cell.render()} />
|
||||
</Table.Cell>
|
||||
</Subscribe>
|
||||
{/each}
|
||||
</Table.Row>
|
||||
</Subscribe>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
<div class="flex items-center justify-end space-x-4 py-4">
|
||||
<div class="flex-1 text-sm text-muted-foreground">
|
||||
{Object.keys($selectedDataIds).length} of{" "}
|
||||
{$rows.length} row(s) selected.
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
on:click={() => ($pageIndex = $pageIndex - 1)}
|
||||
disabled={!$hasPreviousPage}>Previous</Button
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!$hasNextPage}
|
||||
on:click={() => ($pageIndex = $pageIndex + 1)}>Next</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import prisma from '$lib/prisma';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle.js';
|
||||
import { wishlists } from '../../../../schema.js';
|
||||
|
||||
export async function load({ locals }) {
|
||||
if (!locals.user) {
|
||||
|
|
@ -7,23 +9,12 @@ export async function load({ locals }) {
|
|||
}
|
||||
|
||||
try {
|
||||
let wishlists = await prisma.wishlist.findMany({
|
||||
where: {
|
||||
user_id: session.userId
|
||||
}
|
||||
const userWishlists = await db.query.wishlists.findMany({
|
||||
where: eq(wishlists.user_id, locals.user.id)
|
||||
});
|
||||
|
||||
if (wishlists.length === 0) {
|
||||
const wishlist = await prisma.wishlist.create({
|
||||
data: {
|
||||
user_id: session.userId
|
||||
}
|
||||
});
|
||||
wishlists.push(wishlist);
|
||||
}
|
||||
|
||||
return {
|
||||
wishlists
|
||||
wishlsits: userWishlists
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
|
|||
|
|
@ -5,20 +5,18 @@
|
|||
const wishlists = data.wishlists || [];
|
||||
</script>
|
||||
|
||||
|
||||
<aside class="wishlists">
|
||||
<h2>Your Wishlists</h2>
|
||||
<div class="separator"></div>
|
||||
{#each wishlists as wishlist}
|
||||
<h2 class="wishlist"><a href={`/wishlist/${wishlist.id}`}>{wishlist.name}</a></h2>
|
||||
{/each}
|
||||
</aside>
|
||||
<div class="content">
|
||||
<Transition url={data.url} transition={{ type: 'page' }}>
|
||||
<slot />
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<aside class="wishlists">
|
||||
<h2>Your Wishlists</h2>
|
||||
<div class="separator"></div>
|
||||
{#each wishlists as wishlist}
|
||||
<h2 class="wishlist"><a href={`/wishlist/${wishlist.id}`}>{wishlist.name}</a></h2>
|
||||
{/each}
|
||||
</aside>
|
||||
<div class="content">
|
||||
<Transition url={data.url} transition={{ type: 'page' }}>
|
||||
<slot />
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.wishlists {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import { type Actions, fail, redirect } from "@sveltejs/kit";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { zod } from "sveltekit-superforms/adapters";
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import prisma from '$lib/prisma';
|
||||
import db from "$lib/drizzle.js";
|
||||
import { modifyListGameSchema } from "$lib/validations/zod-schemas";
|
||||
import { games, wishlist_items, wishlists } from "../../../../../schema.js";
|
||||
|
||||
export async function load({ params, locals }) {
|
||||
const user = locals.user;
|
||||
|
|
@ -9,28 +13,18 @@ export async function load({ params, locals }) {
|
|||
}
|
||||
|
||||
try {
|
||||
let wishlist = await prisma.wishlist.findUnique({
|
||||
where: {
|
||||
id: params.id,
|
||||
AND: {
|
||||
user_id: user.id
|
||||
}
|
||||
const wishlist = await db.select({
|
||||
wishlistId: wishlists.id,
|
||||
wishlistItems: {
|
||||
id: wishlist_items.id,
|
||||
gameId: wishlist_items.game_id,
|
||||
gameName: games.name,
|
||||
gameThumbUrl: games.thumb_url
|
||||
},
|
||||
include: {
|
||||
items: {
|
||||
include: {
|
||||
game: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
thumb_url: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}).from(wishlists)
|
||||
.leftJoin(wishlist_items, eq(wishlists.id, wishlist_items.wishlist_id))
|
||||
.leftJoin(games, eq(games.id, wishlist_items.game_id))
|
||||
.where(eq(wishlists.id, params.id));
|
||||
return {
|
||||
wishlist
|
||||
};
|
||||
|
|
@ -43,35 +37,31 @@ export async function load({ params, locals }) {
|
|||
export const actions: Actions = {
|
||||
// Add game to a wishlist
|
||||
add: async (event) => {
|
||||
const { params, locals, request } = event;
|
||||
const { params, locals } = event;
|
||||
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
|
||||
if (!params?.id) {
|
||||
throw fail(400, {
|
||||
message: 'Invalid Request'
|
||||
});
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
where: {
|
||||
id: form.id
|
||||
}
|
||||
const game = await db.query.games.findFirst({
|
||||
where: eq(games.id, form.id)
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
// game = await prisma.game.create({
|
||||
// data: {
|
||||
// name: form.name
|
||||
// }
|
||||
// });
|
||||
return fail(400, {
|
||||
message: 'Game not found'
|
||||
});
|
||||
}
|
||||
|
||||
const wishlist = await prisma.wishlist.findUnique({
|
||||
where: {
|
||||
id: params.id
|
||||
}
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
where: eq(wishlists.id, params.id)
|
||||
});
|
||||
|
||||
if (wishlist?.user_id !== locals.user.id) {
|
||||
|
|
@ -84,11 +74,9 @@ export const actions: Actions = {
|
|||
redirect(302, '/404');
|
||||
}
|
||||
|
||||
const wishlistItem = await prisma.wishlistItem.create({
|
||||
data: {
|
||||
game_id: game.id,
|
||||
wishlist_id: wishlist.id
|
||||
}
|
||||
const wishlistItem = await db.insert(wishlist_items).values({
|
||||
game_id: game.id,
|
||||
wishlist_id: wishlist.id
|
||||
});
|
||||
|
||||
if (!wishlistItem) {
|
||||
|
|
@ -102,19 +90,19 @@ export const actions: Actions = {
|
|||
};
|
||||
},
|
||||
// Create new wishlist
|
||||
create: async ({ params, locals, request }) => {
|
||||
create: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
},
|
||||
// Delete a wishlist
|
||||
delete: async ({ params, locals, request }) => {
|
||||
delete: async ({ locals}) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
},
|
||||
// Remove game from a wishlist
|
||||
remove: async ({ params, locals, request }) => {
|
||||
remove: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,37 +17,37 @@ export const load: PageServerLoad = async (event) => {
|
|||
|
||||
const { user } = event.locals;
|
||||
|
||||
const dbUser = await db.query
|
||||
.users
|
||||
.findFirst({
|
||||
where: eq(users.id, user.id)
|
||||
});
|
||||
const dbUser = await db.query.users.findFirst({
|
||||
where: eq(users.id, user.id),
|
||||
});
|
||||
|
||||
const profileForm = await superValidate(zod(profileSchema), {
|
||||
defaults: {
|
||||
firstName: dbUser?.first_name || '',
|
||||
lastName: dbUser?.last_name || '',
|
||||
username: dbUser?.username || '',
|
||||
}
|
||||
firstName: dbUser?.first_name ?? '',
|
||||
lastName: dbUser?.last_name ?? '',
|
||||
username: dbUser?.username ?? '',
|
||||
},
|
||||
});
|
||||
const emailForm = await superValidate(zod(changeEmailSchema), {
|
||||
defaults: {
|
||||
email: dbUser?.email || '',
|
||||
}
|
||||
email: dbUser?.email ?? '',
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
profileForm,
|
||||
emailForm,
|
||||
hasSetupTwoFactor: !!dbUser?.two_factor_enabled,
|
||||
};
|
||||
};
|
||||
|
||||
const changeEmailIfNotEmpty = z.object({
|
||||
email: z.string()
|
||||
email: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(64, { message: 'Email must be less than 64 characters' })
|
||||
.email({ message: 'Please enter a valid email' })
|
||||
});
|
||||
.email({ message: 'Please enter a valid email' }),
|
||||
});
|
||||
|
||||
export const actions: Actions = {
|
||||
profileUpdate: async (event) => {
|
||||
|
|
@ -55,7 +55,7 @@ export const actions: Actions = {
|
|||
|
||||
if (!form.valid) {
|
||||
return fail(400, {
|
||||
form
|
||||
form,
|
||||
});
|
||||
}
|
||||
if (!event.locals.user) {
|
||||
|
|
@ -66,14 +66,10 @@ export const actions: Actions = {
|
|||
console.log('updating profile');
|
||||
|
||||
const user = event.locals.user;
|
||||
|
||||
const newUsername = form.data.username;
|
||||
const existingUser = await db.query
|
||||
.users
|
||||
.findFirst({
|
||||
where: eq(users.username, newUsername)
|
||||
}
|
||||
);
|
||||
const existingUser = await db.query.users.findFirst({
|
||||
where: eq(users.username, newUsername),
|
||||
});
|
||||
|
||||
if (existingUser && existingUser.id !== user.id) {
|
||||
return setError(form, 'username', 'That username is already taken');
|
||||
|
|
@ -84,7 +80,7 @@ export const actions: Actions = {
|
|||
.set({
|
||||
first_name: form.data.firstName,
|
||||
last_name: form.data.lastName,
|
||||
username: form.data.username
|
||||
username: form.data.username,
|
||||
})
|
||||
.where(eq(users.id, user.id));
|
||||
} catch (e) {
|
||||
|
|
@ -102,29 +98,30 @@ export const actions: Actions = {
|
|||
const form = await superValidate(event, zod(changeEmailSchema));
|
||||
|
||||
const newEmail = form.data?.email;
|
||||
if (!form.valid || !newEmail || (newEmail !== '' && changeEmailIfNotEmpty.safeParse(form.data).success === false)) {
|
||||
if (
|
||||
!form.valid ||
|
||||
!newEmail ||
|
||||
(newEmail !== '' && !changeEmailIfNotEmpty.safeParse(form.data).success)
|
||||
) {
|
||||
return fail(400, {
|
||||
form
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
if (!event.locals.user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const user = event.locals.user;
|
||||
const existingUser = await db.query.users.findFirst({
|
||||
where: eq(users.email, newEmail)
|
||||
where: eq(users.email, newEmail),
|
||||
});
|
||||
|
||||
if (existingUser && existingUser.id !== user.id) {
|
||||
return setError(form, 'email', 'That email is already taken');
|
||||
}
|
||||
|
||||
await db
|
||||
.update(users)
|
||||
.set({ email: form.data.email })
|
||||
.where(eq(users.id, user.id));
|
||||
await db.update(users).set({ email: form.data.email }).where(eq(users.id, user.id));
|
||||
|
||||
if (user.email !== form.data.email) {
|
||||
// Send email to confirm new email?
|
||||
|
|
@ -143,5 +140,5 @@ export const actions: Actions = {
|
|||
}
|
||||
|
||||
return message(form, { type: 'success', message: 'Email updated successfully!' });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue