mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Using Svelte 5, refactor to use a separate table for user two factor details, and update the whole application to use the new table.
This commit is contained in:
parent
d83eaadc0b
commit
42292c15b2
37 changed files with 1095 additions and 3881 deletions
14
package.json
14
package.json
|
|
@ -35,7 +35,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
||||||
"@typescript-eslint/parser": "^7.13.0",
|
"@typescript-eslint/parser": "^7.13.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"drizzle-kit": "^0.22.8",
|
"drizzle-kit": "^0.23.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-svelte": "^2.41.0",
|
"eslint-plugin-svelte": "^2.41.0",
|
||||||
|
|
@ -47,18 +47,18 @@
|
||||||
"postcss-preset-env": "^9.6.0",
|
"postcss-preset-env": "^9.6.0",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"prettier-plugin-svelte": "^3.2.5",
|
"prettier-plugin-svelte": "^3.2.5",
|
||||||
"sass": "^1.77.6",
|
"sass": "^1.77.8",
|
||||||
"satori": "^0.10.13",
|
"satori": "^0.10.13",
|
||||||
"satori-html": "^0.3.2",
|
"satori-html": "^0.3.2",
|
||||||
"svelte": "5.0.0-next.175",
|
"svelte": "5.0.0-next.175",
|
||||||
"svelte-check": "^3.8.4",
|
"svelte-check": "^3.8.4",
|
||||||
"svelte-headless-table": "^0.18.2",
|
"svelte-headless-table": "^0.18.2",
|
||||||
"svelte-meta-tags": "^3.1.2",
|
"svelte-meta-tags": "^3.1.2",
|
||||||
"svelte-preprocess": "^6.0.1",
|
"svelte-preprocess": "^6.0.2",
|
||||||
"svelte-sequential-preprocessor": "^2.0.1",
|
"svelte-sequential-preprocessor": "^2.0.1",
|
||||||
"sveltekit-flash-message": "^2.4.4",
|
"sveltekit-flash-message": "^2.4.4",
|
||||||
"sveltekit-rate-limiter": "^0.5.1",
|
"sveltekit-rate-limiter": "^0.5.1",
|
||||||
"sveltekit-superforms": "^2.15.2",
|
"sveltekit-superforms": "^2.16.0",
|
||||||
"tailwindcss": "^3.4.4",
|
"tailwindcss": "^3.4.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.6.3",
|
||||||
|
|
@ -91,7 +91,7 @@
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"dotenv-expand": "^11.0.6",
|
"dotenv-expand": "^11.0.6",
|
||||||
"drizzle-orm": "^0.31.2",
|
"drizzle-orm": "^0.32.0",
|
||||||
"feather-icons": "^4.29.2",
|
"feather-icons": "^4.29.2",
|
||||||
"formsnap": "^1.0.1",
|
"formsnap": "^1.0.1",
|
||||||
"html-entities": "^2.5.2",
|
"html-entities": "^2.5.2",
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "3.2.0",
|
"lucia": "3.2.0",
|
||||||
"lucide-svelte": "^0.390.0",
|
"lucide-svelte": "^0.407.0",
|
||||||
"open-props": "^1.7.5",
|
"open-props": "^1.7.5",
|
||||||
"oslo": "^1.2.1",
|
"oslo": "^1.2.1",
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
|
|
@ -109,7 +109,7 @@
|
||||||
"radix-svelte": "^0.9.0",
|
"radix-svelte": "^0.9.0",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svelte-lazy-loader": "^1.0.0",
|
"svelte-lazy-loader": "^1.0.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.4.0",
|
||||||
"tailwind-variants": "^0.2.1",
|
"tailwind-variants": "^0.2.1",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod-to-json-schema": "^3.23.1"
|
"zod-to-json-schema": "^3.23.1"
|
||||||
|
|
|
||||||
613
pnpm-lock.yaml
613
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -23,5 +23,4 @@ try {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// await connection.end();
|
|
||||||
process.exit();
|
process.exit();
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "public"."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" (
|
CREATE TABLE IF NOT EXISTS "categories" (
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "categories_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "categories_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -26,8 +32,8 @@ CREATE TABLE IF NOT EXISTS "collection_items" (
|
||||||
"collection_id" uuid NOT NULL,
|
"collection_id" uuid NOT NULL,
|
||||||
"game_id" uuid NOT NULL,
|
"game_id" uuid NOT NULL,
|
||||||
"times_played" integer DEFAULT 0,
|
"times_played" integer DEFAULT 0,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "collection_items_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "collection_items_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -36,8 +42,8 @@ CREATE TABLE IF NOT EXISTS "collections" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" uuid NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"name" text DEFAULT 'My Collection' NOT NULL,
|
"name" text DEFAULT 'My Collection' NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -46,15 +52,15 @@ CREATE TABLE IF NOT EXISTS "expansions" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"base_game_id" uuid NOT NULL,
|
"base_game_id" uuid NOT NULL,
|
||||||
"game_id" uuid NOT NULL,
|
"game_id" uuid NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "expansions_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "expansions_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "external_ids" (
|
CREATE TABLE IF NOT EXISTS "external_ids" (
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"type" "external_id_type" NOT NULL,
|
"type" "external_id_type",
|
||||||
"external_id" text NOT NULL,
|
"external_id" text NOT NULL,
|
||||||
CONSTRAINT "external_ids_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "external_ids_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
|
|
@ -76,8 +82,8 @@ CREATE TABLE IF NOT EXISTS "games" (
|
||||||
"thumb_url" text,
|
"thumb_url" text,
|
||||||
"url" text,
|
"url" text,
|
||||||
"last_sync_at" timestamp,
|
"last_sync_at" timestamp,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -92,8 +98,8 @@ CREATE TABLE IF NOT EXISTS "mechanics" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "mechanics_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "mechanics_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -113,7 +119,8 @@ CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
"user_id" uuid NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"expires_at" timestamp,
|
"expires_at" timestamp,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "publishers" (
|
CREATE TABLE IF NOT EXISTS "publishers" (
|
||||||
|
|
@ -121,8 +128,8 @@ CREATE TABLE IF NOT EXISTS "publishers" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "publishers_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "publishers_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -143,16 +150,16 @@ CREATE TABLE IF NOT EXISTS "recovery_codes" (
|
||||||
"user_id" uuid NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"code" text NOT NULL,
|
"code" text NOT NULL,
|
||||||
"used" boolean DEFAULT false,
|
"used" boolean DEFAULT false,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "roles" (
|
CREATE TABLE IF NOT EXISTS "roles" (
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text NOT NULL,
|
"cuid" text NOT NULL,
|
||||||
"name" text NOT NULL,
|
"name" text NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
|
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
|
||||||
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
||||||
);
|
);
|
||||||
|
|
@ -167,14 +174,27 @@ CREATE TABLE IF NOT EXISTS "sessions" (
|
||||||
"is_two_factor_authenticated" boolean DEFAULT false
|
"is_two_factor_authenticated" boolean DEFAULT false
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "two_factor" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"cuid" text,
|
||||||
|
"two_factor_secret" text NOT NULL,
|
||||||
|
"two_factor_enabled" boolean DEFAULT false NOT NULL,
|
||||||
|
"initiated_time" timestamp with time zone NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
CONSTRAINT "two_factor_cuid_unique" UNIQUE("cuid"),
|
||||||
|
CONSTRAINT "two_factor_user_id_unique" UNIQUE("user_id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "user_roles" (
|
CREATE TABLE IF NOT EXISTS "user_roles" (
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" uuid NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"role_id" uuid NOT NULL,
|
"role_id" uuid NOT NULL,
|
||||||
"primary" boolean DEFAULT false,
|
"primary" boolean DEFAULT false,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -189,10 +209,8 @@ CREATE TABLE IF NOT EXISTS "users" (
|
||||||
"verified" boolean DEFAULT false,
|
"verified" boolean DEFAULT false,
|
||||||
"receive_email" boolean DEFAULT false,
|
"receive_email" boolean DEFAULT false,
|
||||||
"theme" text DEFAULT 'system',
|
"theme" text DEFAULT 'system',
|
||||||
"two_factor_secret" text DEFAULT '',
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"two_factor_enabled" boolean DEFAULT false,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
|
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
|
||||||
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
||||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
CONSTRAINT "users_email_unique" UNIQUE("email")
|
||||||
|
|
@ -203,8 +221,8 @@ CREATE TABLE IF NOT EXISTS "wishlist_items" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"wishlist_id" uuid NOT NULL,
|
"wishlist_id" uuid NOT NULL,
|
||||||
"game_id" uuid NOT NULL,
|
"game_id" uuid NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -213,8 +231,8 @@ CREATE TABLE IF NOT EXISTS "wishlists" (
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" uuid NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"name" text DEFAULT 'My Wishlist' NOT NULL,
|
"name" text DEFAULT 'My Wishlist' NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
|
@ -350,6 +368,12 @@ EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
2
src/db/migrations/0001_noisy_sally_floyd.sql
Normal file
2
src/db/migrations/0001_noisy_sally_floyd.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE "two_factor" RENAME COLUMN "two_factor_secret" TO "secret";--> statement-breakpoint
|
||||||
|
ALTER TABLE "two_factor" RENAME COLUMN "two_factor_enabled" TO "enabled";
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "external_ids" ALTER COLUMN "type" DROP NOT NULL;
|
|
||||||
1
src/db/migrations/0002_fancy_valkyrie.sql
Normal file
1
src/db/migrations/0002_fancy_valkyrie.sql
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE "two_factor" ALTER COLUMN "initiated_time" DROP NOT NULL;
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "public"."external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "users" ADD COLUMN "initiated_time" timestamp;
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS "two_factor" (
|
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
||||||
"cuid" text,
|
|
||||||
"two_factor_secret" text NOT NULL,
|
|
||||||
"two_factor_enabled" boolean DEFAULT false NOT NULL,
|
|
||||||
"initiated_time" timestamp with time zone NOT NULL,
|
|
||||||
"user_id" text NOT NULL,
|
|
||||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
||||||
CONSTRAINT "two_factor_cuid_unique" UNIQUE("cuid"),
|
|
||||||
CONSTRAINT "two_factor_user_id_unique" UNIQUE("user_id")
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ALTER COLUMN "created_at" SET DATA TYPE timestamp with time zone;--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ALTER COLUMN "updated_at" SET DATA TYPE timestamp with time zone;--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" DROP COLUMN IF EXISTS "two_factor_secret";--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" DROP COLUMN IF EXISTS "two_factor_enabled";--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" DROP COLUMN IF EXISTS "initiated_time";
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"id": "7871a9e4-6916-4122-b200-42a9f21d4c8d",
|
"id": "e120d11a-bf28-4c96-9f2f-96e23e23c7e2",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
|
|
@ -35,14 +35,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -213,14 +213,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -298,14 +298,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -369,14 +369,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -444,7 +444,7 @@
|
||||||
"type": "external_id_type",
|
"type": "external_id_type",
|
||||||
"typeSchema": "public",
|
"typeSchema": "public",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": false
|
||||||
},
|
},
|
||||||
"external_id": {
|
"external_id": {
|
||||||
"name": "external_id",
|
"name": "external_id",
|
||||||
|
|
@ -569,14 +569,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -699,14 +699,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -863,7 +863,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -919,14 +926,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1091,14 +1098,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1148,14 +1155,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1249,6 +1256,97 @@
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
|
"public.two_factor": {
|
||||||
|
"name": "two_factor",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"cuid": {
|
||||||
|
"name": "cuid",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"two_factor_secret": {
|
||||||
|
"name": "two_factor_secret",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"two_factor_enabled": {
|
||||||
|
"name": "two_factor_enabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"initiated_time": {
|
||||||
|
"name": "initiated_time",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"two_factor_user_id_users_id_fk": {
|
||||||
|
"name": "two_factor_user_id_users_id_fk",
|
||||||
|
"tableFrom": "two_factor",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"two_factor_cuid_unique": {
|
||||||
|
"name": "two_factor_cuid_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"cuid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"two_factor_user_id_unique": {
|
||||||
|
"name": "two_factor_user_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"user_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"public.user_roles": {
|
"public.user_roles": {
|
||||||
"name": "user_roles",
|
"name": "user_roles",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
|
|
@ -1287,14 +1385,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1408,30 +1506,16 @@
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"default": "'system'"
|
"default": "'system'"
|
||||||
},
|
},
|
||||||
"two_factor_secret": {
|
|
||||||
"name": "two_factor_secret",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "''"
|
|
||||||
},
|
|
||||||
"two_factor_enabled": {
|
|
||||||
"name": "two_factor_enabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1495,14 +1579,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1580,14 +1664,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1621,7 +1705,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enums": {},
|
"enums": {
|
||||||
|
"public.external_id_type": {
|
||||||
|
"name": "external_id_type",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"game",
|
||||||
|
"category",
|
||||||
|
"mechanic",
|
||||||
|
"publisher",
|
||||||
|
"designer",
|
||||||
|
"artist"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"schemas": {},
|
"schemas": {},
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"columns": {},
|
"columns": {},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"id": "c4b2e9ac-5e60-4de1-b860-eb11e4ca6bd6",
|
"id": "52e7c416-89cb-4c6a-9118-68a03cfc2920",
|
||||||
"prevId": "7871a9e4-6916-4122-b200-42a9f21d4c8d",
|
"prevId": "e120d11a-bf28-4c96-9f2f-96e23e23c7e2",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
|
|
@ -35,14 +35,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -213,14 +213,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -298,14 +298,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -369,14 +369,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -569,14 +569,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -699,14 +699,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -863,7 +863,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -919,14 +926,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1091,14 +1098,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1148,14 +1155,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1249,6 +1256,97 @@
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
|
"public.two_factor": {
|
||||||
|
"name": "two_factor",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"cuid": {
|
||||||
|
"name": "cuid",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"secret": {
|
||||||
|
"name": "secret",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"initiated_time": {
|
||||||
|
"name": "initiated_time",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"two_factor_user_id_users_id_fk": {
|
||||||
|
"name": "two_factor_user_id_users_id_fk",
|
||||||
|
"tableFrom": "two_factor",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"two_factor_cuid_unique": {
|
||||||
|
"name": "two_factor_cuid_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"cuid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"two_factor_user_id_unique": {
|
||||||
|
"name": "two_factor_user_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"user_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"public.user_roles": {
|
"public.user_roles": {
|
||||||
"name": "user_roles",
|
"name": "user_roles",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
|
|
@ -1287,14 +1385,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1408,30 +1506,16 @@
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"default": "'system'"
|
"default": "'system'"
|
||||||
},
|
},
|
||||||
"two_factor_secret": {
|
|
||||||
"name": "two_factor_secret",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "''"
|
|
||||||
},
|
|
||||||
"two_factor_enabled": {
|
|
||||||
"name": "two_factor_enabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1495,14 +1579,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1580,14 +1664,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1621,7 +1705,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enums": {},
|
"enums": {
|
||||||
|
"public.external_id_type": {
|
||||||
|
"name": "external_id_type",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"game",
|
||||||
|
"category",
|
||||||
|
"mechanic",
|
||||||
|
"publisher",
|
||||||
|
"designer",
|
||||||
|
"artist"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"schemas": {},
|
"schemas": {},
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"columns": {},
|
"columns": {},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"id": "43322acf-8c50-4c6d-9575-df44978be5a0",
|
"id": "79adee85-e57c-4a9f-87df-835457b68129",
|
||||||
"prevId": "c4b2e9ac-5e60-4de1-b860-eb11e4ca6bd6",
|
"prevId": "52e7c416-89cb-4c6a-9118-68a03cfc2920",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
|
|
@ -35,14 +35,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -213,14 +213,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -298,14 +298,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -369,14 +369,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -569,14 +569,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -699,14 +699,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -863,7 +863,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -919,14 +926,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1091,14 +1098,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1148,14 +1155,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1249,6 +1256,97 @@
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
|
"public.two_factor": {
|
||||||
|
"name": "two_factor",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"cuid": {
|
||||||
|
"name": "cuid",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"secret": {
|
||||||
|
"name": "secret",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"initiated_time": {
|
||||||
|
"name": "initiated_time",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"two_factor_user_id_users_id_fk": {
|
||||||
|
"name": "two_factor_user_id_users_id_fk",
|
||||||
|
"tableFrom": "two_factor",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"two_factor_cuid_unique": {
|
||||||
|
"name": "two_factor_cuid_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"cuid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"two_factor_user_id_unique": {
|
||||||
|
"name": "two_factor_user_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"user_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"public.user_roles": {
|
"public.user_roles": {
|
||||||
"name": "user_roles",
|
"name": "user_roles",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
|
|
@ -1287,14 +1385,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1408,30 +1506,16 @@
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"default": "'system'"
|
"default": "'system'"
|
||||||
},
|
},
|
||||||
"two_factor_secret": {
|
|
||||||
"name": "two_factor_secret",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "''"
|
|
||||||
},
|
|
||||||
"two_factor_enabled": {
|
|
||||||
"name": "two_factor_enabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1495,14 +1579,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
@ -1580,14 +1664,14 @@
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp with time zone",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -5,36 +5,22 @@
|
||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1718402690897,
|
"when": 1720625651245,
|
||||||
"tag": "0000_premium_pepper_potts",
|
"tag": "0000_dazzling_stick",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1718404319259,
|
"when": 1720625948784,
|
||||||
"tag": "0001_spicy_legion",
|
"tag": "0001_noisy_sally_floyd",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 2,
|
"idx": 2,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1718405257084,
|
"when": 1720626020902,
|
||||||
"tag": "0002_third_black_tom",
|
"tag": "0002_fancy_valkyrie",
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 3,
|
|
||||||
"version": "7",
|
|
||||||
"when": 1720415770693,
|
|
||||||
"tag": "0003_premium_ravenous",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 4,
|
|
||||||
"version": "7",
|
|
||||||
"when": 1720454952583,
|
|
||||||
"tag": "0004_glossy_gideon",
|
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import categoriesToExternalIds from './categoriesToExternalIds';
|
import categoriesToExternalIds from './categoriesToExternalIds';
|
||||||
import categories_to_games from './categoriesToGames';
|
import categories_to_games from './categoriesToGames';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const categories = pgTable('categories', {
|
const categories = pgTable('categories', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -11,8 +12,7 @@ const categories = pgTable('categories', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Categories = InferSelectModel<typeof categories>;
|
export type Categories = InferSelectModel<typeof categories>;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { integer, pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import collections from './collections';
|
import collections from './collections';
|
||||||
import games from './games';
|
import games from './games';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const collection_items = pgTable('collection_items', {
|
const collection_items = pgTable('collection_items', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -16,8 +17,7 @@ const collection_items = pgTable('collection_items', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'cascade' }),
|
.references(() => games.id, { onDelete: 'cascade' }),
|
||||||
times_played: integer('times_played').default(0),
|
times_played: integer('times_played').default(0),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const collections = pgTable('collections', {
|
const collections = pgTable('collections', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -12,8 +13,7 @@ const collections = pgTable('collections', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
name: text('name').notNull().default('My Collection'),
|
name: text('name').notNull().default('My Collection'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collection_relations = relations(collections, ({ one }) => ({
|
export const collection_relations = relations(collections, ({ one }) => ({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import games from './games';
|
import games from './games';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
export const expansions = pgTable('expansions', {
|
export const expansions = pgTable('expansions', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -14,8 +15,7 @@ export const expansions = pgTable('expansions', {
|
||||||
game_id: uuid('game_id')
|
game_id: uuid('game_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Expansions = InferSelectModel<typeof expansions>;
|
export type Expansions = InferSelectModel<typeof expansions>;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import categoriesToGames from './categoriesToGames';
|
||||||
import gamesToExternalIds from './gamesToExternalIds';
|
import gamesToExternalIds from './gamesToExternalIds';
|
||||||
import mechanicsToGames from './mechanicsToGames';
|
import mechanicsToGames from './mechanicsToGames';
|
||||||
import publishersToGames from './publishersToGames';
|
import publishersToGames from './publishersToGames';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const games = pgTable(
|
const games = pgTable(
|
||||||
'games',
|
'games',
|
||||||
|
|
@ -27,8 +28,7 @@ const games = pgTable(
|
||||||
thumb_url: text('thumb_url'),
|
thumb_url: text('thumb_url'),
|
||||||
url: text('url'),
|
url: text('url'),
|
||||||
last_sync_at: timestamp('last_sync_at'),
|
last_sync_at: timestamp('last_sync_at'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
searchIndex: index('search_index').using(
|
searchIndex: index('search_index').using(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import mechanicsToGames from './mechanicsToGames';
|
import mechanicsToGames from './mechanicsToGames';
|
||||||
import mechanicsToExternalIds from './mechanicsToExternalIds';
|
import mechanicsToExternalIds from './mechanicsToExternalIds';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const mechanics = pgTable('mechanics', {
|
const mechanics = pgTable('mechanics', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -11,8 +12,7 @@ const mechanics = pgTable('mechanics', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Mechanics = InferSelectModel<typeof mechanics>;
|
export type Mechanics = InferSelectModel<typeof mechanics>;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const password_reset_tokens = pgTable('password_reset_tokens', {
|
const password_reset_tokens = pgTable('password_reset_tokens', {
|
||||||
id: text('id')
|
id: text('id')
|
||||||
|
|
@ -11,7 +12,7 @@ const password_reset_tokens = pgTable('password_reset_tokens', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
expires_at: timestamp('expires_at'),
|
expires_at: timestamp('expires_at'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
|
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import publishers_to_games from './publishersToGames';
|
import publishers_to_games from './publishersToGames';
|
||||||
import publishersToExternalIds from './publishersToExternalIds';
|
import publishersToExternalIds from './publishersToExternalIds';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const publishers = pgTable('publishers', {
|
const publishers = pgTable('publishers', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -11,8 +12,7 @@ const publishers = pgTable('publishers', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Publishers = InferSelectModel<typeof publishers>;
|
export type Publishers = InferSelectModel<typeof publishers>;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import type { InferSelectModel } from 'drizzle-orm';
|
import type { InferSelectModel } from 'drizzle-orm';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const recovery_codes = pgTable('recovery_codes', {
|
const recovery_codes = pgTable('recovery_codes', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -9,8 +10,7 @@ const recovery_codes = pgTable('recovery_codes', {
|
||||||
.references(() => users.id),
|
.references(() => users.id),
|
||||||
code: text('code').notNull(),
|
code: text('code').notNull(),
|
||||||
used: boolean('used').default(false),
|
used: boolean('used').default(false),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import user_roles from './userRoles';
|
import user_roles from './userRoles';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const roles = pgTable('roles', {
|
const roles = pgTable('roles', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -10,8 +11,7 @@ const roles = pgTable('roles', {
|
||||||
.$defaultFn(() => cuid2())
|
.$defaultFn(() => cuid2())
|
||||||
.notNull(),
|
.notNull(),
|
||||||
name: text('name').unique().notNull(),
|
name: text('name').unique().notNull(),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Roles = InferSelectModel<typeof roles>;
|
export type Roles = InferSelectModel<typeof roles>;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { timestamps } from '../utils';
|
import { timestamps } from '../utils';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
|
||||||
const twoFactorTable = pgTable('two_factor', {
|
const twoFactorTable = pgTable('two_factor', {
|
||||||
id: uuid('id')
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
.primaryKey().defaultRandom(),
|
|
||||||
cuid: text('cuid')
|
cuid: text('cuid')
|
||||||
.unique()
|
.unique()
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
two_factor_secret: text('two_factor_secret').notNull(),
|
secret: text('secret').notNull(),
|
||||||
two_factor_enabled: boolean('two_factor_enabled').notNull().default(false),
|
enabled: boolean('enabled').notNull().default(false),
|
||||||
initiated_time: timestamp('initiated_time', {
|
initiatedTime: timestamp('initiated_time', {
|
||||||
mode: 'date',
|
mode: 'date',
|
||||||
withTimezone: true,
|
withTimezone: true,
|
||||||
}).notNull(),
|
}),
|
||||||
userId: text('user_id')
|
userId: uuid('user_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id)
|
.references(() => users.id)
|
||||||
.unique(),
|
.unique(),
|
||||||
|
|
@ -32,4 +31,4 @@ export const emailVerificationsRelations = relations(twoFactorTable, ({ one }) =
|
||||||
|
|
||||||
export type TwoFactor = InferSelectModel<typeof twoFactorTable>;
|
export type TwoFactor = InferSelectModel<typeof twoFactorTable>;
|
||||||
|
|
||||||
export default twoFactorTable;
|
export default twoFactorTable;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
import roles from './roles';
|
import roles from './roles';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const user_roles = pgTable('user_roles', {
|
const user_roles = pgTable('user_roles', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -16,8 +17,7 @@ const user_roles = pgTable('user_roles', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => roles.id, { onDelete: 'cascade' }),
|
.references(() => roles.id, { onDelete: 'cascade' }),
|
||||||
primary: boolean('primary').default(false),
|
primary: boolean('primary').default(false),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import wishlists from './wishlists';
|
import wishlists from './wishlists';
|
||||||
import games from './games';
|
import games from './games';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const wishlist_items = pgTable('wishlist_items', {
|
const wishlist_items = pgTable('wishlist_items', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -15,8 +16,7 @@ const wishlist_items = pgTable('wishlist_items', {
|
||||||
game_id: uuid('game_id')
|
game_id: uuid('game_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'cascade' }),
|
.references(() => games.id, { onDelete: 'cascade' }),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
const wishlists = pgTable('wishlists', {
|
const wishlists = pgTable('wishlists', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -12,8 +13,7 @@ const wishlists = pgTable('wishlists', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
name: text('name').notNull().default('My Wishlist'),
|
name: text('name').notNull().default('My Wishlist'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
...timestamps,
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Wishlists = InferSelectModel<typeof wishlists>;
|
export type Wishlists = InferSelectModel<typeof wishlists>;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ const EnvSchema = z.object({
|
||||||
DATABASE_PORT: z.coerce.number(),
|
DATABASE_PORT: z.coerce.number(),
|
||||||
DATABASE_DB: z.string(),
|
DATABASE_DB: z.string(),
|
||||||
DATABASE_URL: z.string(),
|
DATABASE_URL: z.string(),
|
||||||
|
PUBLIC_SITE_NAME: z.string(),
|
||||||
PUBLIC_SITE_URL: z.string(),
|
PUBLIC_SITE_URL: z.string(),
|
||||||
PUBLIC_UMAMI_DO_NOT_TRACK: z.string(),
|
PUBLIC_UMAMI_DO_NOT_TRACK: z.string(),
|
||||||
PUBLIC_UMAMI_ID: z.string(),
|
PUBLIC_UMAMI_ID: z.string(),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { changeEmailSchema, profileSchema } from '$lib/validations/account';
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages';
|
||||||
import db from '../../../../db';
|
import db from '../../../../db';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { users } from '$db/schema';
|
import { users, twoFactor } from '$db/schema';
|
||||||
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
|
|
@ -35,10 +35,14 @@ export const load: PageServerLoad = async (event) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser!.id!),
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
profileForm,
|
profileForm,
|
||||||
emailForm,
|
emailForm,
|
||||||
hasSetupTwoFactor: !!dbUser?.two_factor_enabled,
|
hasSetupTwoFactor: !!twoFactorDetails?.enabled,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { type Actions, fail } from '@sveltejs/kit';
|
import { type Actions, fail, error } from '@sveltejs/kit';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { encodeHex, decodeHex } from 'oslo/encoding';
|
import { encodeHex, decodeHex } from 'oslo/encoding';
|
||||||
import { Argon2id } from 'oslo/password';
|
import { Argon2id } from 'oslo/password';
|
||||||
import { createTOTPKeyURI, TOTPController } from 'oslo/otp';
|
import { createTOTPKeyURI, TOTPController } from 'oslo/otp';
|
||||||
import { HMAC } from 'oslo/crypto';
|
import { HMAC } from 'oslo/crypto';
|
||||||
|
import kebabCase from 'just-kebab-case';
|
||||||
import QRCode from 'qrcode';
|
import QRCode from 'qrcode';
|
||||||
import { zod } from 'sveltekit-superforms/adapters';
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
|
|
@ -12,8 +13,9 @@ import type { PageServerLoad } from '../../$types';
|
||||||
import { addTwoFactorSchema, removeTwoFactorSchema } from '$lib/validations/account';
|
import { addTwoFactorSchema, removeTwoFactorSchema } from '$lib/validations/account';
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages';
|
||||||
import db from '../../../../../../db';
|
import db from '../../../../../../db';
|
||||||
import { recoveryCodes, users } from '$db/schema';
|
import { recoveryCodes, twoFactor, users } from '$db/schema';
|
||||||
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
||||||
|
import env from '../../../../../../env';
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const addTwoFactorForm = await superValidate(event, zod(addTwoFactorSchema));
|
const addTwoFactorForm = await superValidate(event, zod(addTwoFactorSchema));
|
||||||
|
|
@ -29,7 +31,11 @@ export const load: PageServerLoad = async (event) => {
|
||||||
where: eq(users.id, user!.id!),
|
where: eq(users.id, user!.id!),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (dbUser?.two_factor_enabled) {
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser!.id!),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (twoFactorDetails?.enabled) {
|
||||||
return {
|
return {
|
||||||
addTwoFactorForm,
|
addTwoFactorForm,
|
||||||
removeTwoFactorForm,
|
removeTwoFactorForm,
|
||||||
|
|
@ -39,17 +45,31 @@ export const load: PageServerLoad = async (event) => {
|
||||||
qrCode: '',
|
qrCode: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const twoFactorSecret = await new HMAC('SHA-1').generateKey();
|
|
||||||
await db
|
|
||||||
.update(users)
|
|
||||||
.set({
|
|
||||||
two_factor_secret: encodeHex(twoFactorSecret),
|
|
||||||
two_factor_enabled: false,
|
|
||||||
})
|
|
||||||
.where(eq(users.id, user!.id!));
|
|
||||||
|
|
||||||
const issuer = 'bored-game';
|
const twoFactorSecret = await new HMAC('SHA-1').generateKey();
|
||||||
const accountName = user!.email! || user!.username!;
|
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.insert(twoFactor)
|
||||||
|
.values({
|
||||||
|
secret: encodeHex(twoFactorSecret),
|
||||||
|
enabled: false,
|
||||||
|
userId: dbUser!.id!,
|
||||||
|
})
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: twoFactor.userId,
|
||||||
|
set: {
|
||||||
|
secret: encodeHex(twoFactorSecret),
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
error(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
const issuer = kebabCase(env.PUBLIC_SITE_NAME);
|
||||||
|
const accountName = dbUser!.email! || dbUser!.username!;
|
||||||
// pass the website's name and the user identifier (e.g. email, username)
|
// pass the website's name and the user identifier (e.g. email, username)
|
||||||
const totpUri = createTOTPKeyURI(issuer, accountName, twoFactorSecret);
|
const totpUri = createTOTPKeyURI(issuer, accountName, twoFactorSecret);
|
||||||
|
|
||||||
|
|
@ -104,7 +124,20 @@ export const actions: Actions = {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbUser?.two_factor_secret === '' || dbUser?.two_factor_secret === null) {
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser?.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!twoFactorDetails) {
|
||||||
|
addTwoFactorForm.data.current_password = '';
|
||||||
|
addTwoFactorForm.data.two_factor_code = '';
|
||||||
|
return setError(
|
||||||
|
addTwoFactorForm,
|
||||||
|
'Error occurred. Please try again or contact support if you need further help.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (twoFactorDetails.secret === '' || twoFactorDetails.secret === null) {
|
||||||
addTwoFactorForm.data.current_password = '';
|
addTwoFactorForm.data.current_password = '';
|
||||||
addTwoFactorForm.data.two_factor_code = '';
|
addTwoFactorForm.data.two_factor_code = '';
|
||||||
return setError(
|
return setError(
|
||||||
|
|
@ -129,19 +162,20 @@ export const actions: Actions = {
|
||||||
const twoFactorCode = addTwoFactorForm.data.two_factor_code;
|
const twoFactorCode = addTwoFactorForm.data.two_factor_code;
|
||||||
const validOTP = await new TOTPController().verify(
|
const validOTP = await new TOTPController().verify(
|
||||||
twoFactorCode,
|
twoFactorCode,
|
||||||
decodeHex(dbUser.two_factor_secret),
|
decodeHex(twoFactorDetails.secret),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!validOTP) {
|
if (!validOTP) {
|
||||||
return setError(addTwoFactorForm, 'two_factor_code', 'Invalid code');
|
return setError(addTwoFactorForm, 'two_factor_code', 'Invalid code');
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.update(users).set({ two_factor_enabled: true }).where(eq(users.id, user!.id!));
|
await db.update(twoFactor).set({ enabled: true }).where(eq(twoFactor.userId, user!.id!));
|
||||||
|
|
||||||
redirect(302, '/profile/security/two-factor/recovery-codes');
|
redirect(302, '/profile/security/two-factor/recovery-codes');
|
||||||
},
|
},
|
||||||
disableTwoFactor: async (event) => {
|
disableTwoFactor: async (event) => {
|
||||||
const { cookies } = event;
|
const { locals } = event;
|
||||||
|
const { user, session } = locals;
|
||||||
const removeTwoFactorForm = await superValidate(event, zod(removeTwoFactorSchema));
|
const removeTwoFactorForm = await superValidate(event, zod(removeTwoFactorSchema));
|
||||||
|
|
||||||
if (!removeTwoFactorForm.valid) {
|
if (!removeTwoFactorForm.valid) {
|
||||||
|
|
@ -150,16 +184,12 @@ export const actions: Actions = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event.locals.user) {
|
if (!user || !session) {
|
||||||
redirect(302, '/login', notSignedInMessage, event);
|
return fail(401, {
|
||||||
|
removeTwoFactorForm,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event.locals.session) {
|
|
||||||
return fail(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = event.locals.user;
|
|
||||||
|
|
||||||
const dbUser = await db.query.users.findFirst({
|
const dbUser = await db.query.users.findFirst({
|
||||||
where: eq(users.id, user.id),
|
where: eq(users.id, user.id),
|
||||||
});
|
});
|
||||||
|
|
@ -181,16 +211,28 @@ export const actions: Actions = {
|
||||||
return setError(removeTwoFactorForm, 'current_password', 'Your password is incorrect');
|
return setError(removeTwoFactorForm, 'current_password', 'Your password is incorrect');
|
||||||
}
|
}
|
||||||
|
|
||||||
await db
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
.update(users)
|
where: eq(twoFactor.userId, dbUser.id),
|
||||||
.set({ two_factor_enabled: false, two_factor_secret: null })
|
});
|
||||||
.where(eq(users.id, user.id));
|
|
||||||
|
if (!twoFactorDetails) {
|
||||||
|
return fail(500, {
|
||||||
|
removeTwoFactorForm,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.update(twoFactor).set({ enabled: false }).where(eq(twoFactor.userId, user.id));
|
||||||
await db.delete(recoveryCodes).where(eq(recoveryCodes.userId, user.id));
|
await db.delete(recoveryCodes).where(eq(recoveryCodes.userId, user.id));
|
||||||
|
|
||||||
// setFlash({ type: 'success', message: 'Two-Factor Authentication has been disabled.' }, cookies);
|
// setFlash({ type: 'success', message: 'Two-Factor Authentication has been disabled.' }, cookies);
|
||||||
redirect(302, '/profile/security/two-factor', {
|
redirect(
|
||||||
type: 'success',
|
302,
|
||||||
message: 'Two-Factor Authentication has been disabled.',
|
'/profile/security/two-factor',
|
||||||
}, event);
|
{
|
||||||
|
type: 'success',
|
||||||
|
message: 'Two-Factor Authentication has been disabled.',
|
||||||
|
},
|
||||||
|
event,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { alphabet, generateRandomString } from 'oslo/crypto';
|
||||||
import { redirect } from 'sveltekit-flash-message/server';
|
import { redirect } from 'sveltekit-flash-message/server';
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages';
|
||||||
import type { PageServerLoad } from '../../../$types';
|
import type { PageServerLoad } from '../../../$types';
|
||||||
import { recoveryCodes, users } from '$db/schema';
|
import {recoveryCodes, twoFactor, users} from '$db/schema';
|
||||||
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
|
|
@ -19,7 +19,11 @@ export const load: PageServerLoad = async (event) => {
|
||||||
where: eq(users.id, user!.id),
|
where: eq(users.id, user!.id),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (dbUser?.two_factor_enabled) {
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser!.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (twoFactorDetails?.enabled) {
|
||||||
const dbRecoveryCodes = await db.query.recoveryCodes.findMany({
|
const dbRecoveryCodes = await db.query.recoveryCodes.findMany({
|
||||||
where: eq(recoveryCodes.userId, user!.id),
|
where: eq(recoveryCodes.userId, user!.id),
|
||||||
});
|
});
|
||||||
|
|
@ -46,6 +50,7 @@ export const load: PageServerLoad = async (event) => {
|
||||||
recoveryCodes: [],
|
recoveryCodes: [],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
console.error('2FA not enabled');
|
||||||
redirect(
|
redirect(
|
||||||
302,
|
302,
|
||||||
'/profile',
|
'/profile',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { fail, error, type Actions } from '@sveltejs/kit';
|
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||||
import { and, eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { Argon2id } from 'oslo/password';
|
import { Argon2id } from 'oslo/password';
|
||||||
import { zod } from 'sveltekit-superforms/adapters';
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
|
|
@ -8,7 +8,7 @@ import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||||
import db from '../../../db';
|
import db from '../../../db';
|
||||||
import { lucia } from '$lib/server/auth';
|
import { lucia } from '$lib/server/auth';
|
||||||
import { signInSchema } from '$lib/validations/auth';
|
import { signInSchema } from '$lib/validations/auth';
|
||||||
import { users, type Users } from '$db/schema';
|
import { twoFactor, users, type Users } from '$db/schema';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { userFullyAuthenticated, userNotFullyAuthenticated } from '$lib/server/auth-utils';
|
import { userFullyAuthenticated, userNotFullyAuthenticated } from '$lib/server/auth-utils';
|
||||||
|
|
||||||
|
|
@ -66,6 +66,8 @@ export const actions: Actions = {
|
||||||
return setError(form, 'username', 'Your username or password is incorrect.');
|
return setError(form, 'username', 'Your username or password is incorrect.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let twoFactorDetails;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const password = form.data.password;
|
const password = form.data.password;
|
||||||
console.log('user', JSON.stringify(user, null, 2));
|
console.log('user', JSON.stringify(user, null, 2));
|
||||||
|
|
@ -85,21 +87,33 @@ export const actions: Actions = {
|
||||||
|
|
||||||
console.log('ip', locals.ip);
|
console.log('ip', locals.ip);
|
||||||
console.log('country', locals.country);
|
console.log('country', locals.country);
|
||||||
await db
|
|
||||||
.update(users)
|
|
||||||
.set({
|
|
||||||
initiated_time: new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
session = await lucia.createSession(user.id, {
|
twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
ip_country: locals.country,
|
where: eq(twoFactor.userId, user?.id),
|
||||||
ip_address: locals.ip,
|
|
||||||
twoFactorAuthEnabled:
|
|
||||||
user?.two_factor_enabled &&
|
|
||||||
user?.two_factor_secret !== null &&
|
|
||||||
user?.two_factor_secret !== '',
|
|
||||||
isTwoFactorAuthenticated: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (twoFactorDetails?.secret && twoFactorDetails?.enabled) {
|
||||||
|
await db.update(twoFactor).set({
|
||||||
|
initiated_time: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
session = await lucia.createSession(user.id, {
|
||||||
|
ip_country: locals.country,
|
||||||
|
ip_address: locals.ip,
|
||||||
|
twoFactorAuthEnabled:
|
||||||
|
twoFactorDetails?.enabled &&
|
||||||
|
twoFactorDetails?.secret !== null &&
|
||||||
|
twoFactorDetails?.secret !== '',
|
||||||
|
isTwoFactorAuthenticated: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
session = await lucia.createSession(user.id, {
|
||||||
|
ip_country: locals.country,
|
||||||
|
ip_address: locals.ip,
|
||||||
|
twoFactorAuthEnabled: false,
|
||||||
|
isTwoFactorAuthenticated: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
console.log('logging in session', session);
|
console.log('logging in session', session);
|
||||||
sessionCookie = lucia.createSessionCookie(session.id);
|
sessionCookie = lucia.createSessionCookie(session.id);
|
||||||
console.log('logging in session cookie', sessionCookie);
|
console.log('logging in session cookie', sessionCookie);
|
||||||
|
|
@ -120,9 +134,9 @@ export const actions: Actions = {
|
||||||
form.data.password = '';
|
form.data.password = '';
|
||||||
|
|
||||||
if (
|
if (
|
||||||
user?.two_factor_enabled &&
|
twoFactorDetails?.enabled &&
|
||||||
user?.two_factor_secret !== null &&
|
twoFactorDetails?.secret !== null &&
|
||||||
user?.two_factor_secret !== ''
|
twoFactorDetails?.secret !== ''
|
||||||
) {
|
) {
|
||||||
console.log('redirecting to TOTP page');
|
console.log('redirecting to TOTP page');
|
||||||
const message = { type: 'success', message: 'Please enter your TOTP code.' } as const;
|
const message = { type: 'success', message: 'Please enter your TOTP code.' } as const;
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@
|
||||||
},
|
},
|
||||||
syncFlashMessage: false,
|
syncFlashMessage: false,
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: zodClient(signInSchema),
|
// validators: zodClient(signInSchema),
|
||||||
validationMethod: 'oninput',
|
// validationMethod: 'oninput',
|
||||||
delayMs: 0,
|
delayMs: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
import { redirect } from 'sveltekit-flash-message/server';
|
import { redirect } from 'sveltekit-flash-message/server';
|
||||||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||||
import { TWO_FACTOR_TIMEOUT } from '../env';
|
|
||||||
import db from '../../../db';
|
import db from '../../../db';
|
||||||
import { lucia } from '$lib/server/auth';
|
import { lucia } from '$lib/server/auth';
|
||||||
import { totpSchema } from '$lib/validations/auth';
|
import { totpSchema } from '$lib/validations/auth';
|
||||||
import { users, recoveryCodes } from '$db/schema';
|
import { users, twoFactor, recoveryCodes } from '$db/schema';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages';
|
||||||
|
import { TWO_FACTOR_TIMEOUT } from '../../../env';
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const { user, session } = event.locals;
|
const { user, session } = event.locals;
|
||||||
|
|
@ -27,8 +27,12 @@ export const load: PageServerLoad = async (event) => {
|
||||||
where: eq(users.username, user.username),
|
where: eq(users.username, user.username),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser!.id!),
|
||||||
|
});
|
||||||
|
|
||||||
// Check if two factor started less than TWO_FACTOR_TIMEOUT
|
// Check if two factor started less than TWO_FACTOR_TIMEOUT
|
||||||
if (Date.now() - dbUser?.initiated_time > TWO_FACTOR_TIMEOUT) {
|
if (Date.now() - twoFactorDetails?.initiatedTime > TWO_FACTOR_TIMEOUT) {
|
||||||
const message = { type: 'error', message: 'Two factor authentication has expired' } as const;
|
const message = { type: 'error', message: 'Two factor authentication has expired' } as const;
|
||||||
redirect(302, '/login', message, event);
|
redirect(302, '/login', message, event);
|
||||||
}
|
}
|
||||||
|
|
@ -40,8 +44,8 @@ export const load: PageServerLoad = async (event) => {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isTwoFactorAuthenticated &&
|
isTwoFactorAuthenticated &&
|
||||||
dbUser?.two_factor_enabled &&
|
twoFactorDetails?.enabled &&
|
||||||
dbUser?.two_factor_secret !== ''
|
twoFactorDetails?.secret !== ''
|
||||||
) {
|
) {
|
||||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||||
throw redirect('/', message, event);
|
throw redirect('/', message, event);
|
||||||
|
|
@ -83,11 +87,14 @@ export const actions: Actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTwoFactorAuthenticated = session?.isTwoFactorAuthenticated;
|
const isTwoFactorAuthenticated = session?.isTwoFactorAuthenticated;
|
||||||
|
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||||
|
where: eq(twoFactor.userId, dbUser!.id!),
|
||||||
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isTwoFactorAuthenticated &&
|
isTwoFactorAuthenticated &&
|
||||||
dbUser?.two_factor_enabled &&
|
twoFactorDetails?.enabled &&
|
||||||
dbUser?.two_factor_secret !== ''
|
twoFactorDetails?.secret !== ''
|
||||||
) {
|
) {
|
||||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||||
throw redirect('/', message, event);
|
throw redirect('/', message, event);
|
||||||
|
|
@ -107,8 +114,8 @@ export const actions: Actions = {
|
||||||
const totpToken = form?.data?.totpToken;
|
const totpToken = form?.data?.totpToken;
|
||||||
|
|
||||||
const twoFactorSecretPopulated =
|
const twoFactorSecretPopulated =
|
||||||
dbUser?.two_factor_secret !== '' && dbUser?.two_factor_secret !== null;
|
twoFactorDetails?.secret !== '' && twoFactorDetails?.secret !== null;
|
||||||
if (dbUser?.two_factor_enabled && !twoFactorSecretPopulated && !totpToken) {
|
if (twoFactorDetails.enabled && !twoFactorSecretPopulated && !totpToken) {
|
||||||
return fail(400, {
|
return fail(400, {
|
||||||
form,
|
form,
|
||||||
});
|
});
|
||||||
|
|
@ -116,7 +123,7 @@ export const actions: Actions = {
|
||||||
console.log('totpToken', totpToken);
|
console.log('totpToken', totpToken);
|
||||||
const validOTP = await new TOTPController().verify(
|
const validOTP = await new TOTPController().verify(
|
||||||
totpToken,
|
totpToken,
|
||||||
decodeHex(dbUser.two_factor_secret ?? ''),
|
decodeHex(twoFactorDetails.secret ?? ''),
|
||||||
);
|
);
|
||||||
console.log('validOTP', validOTP);
|
console.log('validOTP', validOTP);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue