Add services and auth
This commit is contained in:
parent
9b0b5dc040
commit
5dec454afb
46 changed files with 900 additions and 31 deletions
221
package-lock.json
generated
221
package-lock.json
generated
|
|
@ -11,10 +11,13 @@
|
|||
"dependencies": {
|
||||
"@prisma/adapter-pg": "^7.2.0",
|
||||
"@prisma/client": "^7.2.0",
|
||||
"argon2": "^0.44.0",
|
||||
"fastify": "^5.6.2",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"pg": "^8.16.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/pg": "^8.16.0",
|
||||
"dotenv": "^17.2.3",
|
||||
|
|
@ -103,6 +106,12 @@
|
|||
"@electric-sql/pglite": "0.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@epic-web/invariant": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
|
||||
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@fastify/ajv-compiler": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz",
|
||||
|
|
@ -269,6 +278,15 @@
|
|||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@phc/format": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
|
||||
"integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinojs/redact": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
|
||||
|
|
@ -494,6 +512,24 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "9.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
|
||||
"integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/ms": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
|
||||
|
|
@ -599,6 +635,22 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argon2": {
|
||||
"version": "0.44.0",
|
||||
"resolved": "https://registry.npmjs.org/argon2/-/argon2-0.44.0.tgz",
|
||||
"integrity": "sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@phc/format": "^1.0.0",
|
||||
"cross-env": "^10.0.0",
|
||||
"node-addon-api": "^8.5.0",
|
||||
"node-gyp-build": "^4.8.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/atomic-sleep": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
|
||||
|
|
@ -628,6 +680,12 @@
|
|||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/c12": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz",
|
||||
|
|
@ -748,11 +806,27 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
|
||||
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@epic-web/invariant": "^1.0.0",
|
||||
"cross-spawn": "^7.0.6"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "dist/bin/cross-env.js",
|
||||
"cross-env-shell": "dist/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
|
|
@ -837,6 +911,15 @@
|
|||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/effect": {
|
||||
"version": "3.18.4",
|
||||
"resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz",
|
||||
|
|
@ -1125,7 +1208,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
|
|
@ -1163,6 +1245,49 @@
|
|||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||
"integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jws": "^4.0.1",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "^1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
|
||||
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/light-my-request": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz",
|
||||
|
|
@ -1217,6 +1342,48 @@
|
|||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
|
|
@ -1247,6 +1414,12 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.15.3",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz",
|
||||
|
|
@ -1281,6 +1454,15 @@
|
|||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
|
||||
"integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch-native": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
|
||||
|
|
@ -1288,6 +1470,17 @@
|
|||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"node-gyp-build": "bin.js",
|
||||
"node-gyp-build-optional": "optional.js",
|
||||
"node-gyp-build-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/nypm": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
|
||||
|
|
@ -1328,7 +1521,6 @@
|
|||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
|
|
@ -1760,6 +1952,26 @@
|
|||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-regex2": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz",
|
||||
|
|
@ -1847,7 +2059,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
|
|
@ -1860,7 +2071,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
|
|
@ -2046,7 +2256,6 @@
|
|||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"start": "npx tsc && node --env-file=.env dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/pg": "^8.16.0",
|
||||
"dotenv": "^17.2.3",
|
||||
|
|
@ -25,7 +26,9 @@
|
|||
"dependencies": {
|
||||
"@prisma/adapter-pg": "^7.2.0",
|
||||
"@prisma/client": "^7.2.0",
|
||||
"argon2": "^0.44.0",
|
||||
"fastify": "^5.6.2",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"pg": "^8.16.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
56
src/controllers/auth/auth.ts
Normal file
56
src/controllers/auth/auth.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
ILoginRequest,
|
||||
IRegisterResponseError,
|
||||
IRegisterResponseSuccess,
|
||||
IRegisterRequest,
|
||||
ILoginResponseError,
|
||||
ILoginResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { loginUser, registerUser } from "../../services/auth/auth.js";
|
||||
|
||||
const postRegister = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { username, password, email } = request.body as IRegisterRequest;
|
||||
|
||||
const newUser = await registerUser({
|
||||
username: username,
|
||||
password: password,
|
||||
email: email,
|
||||
});
|
||||
|
||||
if (!newUser) {
|
||||
return {
|
||||
error: "user already exists",
|
||||
} as IRegisterResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: newUser.id,
|
||||
username: newUser.username,
|
||||
registerDate: newUser.registerDate?.getTime(),
|
||||
} as IRegisterResponseSuccess;
|
||||
};
|
||||
|
||||
const postLogin = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { username, password } = request.body as ILoginRequest;
|
||||
|
||||
const session = await loginUser({
|
||||
username: username,
|
||||
password: password,
|
||||
});
|
||||
|
||||
if (!session) {
|
||||
return {
|
||||
ownerId: "",
|
||||
error: "incorrect credentials",
|
||||
} as ILoginResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
ownerId: session.userId,
|
||||
token: session.token,
|
||||
} as ILoginResponseSuccess;
|
||||
};
|
||||
|
||||
export { postRegister, postLogin };
|
||||
3
src/controllers/auth/index.ts
Normal file
3
src/controllers/auth/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./auth.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
9
src/controllers/auth/routes.ts
Normal file
9
src/controllers/auth/routes.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./auth.js";
|
||||
|
||||
const authRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.post(`/register`, controller.postRegister);
|
||||
fastify.post(`/login`, controller.postLogin);
|
||||
};
|
||||
|
||||
export { authRoutes };
|
||||
40
src/controllers/auth/types.ts
Normal file
40
src/controllers/auth/types.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
interface IRegisterRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
email?: string;
|
||||
}
|
||||
|
||||
interface IRegisterResponseSuccess {
|
||||
id: string;
|
||||
username: string;
|
||||
registerDate: number;
|
||||
}
|
||||
|
||||
interface IRegisterResponseError {
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface ILoginRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
interface ILoginResponseSuccess {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface ILoginResponseError {
|
||||
ownerId: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IRegisterRequest,
|
||||
type IRegisterResponseSuccess,
|
||||
type IRegisterResponseError,
|
||||
type ILoginRequest,
|
||||
type ILoginResponseSuccess,
|
||||
type ILoginResponseError,
|
||||
};
|
||||
27
src/controllers/channel/channel.ts
Normal file
27
src/controllers/channel/channel.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
IChannelParams,
|
||||
IChannelResponseError,
|
||||
IChannelResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { getChannelById } from "../../services/channel/channel.js";
|
||||
|
||||
const getChannel = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as IChannelParams;
|
||||
|
||||
const channel = await getChannelById(id);
|
||||
if (!channel) {
|
||||
return {
|
||||
id: id,
|
||||
error: "channel does not exist",
|
||||
} as IChannelResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: channel.id,
|
||||
name: channel.name,
|
||||
communityId: channel.communityId,
|
||||
} as IChannelResponseSuccess;
|
||||
};
|
||||
|
||||
export { getChannel };
|
||||
3
src/controllers/channel/index.ts
Normal file
3
src/controllers/channel/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./channel.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
8
src/controllers/channel/routes.ts
Normal file
8
src/controllers/channel/routes.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./channel.js";
|
||||
|
||||
const channelRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get(`/:id`, controller.getChannel);
|
||||
};
|
||||
|
||||
export { channelRoutes };
|
||||
20
src/controllers/channel/types.ts
Normal file
20
src/controllers/channel/types.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface IChannelParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IChannelResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface IChannelResponseSuccess {
|
||||
id: string;
|
||||
name: string;
|
||||
communityId: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IChannelParams,
|
||||
type IChannelResponseError,
|
||||
type IChannelResponseSuccess,
|
||||
};
|
||||
27
src/controllers/community/community.ts
Normal file
27
src/controllers/community/community.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
ICommunityParams,
|
||||
ICommunityResponseError,
|
||||
ICommunityResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { getCommunityById } from "../../services/community/community.js";
|
||||
|
||||
const getCommunity = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as ICommunityParams;
|
||||
|
||||
const community = await getCommunityById(id);
|
||||
if (!community) {
|
||||
return {
|
||||
id: id,
|
||||
error: "community does not exist",
|
||||
} as ICommunityResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: community.id,
|
||||
name: community.name,
|
||||
description: community.description,
|
||||
} as ICommunityResponseSuccess;
|
||||
};
|
||||
|
||||
export { getCommunity };
|
||||
3
src/controllers/community/index.ts
Normal file
3
src/controllers/community/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./community.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
8
src/controllers/community/routes.ts
Normal file
8
src/controllers/community/routes.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./community.js";
|
||||
|
||||
const communityRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get(`/:id`, controller.getCommunity);
|
||||
};
|
||||
|
||||
export { communityRoutes };
|
||||
20
src/controllers/community/types.ts
Normal file
20
src/controllers/community/types.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface ICommunityParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface ICommunityResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface ICommunityResponseSuccess {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type ICommunityParams,
|
||||
type ICommunityResponseError,
|
||||
type ICommunityResponseSuccess,
|
||||
};
|
||||
3
src/controllers/role/index.ts
Normal file
3
src/controllers/role/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./role.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
27
src/controllers/role/role.ts
Normal file
27
src/controllers/role/role.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
IRoleParams,
|
||||
IRoleResponseError,
|
||||
IRoleResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { getRoleById } from "../../services/role/role.js";
|
||||
|
||||
const getRole = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as IRoleParams;
|
||||
|
||||
const role = await getRoleById(id);
|
||||
if (!role) {
|
||||
return {
|
||||
id: id,
|
||||
error: "role does not exist",
|
||||
} as IRoleResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
communityId: role.communityId,
|
||||
} as IRoleResponseSuccess;
|
||||
};
|
||||
|
||||
export { getRole };
|
||||
8
src/controllers/role/routes.ts
Normal file
8
src/controllers/role/routes.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./role.js";
|
||||
|
||||
const roleRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get(`/:id`, controller.getRole);
|
||||
};
|
||||
|
||||
export { roleRoutes };
|
||||
16
src/controllers/role/types.ts
Normal file
16
src/controllers/role/types.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
interface IRoleParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IRoleResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface IRoleResponseSuccess {
|
||||
id: string;
|
||||
name: string;
|
||||
communityId: string;
|
||||
}
|
||||
|
||||
export { type IRoleParams, type IRoleResponseError, type IRoleResponseSuccess };
|
||||
3
src/controllers/session/index.ts
Normal file
3
src/controllers/session/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./session.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
8
src/controllers/session/routes.ts
Normal file
8
src/controllers/session/routes.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./session.js";
|
||||
|
||||
const sessionRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get(`/:id`, controller.getSession);
|
||||
};
|
||||
|
||||
export { sessionRoutes };
|
||||
26
src/controllers/session/session.ts
Normal file
26
src/controllers/session/session.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
ISessionParams,
|
||||
ISessionResponseError,
|
||||
ISessionResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { getSessionById } from "../../services/session/session.js";
|
||||
|
||||
const getSession = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as ISessionParams;
|
||||
|
||||
const session = await getSessionById(id);
|
||||
if (!session) {
|
||||
return {
|
||||
id: id,
|
||||
error: "session does not exist",
|
||||
} as ISessionResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
userId: session.userId,
|
||||
} as ISessionResponseSuccess;
|
||||
};
|
||||
|
||||
export { getSession };
|
||||
19
src/controllers/session/types.ts
Normal file
19
src/controllers/session/types.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
interface ISessionParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface ISessionResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface ISessionResponseSuccess {
|
||||
id: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type ISessionParams,
|
||||
type ISessionResponseError,
|
||||
type ISessionResponseSuccess,
|
||||
};
|
||||
|
|
@ -2,7 +2,8 @@ import { type FastifyInstance } from "fastify";
|
|||
import * as controller from "./test.js";
|
||||
|
||||
const testRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get("/test", controller.test);
|
||||
fastify.get("/ping", controller.getPing);
|
||||
fastify.get("/test", controller.getTest);
|
||||
};
|
||||
|
||||
export { testRoutes };
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import { testdb } from "../../store/store.js";
|
||||
|
||||
const test = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
testdb();
|
||||
|
||||
return [{ name: "Alice" }];
|
||||
const getPing = async (_request: FastifyRequest, _reply: FastifyReply) => {
|
||||
return [{ message: "pong" }];
|
||||
};
|
||||
|
||||
export { test };
|
||||
const getTest = async (_request: FastifyRequest, _reply: FastifyReply) => {
|
||||
return [{ message: "ok" }];
|
||||
};
|
||||
|
||||
export { getPing, getTest };
|
||||
|
|
|
|||
3
src/controllers/user/index.ts
Normal file
3
src/controllers/user/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./user.js";
|
||||
export * from "./routes.js";
|
||||
export * from "./types.js";
|
||||
9
src/controllers/user/routes.ts
Normal file
9
src/controllers/user/routes.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { type FastifyInstance } from "fastify";
|
||||
import * as controller from "./user.js";
|
||||
|
||||
const userRoutes = async (fastify: FastifyInstance) => {
|
||||
fastify.get(`/:id`, controller.getUser);
|
||||
fastify.get(`/:id/sessions`, controller.getSessions);
|
||||
};
|
||||
|
||||
export { userRoutes };
|
||||
41
src/controllers/user/types.ts
Normal file
41
src/controllers/user/types.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
interface IUserParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IUserResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface IUserResponseSuccess {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
description: string;
|
||||
admin: boolean;
|
||||
registerDate: number;
|
||||
lastLogin: number;
|
||||
}
|
||||
|
||||
interface ISessionsResponseError {
|
||||
id: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface ISessionsResponseSuccess {
|
||||
sessions: ISessionsResponseSession[];
|
||||
}
|
||||
|
||||
interface ISessionsResponseSession {
|
||||
id: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IUserParams,
|
||||
type IUserResponseError,
|
||||
type IUserResponseSuccess,
|
||||
type ISessionsResponseError,
|
||||
type ISessionsResponseSuccess,
|
||||
type ISessionsResponseSession,
|
||||
};
|
||||
53
src/controllers/user/user.ts
Normal file
53
src/controllers/user/user.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||
import type {
|
||||
IUserParams,
|
||||
IUserResponseError,
|
||||
IUserResponseSuccess,
|
||||
ISessionsResponseError,
|
||||
ISessionsResponseSuccess,
|
||||
} from "./types.js";
|
||||
import { getUserById, getUserSessionsById } from "../../services/user/user.js";
|
||||
|
||||
const getUser = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as IUserParams;
|
||||
|
||||
const user = await getUserById(id);
|
||||
if (!user) {
|
||||
return {
|
||||
id: id,
|
||||
error: "user does not exist",
|
||||
} as IUserResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
description: user.description,
|
||||
admin: user.admin,
|
||||
registerDate: user.registerDate.getTime(),
|
||||
lastLogin: user.lastLogin?.getTime() ?? 0,
|
||||
} as IUserResponseSuccess;
|
||||
};
|
||||
|
||||
const getSessions = async (request: FastifyRequest, _reply: FastifyReply) => {
|
||||
const { id } = request.params as IUserParams;
|
||||
const authHeader = request.headers["authorization"];
|
||||
|
||||
const sessions = await getUserSessionsById(id, authHeader);
|
||||
if (!sessions) {
|
||||
return {
|
||||
id: id,
|
||||
error: "user does not exist or you have no access",
|
||||
} as ISessionsResponseError;
|
||||
}
|
||||
|
||||
return {
|
||||
sessions: sessions.map((session) => ({
|
||||
id: session.id,
|
||||
userId: session.userId,
|
||||
})),
|
||||
} as ISessionsResponseSuccess;
|
||||
};
|
||||
|
||||
export { getUser, getSessions };
|
||||
59
src/helpers.ts
Normal file
59
src/helpers.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import jwt from "jsonwebtoken";
|
||||
import type { Session, User } from "./generated/prisma/client.js";
|
||||
import { getDB } from "./store/store.js";
|
||||
|
||||
const getJwtSecret = () => {
|
||||
return process.env.JWT_SECRET || "";
|
||||
};
|
||||
|
||||
const verifyToken = (token: string): string | jwt.JwtPayload | null => {
|
||||
try {
|
||||
return jwt.verify(token, getJwtSecret());
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getSessionFromToken = async (token: string): Promise<Session | null> => {
|
||||
return await getDB().session.findFirst({
|
||||
where: {
|
||||
token: token,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getUserFromToken = async (token: string): Promise<User | null> => {
|
||||
const session = await getSessionFromToken(token);
|
||||
|
||||
return await getDB().user.findFirst({
|
||||
where: {
|
||||
id: session?.userId ?? "invalid",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getUserFromAuth = async (
|
||||
authHeader: string | undefined,
|
||||
): Promise<User | null> => {
|
||||
const token = authHeader?.replace("Bearer ", "");
|
||||
|
||||
const verified = verifyToken(token ?? "") !== null;
|
||||
if (!verified || !token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await getUserFromToken(token);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export {
|
||||
getJwtSecret,
|
||||
verifyToken,
|
||||
getSessionFromToken,
|
||||
getUserFromToken,
|
||||
getUserFromAuth,
|
||||
};
|
||||
12
src/index.ts
12
src/index.ts
|
|
@ -2,12 +2,24 @@ import { config } from "./config.js";
|
|||
|
||||
import Fastify from "fastify";
|
||||
import { testRoutes } from "./controllers/test/routes.js";
|
||||
import { authRoutes } from "./controllers/auth/routes.js";
|
||||
import { userRoutes } from "./controllers/user/routes.js";
|
||||
import { sessionRoutes } from "./controllers/session/routes.js";
|
||||
import { communityRoutes } from "./controllers/community/routes.js";
|
||||
import { channelRoutes } from "./controllers/channel/routes.js";
|
||||
import { roleRoutes } from "./controllers/role/routes.js";
|
||||
|
||||
const app = Fastify({
|
||||
logger: true,
|
||||
});
|
||||
|
||||
app.register(testRoutes);
|
||||
app.register(authRoutes, { prefix: "/api/v1/auth" });
|
||||
app.register(userRoutes, { prefix: "/api/v1/user" });
|
||||
app.register(sessionRoutes, { prefix: "/api/v1/session" });
|
||||
app.register(communityRoutes, { prefix: "/api/v1/community" });
|
||||
app.register(channelRoutes, { prefix: "/api/v1/channel" });
|
||||
app.register(roleRoutes, { prefix: "/api/v1/role" });
|
||||
|
||||
app.listen({ port: config.port }, (err, address) => {
|
||||
if (err) throw err;
|
||||
|
|
|
|||
72
src/services/auth/auth.ts
Normal file
72
src/services/auth/auth.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import argon2 from "argon2";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
import type { User, Session } from "../../generated/prisma/client.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
import type { IUserLogin, IUserRegistration } from "./types.js";
|
||||
import { getJwtSecret } from "../../helpers.js";
|
||||
|
||||
const registerUser = async (
|
||||
registration: IUserRegistration,
|
||||
): Promise<User | null> => {
|
||||
const existingUser = await getDB().user.findUnique({
|
||||
where: { username: registration.username },
|
||||
});
|
||||
if (existingUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const passwordHash = await hashPassword(registration.password);
|
||||
|
||||
let newUser: User | null = null;
|
||||
try {
|
||||
newUser = await getDB().user.create({
|
||||
data: {
|
||||
username: registration.username,
|
||||
passwordHash: passwordHash,
|
||||
email: registration.email ?? null,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
return newUser;
|
||||
};
|
||||
|
||||
const loginUser = async (login: IUserLogin): Promise<Session | null> => {
|
||||
const user = await getDB().user.findUnique({
|
||||
where: { username: login.username },
|
||||
});
|
||||
|
||||
const passwordCorrect = await argon2.verify(
|
||||
user?.passwordHash ?? "",
|
||||
login.password,
|
||||
);
|
||||
|
||||
if (!user || !passwordCorrect) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await getDB().session.create({
|
||||
data: {
|
||||
token: createToken(user.id),
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const hashPassword = async (password: string): Promise<string> => {
|
||||
return await argon2.hash(password, {
|
||||
type: argon2.argon2id,
|
||||
memoryCost: 2 ** 16,
|
||||
timeCost: 4,
|
||||
parallelism: 1,
|
||||
});
|
||||
};
|
||||
|
||||
const createToken = (userId: string) => {
|
||||
return jwt.sign({ sub: userId }, getJwtSecret());
|
||||
};
|
||||
|
||||
export { registerUser, loginUser, hashPassword };
|
||||
2
src/services/auth/index.ts
Normal file
2
src/services/auth/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./auth.js";
|
||||
export * from "./types.js";
|
||||
12
src/services/auth/types.ts
Normal file
12
src/services/auth/types.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
interface IUserRegistration {
|
||||
username: string;
|
||||
password: string;
|
||||
email?: string | undefined;
|
||||
}
|
||||
|
||||
interface IUserLogin {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export { type IUserRegistration, type IUserLogin };
|
||||
10
src/services/channel/channel.ts
Normal file
10
src/services/channel/channel.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import type { Channel } from "../../generated/prisma/client.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
|
||||
const getChannelById = async (id: string): Promise<Channel | null> => {
|
||||
return await getDB().channel.findUnique({
|
||||
where: { id: id },
|
||||
});
|
||||
};
|
||||
|
||||
export { getChannelById };
|
||||
1
src/services/channel/index.ts
Normal file
1
src/services/channel/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./channel.js";
|
||||
10
src/services/community/community.ts
Normal file
10
src/services/community/community.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import type { Community } from "../../generated/prisma/client.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
|
||||
const getCommunityById = async (id: string): Promise<Community | null> => {
|
||||
return await getDB().community.findUnique({
|
||||
where: { id: id },
|
||||
});
|
||||
};
|
||||
|
||||
export { getCommunityById };
|
||||
1
src/services/community/index.ts
Normal file
1
src/services/community/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./community.js";
|
||||
1
src/services/role/index.ts
Normal file
1
src/services/role/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./role.js";
|
||||
10
src/services/role/role.ts
Normal file
10
src/services/role/role.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import type { Role } from "../../generated/prisma/client.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
|
||||
const getRoleById = async (id: string): Promise<Role | null> => {
|
||||
return await getDB().role.findUnique({
|
||||
where: { id: id },
|
||||
});
|
||||
};
|
||||
|
||||
export { getRoleById };
|
||||
1
src/services/session/index.ts
Normal file
1
src/services/session/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./session.js";
|
||||
10
src/services/session/session.ts
Normal file
10
src/services/session/session.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import type { Session } from "../../generated/prisma/client.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
|
||||
const getSessionById = async (id: string): Promise<Session | null> => {
|
||||
return await getDB().session.findUnique({
|
||||
where: { id: id },
|
||||
});
|
||||
};
|
||||
|
||||
export { getSessionById };
|
||||
1
src/services/user/index.ts
Normal file
1
src/services/user/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./user.js";
|
||||
27
src/services/user/user.ts
Normal file
27
src/services/user/user.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import type { User, Session } from "../../generated/prisma/client.js";
|
||||
import { getUserFromAuth } from "../../helpers.js";
|
||||
import { getDB } from "../../store/store.js";
|
||||
|
||||
const getUserById = async (id: string): Promise<User | null> => {
|
||||
return await getDB().user.findUnique({
|
||||
where: { id: id },
|
||||
});
|
||||
};
|
||||
|
||||
const getUserSessionsById = async (
|
||||
id: string,
|
||||
authHeader: string | undefined,
|
||||
): Promise<Session[] | null> => {
|
||||
const user = await getUserFromAuth(authHeader);
|
||||
if (!user || user.id !== id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await getDB().session.findMany({
|
||||
where: {
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { getUserById, getUserSessionsById };
|
||||
|
|
@ -1,2 +1 @@
|
|||
export * from "./store.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
|||
|
|
@ -10,18 +10,8 @@ const adapter = new PrismaPg(pool);
|
|||
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
async function testdb() {
|
||||
const test = await prisma.user.findMany();
|
||||
/*
|
||||
const user = await prisma.user.create({
|
||||
data: { name: "Alice", email: `alice${Math.random()}@example.com` },
|
||||
});
|
||||
const getDB = (): PrismaClient => {
|
||||
return prisma;
|
||||
};
|
||||
|
||||
console.log("Created user:", user);
|
||||
|
||||
const test = await prisma.user.findMany();
|
||||
console.log(test);
|
||||
*/
|
||||
}
|
||||
|
||||
export { testdb };
|
||||
export { getDB };
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
interface IState {}
|
||||
|
||||
export { type IState };
|
||||
Loading…
Add table
Add a link
Reference in a new issue