@adaptivestone/framework 3.4.3 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +37 -3
  2. package/LICENCE +21 -0
  3. package/cluster.js +3 -3
  4. package/commands/CreateUser.js +27 -0
  5. package/commands/Documentation.js +1 -1
  6. package/commands/GetOpenApiJson.js +53 -23
  7. package/commands/migration/Create.js +2 -2
  8. package/config/auth.js +1 -1
  9. package/config/i18n.js +4 -3
  10. package/config/mail.js +5 -1
  11. package/controllers/Home.js +2 -2
  12. package/controllers/Home.test.js +11 -0
  13. package/controllers/index.js +15 -15
  14. package/folderConfig.js +1 -1
  15. package/helpers/yup.js +24 -0
  16. package/index.js +8 -0
  17. package/models/User.js +40 -30
  18. package/models/User.test.js +68 -18
  19. package/modules/AbstractController.js +144 -208
  20. package/modules/AbstractModel.js +2 -1
  21. package/modules/Base.js +3 -2
  22. package/modules/BaseCli.js +6 -2
  23. package/package.json +20 -16
  24. package/server.d.ts +1 -1
  25. package/server.js +25 -8
  26. package/services/cache/Cache.d.ts +3 -3
  27. package/services/cache/Cache.js +17 -3
  28. package/services/documentation/DocumentationGenerator.js +171 -0
  29. package/services/http/HttpServer.js +16 -96
  30. package/services/http/middleware/AbstractMiddleware.js +20 -0
  31. package/services/http/middleware/GetUserByToken.js +4 -0
  32. package/services/http/middleware/I18n.js +119 -0
  33. package/services/http/middleware/I18n.test.js +77 -0
  34. package/services/http/middleware/Pagination.js +56 -0
  35. package/services/http/middleware/PrepareAppInfo.test.js +22 -0
  36. package/services/http/middleware/{Middlewares.test.js → RateLimiter.test.js} +1 -1
  37. package/services/http/middleware/RequestLogger.js +22 -0
  38. package/services/http/middleware/RequestParser.js +36 -0
  39. package/services/messaging/email/index.js +162 -42
  40. package/services/messaging/email/resources/.gitkeep +1 -0
  41. package/services/validate/ValidateService.js +161 -0
  42. package/services/validate/ValidateService.test.js +105 -0
  43. package/services/validate/drivers/AbstractValidator.js +37 -0
  44. package/services/validate/drivers/CustomValidator.js +52 -0
  45. package/services/validate/drivers/YupValidator.js +103 -0
  46. package/tests/setup.js +2 -0
  47. package/services/messaging/email/templates/emptyTemplate/style.less +0 -0
  48. package/services/messaging/email/templates/password/html.handlebars +0 -13
  49. package/services/messaging/email/templates/password/style.less +0 -0
  50. package/services/messaging/email/templates/password/subject.handlebars +0 -1
  51. package/services/messaging/email/templates/password/text.handlebars +0 -1
  52. package/services/messaging/email/templates/verification/style.less +0 -0
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "3.4.3",
3
+ "version": "4.1.0",
4
4
  "description": "Adaptive stone node js framework",
5
- "main": "src/index.js",
5
+ "main": "index.js",
6
6
  "engines": {
7
- "node": ">=16.0.0"
7
+ "node": ">=18.0.0"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -15,9 +15,14 @@
15
15
  "dev": "nodemon ./index.js",
16
16
  "prod": "nodemon ./cluster.js",
17
17
  "test": "jest --coverage=true",
18
- "codestyle": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
18
+ "prettier": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
19
+ "lint": "eslint '**/*.js'",
20
+ "lint:fix": "eslint '**/*.js' --fix",
21
+ "codestyle": "npm run prettier && npm run lint",
19
22
  "prepare": "husky install",
20
- "cli": "node cliCommand"
23
+ "cli": "node cliCommand",
24
+ "benchmark": "h2load -n 10000 -c 50 -p 'http/1.1' http://localhost:3300/",
25
+ "benchmark2": "h2load -n 10000 -c 50 https://localhost:3300/"
21
26
  },
22
27
  "jest": {
23
28
  "setupFilesAfterEnv": [
@@ -34,18 +39,18 @@
34
39
  "author": "Andrey Logunov",
35
40
  "license": "MIT",
36
41
  "dependencies": {
37
- "bcrypt": "^5.0.1",
38
42
  "cors": "^2.8.5",
39
43
  "deepmerge": "^4.2.2",
40
44
  "dotenv": "^16.0.0",
41
- "email-templates": "^10.0.0",
42
45
  "express": "^4.17.1",
43
- "i18next": "^22.0.4",
46
+ "formidable": "^2.1.1",
47
+ "html-to-text": "^9.0.3",
48
+ "i18next": "^23.2.8",
44
49
  "i18next-chained-backend": "^4.0.0",
45
50
  "i18next-fs-backend": "^2.0.0",
46
- "i18next-http-middleware": "^3.1.4",
51
+ "juice": "^9.0.0",
47
52
  "minimist": "^1.2.5",
48
- "mongoose": "^6.0.0",
53
+ "mongoose": "^7.0.0",
49
54
  "nodemailer": "^6.6.3",
50
55
  "nodemailer-sendmail-transport": "^1.0.2",
51
56
  "nodemailer-stub-transport": "^1.1.0",
@@ -54,20 +59,19 @@
54
59
  "redis": "^4.3.1",
55
60
  "winston": "^3.3.3",
56
61
  "winston-transport-sentry-node": "^2.0.0",
57
- "yup": "^0.32.9"
62
+ "yup": "^1.0.0"
58
63
  },
59
64
  "devDependencies": {
60
65
  "eslint": "^8.0.0",
61
66
  "eslint-config-airbnb-base": "^15.0.0",
62
- "eslint-config-prettier": "^8.3.0",
63
- "eslint-plugin-import": "^2.23.4",
67
+ "eslint-config-prettier": "^9.0.0",
64
68
  "eslint-plugin-jest": "^27.0.0",
65
69
  "husky": "^8.0.0",
66
70
  "jest": "^29.0.0",
67
- "lint-staged": "^13.0.0",
71
+ "lint-staged": "^14.0.0",
68
72
  "mongodb-memory-server": "^8.0.2",
69
- "nodemon": "^2.0.12",
70
- "prettier": "^2.3.2",
73
+ "nodemon": "^3.0.1",
74
+ "prettier": "^3.0.0",
71
75
  "supertest": "^6.1.4"
72
76
  },
73
77
  "lint-staged": {
package/server.d.ts CHANGED
@@ -19,7 +19,7 @@ declare class Server {
19
19
  getModel: Server['getModel'];
20
20
  runCliCommand: Server['runCliCommand'];
21
21
  updateConfig: Server['updateConfig'];
22
- foldersConfig: Server['config'];
22
+ foldersConfig: Server['config']['folders'];
23
23
  events: EventEmitter;
24
24
  get cache(): Server['cacheService'];
25
25
  httpServer: null;
package/server.js CHANGED
@@ -1,7 +1,8 @@
1
- /* eslint-disable global-require */
1
+ /* eslint-disable no-console */
2
+ const EventEmitter = require('node:events');
3
+
2
4
  require('dotenv').config();
3
5
  const merge = require('deepmerge');
4
- const EventEmitter = require('events');
5
6
 
6
7
  /**
7
8
  * Main framework class.
@@ -50,16 +51,27 @@ class Server {
50
51
  * @returns {Promise}
51
52
  */
52
53
  async startServer(callbackBefore404 = async () => Promise.resolve()) {
53
- const HttpServer = require('./services/http/HttpServer'); // Speed optimisation
54
- const ControllerManager = require('./controllers/index'); // Speed optimisation
54
+ // eslint-disable-next-line global-require
55
+ const HttpServer = require('./services/http/HttpServer');
56
+ // eslint-disable-next-line global-require
57
+ const ControllerManager = require('./controllers/index');
58
+ // TODO wait until https://github.com/nodejs/node/issues/35889
59
+ // const [{ default: HttpServer }, { default: ControllerManager }] =
60
+ // await Promise.all([
61
+ // // eslint-disable-next-line import/extensions
62
+ // import('./services/http/HttpServer.js'), // Speed optimisation
63
+ // // eslint-disable-next-line import/extensions
64
+ // import('./controllers/index.js'), // Speed optimisation
65
+ // ]);
66
+
55
67
  this.addErrorHandling();
56
68
 
57
69
  // TODO config
58
- this.app.httpServer = new HttpServer(this.app, this.config);
70
+ this.app.httpServer = new HttpServer(this.app);
59
71
 
60
72
  this.app.controllerManager = new ControllerManager(this.app);
61
73
 
62
- await this.app.controllerManager.initControllers(this.config);
74
+ await this.app.controllerManager.initControllers();
63
75
  await callbackBefore404();
64
76
  this.app.httpServer.add404Page();
65
77
  }
@@ -70,7 +82,7 @@ class Server {
70
82
  // eslint-disable-next-line class-methods-use-this
71
83
  addErrorHandling() {
72
84
  process.on('uncaughtException', console.error);
73
- process.on('unhandledRejection', function (reason, p) {
85
+ process.on('unhandledRejection', (reason, p) => {
74
86
  console.log(
75
87
  'Possibly Unhandled Rejection at: Promise ',
76
88
  p,
@@ -166,7 +178,11 @@ class Server {
166
178
  */
167
179
  async runCliCommand(commandName, args) {
168
180
  if (!this.cli) {
169
- const BaseCli = require('./modules/BaseCli'); // Speed optimisation
181
+ // eslint-disable-next-line import/extensions
182
+ // TODO wait until https://github.com/nodejs/node/issues/35889
183
+ // const { default: BaseCli } = await import('./modules/BaseCli.js'); // Speed optimisation
184
+ // eslint-disable-next-line global-require
185
+ const BaseCli = require('./modules/BaseCli');
170
186
  this.cli = new BaseCli(this);
171
187
  }
172
188
  return this.cli.run(commandName, args);
@@ -178,6 +194,7 @@ class Server {
178
194
  */
179
195
  getCache() {
180
196
  if (!this.cacheService) {
197
+ // eslint-disable-next-line global-require
181
198
  const Cache = require('./services/cache/Cache'); // Speed optimisation
182
199
  this.cacheService = new Cache(this.app);
183
200
  }
@@ -11,7 +11,7 @@ declare class Cache extends Base {
11
11
  * Function return new key with added namespace
12
12
  * @param key key to add namespace
13
13
  */
14
- getKeyWithNameSpace(key: String): String;
14
+ getKeyWithNameSpace(key: string): string;
15
15
 
16
16
  /**
17
17
  * Get value from cache. Set and get if not eists
@@ -20,7 +20,7 @@ declare class Cache extends Base {
20
20
  * @param storeTime how long we should store value on cache
21
21
  */
22
22
  getSetValue(
23
- key: String,
23
+ key: string,
24
24
  onNotFound: () => Promise<any>,
25
25
  storeTime: number,
26
26
  ): Promise<any>;
@@ -29,7 +29,7 @@ declare class Cache extends Base {
29
29
  * Remove key from cache
30
30
  * @param key key to remove
31
31
  */
32
- removeKey(key: String): Promise<number>;
32
+ removeKey(key: string): Promise<number>;
33
33
  }
34
34
 
35
35
  export = Cache;
@@ -66,13 +66,27 @@ class Cache extends Base {
66
66
  return Promise.reject(e);
67
67
  }
68
68
 
69
- this.redisClient.setEx(key, storeTime, JSON.stringify(result));
69
+ this.redisClient.setEx(
70
+ key,
71
+ storeTime,
72
+ JSON.stringify(result, (jsonkey, value) =>
73
+ typeof value === 'bigint' ? `${value}n` : value,
74
+ ),
75
+ );
70
76
  } else {
71
77
  this.logger.verbose(
72
- `getSetValueFromCache FROM CACHE key ${key}, value ${result}`,
78
+ `getSetValueFromCache FROM CACHE key ${key}, value ${result.substring(
79
+ 0,
80
+ 100,
81
+ )}`,
73
82
  );
74
83
  try {
75
- result = JSON.parse(result);
84
+ result = JSON.parse(result, (jsonkey, value) => {
85
+ if (typeof value === 'string' && /^\d+n$/.test(value)) {
86
+ return BigInt(value.slice(0, value.length - 1));
87
+ }
88
+ return value;
89
+ });
76
90
  } catch (e) {
77
91
  this.logger.warn(
78
92
  'Not able to parse json from redis cache. That can be a normal in case you store string here',
@@ -0,0 +1,171 @@
1
+ const Base = require('../../modules/Base');
2
+ const ValidateService = require('../validate/ValidateService');
3
+
4
+ class DocumentationGenerator extends Base {
5
+ static processingFields(fieldsByRoute) {
6
+ const fields = [];
7
+ if (!fieldsByRoute) {
8
+ return fields;
9
+ }
10
+ const entries = Object.entries(fieldsByRoute);
11
+ entries.forEach(([key, value]) => {
12
+ const field = {};
13
+ field.name = key;
14
+ field.type = value.type;
15
+ if (value.exclusiveTests) {
16
+ field.required = value.exclusiveTests.required;
17
+ }
18
+ if (value?.innerType) {
19
+ field.innerType = value?.innerType?.type;
20
+ }
21
+
22
+ if (value.fields) {
23
+ field.fields = [];
24
+ // eslint-disable-next-line no-shadow
25
+ const entries = Object.entries(value.fields);
26
+ // eslint-disable-next-line no-shadow
27
+ entries.forEach(([key, value]) => {
28
+ field.fields.push({
29
+ name: key,
30
+ type: value.type,
31
+ });
32
+ });
33
+ }
34
+ fields.push(field);
35
+ });
36
+ return fields;
37
+ }
38
+
39
+ static selectUniqueFields(fields) {
40
+ return Array.from(
41
+ new Map(fields.map((item) => [item.name, item])).values(),
42
+ ).reduce((uniqueArray, item) => {
43
+ const existingItem = uniqueArray.find(
44
+ (uniqueItem) => uniqueItem.name === item.name,
45
+ );
46
+ if (!existingItem) {
47
+ uniqueArray.push(item);
48
+ } else if (item.required) {
49
+ existingItem.required = true;
50
+ }
51
+ return uniqueArray;
52
+ }, []);
53
+ }
54
+
55
+ static groupFieldsFromSchemas(schemas) {
56
+ const result = [];
57
+ schemas.forEach((schema) => {
58
+ const convertedSchema = new ValidateService(this.app, schema).validator;
59
+
60
+ for (const [key, value] of Object.entries(
61
+ convertedSchema?.fieldsInJsonFormat,
62
+ )) {
63
+ result.push({
64
+ name: key,
65
+ type: value.type,
66
+ required: value.required,
67
+ });
68
+ }
69
+ });
70
+
71
+ return result;
72
+ }
73
+
74
+ static convertDataToDocumentationElement(
75
+ controllerName,
76
+ routesInfo,
77
+ middlewaresInfo,
78
+ routeMiddlewaresReg,
79
+ ) {
80
+ return {
81
+ contollerName: controllerName,
82
+ routesInfo: routesInfo.map((route) => {
83
+ const middlewareQueryParams = ValidateService.getMiddlewareParams(
84
+ middlewaresInfo,
85
+ routeMiddlewaresReg,
86
+ {
87
+ method: route.method.toLowerCase(),
88
+ path: route.fullPath,
89
+ },
90
+ ).query;
91
+
92
+ const middlewareRequestParams = ValidateService.getMiddlewareParams(
93
+ middlewaresInfo,
94
+ routeMiddlewaresReg,
95
+ {
96
+ method: route.method.toLowerCase(),
97
+ path: route.fullPath,
98
+ },
99
+ ).request;
100
+
101
+ const queryParams = this.groupFieldsFromSchemas(middlewareQueryParams);
102
+
103
+ const requestParams = this.groupFieldsFromSchemas(
104
+ middlewareRequestParams,
105
+ );
106
+
107
+ return {
108
+ [route.fullPath]: {
109
+ method: route.method,
110
+ name: route.name,
111
+ description: route?.description,
112
+ fields: this.selectUniqueFields([
113
+ ...this.processingFields(route.fields),
114
+ ...requestParams,
115
+ ]),
116
+ queryFields: this.selectUniqueFields([
117
+ ...this.processingFields(route.queryFields),
118
+ ...queryParams,
119
+ ]),
120
+ routeMiddlewares: routeMiddlewaresReg
121
+ .map((middleware) => {
122
+ const routeFullPath = route.fullPath.toUpperCase();
123
+ const middlewareFullPath = middleware.fullPath.toUpperCase();
124
+ if (
125
+ route.method.toLowerCase() ===
126
+ middleware.method.toLowerCase() &&
127
+ (middlewareFullPath === routeFullPath ||
128
+ middlewareFullPath === `${routeFullPath}*`)
129
+ ) {
130
+ return {
131
+ name: middleware.name,
132
+ params: middleware.params,
133
+ authParams: middleware.authParams,
134
+ };
135
+ }
136
+ return null;
137
+ })
138
+ .filter(Boolean),
139
+ controllerMiddlewares: [
140
+ ...new Set(
141
+ middlewaresInfo
142
+ .filter((middleware) => {
143
+ const routeFullPath = route.fullPath.toUpperCase();
144
+ const middlewareFullPath =
145
+ middleware.fullPath.toUpperCase();
146
+ const middlewareFullPathWithSliced = middleware.fullPath
147
+ .toUpperCase()
148
+ .slice(0, -1);
149
+
150
+ return (
151
+ middlewareFullPath === routeFullPath ||
152
+ middlewareFullPath === `${routeFullPath}*` ||
153
+ routeFullPath?.indexOf(middlewareFullPathWithSliced) !==
154
+ -1
155
+ );
156
+ })
157
+ .map(({ name, params, authParams }) => ({
158
+ name,
159
+ params,
160
+ authParams,
161
+ })),
162
+ ),
163
+ ],
164
+ },
165
+ };
166
+ }),
167
+ };
168
+ }
169
+ }
170
+
171
+ module.exports = DocumentationGenerator;
@@ -1,13 +1,12 @@
1
+ const http = require('node:http');
2
+ const path = require('node:path');
1
3
  const express = require('express');
2
- const http = require('http');
3
- const path = require('path');
4
4
  const cors = require('cors');
5
5
 
6
- const i18next = require('i18next');
7
- const i18nextMiddleware = require('i18next-http-middleware');
8
- const BackendFS = require('i18next-fs-backend');
9
- const Backend = require('i18next-chained-backend');
6
+ const RequestLoggerMiddleware = require('./middleware/RequestLogger');
7
+ const I18nMiddleware = require('./middleware/I18n');
10
8
  const PrepareAppInfoMiddleware = require('./middleware/PrepareAppInfo');
9
+ const RequestParserMiddleware = require('./middleware/RequestParser');
11
10
 
12
11
  const Base = require('../../modules/Base');
13
12
 
@@ -15,25 +14,19 @@ const Base = require('../../modules/Base');
15
14
  * HTTP server based on Express
16
15
  */
17
16
  class HttpServer extends Base {
18
- constructor(app, folderConfig) {
17
+ constructor(app) {
19
18
  super(app);
20
19
  this.express = express();
20
+ this.express.disable('x-powered-by');
21
21
  this.express.set('views', [
22
- folderConfig.folders.views,
22
+ this.app.foldersConfig.views,
23
23
  path.join(__dirname, '../../views'),
24
24
  ]);
25
25
  this.express.set('view engine', 'pug');
26
- this.express.use((req, res, next) => {
27
- const startTime = Date.now();
28
- const text = `Request is [${req.method}] ${req.url}`;
29
- this.logger.info(text);
30
- res.on('finish', () => {
31
- const duration = Date.now() - startTime;
32
- this.logger.info(`Finished ${text}. Duration ${duration} ms`);
33
- });
34
- next();
35
- });
36
- this.enableI18N(folderConfig);
26
+
27
+ this.express.use(new PrepareAppInfoMiddleware(this.app).getMiddleware());
28
+ this.express.use(new RequestLoggerMiddleware(this.app).getMiddleware());
29
+ this.express.use(new I18nMiddleware(this.app).getMiddleware());
37
30
 
38
31
  const httpConfig = this.app.getConfig('http');
39
32
  this.express.use(
@@ -41,17 +34,16 @@ class HttpServer extends Base {
41
34
  origin: httpConfig.corsDomains,
42
35
  }),
43
36
  ); // todo whitelist
44
- this.express.use(express.urlencoded({ limit: '50mb', extended: true }));
45
- this.express.use(express.json({ limit: '50mb' }));
46
- this.express.use(express.static(folderConfig.folders.public));
37
+ this.express.use(express.static(this.app.foldersConfig.public));
47
38
  this.express.use(express.static('./public'));
48
39
 
49
- this.express.use(new PrepareAppInfoMiddleware(this.app).getMiddleware());
40
+ this.express.use(new RequestParserMiddleware(this.app).getMiddleware());
50
41
 
51
42
  // As exprress will check numbersof arguments
52
43
  // eslint-disable-next-line no-unused-vars
53
44
  this.express.use((err, req, res, next) => {
54
45
  // error handling
46
+ // eslint-disable-next-line no-console
55
47
  console.error(err.stack);
56
48
  // TODO
57
49
  res.status(500).send('Something broke!');
@@ -79,85 +71,13 @@ class HttpServer extends Base {
79
71
  );
80
72
  }
81
73
 
82
- /**
83
- * Enable support for i18n
84
- * @param {object} folderConfig config
85
- * @param {object} folderConfig.folders folder config
86
- * @param {string} folderConfig.folders.config path to folder with config files
87
- * @param {string} folderConfig.folders.models path to folder with moidels files
88
- * @param {string} folderConfig.folders.controllers path to folder with controllers files
89
- * @param {string} folderConfig.folders.views path to folder with view files
90
- * @param {string} folderConfig.folders.public path to folder with public files
91
- * @param {string} folderConfig.folders.locales path to folder with locales files
92
- * @param {string} folderConfig.folders.emails path to folder with emails files
93
- */
94
- enableI18N(folderConfig) {
95
- const I18NConfig = this.app.getConfig('i18n');
96
- if (!I18NConfig.enabled) {
97
- return;
98
- }
99
- const lngDetector = new i18nextMiddleware.LanguageDetector();
100
- lngDetector.addDetector({
101
- name: 'xLang',
102
- // eslint-disable-next-line no-unused-vars
103
- lookup: (req, res, options) => {
104
- const lng = req.get('X-Lang');
105
- if (lng) {
106
- return lng;
107
- }
108
- return false;
109
- },
110
- // eslint-disable-next-line no-unused-vars
111
- cacheUserLanguage: (req, res, lng, options) => {},
112
- });
113
- this.logger.info('Enabling i18n support');
114
- i18next
115
- .use(Backend)
116
- .use(lngDetector)
117
- .init({
118
- backend: {
119
- backends: [
120
- BackendFS,
121
- // BackendFS,
122
- ],
123
- backendOptions: [
124
- // {
125
- // loadPath: __dirname + '/../../locales/{{lng}}/{{ns}}.json',
126
- // addPath: __dirname + '/../../locales/{{lng}}/{{ns}}.missing.json'
127
- // },
128
- {
129
- loadPath: `${folderConfig.folders.locales}/{{lng}}/{{ns}}.json`,
130
- addPath: `${folderConfig.folders.locales}/{{lng}}/{{ns}}.missing.json`,
131
- },
132
- ],
133
- },
134
- fallbackLng: I18NConfig.fallbackLng,
135
- preload: I18NConfig.preload,
136
- saveMissing: I18NConfig.saveMissing,
137
- debug: I18NConfig.debug,
138
- detection: {
139
- // caches: ['cookie'],
140
- order: I18NConfig.langDetectionOders || ['xLang'],
141
- lookupQuerystring: I18NConfig.lookupQuerystring,
142
- },
143
- });
144
- this.express.use(i18nextMiddleware.handle(i18next));
145
- this.express.use((req, res, next) => {
146
- // f ix ru-Ru, en-US, etc
147
- if (res.locals.language.length !== 2) {
148
- [res.locals.language] = res.locals.language.split('-');
149
- }
150
- next();
151
- });
152
- }
153
-
154
74
  /**
155
75
  * Add handle for 404 error
156
76
  */
157
77
  add404Page() {
158
78
  this.express.use((req, res) => {
159
79
  // error handling
160
- res.status(404).render('404');
80
+ res.status(404).json({ message: '404' });
161
81
  });
162
82
  }
163
83
 
@@ -1,3 +1,4 @@
1
+ const yup = require('yup');
1
2
  const Base = require('../../../modules/Base');
2
3
 
3
4
  class AbstractMiddleware extends Base {
@@ -14,6 +15,25 @@ class AbstractMiddleware extends Base {
14
15
  return [];
15
16
  }
16
17
 
18
+ // eslint-disable-next-line class-methods-use-this
19
+ get relatedQueryParameters() {
20
+ // For example yup.object().shape({page: yup.number().required(),limit: yup.number()})
21
+ return yup.object().shape({});
22
+ }
23
+
24
+ // eslint-disable-next-line class-methods-use-this
25
+ get relatedRequestParameters() {
26
+ // For example yup.object().shape({page: yup.number().required(),limit: yup.number()})
27
+ return yup.object().shape({});
28
+ }
29
+
30
+ get relatedReqParameters() {
31
+ return {
32
+ request: this.relatedRequestParameters,
33
+ query: this.relatedQueryParameters,
34
+ };
35
+ }
36
+
17
37
  async middleware(req, res, next) {
18
38
  this.logger.warn('Middleware is not implemented');
19
39
  next();
@@ -17,6 +17,10 @@ class GetUserByToken extends AbstractMiddleware {
17
17
  }
18
18
 
19
19
  async middleware(req, res, next) {
20
+ if (req.appInfo.user) {
21
+ this.logger.warn('You call GetUserByToken more then once');
22
+ return next();
23
+ }
20
24
  let { token } = req.body;
21
25
  this.logger.verbose(
22
26
  `GetUserByToken token in BODY ${token}. Token if Authorization header ${req.get(