api login
This commit is contained in:
parent
bd0daf5858
commit
1a7473362b
8 changed files with 613 additions and 60 deletions
|
|
@ -4,10 +4,13 @@
|
|||
],
|
||||
"ext": "ts,json",
|
||||
"ignore": [
|
||||
"src/**/*.test.ts",
|
||||
"node_modules"
|
||||
"node_modules",
|
||||
"dist",
|
||||
"src/routes/routes.ts",
|
||||
"src/public/swagger.json",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"exec": "ts-node -r tsconfig-paths/register src/server.ts",
|
||||
"exec": "npm run build && node dist/server.js",
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
}
|
||||
|
|
|
|||
528
Backend/package-lock.json
generated
528
Backend/package-lock.json
generated
|
|
@ -45,6 +45,7 @@
|
|||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
},
|
||||
|
|
@ -609,6 +610,448 @@
|
|||
"kuler": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
|
||||
"integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
|
||||
"integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
|
||||
"integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
|
||||
"integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
|
||||
"integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
|
||||
"integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
|
||||
"integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
|
||||
"integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
|
||||
"integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
|
||||
"integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
|
||||
"integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
||||
|
|
@ -4172,6 +4615,48 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
|
||||
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.27.2",
|
||||
"@esbuild/android-arm": "0.27.2",
|
||||
"@esbuild/android-arm64": "0.27.2",
|
||||
"@esbuild/android-x64": "0.27.2",
|
||||
"@esbuild/darwin-arm64": "0.27.2",
|
||||
"@esbuild/darwin-x64": "0.27.2",
|
||||
"@esbuild/freebsd-arm64": "0.27.2",
|
||||
"@esbuild/freebsd-x64": "0.27.2",
|
||||
"@esbuild/linux-arm": "0.27.2",
|
||||
"@esbuild/linux-arm64": "0.27.2",
|
||||
"@esbuild/linux-ia32": "0.27.2",
|
||||
"@esbuild/linux-loong64": "0.27.2",
|
||||
"@esbuild/linux-mips64el": "0.27.2",
|
||||
"@esbuild/linux-ppc64": "0.27.2",
|
||||
"@esbuild/linux-riscv64": "0.27.2",
|
||||
"@esbuild/linux-s390x": "0.27.2",
|
||||
"@esbuild/linux-x64": "0.27.2",
|
||||
"@esbuild/netbsd-arm64": "0.27.2",
|
||||
"@esbuild/netbsd-x64": "0.27.2",
|
||||
"@esbuild/openbsd-arm64": "0.27.2",
|
||||
"@esbuild/openbsd-x64": "0.27.2",
|
||||
"@esbuild/openharmony-arm64": "0.27.2",
|
||||
"@esbuild/sunos-x64": "0.27.2",
|
||||
"@esbuild/win32-arm64": "0.27.2",
|
||||
"@esbuild/win32-ia32": "0.27.2",
|
||||
"@esbuild/win32-x64": "0.27.2"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
|
|
@ -5033,6 +5518,19 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
|
||||
"integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
|
|
@ -7707,6 +8205,16 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve.exports": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
|
||||
|
|
@ -8725,6 +9233,26 @@
|
|||
"yarn": ">=1.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
|
||||
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "~0.27.0",
|
||||
"get-tsconfig": "^4.7.5"
|
||||
},
|
||||
"bin": {
|
||||
"tsx": "dist/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"main": "dist/server.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon",
|
||||
"build": "tsoa spec-and-routes && tsc",
|
||||
"build": "npm run tsoa:gen && tsc",
|
||||
"start": "node dist/server.js",
|
||||
"tsoa:gen": "tsoa spec-and-routes",
|
||||
"prisma:generate": "prisma generate",
|
||||
|
|
@ -18,15 +18,6 @@
|
|||
"lint": "eslint . --ext .ts",
|
||||
"format": "prettier --write \"src/**/*.ts\""
|
||||
},
|
||||
"keywords": [
|
||||
"e-learning",
|
||||
"typescript",
|
||||
"tsoa",
|
||||
"express",
|
||||
"prisma"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.22.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
|
|
@ -62,11 +53,7 @@
|
|||
"prisma": "^5.22.0",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "node prisma/seed.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,22 +37,28 @@ async function main() {
|
|||
// Seed Roles
|
||||
console.log('👥 Seeding roles...');
|
||||
const roles = await Promise.all([
|
||||
prisma.role.create({
|
||||
data: {
|
||||
prisma.role.upsert({
|
||||
where: { code: 'ADMIN' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'ADMIN',
|
||||
name: { th: 'ผู้ดูแลระบบ', en: 'Administrator' },
|
||||
description: { th: 'มีสิทธิ์เข้าถึงทุกฟังก์ชัน', en: 'Full system access' }
|
||||
}
|
||||
}),
|
||||
prisma.role.create({
|
||||
data: {
|
||||
prisma.role.upsert({
|
||||
where: { code: 'INSTRUCTOR' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'INSTRUCTOR',
|
||||
name: { th: 'ผู้สอน', en: 'Instructor' },
|
||||
description: { th: 'สามารถสร้างและจัดการคอร์สเรียน', en: 'Can create and manage courses' }
|
||||
}
|
||||
}),
|
||||
prisma.role.create({
|
||||
data: {
|
||||
prisma.role.upsert({
|
||||
where: { code: 'STUDENT' },
|
||||
update: {},
|
||||
create: {
|
||||
code: 'STUDENT',
|
||||
name: { th: 'นักเรียน', en: 'Student' },
|
||||
description: { th: 'สามารถลงทะเบียนและเรียนคอร์ส', en: 'Can enroll and learn courses' }
|
||||
|
|
@ -64,8 +70,10 @@ async function main() {
|
|||
console.log('👤 Seeding users...');
|
||||
const hashedPassword = await bcrypt.hash('admin123', 10);
|
||||
|
||||
const admin = await prisma.user.create({
|
||||
data: {
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { username: 'admin' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'admin',
|
||||
email: 'admin@elearning.local',
|
||||
password: hashedPassword,
|
||||
|
|
@ -81,8 +89,10 @@ async function main() {
|
|||
}
|
||||
});
|
||||
|
||||
const instructor = await prisma.user.create({
|
||||
data: {
|
||||
const instructor = await prisma.user.upsert({
|
||||
where: { username: 'instructor' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'instructor',
|
||||
email: 'instructor@elearning.local',
|
||||
password: hashedPassword,
|
||||
|
|
@ -98,8 +108,10 @@ async function main() {
|
|||
}
|
||||
});
|
||||
|
||||
const student = await prisma.user.create({
|
||||
data: {
|
||||
const student = await prisma.user.upsert({
|
||||
where: { username: 'student' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'student',
|
||||
email: 'student@elearning.local',
|
||||
password: hashedPassword,
|
||||
|
|
@ -118,8 +130,10 @@ async function main() {
|
|||
// Seed Categories
|
||||
console.log('📚 Seeding categories...');
|
||||
const categories = await Promise.all([
|
||||
prisma.category.create({
|
||||
data: {
|
||||
prisma.category.upsert({
|
||||
where: { slug: 'programming' },
|
||||
update: {},
|
||||
create: {
|
||||
name: { th: 'การเขียนโปรแกรม', en: 'Programming' },
|
||||
slug: 'programming',
|
||||
description: { th: 'เรียนรู้การเขียนโปรแกรมและพัฒนาซอฟต์แวร์', en: 'Learn programming and software development' },
|
||||
|
|
@ -128,8 +142,10 @@ async function main() {
|
|||
created_by: admin.id
|
||||
}
|
||||
}),
|
||||
prisma.category.create({
|
||||
data: {
|
||||
prisma.category.upsert({
|
||||
where: { slug: 'design' },
|
||||
update: {},
|
||||
create: {
|
||||
name: { th: 'การออกแบบ', en: 'Design' },
|
||||
slug: 'design',
|
||||
description: { th: 'เรียนรู้การออกแบบกราฟิกและ UI/UX', en: 'Learn graphic design and UI/UX' },
|
||||
|
|
@ -138,8 +154,10 @@ async function main() {
|
|||
created_by: admin.id
|
||||
}
|
||||
}),
|
||||
prisma.category.create({
|
||||
data: {
|
||||
prisma.category.upsert({
|
||||
where: { slug: 'business' },
|
||||
update: {},
|
||||
create: {
|
||||
name: { th: 'ธุรกิจ', en: 'Business' },
|
||||
slug: 'business',
|
||||
description: { th: 'เรียนรู้การบริหารธุรกิจและการตลาด', en: 'Learn business management and marketing' },
|
||||
|
|
@ -152,7 +170,15 @@ async function main() {
|
|||
|
||||
// Seed Sample Course
|
||||
console.log('🎓 Seeding sample course...');
|
||||
const course = await prisma.course.create({
|
||||
|
||||
// Check if course already exists
|
||||
let course = await prisma.course.findUnique({
|
||||
where: { slug: 'javascript-fundamentals' },
|
||||
include: { chapters: { include: { lessons: true } } }
|
||||
});
|
||||
|
||||
if (!course) {
|
||||
course = await prisma.course.create({
|
||||
data: {
|
||||
title: { th: 'พื้นฐาน JavaScript', en: 'JavaScript Fundamentals' },
|
||||
slug: 'javascript-fundamentals',
|
||||
|
|
@ -351,6 +377,9 @@ async function main() {
|
|||
created_by: instructor.id
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(' ⏭️ Course already exists, skipping...');
|
||||
}
|
||||
|
||||
console.log('✅ Database seeding completed!');
|
||||
console.log('\n📊 Summary:');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Body, Post, Route, Tags, SuccessResponse, Response, Example } from 'tsoa';
|
||||
import { Body, Post, Route, Tags, SuccessResponse, Response, Example, Controller } from 'tsoa';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import {
|
||||
LoginRequest,
|
||||
|
|
@ -18,7 +18,7 @@ export class AuthController {
|
|||
|
||||
/**
|
||||
* User login
|
||||
* @summary Login with username and password
|
||||
* @summary Login with email and password
|
||||
* @param body Login credentials
|
||||
* @returns JWT token and user information
|
||||
*/
|
||||
|
|
@ -52,7 +52,8 @@ export class AuthController {
|
|||
})
|
||||
public async login(@Body() body: LoginRequest): Promise<LoginResponse> {
|
||||
// Validate input
|
||||
const { error } = loginSchema.validate(body);
|
||||
const { error, value } = loginSchema.validate(body);
|
||||
|
||||
if (error) {
|
||||
throw new ValidationError(error.details[0].message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,34 +19,33 @@ export class AuthService {
|
|||
* User login
|
||||
*/
|
||||
async login(data: LoginRequest): Promise<LoginResponse> {
|
||||
const { username, password } = data;
|
||||
const { email, password } = data;
|
||||
|
||||
// Find user with role and profile
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username },
|
||||
where: { email },
|
||||
include: {
|
||||
role: true,
|
||||
profile: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
logger.warn('Login attempt with invalid username', { username });
|
||||
throw new UnauthorizedError('Invalid username or password');
|
||||
logger.warn('Login attempt with invalid email', { email });
|
||||
throw new UnauthorizedError('Invalid email or password');
|
||||
}
|
||||
|
||||
// Verify password
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) {
|
||||
logger.warn('Login attempt with invalid password', { username });
|
||||
throw new UnauthorizedError('Invalid username or password');
|
||||
logger.warn('Login attempt with invalid password', { email });
|
||||
throw new UnauthorizedError('Invalid email or password');
|
||||
}
|
||||
|
||||
// Generate tokens
|
||||
const token = this.generateAccessToken(user.id, user.username, user.email, user.role.code);
|
||||
const token = this.generateAccessToken(user.id, user.email, user.email, user.role.code);
|
||||
const refreshToken = this.generateRefreshToken(user.id);
|
||||
|
||||
logger.info('User logged in successfully', { userId: user.id, username: user.username });
|
||||
logger.info('User logged in successfully', { userId: user.id, email: user.email });
|
||||
|
||||
return {
|
||||
token,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
export interface LoginRequest {
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ export interface RegisterRequest {
|
|||
th?: string;
|
||||
en?: string;
|
||||
};
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import Joi from 'joi';
|
||||
|
||||
export const loginSchema = Joi.object({
|
||||
username: Joi.string()
|
||||
.min(3)
|
||||
.max(50)
|
||||
email: Joi.string()
|
||||
.email({ tlds: { allow: false } }) // Allow any TLD including .local
|
||||
.required()
|
||||
.messages({
|
||||
'string.min': 'Username must be at least 3 characters',
|
||||
'string.max': 'Username must not exceed 50 characters',
|
||||
'any.required': 'Username is required'
|
||||
'string.email': 'Please provide a valid email address',
|
||||
'any.required': 'Email is required'
|
||||
}),
|
||||
password: Joi.string()
|
||||
.min(6)
|
||||
|
|
@ -47,6 +45,10 @@ export const registerSchema = Joi.object({
|
|||
'string.max': 'Password must not exceed 100 characters',
|
||||
'any.required': 'Password is required'
|
||||
}),
|
||||
prefix: Joi.object({
|
||||
th: Joi.string().optional(),
|
||||
en: Joi.string().optional()
|
||||
}).optional(),
|
||||
first_name: Joi.string()
|
||||
.min(1)
|
||||
.max(100)
|
||||
|
|
@ -61,10 +63,13 @@ export const registerSchema = Joi.object({
|
|||
.messages({
|
||||
'any.required': 'Last name is required'
|
||||
}),
|
||||
prefix: Joi.object({
|
||||
th: Joi.string().optional(),
|
||||
en: Joi.string().optional()
|
||||
}).optional()
|
||||
phone: Joi.string()
|
||||
.min(10)
|
||||
.max(15)
|
||||
.required()
|
||||
.messages({
|
||||
'any.required': 'Phone number is required'
|
||||
})
|
||||
});
|
||||
|
||||
export const refreshTokenSchema = Joi.object({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue