From 05b74e4c5900c7b830373e46b0db165e138824bc Mon Sep 17 00:00:00 2001 From: Bradley Shellnut Date: Mon, 14 Oct 2024 18:12:05 -0700 Subject: [PATCH] Adding more routes in openapi. --- package.json | 14 +- pnpm-lock.yaml | 172 +++++++++--------- .../api/common/openapi/cuidParamsSchema.ts | 7 + .../api/controllers/collection.controller.ts | 48 +++-- .../api/controllers/collection.routes.ts | 69 +++++++ .../server/api/controllers/iam.controller.ts | 111 ++++++----- src/lib/server/api/controllers/iam.routes.ts | 22 ++- .../api/databases/tables/collections.table.ts | 21 ++- 8 files changed, 288 insertions(+), 176 deletions(-) create mode 100644 src/lib/server/api/common/openapi/cuidParamsSchema.ts create mode 100644 src/lib/server/api/controllers/collection.routes.ts diff --git a/package.json b/package.json index 16e01d6..780b649 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@playwright/test": "^1.48.0", "@sveltejs/adapter-auto": "^3.2.5", "@sveltejs/enhanced-img": "^0.3.9", - "@sveltejs/kit": "^2.7.0", + "@sveltejs/kit": "^2.7.1", "@sveltejs/vite-plugin-svelte": "4.0.0-next.7", "@types/cookie": "^0.6.0", "@types/node": "^20.16.11", @@ -68,7 +68,7 @@ "tslib": "^2.7.0", "tsx": "^4.19.1", "typescript": "^5.6.3", - "vite": "^5.4.8", + "vite": "^5.4.9", "vitest": "^1.6.0", "zod": "^3.23.8" }, @@ -92,13 +92,13 @@ "@oslojs/otp": "^1.0.0", "@oslojs/webauthn": "^1.0.0", "@paralleldrive/cuid2": "^2.2.2", - "@scalar/hono-api-reference": "^0.5.153", - "@sveltejs/adapter-node": "^5.2.6", + "@scalar/hono-api-reference": "^0.5.154", + "@sveltejs/adapter-node": "^5.2.7", "@sveltejs/adapter-vercel": "^5.4.5", "@types/feather-icons": "^4.29.4", "bits-ui": "^0.21.16", "boardgamegeekclient": "^1.9.1", - "bullmq": "^5.19.1", + "bullmq": "^5.20.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cookie": "^0.6.0", @@ -130,10 +130,10 @@ "radix-svelte": "^0.9.0", "rate-limit-redis": "^4.2.0", "reflect-metadata": "^0.2.2", - "stoker": "^1.0.9", + "stoker": "^1.2.3", "svelte-lazy-loader": "^1.0.0", "svelte-sonner": "^0.3.28", - "tailwind-merge": "^2.5.2", + "tailwind-merge": "^2.5.4", "tailwind-variants": "^0.2.1", "tailwindcss-animate": "^1.0.7", "tsyringe": "^4.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e31267e..1be6eda 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,14 +63,14 @@ importers: specifier: ^2.2.2 version: 2.2.2 '@scalar/hono-api-reference': - specifier: ^0.5.153 - version: 0.5.153(hono@4.6.4) + specifier: ^0.5.154 + version: 0.5.154(hono@4.6.4) '@sveltejs/adapter-node': - specifier: ^5.2.6 - version: 5.2.6(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))) + specifier: ^5.2.7 + version: 5.2.7(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))) '@sveltejs/adapter-vercel': specifier: ^5.4.5 - version: 5.4.5(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))) + version: 5.4.5(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))) '@types/feather-icons': specifier: ^4.29.4 version: 4.29.4 @@ -81,8 +81,8 @@ importers: specifier: ^1.9.1 version: 1.9.1 bullmq: - specifier: ^5.19.1 - version: 5.19.1 + specifier: ^5.20.0 + version: 5.20.0 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -109,7 +109,7 @@ importers: version: 4.29.2 formsnap: specifier: ^1.0.1 - version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)) + version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)) handlebars: specifier: ^4.7.8 version: 4.7.8 @@ -177,8 +177,8 @@ importers: specifier: ^0.2.2 version: 0.2.2 stoker: - specifier: ^1.0.9 - version: 1.0.9(@asteasolutions/zod-to-openapi@7.1.2(zod@3.23.8))(@hono/zod-openapi@0.15.3(hono@4.6.4)(zod@3.23.8))(hono@4.6.4)(openapi3-ts@4.4.0) + specifier: ^1.2.3 + version: 1.2.3(@asteasolutions/zod-to-openapi@7.1.2(zod@3.23.8))(@hono/zod-openapi@0.15.3(hono@4.6.4)(zod@3.23.8))(hono@4.6.4)(openapi3-ts@4.4.0) svelte-lazy-loader: specifier: ^1.0.0 version: 1.0.0 @@ -186,8 +186,8 @@ importers: specifier: ^0.3.28 version: 0.3.28(svelte@5.0.0-next.175) tailwind-merge: - specifier: ^2.5.2 - version: 2.5.3 + specifier: ^2.5.4 + version: 2.5.4 tailwind-variants: specifier: ^0.2.1 version: 0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))) @@ -218,16 +218,16 @@ importers: version: 1.48.0 '@sveltejs/adapter-auto': specifier: ^3.2.5 - version: 3.2.5(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))) + version: 3.2.5(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))) '@sveltejs/enhanced-img': specifier: ^0.3.9 - version: 0.3.9(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + version: 0.3.9(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) '@sveltejs/kit': - specifier: ^2.7.0 - version: 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + specifier: ^2.7.1 + version: 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) '@sveltejs/vite-plugin-svelte': specifier: 4.0.0-next.7 - version: 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + version: 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -317,10 +317,10 @@ importers: version: 2.0.2 sveltekit-flash-message: specifier: ^2.4.4 - version: 2.4.4(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175) + version: 2.4.4(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175) sveltekit-superforms: specifier: ^2.19.1 - version: 2.19.1(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175) + version: 2.19.1(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175) tailwindcss: specifier: ^3.4.13 version: 3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)) @@ -337,8 +337,8 @@ importers: specifier: ^5.6.3 version: 5.6.3 vite: - specifier: ^5.4.8 - version: 5.4.8(@types/node@20.16.11) + specifier: ^5.4.9 + version: 5.4.9(@types/node@20.16.11) vitest: specifier: ^1.6.0 version: 1.6.0(@types/node@20.16.11) @@ -2143,18 +2143,18 @@ packages: cpu: [x64] os: [win32] - '@scalar/hono-api-reference@0.5.153': - resolution: {integrity: sha512-Eo4AeRanOthMI9uD/vC1GZ70ztt9aty+xoL9tUe1TUvhoTpFmGOLKzwRCFyqMSc0W16qcWXo/hkVY0BcYS+oEg==} + '@scalar/hono-api-reference@0.5.154': + resolution: {integrity: sha512-v5ufLt7OG27BsPqO20YtnLvIcTsRZjU5jbFbpMUguW+SFgRWh1gji2RlC4BfK5x9hrK1Ek0hz46OMYweWp4I3w==} engines: {node: '>=18'} peerDependencies: hono: ^4.0.0 - '@scalar/openapi-types@0.1.2': - resolution: {integrity: sha512-TxiAbs9Rw5qnMs/vvg+4Zx1Xf/5RhJXf8w6JOYSgvp4d2IKkOKc9eSOhid8ySvz7bWCjF2yWd8eHNc/BFs8cXg==} + '@scalar/openapi-types@0.1.3': + resolution: {integrity: sha512-UPUquC/ZSAdeSDbpdqMzeBVcgeytqJTj9P3QR4X9IRti5I1jXoCOUBY84CGGLXfcWquB7wfwHxn3DqQEnQmBVw==} engines: {node: '>=18'} - '@scalar/types@0.0.14': - resolution: {integrity: sha512-4yzW5d9nWtRE3eVNfLnuVUScSMf325PYJ9qCJ8CpaVP7hnWrTv9xGw/2n7csEKzu3QJkdff0myibHfxXJ6ICig==} + '@scalar/types@0.0.15': + resolution: {integrity: sha512-9fSBoAuJTsmnt2FTkm/F6LRq+TIeeRI0H8wz+7J3pHfcw0YGFEZrRZOo1WZ8fpovD0fQgg+r4BPrtN8+qJ12wQ==} engines: {node: '>=18'} '@sideway/address@4.1.5': @@ -2177,8 +2177,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/adapter-node@5.2.6': - resolution: {integrity: sha512-FT9MDduZT2srUz/gDFFhQ3U2Mp9reZ3xJdJBEhr/lk+dkieSSpdgIDNNbMkm84hTaXXiC7f4cPNk8fB5nT3N2g==} + '@sveltejs/adapter-node@5.2.7': + resolution: {integrity: sha512-lamfhxiRIaPtuhNpJE9h8haRo/I5TzuimaiphWUGXsRCDqYWsLKtF+mo61awkBIxm+XggC4n1iaNqwf+Kt7K4Q==} peerDependencies: '@sveltejs/kit': ^2.4.0 @@ -2193,8 +2193,8 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: '>= 5.0.0' - '@sveltejs/kit@2.7.0': - resolution: {integrity: sha512-4XyY1SCB/Eyz8E9G7SEBKViysYwVtDftuA7kyQ5bmuFNPWC1KZC4988rMvaJxhH2BbCTsbLPjNOZwiEGXt8/2g==} + '@sveltejs/kit@2.7.1': + resolution: {integrity: sha512-TBVnkwgYQT3EafGQK6Eyh5FlLEBlRhCmqPTwcdOs+QdnyUc3eCAxRWtXlFxIWtmk6pqv11zdng8qTpThdTogew==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -2348,8 +2348,8 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@unhead/schema@1.11.7': - resolution: {integrity: sha512-j9uN7T63aUXrZ6yx2CfjVT7xZHjn0PZO7TPMaWqMFjneIH/NONKvDVCMEqDlXeqdSIERIYtk/xTHgCUMer5eyw==} + '@unhead/schema@1.11.9': + resolution: {integrity: sha512-0V37bxG4sQuiLw3M5DMD+b99ndOOngecMlekQ122TDvBb24W8rWwkHhXvAu5eFg6bQXPdQF1A0U0PuRMcCj/ZA==} '@vercel/nft@0.27.4': resolution: {integrity: sha512-Rioz3LJkEKicKCi9BSyc1RXZ5R6GmXosFMeBSThh6msWSOiArKhb7c75MiWwZEgPL7x0/l3TAfH/l0cxKNuUFA==} @@ -2554,8 +2554,8 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bullmq@5.19.1: - resolution: {integrity: sha512-ziQ2C0ZS39MwerK+C1W88L4niDgrByVTogr8PeLHVEPhSHNCW39a/ROphNAdGWZ4M4hcXolloyAGgdtEz5Fw5A==} + bullmq@5.20.0: + resolution: {integrity: sha512-eCJyYJqNUl9swC39x2fVm1BUv5BuO/nv2eAcAsz58znue0ZCYgSG+yWXZeauRG98Jl0UIBcPgJtbF+c9Wd+Odg==} bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -4524,9 +4524,9 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - sirv@2.0.4: - resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} - engines: {node: '>= 10'} + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -4567,8 +4567,8 @@ packages: std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} - stoker@1.0.9: - resolution: {integrity: sha512-z2U3yEVKn2I0iHHQApNmppOrbfrHBEmbgcZztSFaYweOAHNxeAxEgZ2PGGAXLJHRtDgScQz5PGe9iSVgEUa/Hg==} + stoker@1.2.3: + resolution: {integrity: sha512-i1EKytlmCSHKcyO2O2x5p/z8zzUM0w7o7O2PLw8oK6RZDDu7Cy8YuPM2ERPGZ7AdXS9XpnbQq2hw5k3h3cQxrw==} peerDependencies: '@asteasolutions/zod-to-openapi': ^7.0.0 '@hono/zod-openapi': ^0.16.0 @@ -4786,8 +4786,8 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tailwind-merge@2.5.3: - resolution: {integrity: sha512-d9ZolCAIzom1nf/5p4LdD5zvjmgSxY0BGgdSvmXIoMYAiPdAW/dSpP7joCDYFY7r/HkEa2qmPtkgsu0xjQeQtw==} + tailwind-merge@2.5.4: + resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} tailwind-variants@0.2.1: resolution: {integrity: sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==} @@ -4994,8 +4994,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.4.8: - resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==} + vite@5.4.9: + resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -6507,17 +6507,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.24.0': optional: true - '@scalar/hono-api-reference@0.5.153(hono@4.6.4)': + '@scalar/hono-api-reference@0.5.154(hono@4.6.4)': dependencies: - '@scalar/types': 0.0.14 + '@scalar/types': 0.0.15 hono: 4.6.4 - '@scalar/openapi-types@0.1.2': {} + '@scalar/openapi-types@0.1.3': {} - '@scalar/types@0.0.14': + '@scalar/types@0.0.15': dependencies: - '@scalar/openapi-types': 0.1.2 - '@unhead/schema': 1.11.7 + '@scalar/openapi-types': 0.1.3 + '@unhead/schema': 1.11.9 '@sideway/address@4.1.5': dependencies: @@ -6535,41 +6535,41 @@ snapshots: '@sinclair/typebox@0.32.35': optional: true - '@sveltejs/adapter-auto@3.2.5(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))': + '@sveltejs/adapter-auto@3.2.5(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))': dependencies: - '@sveltejs/kit': 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/kit': 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) import-meta-resolve: 4.1.0 - '@sveltejs/adapter-node@5.2.6(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))': + '@sveltejs/adapter-node@5.2.7(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))': dependencies: '@rollup/plugin-commonjs': 28.0.0(rollup@4.24.0) '@rollup/plugin-json': 6.1.0(rollup@4.24.0) '@rollup/plugin-node-resolve': 15.3.0(rollup@4.24.0) - '@sveltejs/kit': 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/kit': 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) rollup: 4.24.0 - '@sveltejs/adapter-vercel@5.4.5(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))': + '@sveltejs/adapter-vercel@5.4.5(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))': dependencies: - '@sveltejs/kit': 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/kit': 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) '@vercel/nft': 0.27.4 esbuild: 0.21.5 transitivePeerDependencies: - encoding - supports-color - '@sveltejs/enhanced-img@0.3.9(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))': + '@sveltejs/enhanced-img@0.3.9(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))': dependencies: magic-string: 0.30.11 svelte: 5.0.0-next.175 svelte-parse-markup: 0.1.5(svelte@5.0.0-next.175) - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) vite-imagetools: 7.0.4(rollup@4.24.0) transitivePeerDependencies: - rollup - '@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))': + '@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.1.1 @@ -6580,30 +6580,30 @@ snapshots: mrmime: 2.0.0 sade: 1.8.1 set-cookie-parser: 2.7.0 - sirv: 2.0.4 + sirv: 3.0.0 svelte: 5.0.0-next.175 tiny-glob: 0.2.9 - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) - '@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) debug: 4.3.7 svelte: 5.0.0-next.175 - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))': + '@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) debug: 4.3.7 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.11 svelte: 5.0.0-next.175 - vite: 5.4.8(@types/node@20.16.11) - vitefu: 1.0.2(vite@5.4.8(@types/node@20.16.11)) + vite: 5.4.9(@types/node@20.16.11) + vitefu: 1.0.2(vite@5.4.9(@types/node@20.16.11)) transitivePeerDependencies: - supports-color @@ -6762,7 +6762,7 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@unhead/schema@1.11.7': + '@unhead/schema@1.11.9': dependencies: hookable: 5.5.3 zhead: 2.2.4 @@ -7008,7 +7008,7 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bullmq@5.19.1: + bullmq@5.20.0: dependencies: cron-parser: 4.9.0 ioredis: 5.4.1 @@ -7713,11 +7713,11 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)): + formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)): dependencies: nanoid: 5.0.7 svelte: 5.0.0-next.175 - sveltekit-superforms: 2.19.1(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175) + sveltekit-superforms: 2.19.1(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175) forwarded@0.2.0: {} @@ -9063,7 +9063,7 @@ snapshots: dependencies: is-arrayish: 0.3.2 - sirv@2.0.4: + sirv@3.0.0: dependencies: '@polka/url': 1.0.0-next.28 mrmime: 2.0.0 @@ -9101,7 +9101,7 @@ snapshots: std-env@3.7.0: {} - stoker@1.0.9(@asteasolutions/zod-to-openapi@7.1.2(zod@3.23.8))(@hono/zod-openapi@0.15.3(hono@4.6.4)(zod@3.23.8))(hono@4.6.4)(openapi3-ts@4.4.0): + stoker@1.2.3(@asteasolutions/zod-to-openapi@7.1.2(zod@3.23.8))(@hono/zod-openapi@0.15.3(hono@4.6.4)(zod@3.23.8))(hono@4.6.4)(openapi3-ts@4.4.0): dependencies: '@asteasolutions/zod-to-openapi': 7.1.2(zod@3.23.8) hono: 4.6.4 @@ -9292,14 +9292,14 @@ snapshots: magic-string: 0.30.11 zimmerframe: 1.1.2 - sveltekit-flash-message@2.4.4(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175): + sveltekit-flash-message@2.4.4(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175): dependencies: - '@sveltejs/kit': 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/kit': 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) svelte: 5.0.0-next.175 - sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175): + sveltekit-superforms@2.19.1(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175): dependencies: - '@sveltejs/kit': 2.7.0(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)) + '@sveltejs/kit': 2.7.1(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.9(@types/node@20.16.11)) devalue: 5.1.1 just-clone: 6.2.0 memoize-weak: 1.0.2 @@ -9325,11 +9325,11 @@ snapshots: tabbable@6.2.0: {} - tailwind-merge@2.5.3: {} + tailwind-merge@2.5.4: {} tailwind-variants@0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))): dependencies: - tailwind-merge: 2.5.3 + tailwind-merge: 2.5.4 tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)) tailwindcss-animate@1.0.7(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))): @@ -9532,7 +9532,7 @@ snapshots: debug: 4.3.7 pathe: 1.1.2 picocolors: 1.1.0 - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) transitivePeerDependencies: - '@types/node' - less @@ -9544,7 +9544,7 @@ snapshots: - supports-color - terser - vite@5.4.8(@types/node@20.16.11): + vite@5.4.9(@types/node@20.16.11): dependencies: esbuild: 0.21.5 postcss: 8.4.47 @@ -9553,9 +9553,9 @@ snapshots: '@types/node': 20.16.11 fsevents: 2.3.3 - vitefu@1.0.2(vite@5.4.8(@types/node@20.16.11)): + vitefu@1.0.2(vite@5.4.9(@types/node@20.16.11)): optionalDependencies: - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) vitest@1.6.0(@types/node@20.16.11): dependencies: @@ -9576,7 +9576,7 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.9.0 tinypool: 0.8.4 - vite: 5.4.8(@types/node@20.16.11) + vite: 5.4.9(@types/node@20.16.11) vite-node: 1.6.0(@types/node@20.16.11) why-is-node-running: 2.3.0 optionalDependencies: diff --git a/src/lib/server/api/common/openapi/cuidParamsSchema.ts b/src/lib/server/api/common/openapi/cuidParamsSchema.ts new file mode 100644 index 0000000..f8b10d5 --- /dev/null +++ b/src/lib/server/api/common/openapi/cuidParamsSchema.ts @@ -0,0 +1,7 @@ +import { z } from '@hono/zod-openapi'; + +const cuidParamsSchema = z.object({ + cuid: z.string().cuid2(), +}); + +export default cuidParamsSchema; diff --git a/src/lib/server/api/controllers/collection.controller.ts b/src/lib/server/api/controllers/collection.controller.ts index 5cc94cd..91c9309 100644 --- a/src/lib/server/api/controllers/collection.controller.ts +++ b/src/lib/server/api/controllers/collection.controller.ts @@ -1,32 +1,40 @@ -import 'reflect-metadata' -import { Controller } from '$lib/server/api/common/types/controller' -import { CollectionsService } from '$lib/server/api/services/collections.service' -import { inject, injectable } from 'tsyringe' -import { requireAuth } from '../middleware/require-auth.middleware' +import 'reflect-metadata'; +import { StatusCodes } from '$lib/constants/status-codes'; +import { Controller } from '$lib/server/api/common/types/controller'; +import { allCollections, getCollectionByCUID, numberOfCollections } from '$lib/server/api/controllers/collection.routes'; +import { CollectionsService } from '$lib/server/api/services/collections.service'; +import { openApi } from 'hono-zod-openapi'; +import { inject, injectable } from 'tsyringe'; +import { requireAuth } from '../middleware/require-auth.middleware'; @injectable() export class CollectionController extends Controller { constructor(@inject(CollectionsService) private readonly collectionsService: CollectionsService) { - super() + super(); } routes() { return this.controller - .get('/', requireAuth, async (c) => { - const user = c.var.user - const collections = await this.collectionsService.findAllByUserId(user.id) - console.log('collections service', collections) - return c.json({ collections }) + .get('/', requireAuth, openApi(allCollections), async (c) => { + const user = c.var.user; + const collections = await this.collectionsService.findAllByUserId(user.id); + console.log('collections service', collections); + return c.json({ collections }, StatusCodes.OK); }) - .get('/count', requireAuth, async (c) => { - const user = c.var.user - const collections = await this.collectionsService.findAllByUserIdWithDetails(user.id) - return c.json({ collections }) - }) - .get('/:cuid', requireAuth, async (c) => { - const cuid = c.req.param('cuid') - const collection = await this.collectionsService.findOneByCuid(cuid) - return c.json({ collection }) + .get('/count', requireAuth, openApi(numberOfCollections), async (c) => { + const user = c.var.user; + const collections = await this.collectionsService.findAllByUserIdWithDetails(user.id); + return c.json({ count: collections?.length || 0 }, StatusCodes.OK); }) + .get('/:cuid', requireAuth, openApi(getCollectionByCUID), async (c) => { + const cuid = c.req.param('cuid'); + const collection = await this.collectionsService.findOneByCuid(cuid); + + if (!collection) { + return c.json('Collection not found', StatusCodes.NOT_FOUND); + } + + return c.json({ collection }, StatusCodes.OK); + }); } } diff --git a/src/lib/server/api/controllers/collection.routes.ts b/src/lib/server/api/controllers/collection.routes.ts new file mode 100644 index 0000000..e3ee453 --- /dev/null +++ b/src/lib/server/api/controllers/collection.routes.ts @@ -0,0 +1,69 @@ +import { StatusCodes } from '$lib/constants/status-codes'; +import { unauthorizedSchema } from '$lib/server/api/common/exceptions'; +import cuidParamsSchema from '$lib/server/api/common/openapi/cuidParamsSchema'; +import { selectCollectionSchema } from '$lib/server/api/databases/tables'; +import { z } from '@hono/zod-openapi'; +import { IdParamsSchema } from 'stoker/openapi/schemas'; +import { createErrorSchema } from 'stoker/openapi/schemas'; +import { taggedAuthRoute } from '../common/openapi/create-auth-route'; + +const tag = 'Collection'; + +export const allCollections = taggedAuthRoute(tag, { + responses: { + [StatusCodes.OK]: { + description: 'User profile', + schema: selectCollectionSchema, + mediaType: 'application/json', + }, + [StatusCodes.UNAUTHORIZED]: { + description: 'Unauthorized', + schema: createErrorSchema(unauthorizedSchema), + mediaType: 'application/json', + }, + }, +}); + +export const numberOfCollections = taggedAuthRoute(tag, { + responses: { + [StatusCodes.OK]: { + description: 'User profile', + mediaType: 'application/json', + }, + [StatusCodes.UNAUTHORIZED]: { + description: 'Unauthorized', + schema: createErrorSchema(unauthorizedSchema), + mediaType: 'application/json', + }, + }, +}); + +export const getCollectionByCUID = taggedAuthRoute(tag, { + request: { + param: { + schema: cuidParamsSchema, + example: { cuid: 'z6uiuc9qz82xjf5dexc5kr2d' }, + }, + }, + responses: { + [StatusCodes.OK]: { + description: 'User profile', + schema: selectCollectionSchema, + mediaType: 'application/json', + }, + [StatusCodes.NOT_FOUND]: { + description: 'The collection does not exist', + schema: z.object({ message: z.string() }).openapi({ + example: { + message: 'The collection does not exist', + }, + }), + mediaType: 'application/json', + }, + [StatusCodes.UNAUTHORIZED]: { + description: 'Unauthorized', + schema: createErrorSchema(unauthorizedSchema), + mediaType: 'application/json', + }, + }, +}); diff --git a/src/lib/server/api/controllers/iam.controller.ts b/src/lib/server/api/controllers/iam.controller.ts index cc8a26e..f907f82 100644 --- a/src/lib/server/api/controllers/iam.controller.ts +++ b/src/lib/server/api/controllers/iam.controller.ts @@ -47,51 +47,72 @@ export class IamController extends Controller { return c.json({ user: updatedUser }, StatusCodes.OK); }, ) - .post('/verify/password', requireAuth, zValidator('json', verifyPasswordDto), openApi(verifyPassword), limiter({ limit: 10, minutes: 60 }), async (c) => { - const user = c.var.user; - const { password } = c.req.valid('json'); - const passwordVerified = await this.iamService.verifyPassword(user.id, { password }); - if (!passwordVerified) { - console.log('Incorrect password'); - return c.json('Incorrect password', StatusCodes.BAD_GATEWAY); - } - return c.json({}, StatusCodes.OK); - }) - .put('/update/password', requireAuth, openApi(updatePassword), zValidator('json', changePasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => { - const user = c.var.user; - const { password, confirm_password } = c.req.valid('json'); - if (password !== confirm_password) { - return c.json('Passwords do not match', StatusCodes.UNPROCESSABLE_ENTITY); - } - try { - await this.iamService.updatePassword(user.id, { password, confirm_password }); - await this.luciaService.lucia.invalidateUserSessions(user.id); - await this.loginRequestService.createUserSession(user.id, c.req, undefined); - const sessionCookie = this.luciaService.lucia.createBlankSessionCookie(); - setCookie(c, sessionCookie.name, sessionCookie.value, { - path: sessionCookie.attributes.path, - maxAge: sessionCookie.attributes.maxAge, - domain: sessionCookie.attributes.domain, - sameSite: sessionCookie.attributes.sameSite as any, - secure: sessionCookie.attributes.secure, - httpOnly: sessionCookie.attributes.httpOnly, - expires: sessionCookie.attributes.expires, - }); - return c.json({ status: 'success' }); - } catch (error) { - console.error('Error updating password', error); - return c.json('Error updating password', StatusCodes.UNPROCESSABLE_ENTITY); - } - }) - .post('/update/email', requireAuth, openApi(updateEmail), zValidator('json', updateEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => { - const user = c.var.user; - const { email } = c.req.valid('json'); - const updatedUser = await this.iamService.updateEmail(user.id, { email }); - if (!updatedUser) { - return c.json('Cannot change email address', StatusCodes.BAD_REQUEST); - } - return c.json({ user: updatedUser }, StatusCodes.OK); - }) + .post( + '/verify/password', + requireAuth, + zValidator('json', verifyPasswordDto), + openApi(verifyPassword), + limiter({ limit: 10, minutes: 60 }), + async (c) => { + const user = c.var.user; + const { password } = c.req.valid('json'); + const passwordVerified = await this.iamService.verifyPassword(user.id, { password }); + if (!passwordVerified) { + console.log('Incorrect password'); + return c.json('Incorrect password', StatusCodes.FORBIDDEN); + } + return c.json({}, StatusCodes.OK); + }, + ) + .put( + '/update/password', + requireAuth, + openApi(updatePassword), + zValidator('json', changePasswordDto), + limiter({ limit: 10, minutes: 60 }), + async (c) => { + const user = c.var.user; + const { password, confirm_password } = c.req.valid('json'); + if (password !== confirm_password) { + return c.json('Passwords do not match', StatusCodes.UNPROCESSABLE_ENTITY); + } + try { + await this.iamService.updatePassword(user.id, { password, confirm_password }); + await this.luciaService.lucia.invalidateUserSessions(user.id); + await this.loginRequestService.createUserSession(user.id, c.req, undefined); + const sessionCookie = this.luciaService.lucia.createBlankSessionCookie(); + setCookie(c, sessionCookie.name, sessionCookie.value, { + path: sessionCookie.attributes.path, + maxAge: sessionCookie.attributes.maxAge, + domain: sessionCookie.attributes.domain, + sameSite: sessionCookie.attributes.sameSite as any, + secure: sessionCookie.attributes.secure, + httpOnly: sessionCookie.attributes.httpOnly, + expires: sessionCookie.attributes.expires, + }); + return c.json({ status: 'success' }); + } catch (error) { + console.error('Error updating password', error); + return c.json('Error updating password', StatusCodes.INTERNAL_SERVER_ERROR); + } + }, + ) + .post( + '/update/email', + requireAuth, + openApi(updateEmail), + zValidator('json', updateEmailDto), + limiter({ limit: 10, minutes: 60 }), + async (c) => { + const user = c.var.user; + const { email } = c.req.valid('json'); + const updatedUser = await this.iamService.updateEmail(user.id, { email }); + if (!updatedUser) { + return c.json('Cannot change email address', StatusCodes.FORBIDDEN); + } + return c.json({ user: updatedUser }, StatusCodes.OK); + }, + ) .post('/logout', requireAuth, openApi(logout), async (c) => { const sessionId = c.var.session.id; await this.iamService.logout(sessionId); diff --git a/src/lib/server/api/controllers/iam.routes.ts b/src/lib/server/api/controllers/iam.routes.ts index 14daba5..be40ab9 100644 --- a/src/lib/server/api/controllers/iam.routes.ts +++ b/src/lib/server/api/controllers/iam.routes.ts @@ -65,7 +65,7 @@ export const verifyPassword = taggedAuthRoute(tag, { schema: createErrorSchema(verifyPasswordDto), mediaType: 'application/json', }, - [StatusCodes.BAD_REQUEST]: { + [StatusCodes.UNPROCESSABLE_ENTITY]: { description: 'Incorrect password', mediaType: 'application/json', }, @@ -91,15 +91,19 @@ export const updatePassword = taggedAuthRoute(tag, { schema: createErrorSchema(changePasswordDto), mediaType: 'application/json', }, - [StatusCodes.BAD_REQUEST]: { - description: 'Incorrect password', - mediaType: 'application/json', - }, [StatusCodes.UNAUTHORIZED]: { description: 'Unauthorized', schema: createErrorSchema(unauthorizedSchema), mediaType: 'application/json', }, + [StatusCodes.FORBIDDEN]: { + description: 'Incorrect password', + mediaType: 'application/json', + }, + [StatusCodes.INTERNAL_SERVER_ERROR]: { + description: 'Error updating password', + mediaType: 'application/json', + }, }, }); @@ -114,15 +118,15 @@ export const updateEmail = taggedAuthRoute(tag, { schema: createErrorSchema(changePasswordDto), mediaType: 'application/json', }, - [StatusCodes.BAD_REQUEST]: { - description: "Cannot change email address", - mediaType: 'application/json', - }, [StatusCodes.UNAUTHORIZED]: { description: 'Unauthorized', schema: createErrorSchema(unauthorizedSchema), mediaType: 'application/json', }, + [StatusCodes.FORBIDDEN]: { + description: 'Cannot change email address', + mediaType: 'application/json', + }, }, }); diff --git a/src/lib/server/api/databases/tables/collections.table.ts b/src/lib/server/api/databases/tables/collections.table.ts index 4b483df..7c29f91 100644 --- a/src/lib/server/api/databases/tables/collections.table.ts +++ b/src/lib/server/api/databases/tables/collections.table.ts @@ -1,9 +1,10 @@ -import { createId as cuid2 } from '@paralleldrive/cuid2' -import { type InferSelectModel, relations } from 'drizzle-orm' -import { pgTable, text, uuid } from 'drizzle-orm/pg-core' -import { timestamps } from '../../common/utils/table' -import { usersTable } from './users.table' -import { collection_items } from './collectionItems.table' +import { createId as cuid2 } from '@paralleldrive/cuid2'; +import { type InferSelectModel, relations } from 'drizzle-orm'; +import { pgTable, text, uuid } from 'drizzle-orm/pg-core'; +import { createSelectSchema } from 'drizzle-zod'; +import { timestamps } from '../../common/utils/table'; +import { collection_items } from './collectionItems.table'; +import { usersTable } from './users.table'; export const collections = pgTable('collections', { id: uuid('id').primaryKey().defaultRandom(), @@ -15,7 +16,7 @@ export const collections = pgTable('collections', { .references(() => usersTable.id, { onDelete: 'cascade' }), name: text('name').notNull().default('My Collection'), ...timestamps, -}) +}); export const collection_relations = relations(collections, ({ one, many }) => ({ user: one(usersTable, { @@ -23,6 +24,8 @@ export const collection_relations = relations(collections, ({ one, many }) => ({ references: [usersTable.id], }), collection_items: many(collection_items), -})) +})); -export type Collections = InferSelectModel +export const selectCollectionSchema = createSelectSchema(collections); + +export type Collections = InferSelectModel;