Updating external id schema types and password validation.

This commit is contained in:
Bradley Shellnut 2024-02-16 16:38:02 -08:00
parent 0c4f93e39c
commit 858a356ddf
15 changed files with 2736 additions and 227 deletions

View file

@ -0,0 +1,7 @@
DO $$ BEGIN
CREATE TYPE "type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE type;

View file

@ -0,0 +1,7 @@
DO $$ BEGIN
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE external_id_type;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,20 @@
"when": 1707951501716, "when": 1707951501716,
"tag": "0007_same_valeria_richards", "tag": "0007_same_valeria_richards",
"breakpoints": true "breakpoints": true
},
{
"idx": 8,
"version": "5",
"when": 1708105454143,
"tag": "0008_complete_manta",
"breakpoints": true
},
{
"idx": 9,
"version": "5",
"when": 1708105890146,
"tag": "0009_equal_christian_walker",
"breakpoints": true
} }
] ]
} }

View file

@ -26,7 +26,7 @@
}, },
"devDependencies": { "devDependencies": {
"@melt-ui/pp": "^0.3.0", "@melt-ui/pp": "^0.3.0",
"@melt-ui/svelte": "^0.73.0", "@melt-ui/svelte": "^0.74.0",
"@playwright/test": "^1.41.2", "@playwright/test": "^1.41.2",
"@resvg/resvg-js": "^2.6.0", "@resvg/resvg-js": "^2.6.0",
"@sveltejs/adapter-auto": "^3.1.1", "@sveltejs/adapter-auto": "^3.1.1",
@ -53,7 +53,7 @@
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.1", "prettier-plugin-svelte": "^3.2.1",
"prisma": "^5.9.1", "prisma": "^5.9.1",
"sass": "^1.70.0", "sass": "^1.71.0",
"satori": "^0.10.13", "satori": "^0.10.13",
"satori-html": "^0.3.2", "satori-html": "^0.3.2",
"svelte": "^4.2.11", "svelte": "^4.2.11",
@ -61,7 +61,8 @@
"svelte-meta-tags": "^3.1.0", "svelte-meta-tags": "^3.1.0",
"svelte-preprocess": "^5.1.3", "svelte-preprocess": "^5.1.3",
"svelte-sequential-preprocessor": "^2.0.1", "svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.4.1", "sveltekit-flash-message": "^2.4.2",
"sveltekit-rate-limiter": "^0.4.3",
"sveltekit-superforms": "^1.13.4", "sveltekit-superforms": "^1.13.4",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
@ -69,7 +70,7 @@
"tsx": "^4.7.1", "tsx": "^4.7.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.1.3", "vite": "^5.1.3",
"vitest": "^1.2.2", "vitest": "^1.3.0",
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"type": "module", "type": "module",
@ -81,7 +82,7 @@
"@fontsource/fira-mono": "^5.0.8", "@fontsource/fira-mono": "^5.0.8",
"@iconify-icons/line-md": "^1.2.26", "@iconify-icons/line-md": "^1.2.26",
"@iconify-icons/mdi": "^1.2.47", "@iconify-icons/mdi": "^1.2.47",
"@lucia-auth/adapter-drizzle": "^1.0.1", "@lucia-auth/adapter-drizzle": "^1.0.2",
"@lucia-auth/adapter-prisma": "4.0.0", "@lucia-auth/adapter-prisma": "4.0.0",
"@lukeed/uuid": "^2.0.1", "@lukeed/uuid": "^2.0.1",
"@neondatabase/serverless": "^0.8.1", "@neondatabase/serverless": "^0.8.1",

View file

@ -15,8 +15,8 @@ dependencies:
specifier: ^1.2.47 specifier: ^1.2.47
version: 1.2.48 version: 1.2.48
'@lucia-auth/adapter-drizzle': '@lucia-auth/adapter-drizzle':
specifier: ^1.0.1 specifier: ^1.0.2
version: 1.0.1(lucia@3.0.1) version: 1.0.2(lucia@3.0.1)
'@lucia-auth/adapter-prisma': '@lucia-auth/adapter-prisma':
specifier: 4.0.0 specifier: 4.0.0
version: 4.0.0(@prisma/client@5.9.1)(lucia@3.0.1) version: 4.0.0(@prisma/client@5.9.1)(lucia@3.0.1)
@ -132,10 +132,10 @@ dependencies:
devDependencies: devDependencies:
'@melt-ui/pp': '@melt-ui/pp':
specifier: ^0.3.0 specifier: ^0.3.0
version: 0.3.0(@melt-ui/svelte@0.73.0)(svelte@4.2.11) version: 0.3.0(@melt-ui/svelte@0.74.0)(svelte@4.2.11)
'@melt-ui/svelte': '@melt-ui/svelte':
specifier: ^0.73.0 specifier: ^0.74.0
version: 0.73.0(svelte@4.2.11) version: 0.74.0(svelte@4.2.11)
'@playwright/test': '@playwright/test':
specifier: ^1.41.2 specifier: ^1.41.2
version: 1.41.2 version: 1.41.2
@ -215,8 +215,8 @@ devDependencies:
specifier: ^5.9.1 specifier: ^5.9.1
version: 5.9.1 version: 5.9.1
sass: sass:
specifier: ^1.70.0 specifier: ^1.71.0
version: 1.70.0 version: 1.71.0
satori: satori:
specifier: ^0.10.13 specifier: ^0.10.13
version: 0.10.13 version: 0.10.13
@ -228,19 +228,22 @@ devDependencies:
version: 4.2.11 version: 4.2.11
svelte-check: svelte-check:
specifier: ^3.6.4 specifier: ^3.6.4
version: 3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11) version: 3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)
svelte-meta-tags: svelte-meta-tags:
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(svelte@4.2.11)(typescript@5.3.3) version: 3.1.0(svelte@4.2.11)(typescript@5.3.3)
svelte-preprocess: svelte-preprocess:
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3) version: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3)
svelte-sequential-preprocessor: svelte-sequential-preprocessor:
specifier: ^2.0.1 specifier: ^2.0.1
version: 2.0.1 version: 2.0.1
sveltekit-flash-message: sveltekit-flash-message:
specifier: ^2.4.1 specifier: ^2.4.2
version: 2.4.1(@sveltejs/kit@2.5.0)(svelte@4.2.11) version: 2.4.2(@sveltejs/kit@2.5.0)(svelte@4.2.11)
sveltekit-rate-limiter:
specifier: ^0.4.3
version: 0.4.3(@sveltejs/kit@2.5.0)
sveltekit-superforms: sveltekit-superforms:
specifier: ^1.13.4 specifier: ^1.13.4
version: 1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4) version: 1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4)
@ -261,10 +264,10 @@ devDependencies:
version: 5.3.3 version: 5.3.3
vite: vite:
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.1.3(@types/node@20.11.19)(sass@1.70.0) version: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vitest: vitest:
specifier: ^1.2.2 specifier: ^1.3.0
version: 1.2.2(@types/node@20.11.19)(sass@1.70.0) version: 1.3.0(@types/node@20.11.19)(sass@1.71.0)
zod: zod:
specifier: ^3.22.4 specifier: ^3.22.4
version: 3.22.4 version: 3.22.4
@ -1391,19 +1394,11 @@ packages:
'@floating-ui/utils': 0.1.6 '@floating-ui/utils': 0.1.6
dev: false dev: false
/@floating-ui/dom@1.6.1:
resolution: {integrity: sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==}
dependencies:
'@floating-ui/core': 1.6.0
'@floating-ui/utils': 0.2.1
dev: true
/@floating-ui/dom@1.6.3: /@floating-ui/dom@1.6.3:
resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
dependencies: dependencies:
'@floating-ui/core': 1.6.0 '@floating-ui/core': 1.6.0
'@floating-ui/utils': 0.2.1 '@floating-ui/utils': 0.2.1
dev: false
/@floating-ui/utils@0.1.6: /@floating-ui/utils@0.1.6:
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
@ -1644,6 +1639,18 @@ packages:
resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==} resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==}
dependencies: dependencies:
'@swc/helpers': 0.5.6 '@swc/helpers': 0.5.6
dev: false
/@internationalized/date@3.5.2:
resolution: {integrity: sha512-vo1yOMUt2hzp63IutEaTUxROdvQg1qlMRsbCvbay2AK2Gai7wIgCyK5weEX3nHkiLgo4qCXHijFNC/ILhlRpOQ==}
dependencies:
'@swc/helpers': 0.5.6
dev: true
/@isaacs/ttlcache@1.4.1:
resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==}
engines: {node: '>=12'}
dev: true
/@jest/schemas@29.6.3: /@jest/schemas@29.6.3:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
@ -1690,8 +1697,8 @@ packages:
'@jridgewell/resolve-uri': 3.1.1 '@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
/@lucia-auth/adapter-drizzle@1.0.1(lucia@3.0.1): /@lucia-auth/adapter-drizzle@1.0.2(lucia@3.0.1):
resolution: {integrity: sha512-xHgYwVh3ZmccEGsmkYWCALp2GlhCnomrpO5sgABCkIWgHvsmMZuJ5BYfgfaKmed1PDok81Dk6xFbj1tMH/uD6A==} resolution: {integrity: sha512-GT2Mp0NaUZ5O4OAvzoNcX9bGotoxBfADo6mTzIEKKJ+uar3HgtQVn/m5Ogj3I2iMv0YBHWgMmlnkUHXN5xFNow==}
peerDependencies: peerDependencies:
lucia: 3.x lucia: 3.x
dependencies: dependencies:
@ -1738,14 +1745,14 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@melt-ui/pp@0.3.0(@melt-ui/svelte@0.73.0)(svelte@4.2.11): /@melt-ui/pp@0.3.0(@melt-ui/svelte@0.74.0)(svelte@4.2.11):
resolution: {integrity: sha512-b07Bdh8l2KcwKVCXOY+SoBw1dk9eWvQfMSi6SoacpRVyVmmfpi0kV4oGt3HYF0tUCB3sEmVicxse50ZzZxEzEA==} resolution: {integrity: sha512-b07Bdh8l2KcwKVCXOY+SoBw1dk9eWvQfMSi6SoacpRVyVmmfpi0kV4oGt3HYF0tUCB3sEmVicxse50ZzZxEzEA==}
engines: {pnpm: '>=8.6.3'} engines: {pnpm: '>=8.6.3'}
peerDependencies: peerDependencies:
'@melt-ui/svelte': '>= 0.29.0' '@melt-ui/svelte': '>= 0.29.0'
svelte: ^3.55.0 || ^4.0.0 || ^5.0.0-next.1 svelte: ^3.55.0 || ^4.0.0 || ^5.0.0-next.1
dependencies: dependencies:
'@melt-ui/svelte': 0.73.0(svelte@4.2.11) '@melt-ui/svelte': 0.74.0(svelte@4.2.11)
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.5 magic-string: 0.30.5
svelte: 4.2.11 svelte: 4.2.11
@ -1765,14 +1772,14 @@ packages:
svelte: 4.2.11 svelte: 4.2.11
dev: false dev: false
/@melt-ui/svelte@0.73.0(svelte@4.2.11): /@melt-ui/svelte@0.74.0(svelte@4.2.11):
resolution: {integrity: sha512-KD9Z+5DDhnZmDUZv1GQ0+LGeXjxl1zwrB8JAwmGeMN6EigTvXMsTPtrFRUYC+TtEjVq82eTlJzuf4C/a88MkjA==} resolution: {integrity: sha512-4rFhTkO34OK5lflvcj13/in1YQ+exsD2A7YSNIYw2iyNeBYFxOgM0n4qH5Y4Tf7vcekkkQ+SEqgiD3XNmVBHzw==}
peerDependencies: peerDependencies:
svelte: '>=3 <5' svelte: '>=3 <5'
dependencies: dependencies:
'@floating-ui/core': 1.6.0 '@floating-ui/core': 1.6.0
'@floating-ui/dom': 1.6.1 '@floating-ui/dom': 1.6.3
'@internationalized/date': 3.5.1 '@internationalized/date': 3.5.2
dequal: 2.0.3 dequal: 2.0.3
focus-trap: 7.5.4 focus-trap: 7.5.4
nanoid: 5.0.5 nanoid: 5.0.5
@ -2994,7 +3001,7 @@ packages:
sirv: 2.0.4 sirv: 2.0.4
svelte: 4.2.11 svelte: 4.2.11
tiny-glob: 0.2.9 tiny-glob: 0.2.9
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3): /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
@ -3007,7 +3014,7 @@ packages:
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.3) '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.3)
debug: 4.3.4 debug: 4.3.4
svelte: 4.2.11 svelte: 4.2.11
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -3025,7 +3032,7 @@ packages:
magic-string: 0.30.5 magic-string: 0.30.5
svelte: 4.2.11 svelte: 4.2.11
svelte-hmr: 0.15.3(svelte@4.2.11) svelte-hmr: 0.15.3(svelte@4.2.11)
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vitefu: 0.2.5(vite@5.1.3) vitefu: 0.2.5(vite@5.1.3)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -3264,38 +3271,38 @@ packages:
yoga-wasm-web: 0.3.3 yoga-wasm-web: 0.3.3
dev: false dev: false
/@vitest/expect@1.2.2: /@vitest/expect@1.3.0:
resolution: {integrity: sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==} resolution: {integrity: sha512-7bWt0vBTZj08B+Ikv70AnLRicohYwFgzNjFqo9SxxqHHxSlUJGSXmCRORhOnRMisiUryKMdvsi1n27Bc6jL9DQ==}
dependencies: dependencies:
'@vitest/spy': 1.2.2 '@vitest/spy': 1.3.0
'@vitest/utils': 1.2.2 '@vitest/utils': 1.3.0
chai: 4.3.10 chai: 4.3.10
dev: true dev: true
/@vitest/runner@1.2.2: /@vitest/runner@1.3.0:
resolution: {integrity: sha512-JctG7QZ4LSDXr5CsUweFgcpEvrcxOV1Gft7uHrvkQ+fsAVylmWQvnaAr/HDp3LAH1fztGMQZugIheTWjaGzYIg==} resolution: {integrity: sha512-1Jb15Vo/Oy7mwZ5bXi7zbgszsdIBNjc4IqP8Jpr/8RdBC4nF1CTzIAn2dxYvpF1nGSseeL39lfLQ2uvs5u1Y9A==}
dependencies: dependencies:
'@vitest/utils': 1.2.2 '@vitest/utils': 1.3.0
p-limit: 5.0.0 p-limit: 5.0.0
pathe: 1.1.1 pathe: 1.1.1
dev: true dev: true
/@vitest/snapshot@1.2.2: /@vitest/snapshot@1.3.0:
resolution: {integrity: sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==} resolution: {integrity: sha512-swmktcviVVPYx9U4SEQXLV6AEY51Y6bZ14jA2yo6TgMxQ3h+ZYiO0YhAHGJNp0ohCFbPAis1R9kK0cvN6lDPQA==}
dependencies: dependencies:
magic-string: 0.30.5 magic-string: 0.30.5
pathe: 1.1.1 pathe: 1.1.1
pretty-format: 29.7.0 pretty-format: 29.7.0
dev: true dev: true
/@vitest/spy@1.2.2: /@vitest/spy@1.3.0:
resolution: {integrity: sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==} resolution: {integrity: sha512-AkCU0ThZunMvblDpPKgjIi025UxR8V7MZ/g/EwmAGpjIujLVV2X6rGYGmxE2D4FJbAy0/ijdROHMWa2M/6JVMw==}
dependencies: dependencies:
tinyspy: 2.2.0 tinyspy: 2.2.1
dev: true dev: true
/@vitest/utils@1.2.2: /@vitest/utils@1.3.0:
resolution: {integrity: sha512-WKITBHLsBHlpjnDQahr+XK6RE7MiAsgrIkr0pGhQ9ygoxBfUeG0lUG5iLlzqjmKSlBv3+j5EGsriBzh+C3Tq9g==} resolution: {integrity: sha512-/LibEY/fkaXQufi4GDlQZhikQsPO2entBKtfuyIpr1jV4DpaeasqkeHjhdOhU24vSHshcSuEyVlWdzvv2XmYCw==}
dependencies: dependencies:
diff-sequences: 29.6.3 diff-sequences: 29.6.3
estree-walker: 3.0.3 estree-walker: 3.0.3
@ -4974,6 +4981,10 @@ packages:
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true hasBin: true
/js-tokens@8.0.3:
resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==}
dev: true
/js-yaml@3.14.1: /js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true hasBin: true
@ -6451,8 +6462,8 @@ packages:
mkdirp: 0.5.6 mkdirp: 0.5.6
rimraf: 2.7.1 rimraf: 2.7.1
/sass@1.70.0: /sass@1.71.0:
resolution: {integrity: sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==} resolution: {integrity: sha512-HKKIKf49Vkxlrav3F/w6qRuPcmImGVbIXJ2I3Kg0VMA+3Bav+8yE9G5XmP5lMj6nl4OlqbPftGAscNaNu28b8w==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
hasBin: true hasBin: true
dependencies: dependencies:
@ -6712,10 +6723,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/strip-literal@1.3.0: /strip-literal@2.0.0:
resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==}
dependencies: dependencies:
acorn: 8.11.2 js-tokens: 8.0.3
dev: true dev: true
/strnum@1.0.5: /strnum@1.0.5:
@ -6753,7 +6764,7 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
/svelte-check@3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11): /svelte-check@3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11):
resolution: {integrity: sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==} resolution: {integrity: sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -6766,7 +6777,7 @@ packages:
picocolors: 1.0.0 picocolors: 1.0.0
sade: 1.8.1 sade: 1.8.1
svelte: 4.2.11 svelte: 4.2.11
svelte-preprocess: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3) svelte-preprocess: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3)
typescript: 5.3.3 typescript: 5.3.3
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
@ -6837,7 +6848,7 @@ packages:
svelte: 4.2.11 svelte: 4.2.11
dev: true dev: true
/svelte-preprocess@5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3): /svelte-preprocess@5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3):
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
engines: {node: '>= 16.0.0', pnpm: ^8.0.0} engines: {node: '>= 16.0.0', pnpm: ^8.0.0}
requiresBuild: true requiresBuild: true
@ -6880,7 +6891,7 @@ packages:
magic-string: 0.30.5 magic-string: 0.30.5
postcss: 8.4.35 postcss: 8.4.35
postcss-load-config: 5.0.3(postcss@8.4.35) postcss-load-config: 5.0.3(postcss@8.4.35)
sass: 1.70.0 sass: 1.71.0
sorcery: 0.11.0 sorcery: 0.11.0
strip-indent: 3.0.0 strip-indent: 3.0.0
svelte: 4.2.11 svelte: 4.2.11
@ -6922,16 +6933,25 @@ packages:
magic-string: 0.30.5 magic-string: 0.30.5
periscopic: 3.1.0 periscopic: 3.1.0
/sveltekit-flash-message@2.4.1(@sveltejs/kit@2.5.0)(svelte@4.2.11): /sveltekit-flash-message@2.4.2(@sveltejs/kit@2.5.0)(svelte@4.2.11):
resolution: {integrity: sha512-n01N62FkXL6tp3VK3u4eCHKz1RwZVgqEEj63pUG/Pj3caHWkjtTUHKX8GRb14kpt9bkML8t93D/B1l1UorskvA==} resolution: {integrity: sha512-iXZSOp8La7kHQuOsXOcjIp7x24J/Ycs2uPoHwtjsbObVCbjgxZrtvjd0XUfA0mYZBp97BtAQ5SW5owRDJCWq6A==}
peerDependencies: peerDependencies:
'@sveltejs/kit': 1.x || 2.x '@sveltejs/kit': 1.x || 2.x
svelte: 3.x || 4.x svelte: 3.x || 4.x || >=5.0.0-next.51
dependencies: dependencies:
'@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3) '@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3)
svelte: 4.2.11 svelte: 4.2.11
dev: true dev: true
/sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.0):
resolution: {integrity: sha512-BKkD2tvgyz5j4Fn1vt0y7FLF0zZ01f9thjWPGDb6fyX3tBXyMrtZ8ISK8M7zjz9Cik/2KrkvFtmldhXF6/hjqw==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
dependencies:
'@isaacs/ttlcache': 1.4.1
'@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3)
dev: true
/sveltekit-superforms@1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4): /sveltekit-superforms@1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4):
resolution: {integrity: sha512-rM2+Ictaw7OAIorCLmvg82orci/mtO9ZouI4emtx8SyYngx9aED+eNZlHPLufgB6D7geL2a+hMSFtM3zmMQixQ==} resolution: {integrity: sha512-rM2+Ictaw7OAIorCLmvg82orci/mtO9ZouI4emtx8SyYngx9aED+eNZlHPLufgB6D7geL2a+hMSFtM3zmMQixQ==}
peerDependencies: peerDependencies:
@ -7058,8 +7078,8 @@ packages:
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
dev: true dev: true
/tinyspy@2.2.0: /tinyspy@2.2.1:
resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
dev: true dev: true
@ -7278,8 +7298,8 @@ packages:
- rollup - rollup
dev: true dev: true
/vite-node@1.2.2(@types/node@20.11.19)(sass@1.70.0): /vite-node@1.3.0(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==} resolution: {integrity: sha512-D/oiDVBw75XMnjAXne/4feCkCEwcbr2SU1bjAhCcfI5Bq3VoOHji8/wCPAfUkDIeohJ5nSZ39fNxM3dNZ6OBOA==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
dependencies: dependencies:
@ -7287,7 +7307,7 @@ packages:
debug: 4.3.4 debug: 4.3.4
pathe: 1.1.1 pathe: 1.1.1
picocolors: 1.0.0 picocolors: 1.0.0
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@ -7299,7 +7319,7 @@ packages:
- terser - terser
dev: true dev: true
/vite@5.1.3(@types/node@20.11.19)(sass@1.70.0): /vite@5.1.3(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==} resolution: {integrity: sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
@ -7331,7 +7351,7 @@ packages:
esbuild: 0.19.12 esbuild: 0.19.12
postcss: 8.4.35 postcss: 8.4.35
rollup: 4.9.6 rollup: 4.9.6
sass: 1.70.0 sass: 1.71.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
@ -7343,17 +7363,17 @@ packages:
vite: vite:
optional: true optional: true
dependencies: dependencies:
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
/vitest@1.2.2(@types/node@20.11.19)(sass@1.70.0): /vitest@1.3.0(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==} resolution: {integrity: sha512-V9qb276J1jjSx9xb75T2VoYXdO1UKi+qfflY7V7w93jzX7oA/+RtYE6TcifxksxsZvygSSMwu2Uw6di7yqDMwg==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@edge-runtime/vm': '*' '@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0 '@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': ^1.0.0 '@vitest/browser': 1.3.0
'@vitest/ui': ^1.0.0 '@vitest/ui': 1.3.0
happy-dom: '*' happy-dom: '*'
jsdom: '*' jsdom: '*'
peerDependenciesMeta: peerDependenciesMeta:
@ -7371,13 +7391,12 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@types/node': 20.11.19 '@types/node': 20.11.19
'@vitest/expect': 1.2.2 '@vitest/expect': 1.3.0
'@vitest/runner': 1.2.2 '@vitest/runner': 1.3.0
'@vitest/snapshot': 1.2.2 '@vitest/snapshot': 1.3.0
'@vitest/spy': 1.2.2 '@vitest/spy': 1.3.0
'@vitest/utils': 1.2.2 '@vitest/utils': 1.3.0
acorn-walk: 8.3.2 acorn-walk: 8.3.2
cac: 6.7.14
chai: 4.3.10 chai: 4.3.10
debug: 4.3.4 debug: 4.3.4
execa: 8.0.1 execa: 8.0.1
@ -7386,11 +7405,11 @@ packages:
pathe: 1.1.1 pathe: 1.1.1
picocolors: 1.0.0 picocolors: 1.0.0
std-env: 3.7.0 std-env: 3.7.0
strip-literal: 1.3.0 strip-literal: 2.0.0
tinybench: 2.5.1 tinybench: 2.5.1
tinypool: 0.8.2 tinypool: 0.8.2
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0) vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vite-node: 1.2.2(@types/node@20.11.19)(sass@1.70.0) vite-node: 1.3.0(@types/node@20.11.19)(sass@1.71.0)
why-is-node-running: 2.2.2 why-is-node-running: 2.2.2
transitivePeerDependencies: transitivePeerDependencies:
- less - less

View file

@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { applyAction, enhance } from '$app/forms'; import { applyAction, enhance } from '$app/forms';
import toast from 'svelte-french-toast';
import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte'; import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte';
import * as DropdownMenu from "$components/ui/dropdown-menu"; import * as DropdownMenu from "$components/ui/dropdown-menu";
import * as Avatar from "$components/ui/avatar"; import * as Avatar from "$components/ui/avatar";
import Logo from '$components/logo.svelte';
import { invalidateAll } from '$app/navigation'; import { invalidateAll } from '$app/navigation';
import toast from 'svelte-french-toast'; import Logo from '$components/logo.svelte';
export let user; export let user: User | null;
let avatar = user?.username.slice(0, 1).toUpperCase() || '?'; let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
</script> </script>
<header> <header>
<div class="corner"> <div class="corner">
<a href="/" class="main-logo" title="Home"> <a href="/" title="Home">
<div class="logo-image"> <div class="logo-image">
<Logo /> <Logo />
</div> </div>
@ -155,8 +155,4 @@
text-decoration: underline; text-decoration: underline;
color: var(--accent-color); color: var(--accent-color);
} }
.separator {
@apply m-[5px] h-[1px] bg-black;
}
</style> </style>

View file

@ -1,4 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-go-game" viewBox="0 0 24 24" stroke-width="1" stroke="var(--fg)" fill="none" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-go-game" viewBox="0 0 24 24"
stroke-width="1" stroke="var(--fg)" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M6 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /> <path d="M6 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
<path d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /> <path d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 671 B

View file

@ -55,18 +55,7 @@ export const signUpSchema = userSchema
terms: true terms: true
}) })
.superRefine(({ confirm_password, password }, ctx) => { .superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) { refinePasswords(confirm_password, password, ctx);
// ctx.addIssue({
// code: 'custom',
// message: 'Password and Confirm Password must match',
// path: ['password']
// });
ctx.addIssue({
code: 'custom',
message: ' Password and Confirm Password must match',
path: ['confirm_password']
});
}
}); });
export const signInSchema = userSchema.pick({ export const signInSchema = userSchema.pick({
@ -77,18 +66,7 @@ export const signInSchema = userSchema.pick({
export const updateUserPasswordSchema = userSchema export const updateUserPasswordSchema = userSchema
.pick({ password: true, confirm_password: true }) .pick({ password: true, confirm_password: true })
.superRefine(({ confirm_password, password }, ctx) => { .superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) { refinePasswords(confirm_password, password, ctx);
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['password']
});
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
}); });
export const changeUserPasswordSchema = z export const changeUserPasswordSchema = z
@ -96,25 +74,91 @@ export const changeUserPasswordSchema = z
current_password: z.string({ required_error: 'Current Password is required' }), current_password: z.string({ required_error: 'Current Password is required' }),
password: z password: z
.string({ required_error: 'Password is required' }) .string({ required_error: 'Password is required' })
.trim() .trim(),
.min(8, { message: 'Password must be at least 8 characters' })
.max(128, { message: 'Password must be less than 128 characters' }),
confirm_password: z confirm_password: z
.string({ required_error: 'Confirm Password is required' }) .string({ required_error: 'Confirm Password is required' })
.trim() .trim()
.min(8, { message: 'Confirm Password must be at least 8 characters' })
}) })
.superRefine(({ confirm_password, password }, ctx) => { .superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) { refinePasswords(confirm_password, password, ctx);
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['password']
});
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
}); });
const refinePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
comparePasswords(confirm_password, password, ctx);
checkPasswordStrength(password, ctx);
}
const comparePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
if (confirm_password !== password) {
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
}
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
const minimumLength = password.length < 8;
const maximumLength = password.length > 128;
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
const containsSpecialChar = (ch: string) =>
/[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
let countOfUpperCase = 0,
countOfLowerCase = 0,
countOfNumbers = 0,
countOfSpecialChar = 0;
for (let i = 0; i < password.length; i++) {
const char = password.charAt(i);
if (!isNaN(+char)) countOfNumbers++;
else if (containsUppercase(char)) countOfUpperCase++;
else if (containsLowercase(char)) countOfLowerCase++;
else if (containsSpecialChar(char)) countOfSpecialChar++;
}
let errors = {
upperCase: { pass: true, message: "At least one upper case." },
lowerCase: { pass: true, message: "At least one lower case." },
specialCharacter: { pass: true, message: "At least one special character." },
totalNumber: { pass: true, message: "At least one number." },
minimumLength: { pass: true, message: "At least 8 characters." },
maximumLength: { pass: true, message: "At most 128 characters." },
};
if (countOfLowerCase < 1) {
errors = { ...errors, lowerCase: { ...errors.lowerCase, pass: false } };
}
if (countOfNumbers < 1) {
errors = {
...errors,
totalNumber: { ...errors.totalNumber, pass: false },
};
}
if (countOfUpperCase < 1) {
errors = { ...errors, upperCase: { ...errors.upperCase, pass: false } };
}
if (countOfSpecialChar < 1) {
errors = { ...errors, specialCharacter: { ...errors.specialCharacter, pass: false } };
}
if (minimumLength) {
errors = { ...errors, minimumLength: { ...errors.minimumLength, pass: false } };
}
if (maximumLength) {
errors = { ...errors, maximumLength: { ...errors.maximumLength, pass: false } };
}
if (
countOfLowerCase < 1 ||
countOfUpperCase < 1 ||
countOfSpecialChar < 1 ||
countOfNumbers < 1
) {
ctx.addIssue({
code: "custom",
message: JSON.stringify(errors),
path: ["password"]
});
}
}

View file

@ -1,6 +1,12 @@
import { drizzle } from "drizzle-orm/node-postgres"; import { drizzle } from 'drizzle-orm/node-postgres';
import pg from 'pg'; import pg from 'pg';
import { DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST, DATABASE_DB, DATABASE_PORT } from '$env/static/private'; import {
DATABASE_USER,
DATABASE_PASSWORD,
DATABASE_HOST,
DATABASE_DB,
DATABASE_PORT
} from '$env/static/private';
import * as schema from '../schema'; import * as schema from '../schema';
// create the connection // create the connection
@ -8,8 +14,8 @@ const pool = new pg.Pool({
user: DATABASE_USER, user: DATABASE_USER,
password: DATABASE_PASSWORD, password: DATABASE_PASSWORD,
host: DATABASE_HOST, host: DATABASE_HOST,
port: new Number(DATABASE_PORT).valueOf(), port: Number(DATABASE_PORT).valueOf(),
database: DATABASE_DB, database: DATABASE_DB
}); });
const db = drizzle(pool, { schema }); const db = drizzle(pool, { schema });

View file

@ -1,10 +1,12 @@
import { fail, redirect, type Actions } from "@sveltejs/kit"; import { fail, redirect, type Actions } from "@sveltejs/kit";
import { message, setError, superValidate } from 'sveltekit-superforms/server'; import { setError, superValidate } from 'sveltekit-superforms/server';
import { Argon2id } from "oslo/password"; import { Argon2id } from "oslo/password";
import { changeUserPasswordSchema } from '$lib/config/zod-schemas.js'; import { changeUserPasswordSchema } from '$lib/config/zod-schemas.js';
import { lucia } from '$lib/server/auth.js'; import { lucia } from '$lib/server/auth.js';
import type { PageServerLoad } from "./$types"; import type { PageServerLoad } from "./$types";
import prisma from "$lib/prisma"; import db from "$lib/drizzle";
import { eq } from "drizzle-orm";
import { users } from "../../../../../schema";
export const load: PageServerLoad = async (event) => { export const load: PageServerLoad = async (event) => {
const form = await superValidate(event, changeUserPasswordSchema); const form = await superValidate(event, changeUserPasswordSchema);
@ -41,10 +43,8 @@ export const actions: Actions = {
const user = event.locals.user; const user = event.locals.user;
const dbUser = await prisma.user.findUnique({ const dbUser = await db.query.users.findFirst({
where: { where: eq(users.id, user.id)
id: user.id
}
}); });
if (!dbUser || !dbUser.hashed_password) { if (!dbUser || !dbUser.hashed_password) {
@ -70,16 +70,11 @@ export const actions: Actions = {
} }
const hashedPassword = await new Argon2id().hash(form.data.password); const hashedPassword = await new Argon2id().hash(form.data.password);
await lucia.invalidateUserSessions(user.id); await lucia.invalidateUserSessions(user.id);
await prisma.user.update({ await db.update(users)
where: { .set({ hashed_password: hashedPassword })
id: user.id .where(eq(users.id, user.id));
},
data: {
hashed_password: hashedPassword
}
});
const session = await lucia.createSession(user.id, { const session = await lucia.createSession(user.id, {
country: event.locals.session.ip, country: event.locals.session?.ip,
}); });
const sessionCookie = lucia.createSessionCookie(session.id); const sessionCookie = lucia.createSessionCookie(session.id);
return new Response(null, { return new Response(null, {

View file

@ -1,11 +1,10 @@
<script lang="ts"> <script lang="ts">
import { superForm } from 'sveltekit-superforms/client'; import { superForm } from 'sveltekit-superforms/client';
//import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
import { changeUserPasswordSchema, userSchema } from '$lib/config/zod-schemas'; import { changeUserPasswordSchema, userSchema } from '$lib/config/zod-schemas';
import { AlertTriangle, KeyRound } from 'lucide-svelte';
import { Label } from '$components/ui/label'; import { Label } from '$components/ui/label';
import { Input } from '$components/ui/input'; import { Input } from '$components/ui/input';
import { Button } from '$components/ui/button'; import { Button } from '$components/ui/button';
import { string } from 'zod';
export let data; export let data;
const { form, errors, enhance, delayed, message } = superForm(data.form, { const { form, errors, enhance, delayed, message } = superForm(data.form, {
@ -34,7 +33,7 @@
<small>{$errors.current_password}</small> <small>{$errors.current_password}</small>
{/if} {/if}
</div> </div>
<div class="mt-6"> <div class="mt-6 grid">
<Label for="password">New Password</Label> <Label for="password">New Password</Label>
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="given-name" data-invalid={$errors.password} bind:value={$form.password} /> <Input type="password" id="password" name="password" placeholder="Password" autocomplete="given-name" data-invalid={$errors.password} bind:value={$form.password} />
{#if $errors.password} {#if $errors.password}

View file

@ -3,23 +3,37 @@
</script> </script>
<div class="container"> <div class="container">
<div class="logo"> <div class="site-logo">
<Logo /> <div class="logo">
<Logo />
</div>
Bored Game
</div> </div>
<h1>Welcome to Bored Game</h1> <h1>Welcome to Bored Game!</h1>
<h2>Keep track of your board games!</h2> <h2>Track the board games you own, the ones you want, and whether you play them enough.</h2>
<p>The ones you own, the ones you want, and whether you play them enough.</p> <p>Get started by joining the <a href="/waitlist">wait list</a> or <a href="/login">log in</a> if you already have an account.</p>
<p>Get started by joinging the <a href="/waitlist">waitlist</a> or <a href="/login">signing in</a>.</p>
</div> </div>
<style lang="postcss"> <style lang="postcss">
a {
text-decoration: underline;
}
.site-logo {
display: flex;
place-items: center;
}
.container { .container {
max-width: 900px;
display: grid; display: grid;
place-content: center;
max-width: 900px;
gap: 0.25rem; gap: 0.25rem;
} }
.logo { .logo {
display: flex;
align-items: center;
width: 4rem; width: 4rem;
height: 4rem; height: 4rem;
} }

View file

@ -1,5 +1,14 @@
import { relations, sql, type InferSelectModel } from 'drizzle-orm'; import { relations, sql, type InferSelectModel } from 'drizzle-orm';
import { pgTable, timestamp, varchar, boolean, integer, text, index, pgEnum } from 'drizzle-orm/pg-core'; import {
pgTable,
timestamp,
varchar,
boolean,
integer,
text,
index,
pgEnum
} from 'drizzle-orm/pg-core';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { tsvector } from './tsVector'; import { tsvector } from './tsVector';
@ -77,7 +86,7 @@ export type Roles = InferSelectModel<typeof roles>;
export const role_relations = relations(roles, ({ many }) => ({ export const role_relations = relations(roles, ({ many }) => ({
user_roles: many(user_roles) user_roles: many(user_roles)
})) }));
export const user_roles = pgTable('user_roles', { export const user_roles = pgTable('user_roles', {
id: varchar('id', { id: varchar('id', {
@ -259,7 +268,12 @@ export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
// Game and related table schemas // Game and related table schemas
export const externalIdType = pgEnum('external_id_type', [ export const externalIdType = pgEnum('external_id_type', [
'game', 'category', 'mechanic', 'publisher', 'designer', 'artist' 'game',
'category',
'mechanic',
'publisher',
'designer',
'artist'
]); ]);
export const externalIds = pgTable('external_ids', { export const externalIds = pgTable('external_ids', {
@ -268,64 +282,68 @@ export const externalIds = pgTable('external_ids', {
}) })
.primaryKey() .primaryKey()
.$defaultFn(() => nanoid()), .$defaultFn(() => nanoid()),
type: varchar('type', { type: externalIdType('type').notNull(),
length: 255
}).notNull(),
externalId: varchar('external_id', { externalId: varchar('external_id', {
length: 255 length: 255
}).notNull() }).notNull()
}); });
export const games = pgTable('games', { export const games = pgTable(
id: varchar('id', { 'games',
length: 255 {
}) id: varchar('id', {
.primaryKey() length: 255
.$defaultFn(() => nanoid()), })
name: varchar('name', { .primaryKey()
length: 255 .$defaultFn(() => nanoid()),
}), name: varchar('name', {
slug: varchar('slug', { length: 255
length: 255 }),
}), slug: varchar('slug', {
description: text('description'), length: 255
year_published: integer('year_published'), }),
min_players: integer('min_players'), description: text('description'),
max_players: integer('max_players'), year_published: integer('year_published'),
playtime: integer('playtime'), min_players: integer('min_players'),
min_playtime: integer('min_playtime'), max_players: integer('max_players'),
max_playtime: integer('max_playtime'), playtime: integer('playtime'),
min_age: integer('min_age'), min_playtime: integer('min_playtime'),
image_url: varchar('image_url', { max_playtime: integer('max_playtime'),
length: 255 min_age: integer('min_age'),
}), image_url: varchar('image_url', {
thumb_url: varchar('thumb_url', { length: 255
length: 255 }),
}), thumb_url: varchar('thumb_url', {
url: varchar('url', { length: 255
length: 255 }),
}), url: varchar('url', {
text_searchable_index: tsvector('text_searchable_index'), length: 255
last_sync_at: timestamp('last_sync_at', { }),
withTimezone: true, text_searchable_index: tsvector('text_searchable_index'),
mode: 'date', last_sync_at: timestamp('last_sync_at', {
precision: 6 withTimezone: true,
}), mode: 'date',
created_at: timestamp('created_at', { precision: 6
withTimezone: true, }),
mode: 'date', created_at: timestamp('created_at', {
precision: 6 withTimezone: true,
}).default(sql`now()`), mode: 'date',
updated_at: timestamp('updated_at', { precision: 6
withTimezone: true, }).default(sql`now()`),
mode: 'date', updated_at: timestamp('updated_at', {
precision: 6 withTimezone: true,
}).default(sql`now()`) mode: 'date',
}, (table) => { precision: 6
return { }).default(sql`now()`)
text_searchable_idx: index("text_searchable_idx").on(table.text_searchable_index).using(sql`'gin'`) },
} (table) => {
}); return {
text_searchable_idx: index('text_searchable_idx')
.on(table.text_searchable_index)
.using(sql`'gin'`)
};
}
);
export type Games = InferSelectModel<typeof games>; export type Games = InferSelectModel<typeof games>;
@ -339,14 +357,14 @@ export const gamesToExternalIds = pgTable('games_to_external_ids', {
length: 255 length: 255
}) })
.notNull() .notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }), .references(() => externalIds.id, { onDelete: 'cascade' })
}); });
export const gameRelations = relations(games, ({ many }) => ({ export const gameRelations = relations(games, ({ many }) => ({
categories_to_games: many(categories_to_games), categories_to_games: many(categories_to_games),
mechanics_to_games: many(mechanics_to_games), mechanics_to_games: many(mechanics_to_games),
publishers_to_games: many(publishers_to_games), publishers_to_games: many(publishers_to_games),
gamesToExternalIds: many(gamesToExternalIds), gamesToExternalIds: many(gamesToExternalIds)
})); }));
export const expansions = pgTable('expansions', { export const expansions = pgTable('expansions', {
@ -387,7 +405,7 @@ export const expansionsToExternalIds = pgTable('expansions_to_external_ids', {
length: 255 length: 255
}) })
.notNull() .notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }), .references(() => externalIds.id, { onDelete: 'cascade' })
}); });
export const expansion_relations = relations(expansions, ({ one, many }) => ({ export const expansion_relations = relations(expansions, ({ one, many }) => ({
@ -437,7 +455,7 @@ export const publishersToExternalIds = pgTable('publishers_to_external_ids', {
length: 255 length: 255
}) })
.notNull() .notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }), .references(() => externalIds.id, { onDelete: 'cascade' })
}); });
export const publishers_relations = relations(publishers, ({ many }) => ({ export const publishers_relations = relations(publishers, ({ many }) => ({
@ -480,8 +498,8 @@ export const categoriesToExternalIds = pgTable('categories_to_external_ids', {
length: 255 length: 255
}) })
.notNull() .notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }), .references(() => externalIds.id, { onDelete: 'cascade' })
}) });
export const categories_to_games = pgTable('categories_to_games', { export const categories_to_games = pgTable('categories_to_games', {
category_id: varchar('category_id', { category_id: varchar('category_id', {
@ -543,8 +561,8 @@ export const mechanicsToExternalIds = pgTable('mechanics_to_external_ids', {
length: 255 length: 255
}) })
.notNull() .notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }), .references(() => externalIds.id, { onDelete: 'cascade' })
}) });
export const mechanic_relations = relations(mechanics, ({ many }) => ({ export const mechanic_relations = relations(mechanics, ({ many }) => ({
mechanics_to_games: many(mechanics_to_games), mechanics_to_games: many(mechanics_to_games),