Feature: Use Api generated by swagger #5

Merged
igorpropisnov merged 12 commits from feature/use-generated-api into main 2024-05-24 20:04:54 +02:00
33 changed files with 2225 additions and 239 deletions
Showing only changes of commit 16773c3ca3 - Show all commits

210
.eslintrc Normal file
View File

@ -0,0 +1,210 @@
{
"root": true,
"plugins": ["import", "prettier", "@stylistic/eslint-plugin-ts", "@stylistic/eslint-plugin", "sort-class-members", "unused-imports"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended"
],
"rules": {
"@stylistic/ts/lines-between-class-members": [
"error",
{
"enforce": [
{ "blankLine": "always", "prev": "*", "next": "method" },
{ "blankLine": "always", "prev": "method", "next": "*" },
{ "blankLine": "never", "prev": "field", "next": "field" }
]
}
],
"@stylistic/ts/block-spacing": ["error"],
"@stylistic/ts/brace-style": "off",
"@stylistic/ts/key-spacing": ["error", { "afterColon": true }],
"@stylistic/ts/keyword-spacing": ["error", { "before": true }],
"@stylistic/ts/no-extra-parens": ["error", "all", {
"nestedBinaryExpressions": false,
"ternaryOperandBinaryExpressions": false
}],
"@stylistic/ts/no-extra-semi": ["error"],
"@stylistic/ts/object-curly-spacing": ["error", "always"],
"@stylistic/ts/quotes": ["error", "single"],
"@stylistic/ts/semi": ["error", "always"],
"@stylistic/ts/space-before-blocks": ["error"],
"@stylistic/ts/space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
"@stylistic/ts/space-infix-ops": ["error"],
// "@stylistic/ts/max-statements-per-line": ["error", { "max": 1 }],
// "@stylistic/ts/multiline-ternary": ["error", "always"],
// "@stylistic/ts/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }],
// "@stylistic/ts/no-confusing-arrow": ["error"],
// "@stylistic/ts/no-floating-decimal": ["error"],
// "@stylistic/ts/no-mixed-operators": ["error"],
// "@stylistic/ts/no-mixed-spaces-and-tabs": ["error"],/
// "@stylistic/ts/no-multi-spaces": ["error"],
// "@stylistic/ts/no-multiple-empty-lines": ["error", { "max": 2 }],
// "@stylistic/ts/no-tabs": ["error", { "allowIndentationTabs": true }],
// "@stylistic/ts/no-whitespace-before-property": ["error"],
// "@stylistic/ts/nonblock-statement-body-position": ["error", "below"],
// "@stylistic/ts/object-curly-newline": ["error", "always"],
// "@stylistic/ts/object-property-newline": ["error"],
// "@stylistic/ts/one-var-declaration-per-line": ["error", "always"],
// "@stylistic/ts/operator-linebreak": ["error", "before"],
// "@stylistic/ts/padded-blocks": ["error", "never"],
// "@stylistic/ts/rest-spread-spacing": ["error", "never"],
// "@stylistic/ts/semi-spacing": ["error"],
// "@stylistic/ts/semi-style": ["error", "last"],
// "@stylistic/ts/space-in-parens": ["error", "never"],
// "@stylistic/ts/space-unary-ops": ["error"],
// "@stylistic/ts/template-curly-spacing": ["error"],
// "@stylistic/ts/template-tag-spacing": ["error"],
// "@stylistic/ts/wrap-regex": ["error"],
"no-console": ["warn", { "allow": ["warn", "error"] }],
"no-debugger": "error",
"no-var": ["error"],
"eqeqeq": ["error", "always"],
"no-eval": "error",
"prefer-const": ["error", { "destructuring": "all", "ignoreReadBeforeAssign": true }],
"prettier/prettier": ["error", { "printWidth": 80 }],
"no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowExpressions": false,
"allowTypedFunctionExpressions": true,
"allowHigherOrderFunctions": false,
"allowDirectConstAssertionInArrowFunctions": false,
"allowConciseArrowFunctionExpressionsStartingWithVoid": false
}
],
"@typescript-eslint/member-ordering": [
"error",
{
"default": [
"public-static-field",
"protected-static-field",
"private-static-field",
"public-instance-field",
"protected-instance-field",
"private-instance-field",
"public-constructor",
"protected-constructor",
"private-constructor",
"public-static-method",
"protected-static-method",
"private-static-method",
"public-instance-method",
"protected-instance-method",
"private-instance-method"
]
}
],
// https://github.com/bryanrsmith/eslint-plugin-sort-class-members -> Read Docs and replace @typescript-eslint/member-ordering
// "sort-class-members/sort-class-members": [
// 2,
// {
// "order": [
// "[public-properties]",
// "[protected-properties]",
// "[private-properties]",
// "everything-else"
// ],
// "groups": {
// "public-properties": [{ "type": "property", "accessibility": "public" }],
// "protected-properties": [{ "type": "property", "accessibility": "protected" }],
// "private-properties": [{ "type": "property", "accessibility": "private" }]
// }
// }
// ],
"padding-line-between-statements": [
"error",
{ "blankLine": "always", "prev": "const", "next": "*" },
{ "blankLine": "always", "prev": "let", "next": "*" },
{ "blankLine": "always", "prev": "var", "next": "*" },
{ "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"] }
],
"@typescript-eslint/no-unused-vars": [
"error",
{
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": false
}
],
"@typescript-eslint/typedef": [
"error",
{
"arrayDestructuring": true,
"arrowParameter": false,
"memberVariableDeclaration": true,
"objectDestructuring": true,
"parameter": true,
"propertyDeclaration": true,
"variableDeclaration": false,
"variableDeclarationIgnoreFunction": true
}
],
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index"
],
"pathGroups": [
{
"pattern": "@angular/**",
"group": "external",
"position": "before"
},
{
"pattern": "@app/**",
"group": "internal",
"position": "before"
},
{
"pattern": "@env/**",
"group": "internal",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["builtin"],
"newlines-between": "always",
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
]
}
},
{
"files": ["*.dto.ts", "*.entity.ts"],
"rules": {
"@stylistic/ts/lines-between-class-members": "off"
}
}
]
}

View File

@ -2,3 +2,5 @@ coverage
dist dist
node_modules node_modules
pnpm-lock.yaml pnpm-lock.yaml
/frontend/pnpm-lock.yaml
/backend/pnpm-lock.yaml

8
backend/.eslintrc Normal file
View File

@ -0,0 +1,8 @@
{
"extends": ["./../.eslintrc"],
"parser": "@typescript-eslint/parser",
"env": {
"node": true,
"jest": true
}
}

View File

@ -1,25 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

View File

@ -14,7 +14,7 @@
"ngVersion": "17.0.0", "ngVersion": "17.0.0",
"npmRepository": null, "npmRepository": null,
"configurationPrefix": null, "configurationPrefix": null,
"apiModulePrefix" : "TicketApi", "apiModulePrefix": "TicketApi",
"providedIn": "any", "providedIn": "any",
"fileNaming": "camelCase", "fileNaming": "camelCase",
"paramNaming": "camelCase", "paramNaming": "camelCase",

View File

@ -18,7 +18,9 @@
"test:cov": "jest --coverage", "test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json", "test:e2e": "jest --config ./test/jest-e2e.json",
"build:api": "pnpm openapi-generator-cli generate" "prettier:fix": "prettier --write .",
"prettier:check": "prettier --check .",
"foramt": "pnpm lint && prettier:fix"
}, },
"dependencies": { "dependencies": {
"@nestjs/common": "^10.0.0", "@nestjs/common": "^10.0.0",
@ -32,10 +34,8 @@
"argon2": "^0.40.1", "argon2": "^0.40.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",
"install": "^0.13.0",
"passport": "^0.7.0", "passport": "^0.7.0",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pg": "^8.11.5", "pg": "^8.11.5",
"reflect-metadata": "^0.2.0", "reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
@ -51,11 +51,8 @@
"@types/jest": "^29.5.2", "@types/jest": "^29.5.2",
"@types/node": "^20.3.1", "@types/node": "^20.3.1",
"@types/supertest": "^6.0.0", "@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0", "@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0", "eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0", "jest": "^29.5.0",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",

View File

@ -38,18 +38,12 @@ dependencies:
class-validator: class-validator:
specifier: ^0.14.1 specifier: ^0.14.1
version: 0.14.1 version: 0.14.1
install:
specifier: ^0.13.0
version: 0.13.0
passport: passport:
specifier: ^0.7.0 specifier: ^0.7.0
version: 0.7.0 version: 0.7.0
passport-jwt: passport-jwt:
specifier: ^4.0.1 specifier: ^4.0.1
version: 4.0.1 version: 4.0.1
passport-local:
specifier: ^1.0.0
version: 1.0.0
pg: pg:
specifier: ^8.11.5 specifier: ^8.11.5
version: 8.11.5 version: 8.11.5
@ -91,21 +85,12 @@ devDependencies:
'@types/supertest': '@types/supertest':
specifier: ^6.0.0 specifier: ^6.0.0
version: 6.0.2 version: 6.0.2
'@typescript-eslint/eslint-plugin':
specifier: ^6.0.0
version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.3)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: ^6.0.0 specifier: ^6.0.0
version: 6.21.0(eslint@8.57.0)(typescript@5.4.3) version: 6.21.0(eslint@8.57.0)(typescript@5.4.3)
eslint: eslint:
specifier: ^8.42.0 specifier: ^8.42.0
version: 8.57.0 version: 8.57.0
eslint-config-prettier:
specifier: ^9.0.0
version: 9.1.0(eslint@8.57.0)
eslint-plugin-prettier:
specifier: ^5.0.0
version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5)
jest: jest:
specifier: ^29.5.0 specifier: ^29.5.0
version: 29.7.0(@types/node@20.12.4)(ts-node@10.9.2) version: 29.7.0(@types/node@20.12.4)(ts-node@10.9.2)
@ -1192,11 +1177,6 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/@pkgr/core@0.1.1:
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
dev: true
/@sinclair/typebox@0.27.8: /@sinclair/typebox@0.27.8:
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
dev: true dev: true
@ -1382,10 +1362,6 @@ packages:
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
dev: true dev: true
/@types/semver@7.5.8:
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
dev: true
/@types/send@0.17.4: /@types/send@0.17.4:
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
dependencies: dependencies:
@ -1433,35 +1409,6 @@ packages:
'@types/yargs-parser': 21.0.3 '@types/yargs-parser': 21.0.3
dev: true dev: true
/@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
'@typescript-eslint/scope-manager': 6.21.0
'@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
'@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
'@typescript-eslint/visitor-keys': 6.21.0
debug: 4.3.4
eslint: 8.57.0
graphemer: 1.4.0
ignore: 5.3.1
natural-compare: 1.4.0
semver: 7.6.0
ts-api-utils: 1.3.0(typescript@5.4.3)
typescript: 5.4.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3): /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
@ -1491,26 +1438,6 @@ packages:
'@typescript-eslint/visitor-keys': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0
dev: true dev: true
/@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3)
'@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
debug: 4.3.4
eslint: 8.57.0
ts-api-utils: 1.3.0(typescript@5.4.3)
typescript: 5.4.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/types@6.21.0: /@typescript-eslint/types@6.21.0:
resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
@ -1538,25 +1465,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
'@types/json-schema': 7.0.15
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 6.21.0
'@typescript-eslint/types': 6.21.0
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3)
eslint: 8.57.0
semver: 7.6.0
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/visitor-keys@6.21.0: /@typescript-eslint/visitor-keys@6.21.0:
resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
@ -2559,36 +2467,6 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
dev: true dev: true
/eslint-config-prettier@9.1.0(eslint@8.57.0):
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
eslint: 8.57.0
dev: true
/eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5):
resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
'@types/eslint': '>=8.0.0'
eslint: '>=8.0.0'
eslint-config-prettier: '*'
prettier: '>=3.0.0'
peerDependenciesMeta:
'@types/eslint':
optional: true
eslint-config-prettier:
optional: true
dependencies:
eslint: 8.57.0
eslint-config-prettier: 9.1.0(eslint@8.57.0)
prettier: 3.2.5
prettier-linter-helpers: 1.0.0
synckit: 0.8.8
dev: true
/eslint-scope@5.1.1: /eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@ -2792,10 +2670,6 @@ packages:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true dev: true
/fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
dev: true
/fast-glob@3.3.2: /fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'} engines: {node: '>=8.6.0'}
@ -3251,11 +3125,6 @@ packages:
wrap-ansi: 6.2.0 wrap-ansi: 6.2.0
dev: true dev: true
/install@0.13.0:
resolution: {integrity: sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==}
engines: {node: '>= 0.10'}
dev: false
/interpret@1.4.0: /interpret@1.4.0:
resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@ -4406,13 +4275,6 @@ packages:
passport-strategy: 1.0.0 passport-strategy: 1.0.0
dev: false dev: false
/passport-local@1.0.0:
resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==}
engines: {node: '>= 0.4.0'}
dependencies:
passport-strategy: 1.0.0
dev: false
/passport-strategy@1.0.0: /passport-strategy@1.0.0:
resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==} resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}
@ -4587,13 +4449,6 @@ packages:
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
dev: true dev: true
/prettier-linter-helpers@1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
dependencies:
fast-diff: 1.3.0
dev: true
/prettier@3.2.5: /prettier@3.2.5:
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -5133,14 +4988,6 @@ packages:
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
dev: true dev: true
/synckit@0.8.8:
resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==}
engines: {node: ^14.18.0 || >=16.0.0}
dependencies:
'@pkgr/core': 0.1.1
tslib: 2.6.2
dev: true
/tapable@2.2.1: /tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'} engines: {node: '>=6'}

View File

@ -1,4 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
import { AppService } from './app.service'; import { AppService } from './app.service';

View File

@ -1,12 +1,13 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service'; import { AppService } from './app.service';
@Controller() @Controller()
export class AppController { export class AppController {
constructor(private readonly appService: AppService) {} public constructor(private readonly appService: AppService) {}
@Get() @Get()
getHello(): string { public getHello(): string {
return this.appService.getHello(); return this.appService.getHello();
} }
} }

View File

@ -1,14 +1,15 @@
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'; import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
import { AppService } from './app.service'; import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config'; import { CorsMiddleware } from './middleware/cors-middleware/cors.middlware';
import { DatabaseModule } from './modules/database-module/database.module';
import { CspMiddleware } from './middleware/csp-middleware/csp.middleware'; import { CspMiddleware } from './middleware/csp-middleware/csp.middleware';
import { SecurityHeadersMiddleware } from './middleware/security-middleware/security.middleware';
import { HttpsRedirectMiddleware } from './middleware/https-middlware/https-redirect.middleware'; import { HttpsRedirectMiddleware } from './middleware/https-middlware/https-redirect.middleware';
import { SecurityHeadersMiddleware } from './middleware/security-middleware/security.middleware';
import { AuthModule } from './modules/auth-module/auth.module'; import { AuthModule } from './modules/auth-module/auth.module';
import { AccessTokenGuard } from './modules/auth-module/common/guards'; import { AccessTokenGuard } from './modules/auth-module/common/guards';
import { CorsMiddleware } from './middleware/cors-middleware/cors.middlware'; import { DatabaseModule } from './modules/database-module/database.module';
@Module({ @Module({
imports: [ imports: [
@ -22,7 +23,7 @@ import { CorsMiddleware } from './middleware/cors-middleware/cors.middlware';
providers: [AppService, { provide: 'APP_GUARD', useClass: AccessTokenGuard }], providers: [AppService, { provide: 'APP_GUARD', useClass: AccessTokenGuard }],
}) })
export class AppModule { export class AppModule {
configure(consumer: MiddlewareConsumer) { public configure(consumer: MiddlewareConsumer): void {
consumer consumer
// TODO Redirect via Reverse Proxy all HTTP requests to HTTPS // TODO Redirect via Reverse Proxy all HTTP requests to HTTPS
.apply( .apply(

View File

@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class AppService { export class AppService {
getHello(): string { public getHello(): string {
return 'Hello World!'; return 'Hello World!';
} }
} }

View File

@ -9,20 +9,20 @@ import {
@Entity() @Entity()
export class UserCredentials { export class UserCredentials {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id: number; public id: number;
@Column({ unique: true }) @Column({ unique: true })
email: string; public email: string;
@Column() @Column()
hash: string; public hash: string;
@Column({ nullable: true }) @Column({ nullable: true })
hashedRt?: string; public hashedRt?: string;
@CreateDateColumn() @CreateDateColumn()
createdAt: Date; public createdAt: Date;
@UpdateDateColumn() @UpdateDateColumn()
updatedAt: Date; public updatedAt: Date;
} }

View File

@ -1,11 +1,13 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';
import * as fs from 'fs'; import * as fs from 'fs';
import { join } from 'path'; import { join } from 'path';
async function setupSwagger(app) { import { INestApplication, ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function setupSwagger(app: INestApplication): Promise<void> {
const config = new DocumentBuilder() const config = new DocumentBuilder()
.setTitle('Tickets API') .setTitle('Tickets API')
.setDescription('Description of the API') .setDescription('Description of the API')
@ -13,9 +15,11 @@ async function setupSwagger(app) {
.build(); .build();
const document = SwaggerModule.createDocument(app, config); const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document); SwaggerModule.setup('api', app, document);
const docsDir = join(process.cwd(), 'docs'); const docsDir = join(process.cwd(), 'docs');
if (!fs.existsSync(docsDir)) { if (!fs.existsSync(docsDir)) {
fs.mkdirSync(docsDir); fs.mkdirSync(docsDir);
} }
@ -26,16 +30,17 @@ async function setupSwagger(app) {
); );
} }
async function setupPrefix(app) { async function setupPrefix(app: INestApplication): Promise<void> {
app.setGlobalPrefix('api'); app.setGlobalPrefix('api');
} }
async function setupClassValidator(app) { async function setupClassValidator(app: INestApplication): Promise<void> {
app.useGlobalPipes(new ValidationPipe()); app.useGlobalPipes(new ValidationPipe());
} }
async function bootstrap() { async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
await setupSwagger(app); await setupSwagger(app);
await setupPrefix(app); await setupPrefix(app);
await setupClassValidator(app); await setupClassValidator(app);

View File

@ -4,7 +4,7 @@ import { Request, Response, NextFunction } from 'express';
@Injectable() @Injectable()
export class CorsMiddleware implements NestMiddleware { export class CorsMiddleware implements NestMiddleware {
constructor(private readonly configService: ConfigService) {} public constructor(private readonly configService: ConfigService) {}
public use(req: Request, res: Response, next: NextFunction): void { public use(req: Request, res: Response, next: NextFunction): void {
if (this.configService.get<string>('NODE_ENV') === 'development') { if (this.configService.get<string>('NODE_ENV') === 'development') {

View File

@ -1,13 +1,14 @@
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { Request, Response, NextFunction } from 'express';
@Injectable() @Injectable()
export class CspMiddleware implements NestMiddleware { export class CspMiddleware implements NestMiddleware {
constructor(private readonly configService: ConfigService) {} public constructor(private readonly configService: ConfigService) {}
public use(req: Request, res: Response, next: NextFunction): void { public use(req: Request, res: Response, next: NextFunction): void {
const cspDirectives = this.configService.get<string>('CSP_DIRECTIVES'); const cspDirectives = this.configService.get<string>('CSP_DIRECTIVES');
if (cspDirectives) { if (cspDirectives) {
res.setHeader('Content-Security-Policy', cspDirectives); res.setHeader('Content-Security-Policy', cspDirectives);
} }

View File

@ -4,12 +4,13 @@ import { NextFunction, Request, Response } from 'express';
@Injectable() @Injectable()
export class HttpsRedirectMiddleware implements NestMiddleware { export class HttpsRedirectMiddleware implements NestMiddleware {
constructor(private readonly configService: ConfigService) {} public constructor(private readonly configService: ConfigService) {}
public use(req: Request, res: Response, next: NextFunction) { public use(req: Request, res: Response, next: NextFunction): void {
if (this.configService.get<string>('NODE_ENV') === 'production') { if (this.configService.get<string>('NODE_ENV') === 'production') {
if (req.protocol === 'http') { if (req.protocol === 'http') {
const httpsUrl = `https://${req.headers.host}${req.url}`; const httpsUrl = `https://${req.headers.host}${req.url}`;
res.redirect(httpsUrl); res.redirect(httpsUrl);
} else { } else {
next(); next();

View File

@ -1,10 +1,10 @@
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { Request, Response, NextFunction } from 'express';
@Injectable() @Injectable()
export class SecurityHeadersMiddleware implements NestMiddleware { export class SecurityHeadersMiddleware implements NestMiddleware {
constructor(private readonly configService: ConfigService) {} public constructor(private readonly configService: ConfigService) {}
public use(req: Request, res: Response, next: NextFunction): void { public use(req: Request, res: Response, next: NextFunction): void {
if (this.configService.get<string>('NODE_ENV') === 'production') { if (this.configService.get<string>('NODE_ENV') === 'production') {

View File

@ -1,13 +1,14 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { AuthService } from './services/auth.service';
import { AuthController } from './controller/auth.controller';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { UserCredentials } from 'src/entities/user-credentials.entity'; import { UserCredentials } from 'src/entities/user-credentials.entity';
import { AuthController } from './controller/auth.controller';
import { UserRepository } from './repositories/user.repository'; import { UserRepository } from './repositories/user.repository';
import { AuthService } from './services/auth.service';
import { EncryptionService } from './services/encryption.service'; import { EncryptionService } from './services/encryption.service';
import { TokenManagementService } from './services/token-management.service'; import { TokenManagementService } from './services/token-management.service';
import { AccessTokenStrategy, RefreshTokenStrategy } from './strategies';
@Module({ @Module({
imports: [ imports: [

View File

@ -5,6 +5,7 @@ export const GetCurrentUserId = createParamDecorator(
(_: undefined, context: ExecutionContext): number => { (_: undefined, context: ExecutionContext): number => {
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
const user = request.user as JwtPayload; const user = request.user as JwtPayload;
return user.sub; return user.sub;
} }
); );

View File

@ -7,6 +7,7 @@ export const GetCurrentUser = createParamDecorator(
context: ExecutionContext context: ExecutionContext
) => { ) => {
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
if (!data) return request.user; if (!data) return request.user;
return request.user[data]; return request.user[data];
} }

View File

@ -1,3 +1,4 @@
import { SetMetadata } from '@nestjs/common'; import { CustomDecorator, SetMetadata } from '@nestjs/common';
export const Public = () => SetMetadata('isPublic', true); export const Public = (): CustomDecorator<string> =>
SetMetadata('isPublic', true);

View File

@ -1,11 +1,11 @@
import { Injectable, ExecutionContext } from '@nestjs/common'; import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@Injectable() @Injectable()
export class AccessTokenGuard extends AuthGuard('jwt-access-token') { export class AccessTokenGuard extends AuthGuard('jwt-access-token') {
constructor(private readonly reflector: Reflector) { public constructor(private readonly reflector: Reflector) {
super(); super();
} }

View File

@ -1,7 +1,7 @@
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
export class RefreshTokenGuard extends AuthGuard('jwt-refresh-token') { export class RefreshTokenGuard extends AuthGuard('jwt-refresh-token') {
constructor() { public constructor() {
super(); super();
} }
} }

View File

@ -6,16 +6,17 @@ import {
HttpStatus, HttpStatus,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthService } from '../services/auth.service';
import { TokensDto, UserCredentialsDto } from '../models/dto';
import { RefreshTokenGuard } from '../common/guards';
import { GetCurrentUser, GetCurrentUserId, Public } from '../common/decorators';
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger'; import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { GetCurrentUser, GetCurrentUserId, Public } from '../common/decorators';
import { RefreshTokenGuard } from '../common/guards';
import { TokensDto, UserCredentialsDto } from '../models/dto';
import { AuthService } from '../services/auth.service';
@ApiTags('Authentication') @ApiTags('Authentication')
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private readonly authService: AuthService) {} public constructor(private readonly authService: AuthService) {}
@ApiCreatedResponse({ @ApiCreatedResponse({
description: 'User signed up successfully', description: 'User signed up successfully',

View File

@ -5,7 +5,7 @@ import { Repository } from 'typeorm';
@Injectable() @Injectable()
export class UserRepository { export class UserRepository {
constructor( public constructor(
@InjectRepository(UserCredentials) @InjectRepository(UserCredentials)
private readonly repository: Repository<UserCredentials> private readonly repository: Repository<UserCredentials>
) {} ) {}
@ -15,6 +15,7 @@ export class UserRepository {
hash: string hash: string
): Promise<UserCredentials> { ): Promise<UserCredentials> {
const user = this.repository.create({ email, hash }); const user = this.repository.create({ email, hash });
return this.repository.save(user); return this.repository.save(user);
} }
@ -35,6 +36,7 @@ export class UserRepository {
hashedRt: string | null hashedRt: string | null
): Promise<number> { ): Promise<number> {
const result = await this.repository.update(userId, { hashedRt }); const result = await this.repository.update(userId, { hashedRt });
return result.affected ?? 0; return result.affected ?? 0;
} }
} }

View File

@ -1,12 +1,14 @@
import { ForbiddenException, Injectable } from '@nestjs/common'; import { ForbiddenException, Injectable } from '@nestjs/common';
import { TokensDto, UserCredentialsDto } from '../models/dto'; import { TokensDto, UserCredentialsDto } from '../models/dto';
import { EncryptionService } from './encryption.service';
import { UserRepository } from '../repositories/user.repository'; import { UserRepository } from '../repositories/user.repository';
import { EncryptionService } from './encryption.service';
import { TokenManagementService } from './token-management.service'; import { TokenManagementService } from './token-management.service';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
constructor( public constructor(
private readonly userRepository: UserRepository, private readonly userRepository: UserRepository,
private readonly tokenManagementService: TokenManagementService, private readonly tokenManagementService: TokenManagementService,
private readonly encryptionService: EncryptionService private readonly encryptionService: EncryptionService
@ -20,6 +22,7 @@ export class AuthService {
userCredentials.email, userCredentials.email,
passwordHashed passwordHashed
); );
return this.generateAndPersistTokens(user.id, user.email); return this.generateAndPersistTokens(user.id, user.email);
} }
@ -27,6 +30,7 @@ export class AuthService {
const user = await this.userRepository.findUserByEmail( const user = await this.userRepository.findUserByEmail(
userCredentials.email userCredentials.email
); );
if (!user) { if (!user) {
throw new ForbiddenException('Access Denied'); throw new ForbiddenException('Access Denied');
} }
@ -35,6 +39,7 @@ export class AuthService {
userCredentials.password, userCredentials.password,
user.hash user.hash
); );
if (!passwordMatch) { if (!passwordMatch) {
throw new ForbiddenException('Access Denied'); throw new ForbiddenException('Access Denied');
} }
@ -47,6 +52,7 @@ export class AuthService {
refreshToken: string refreshToken: string
): Promise<TokensDto> { ): Promise<TokensDto> {
const user = await this.userRepository.findUserById(userId); const user = await this.userRepository.findUserById(userId);
if (!user || !user.hashedRt) { if (!user || !user.hashedRt) {
throw new ForbiddenException('Access Denied'); throw new ForbiddenException('Access Denied');
} }
@ -55,6 +61,7 @@ export class AuthService {
refreshToken, refreshToken,
user.hashedRt user.hashedRt
); );
if (!refreshTokenMatch) { if (!refreshTokenMatch) {
throw new ForbiddenException('Access Denied'); throw new ForbiddenException('Access Denied');
} }
@ -67,6 +74,7 @@ export class AuthService {
userId, userId,
null null
); );
return affected > 0; return affected > 0;
} }
@ -81,6 +89,7 @@ export class AuthService {
const hashedRefreshToken = await this.encryptionService.hashData( const hashedRefreshToken = await this.encryptionService.hashData(
tokens.refresh_token tokens.refresh_token
); );
await this.userRepository.updateUserTokenHash(userId, hashedRefreshToken); await this.userRepository.updateUserTokenHash(userId, hashedRefreshToken);
return tokens; return tokens;
} }

View File

@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt'; import { JwtService } from '@nestjs/jwt';
import { TokensDto } from '../models/dto'; import { TokensDto } from '../models/dto';
@Injectable() @Injectable()
@ -10,7 +11,7 @@ export class TokenManagementService {
private readonly JWT_SECRET_AT: string; private readonly JWT_SECRET_AT: string;
private readonly JWT_SECRET_RT: string; private readonly JWT_SECRET_RT: string;
constructor( public constructor(
private readonly jwt: JwtService, private readonly jwt: JwtService,
private readonly configService: ConfigService private readonly configService: ConfigService
) { ) {
@ -30,6 +31,7 @@ export class TokenManagementService {
): Promise<TokensDto> { ): Promise<TokensDto> {
const access_token: string = await this.createAccessToken(userId, email); const access_token: string = await this.createAccessToken(userId, email);
const refresh_token: string = await this.createRefreshToken(userId, email); const refresh_token: string = await this.createRefreshToken(userId, email);
return { access_token, refresh_token }; return { access_token, refresh_token };
} }

View File

@ -1,7 +1,8 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport'; import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt'; import { Strategy, ExtractJwt } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
import { JwtPayload } from '../models/types'; import { JwtPayload } from '../models/types';
@Injectable() @Injectable()
@ -9,7 +10,7 @@ export class AccessTokenStrategy extends PassportStrategy(
Strategy, Strategy,
'jwt-access-token' 'jwt-access-token'
) { ) {
constructor(private readonly configService: ConfigService) { public constructor(private readonly configService: ConfigService) {
super(AccessTokenStrategy.getJwtConfig(configService)); super(AccessTokenStrategy.getJwtConfig(configService));
} }

View File

@ -1,15 +1,15 @@
import { Injectable, ForbiddenException } from '@nestjs/common'; import { Injectable, ForbiddenException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Request } from 'express'; import { Request } from 'express';
import { Strategy, ExtractJwt } from 'passport-jwt';
@Injectable() @Injectable()
export class RefreshTokenStrategy extends PassportStrategy( export class RefreshTokenStrategy extends PassportStrategy(
Strategy, Strategy,
'jwt-refresh-token' 'jwt-refresh-token'
) { ) {
constructor(private readonly configService: ConfigService) { public constructor(private readonly configService: ConfigService) {
super(RefreshTokenStrategy.createJwtStrategyOptions(configService)); super(RefreshTokenStrategy.createJwtStrategyOptions(configService));
} }

View File

@ -1,6 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService, ConfigModule } from '@nestjs/config'; import { ConfigService, ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { databaseConfigFactory } from './database-config'; import { databaseConfigFactory } from './database-config';
@Module({ @Module({

View File

@ -1,6 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common'; import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest'; import * as request from 'supertest';
import { AppModule } from './../src/app.module'; import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => { describe('AppController (e2e)', () => {

View File

@ -10,6 +10,9 @@
"install:all": "pnpm install && pnpm run install:frontend && pnpm run install:backend", "install:all": "pnpm install && pnpm run install:frontend && pnpm run install:backend",
"install:frontend": "cd frontend && pnpm install", "install:frontend": "cd frontend && pnpm install",
"install:backend": "cd backend && pnpm install", "install:backend": "cd backend && pnpm install",
"format:frontend": "cd frontend && pnpm run format",
"format:backend": "cd backend && concurrently \"pnpm run lint\" \"pnpm run prettier:fix\"",
"format:all": "concurrently \"pnpm run format:frontend\" \"pnpm run format:backend\"",
"build:api": "openapi-generator-cli generate" "build:api": "openapi-generator-cli generate"
}, },
"keywords": [], "keywords": [],
@ -17,6 +20,15 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@openapitools/openapi-generator-cli": "^2.13.4", "@openapitools/openapi-generator-cli": "^2.13.4",
"concurrently": "^8.2.2" "@stylistic/eslint-plugin": "^2.1.0",
"@stylistic/eslint-plugin-ts": "^2.1.0",
"@typescript-eslint/eslint-plugin": "6.19.0",
"concurrently": "^8.2.2",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-sort-class-members": "^1.20.0",
"eslint-plugin-unused-imports": "^3.2.0",
"prettier": "^3.2.5"
} }
} }

File diff suppressed because it is too large Load Diff