@adaptivestone/framework 2.15.3 → 3.0.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.
- package/CHANGELOG.md +72 -0
- package/README.md +2 -0
- package/commands/Documentation.js +14 -0
- package/commands/DropIndex.js +4 -0
- package/commands/migration/Create.js +4 -0
- package/commands/migration/Migrate.js +4 -0
- package/config/http.js +1 -1
- package/config/i18n.js +1 -1
- package/config/log.js +4 -3
- package/controllers/Auth.js +19 -28
- package/controllers/Auth.test.js +4 -9
- package/controllers/Home.js +1 -2
- package/models/User.js +1 -10
- package/modules/AbstractCommand.js +4 -0
- package/modules/AbstractController.js +251 -218
- package/modules/AbstractModel.js +15 -22
- package/modules/Base.d.ts +36 -0
- package/modules/Base.js +0 -12
- package/package.json +10 -16
- package/server.d.ts +75 -0
- package/server.js +8 -1
- package/services/cache/Cache.d.ts +22 -0
- package/services/cache/Cache.js +4 -0
- package/services/http/HttpServer.js +5 -3
- package/services/http/middleware/AbstractMiddleware.js +14 -0
- package/services/http/middleware/Auth.js +4 -0
- package/services/http/middleware/GetUserByToken.js +4 -0
- package/services/http/middleware/PrepareAppInfo.js +4 -0
- package/services/http/middleware/RateLimiter.js +5 -1
- package/services/http/middleware/Role.js +29 -0
- package/tests/setup.js +2 -2
- package/types/Expand.d.ts +11 -0
- package/types/TFoldersConfig.d.ts +19 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
/* eslint-disable array-callback-return */
|
|
1
2
|
/* eslint-disable no-restricted-syntax */
|
|
2
3
|
/* eslint-disable guard-for-in */
|
|
3
4
|
const express = require('express');
|
|
4
|
-
const
|
|
5
|
+
const merge = require('deepmerge');
|
|
5
6
|
|
|
6
7
|
const Base = require('./Base');
|
|
7
|
-
const PrepareAppInfo = require('../services/http/middleware/PrepareAppInfo');
|
|
8
8
|
const GetUserByToken = require('../services/http/middleware/GetUserByToken');
|
|
9
9
|
const Auth = require('../services/http/middleware/Auth');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Abstract controller. You
|
|
12
|
+
* Abstract controller. You should extend any controller from them.
|
|
13
13
|
* Place you cintroller into controller folder and it be inited in auto way.
|
|
14
14
|
* By default name of route will be controller name not file name. But please name it in same ways.
|
|
15
15
|
* You can overwrite base controllers byt creating controllers with tha same file name (yes file name, not class name)
|
|
@@ -22,66 +22,108 @@ class AbstractController extends Base {
|
|
|
22
22
|
this.prefix = prefix;
|
|
23
23
|
this.router = express.Router();
|
|
24
24
|
const { routes } = this;
|
|
25
|
-
|
|
26
25
|
const expressPath = this.getExpressPath();
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Grab route middleware onlo one Map
|
|
29
|
+
*/
|
|
30
|
+
const routeMiddlewares = new Map();
|
|
31
|
+
Object.entries(routes).forEach(([method, methodRoutes]) => {
|
|
32
|
+
Object.entries(methodRoutes).forEach(([route, routeParam]) => {
|
|
33
|
+
if (routeParam?.middleware) {
|
|
34
|
+
const fullRoute = method.toUpperCase() + route;
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (typeof realPath !== 'string') {
|
|
39
|
-
this.logger.error(`Path not a string ${realPath}. Please check it`);
|
|
40
|
-
// eslint-disable-next-line no-continue
|
|
41
|
-
continue;
|
|
36
|
+
if (!routeMiddlewares.has(fullRoute)) {
|
|
37
|
+
routeMiddlewares.set(fullRoute, []);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
routeMiddlewares.set(fullRoute, [
|
|
41
|
+
...routeMiddlewares.get(fullRoute),
|
|
42
|
+
...routeParam.middleware,
|
|
43
|
+
]);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse middlewares to be an object.
|
|
50
|
+
*/
|
|
51
|
+
const parseMiddlewares = (middlewareMap) => {
|
|
52
|
+
const middlewaresInfo = [];
|
|
53
|
+
// eslint-disable-next-line prefer-const
|
|
54
|
+
for (let [path, middleware] of middlewareMap) {
|
|
55
|
+
if (!Array.isArray(middleware)) {
|
|
56
|
+
middleware = [middleware];
|
|
57
|
+
}
|
|
58
|
+
for (const M of middleware) {
|
|
59
|
+
let method = 'all';
|
|
60
|
+
let realPath = path;
|
|
61
|
+
if (typeof realPath !== 'string') {
|
|
62
|
+
this.logger.error(`Path not a string ${realPath}. Please check it`);
|
|
47
63
|
// eslint-disable-next-line no-continue
|
|
48
64
|
continue;
|
|
49
65
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
if (!realPath.startsWith('/')) {
|
|
67
|
+
method = realPath.split('/')[0]?.toLowerCase();
|
|
68
|
+
if (!method) {
|
|
69
|
+
this.logger.error(`Method not found for ${realPath}`);
|
|
70
|
+
// eslint-disable-next-line no-continue
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
realPath = realPath.substring(method.length);
|
|
74
|
+
}
|
|
75
|
+
if (typeof this.router[method] !== 'function') {
|
|
76
|
+
this.logger.error(
|
|
77
|
+
`Method ${method} not exist for middleware. Please check your codebase`,
|
|
78
|
+
);
|
|
79
|
+
// eslint-disable-next-line no-continue
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const fullPath = `/${expressPath}/${realPath.toUpperCase()}`
|
|
83
|
+
.split('//')
|
|
84
|
+
.join('/')
|
|
85
|
+
.split('//')
|
|
86
|
+
.join('/');
|
|
87
|
+
let MiddlewareFunction = M;
|
|
88
|
+
let middlewareParams = {};
|
|
89
|
+
if (Array.isArray(M)) {
|
|
90
|
+
[MiddlewareFunction, middlewareParams] = M;
|
|
91
|
+
}
|
|
92
|
+
middlewaresInfo.push({
|
|
93
|
+
name: MiddlewareFunction.name,
|
|
94
|
+
method,
|
|
95
|
+
path: realPath,
|
|
96
|
+
fullPath,
|
|
97
|
+
params: middlewareParams,
|
|
98
|
+
MiddlewareFunction,
|
|
99
|
+
});
|
|
68
100
|
}
|
|
69
|
-
middlewaresInfo.push({
|
|
70
|
-
name: M.name,
|
|
71
|
-
method: method.toUpperCase(),
|
|
72
|
-
path: realPath,
|
|
73
|
-
fullPath,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
this.router[method](
|
|
77
|
-
realPath,
|
|
78
|
-
new MiddlewareFunction(this.app, middlewareParams).getMiddleware(),
|
|
79
|
-
);
|
|
80
101
|
}
|
|
81
|
-
|
|
102
|
+
return middlewaresInfo;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const routeMiddlewaresReg = parseMiddlewares(routeMiddlewares);
|
|
106
|
+
const middlewaresInfo = parseMiddlewares(this.constructor.middleware);
|
|
82
107
|
|
|
83
108
|
const routesInfo = [];
|
|
109
|
+
let routeObjectClone = {};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Register controller middleware
|
|
113
|
+
*/
|
|
114
|
+
for (const middleware of middlewaresInfo) {
|
|
115
|
+
this.router[middleware.method](
|
|
116
|
+
middleware.path,
|
|
117
|
+
new middleware.MiddlewareFunction(
|
|
118
|
+
this.app,
|
|
119
|
+
middleware.params,
|
|
120
|
+
).getMiddleware(),
|
|
121
|
+
);
|
|
122
|
+
}
|
|
84
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Register routes itself
|
|
126
|
+
*/
|
|
85
127
|
for (const verb in routes) {
|
|
86
128
|
if (typeof this.router[verb] !== 'function') {
|
|
87
129
|
this.logger.error(
|
|
@@ -91,20 +133,18 @@ class AbstractController extends Base {
|
|
|
91
133
|
continue;
|
|
92
134
|
}
|
|
93
135
|
for (const path in routes[verb]) {
|
|
136
|
+
const routeAdditionalMiddlewares = routeMiddlewaresReg.filter(
|
|
137
|
+
(middleware) => middleware.path === path,
|
|
138
|
+
);
|
|
94
139
|
let routeObject = routes[verb][path];
|
|
140
|
+
routeObjectClone = merge({}, routeObject);
|
|
95
141
|
if (Object.prototype.toString.call(routeObject) !== '[object Object]') {
|
|
96
142
|
routeObject = {
|
|
97
143
|
handler: routeObject,
|
|
98
144
|
request: null,
|
|
145
|
+
middleware: null,
|
|
99
146
|
};
|
|
100
147
|
|
|
101
|
-
if (typeof routeObject.handler === 'string') {
|
|
102
|
-
routeObject.handler = this[routeObject];
|
|
103
|
-
this.logger.warn(
|
|
104
|
-
'Using string as a controller callback deprecated. Please use function instead',
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
148
|
if (typeof routeObject.handler !== 'function') {
|
|
109
149
|
this.logger.error(
|
|
110
150
|
`Can't resolve function '${
|
|
@@ -137,166 +177,175 @@ class AbstractController extends Base {
|
|
|
137
177
|
// `Controller '${this.getConstructorName()}' register function '${fnName}' for method '${verb}' and path '${path}' Full path '${fullPath}'`,
|
|
138
178
|
// );
|
|
139
179
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
this.
|
|
147
|
-
|
|
180
|
+
let additionalMiddlewares;
|
|
181
|
+
|
|
182
|
+
if (routeAdditionalMiddlewares.length > 0) {
|
|
183
|
+
additionalMiddlewares = Array.from(
|
|
184
|
+
routeAdditionalMiddlewares,
|
|
185
|
+
({ MiddlewareFunction, params }) =>
|
|
186
|
+
new MiddlewareFunction(this.app, params).getMiddleware(),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.router[verb](
|
|
191
|
+
path,
|
|
192
|
+
additionalMiddlewares || [],
|
|
193
|
+
async (req, res, next) => {
|
|
194
|
+
if (routeObject.request) {
|
|
195
|
+
if (typeof routeObject.request.validate !== 'function') {
|
|
196
|
+
this.logger.error('request.validate should be a function');
|
|
197
|
+
}
|
|
198
|
+
if (typeof routeObject.request.cast !== 'function') {
|
|
199
|
+
this.logger.error('request.cast should be a function');
|
|
200
|
+
}
|
|
201
|
+
const bodyAndQuery = merge(req.query, req.body);
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
await routeObject.request.validate(bodyAndQuery);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
let { errors } = e;
|
|
207
|
+
// translate it
|
|
208
|
+
if (req.i18n) {
|
|
209
|
+
errors = e.errors.map((err) => req.i18n.t(err));
|
|
210
|
+
}
|
|
211
|
+
this.logger.error(`Request validation failed: ${errors}`);
|
|
148
212
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
errors: {
|
|
158
|
-
[e.path]: errors,
|
|
159
|
-
},
|
|
213
|
+
return res.status(400).json({
|
|
214
|
+
errors: {
|
|
215
|
+
[e.path]: errors,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
req.appInfo.request = routeObject.request.cast(bodyAndQuery, {
|
|
220
|
+
stripUnknown: true,
|
|
160
221
|
});
|
|
161
222
|
}
|
|
162
|
-
req.
|
|
163
|
-
|
|
223
|
+
req.body = new Proxy(req.body, {
|
|
224
|
+
get: (target, prop) => {
|
|
225
|
+
this.logger.warn(
|
|
226
|
+
'Please not use "req.body" directly. Implement "request" and use "req.appInfo.request" ',
|
|
227
|
+
);
|
|
228
|
+
return target[prop];
|
|
229
|
+
},
|
|
164
230
|
});
|
|
165
|
-
}
|
|
166
|
-
req.body = new Proxy(req.body, {
|
|
167
|
-
get: (target, prop) => {
|
|
168
|
-
this.logger.warn(
|
|
169
|
-
'Please not use "req.body" directly. Implement "request" and use "req.appInfo.request" ',
|
|
170
|
-
);
|
|
171
|
-
return target[prop];
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
231
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
232
|
+
if (routeObject.handler.constructor.name !== 'AsyncFunction') {
|
|
233
|
+
const error =
|
|
234
|
+
"Handler should be AsyncFunction. Perhabs you miss 'async' of function declaration?";
|
|
235
|
+
this.logger.error(error);
|
|
236
|
+
return res.status(500).json({
|
|
237
|
+
message:
|
|
238
|
+
'Platform error. Please check later or contact support',
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return routeObject.handler.call(this, req, res, next).catch((e) => {
|
|
242
|
+
this.logger.error(e.message);
|
|
243
|
+
console.error(e);
|
|
244
|
+
return res.status(500).json({
|
|
245
|
+
message:
|
|
246
|
+
'Platform error. Please check later or contact support',
|
|
247
|
+
});
|
|
190
248
|
});
|
|
191
|
-
}
|
|
192
|
-
|
|
249
|
+
},
|
|
250
|
+
);
|
|
193
251
|
}
|
|
194
252
|
}
|
|
195
253
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
];
|
|
254
|
+
/**
|
|
255
|
+
* Generate text info
|
|
256
|
+
*/
|
|
257
|
+
const text = ['', `Controller '${this.getConstructorName()}' registered.`];
|
|
201
258
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
259
|
+
const reports = {
|
|
260
|
+
'Middlewares:': middlewaresInfo,
|
|
261
|
+
'Route middlewares:': routeMiddlewaresReg,
|
|
262
|
+
'Callbacks:': routesInfo,
|
|
263
|
+
};
|
|
264
|
+
for (const key in reports) {
|
|
265
|
+
text.push(`${key}`);
|
|
266
|
+
for (const item of reports[key]) {
|
|
267
|
+
text.push(
|
|
268
|
+
`Path:'${item.path}'. Full path: '${
|
|
269
|
+
item.fullPath
|
|
270
|
+
}'. Method: '${item.method.toUpperCase()}'. Function: '${item.name}'`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
208
274
|
|
|
209
|
-
routesInfo.forEach((m) => {
|
|
210
|
-
text.push(
|
|
211
|
-
`Path:'${m.path}'. Full path: '${m.fullPath}'. Method: '${m.method}'. Callback: '${m.name}'`,
|
|
212
|
-
);
|
|
213
|
-
});
|
|
214
275
|
text.push(`Time: ${Date.now() - time} ms`);
|
|
215
276
|
|
|
216
277
|
this.logger.verbose(text.join('\n'));
|
|
217
278
|
|
|
218
|
-
|
|
219
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Generate documentation
|
|
281
|
+
*/
|
|
282
|
+
if (!this.app.httpServer) {
|
|
283
|
+
const fields = [];
|
|
284
|
+
if (routeObjectClone.request) {
|
|
285
|
+
const reqFields = routeObjectClone.request.fields;
|
|
286
|
+
const entries = Object.entries(reqFields);
|
|
287
|
+
entries.forEach(([key, value]) => {
|
|
288
|
+
const field = {};
|
|
289
|
+
field.name = key;
|
|
290
|
+
field.type = value.type;
|
|
291
|
+
if (value.exclusiveTests) {
|
|
292
|
+
field.isRequired = value.exclusiveTests.required;
|
|
293
|
+
}
|
|
220
294
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
* 'Error message'
|
|
236
|
-
* ]
|
|
237
|
-
* })
|
|
238
|
-
* @example
|
|
239
|
-
* // We can pass function to validator.js
|
|
240
|
-
* validate({
|
|
241
|
-
* someKey: 'test_at_test.com'
|
|
242
|
-
* },{
|
|
243
|
-
* 'someKey':[
|
|
244
|
-
* 'isEmail',
|
|
245
|
-
* 'Please provide valid email'
|
|
246
|
-
* ]
|
|
247
|
-
* })
|
|
248
|
-
* @example
|
|
249
|
-
* // We can pass function to validator.js with params
|
|
250
|
-
* validate({
|
|
251
|
-
* someKey: 'test_at_test.com'
|
|
252
|
-
* },{
|
|
253
|
-
* 'someKey':[
|
|
254
|
-
* ['isEmail',{'require_tld':false}],
|
|
255
|
-
* 'Please provide valid email'
|
|
256
|
-
* ]
|
|
257
|
-
* })
|
|
258
|
-
*/
|
|
259
|
-
validate(obj, rules) {
|
|
260
|
-
this.logger.warn(
|
|
261
|
-
'Validate deprecated. Please do not use it. Will be revomed it future release',
|
|
262
|
-
);
|
|
263
|
-
const errors = {};
|
|
264
|
-
for (const name in rules) {
|
|
265
|
-
let validationResult = false;
|
|
266
|
-
if (typeof rules[name][0] === 'function') {
|
|
267
|
-
validationResult = rules[name][0](obj[name]);
|
|
268
|
-
if (
|
|
269
|
-
Object.prototype.toString.call(validationResult) === '[object Array]'
|
|
270
|
-
) {
|
|
271
|
-
[errors[name]] = validationResult;
|
|
272
|
-
validationResult = false;
|
|
273
|
-
}
|
|
274
|
-
} else if (typeof validator[rules[name][0]] === 'function') {
|
|
275
|
-
// use from validator then
|
|
276
|
-
validationResult = validator[rules[name][0]](obj[name]);
|
|
277
|
-
} else if (
|
|
278
|
-
Object.prototype.toString.call(rules[name][0]) === '[object Array]' &&
|
|
279
|
-
typeof validator[rules[name][0][0]] === 'function'
|
|
280
|
-
) {
|
|
281
|
-
// use from validator then
|
|
282
|
-
validationResult = validator[rules[name][0][0]](
|
|
283
|
-
`${obj[name]}`,
|
|
284
|
-
rules[name][0][1],
|
|
285
|
-
);
|
|
286
|
-
} else {
|
|
287
|
-
this.logger.warn(
|
|
288
|
-
`No rule found for ${name}. Swith to existing checking`,
|
|
289
|
-
);
|
|
290
|
-
validationResult = !!obj[name];
|
|
291
|
-
}
|
|
292
|
-
if (!validationResult && !errors[name]) {
|
|
293
|
-
[, errors[name]] = rules[name];
|
|
295
|
+
if (value.fields) {
|
|
296
|
+
field.fields = [];
|
|
297
|
+
// eslint-disable-next-line no-shadow
|
|
298
|
+
const entries = Object.entries(value.fields);
|
|
299
|
+
// eslint-disable-next-line no-shadow
|
|
300
|
+
entries.forEach(([key, value]) => {
|
|
301
|
+
field.fields.push({
|
|
302
|
+
name: key,
|
|
303
|
+
type: value.type,
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
fields.push(field);
|
|
308
|
+
});
|
|
294
309
|
}
|
|
310
|
+
|
|
311
|
+
this.app.documentation.push({
|
|
312
|
+
contollerName: this.getConstructorName(),
|
|
313
|
+
routesInfo: routesInfo.map((route) => ({
|
|
314
|
+
[route.fullPath]: {
|
|
315
|
+
method: route.method,
|
|
316
|
+
name: route.name,
|
|
317
|
+
fields,
|
|
318
|
+
routeMiddlewares: routeMiddlewaresReg
|
|
319
|
+
// eslint-disable-next-line consistent-return
|
|
320
|
+
.map((middleware) => {
|
|
321
|
+
if (
|
|
322
|
+
route.fullPath.toUpperCase() ===
|
|
323
|
+
middleware.fullPath.toUpperCase()
|
|
324
|
+
) {
|
|
325
|
+
return {
|
|
326
|
+
name: middleware.name,
|
|
327
|
+
params: middleware.params,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
})
|
|
331
|
+
.filter(Boolean),
|
|
332
|
+
controllerMiddlewares: [
|
|
333
|
+
...new Set(
|
|
334
|
+
middlewaresInfo
|
|
335
|
+
.filter(
|
|
336
|
+
(middleware) =>
|
|
337
|
+
middleware.fullPath.toUpperCase() ===
|
|
338
|
+
route.fullPath.toUpperCase(),
|
|
339
|
+
)
|
|
340
|
+
.map(({ name, params }) => ({ name, params })),
|
|
341
|
+
),
|
|
342
|
+
],
|
|
343
|
+
},
|
|
344
|
+
})),
|
|
345
|
+
});
|
|
346
|
+
} else {
|
|
347
|
+
this.app.httpServer.express.use(expressPath, this.router);
|
|
295
348
|
}
|
|
296
|
-
if (Object.entries(errors).length === 0 && errors.constructor === Object) {
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
return errors;
|
|
300
349
|
}
|
|
301
350
|
|
|
302
351
|
/**
|
|
@@ -306,24 +355,14 @@ class AbstractController extends Base {
|
|
|
306
355
|
* Be default path apply to ANY' method, but you can preattach 'METHOD' into patch to scope patch to this METHOD
|
|
307
356
|
* @example
|
|
308
357
|
* return new Map([
|
|
309
|
-
* ['/*', [
|
|
358
|
+
* ['/*', [GetUserByToken]] // for any method for this controller
|
|
310
359
|
* ['POST/', [Auth]] // for POST method
|
|
311
360
|
* ['/superSecretMethod', [OnlySuperSecretUsers]] // route with ANY method
|
|
312
361
|
* ['PUT/superSecretMathod', [OnlySuperSecretAdmin]] // route with PUT method
|
|
313
362
|
* ]);
|
|
314
363
|
*/
|
|
315
364
|
static get middleware() {
|
|
316
|
-
return new Map([['/*', [
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Part of abstract contorller.
|
|
321
|
-
* When you do not need controller name to append in route then return false here.
|
|
322
|
-
* Useful for home(root) controllers
|
|
323
|
-
* @deprecated please use getExpressPath instead
|
|
324
|
-
*/
|
|
325
|
-
static get isUseControllerNameForRouting() {
|
|
326
|
-
return true;
|
|
365
|
+
return new Map([['/*', [GetUserByToken, Auth]]]);
|
|
327
366
|
}
|
|
328
367
|
|
|
329
368
|
/**
|
|
@@ -342,12 +381,6 @@ class AbstractController extends Base {
|
|
|
342
381
|
* Get express path with inheritance of path
|
|
343
382
|
*/
|
|
344
383
|
getExpressPath() {
|
|
345
|
-
if (!this.constructor.isUseControllerNameForRouting) {
|
|
346
|
-
console.warn(
|
|
347
|
-
'isUseControllerNameForRouting is DEPRECATED. Please use getExpressPath instead',
|
|
348
|
-
);
|
|
349
|
-
return '/';
|
|
350
|
-
}
|
|
351
384
|
return `/${this.getConstructorName().toLowerCase()}`.replace('//', '/');
|
|
352
385
|
}
|
|
353
386
|
|
package/modules/AbstractModel.js
CHANGED
|
@@ -20,28 +20,21 @@ class AbstractModel extends Base {
|
|
|
20
20
|
);
|
|
21
21
|
if (!mongoose.connection.readyState) {
|
|
22
22
|
// do not connect on test
|
|
23
|
-
mongoose
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
callback();
|
|
40
|
-
},
|
|
41
|
-
(error) => {
|
|
42
|
-
this.logger.error("Can't install mongodb connection", error);
|
|
43
|
-
},
|
|
44
|
-
);
|
|
23
|
+
mongoose.connect(this.app.getConfig('mongo').connectionString, {}).then(
|
|
24
|
+
() => {
|
|
25
|
+
this.logger.info('Mongo connection success');
|
|
26
|
+
this.app.events.on('die', async () => {
|
|
27
|
+
for (const c of mongoose.connections) {
|
|
28
|
+
c.close(true);
|
|
29
|
+
}
|
|
30
|
+
// await mongoose.disconnect(); // TODO it have problems with replica-set
|
|
31
|
+
});
|
|
32
|
+
callback();
|
|
33
|
+
},
|
|
34
|
+
(error) => {
|
|
35
|
+
this.logger.error("Can't install mongodb connection", error);
|
|
36
|
+
},
|
|
37
|
+
);
|
|
45
38
|
} else {
|
|
46
39
|
callback();
|
|
47
40
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import Server from '../server';
|
|
3
|
+
|
|
4
|
+
declare class Base {
|
|
5
|
+
app: Server['app'];
|
|
6
|
+
_realLogger: null;
|
|
7
|
+
|
|
8
|
+
constructor(app: Server['app']);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* In case of logging sometimes we might need to replace name
|
|
12
|
+
*/
|
|
13
|
+
getConstructorName(): string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Optimzation to lazy load logger. It will be inited only on request
|
|
17
|
+
*/
|
|
18
|
+
get logger(): winston.Logger;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get winston loger for given label
|
|
22
|
+
* @param label name of logger
|
|
23
|
+
*/
|
|
24
|
+
getLogger(label: string): winston.Logger;
|
|
25
|
+
|
|
26
|
+
getFilesPathWithInheritance(
|
|
27
|
+
internalFolder: string,
|
|
28
|
+
externalFolder: string,
|
|
29
|
+
): Promise<string[]>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Return logger group. Just to have all logs groupped logically
|
|
33
|
+
*/
|
|
34
|
+
static get loggerGroup(): string;
|
|
35
|
+
}
|
|
36
|
+
export = Base;
|
package/modules/Base.js
CHANGED
|
@@ -3,9 +3,6 @@ const fs = require('fs').promises;
|
|
|
3
3
|
const { join } = require('path');
|
|
4
4
|
|
|
5
5
|
class Base {
|
|
6
|
-
/**
|
|
7
|
-
* @param {import('../Server')} app //TODO change to *.d.ts as this is a Server, not app
|
|
8
|
-
*/
|
|
9
6
|
constructor(app) {
|
|
10
7
|
this.app = app;
|
|
11
8
|
this._realLogger = null;
|
|
@@ -98,15 +95,6 @@ class Base {
|
|
|
98
95
|
});
|
|
99
96
|
}
|
|
100
97
|
|
|
101
|
-
async loadFilesWithInheritance(internalFolder, externalFolder) {
|
|
102
|
-
this.logger.warn(
|
|
103
|
-
'Method "loadFilesWithInheritance" deprecated. Please use "getFilesPathWithInheritance"',
|
|
104
|
-
);
|
|
105
|
-
return (
|
|
106
|
-
await this.getFilesPathWithInheritance(internalFolder, externalFolder)
|
|
107
|
-
).map((file) => file.path);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
98
|
async getFilesPathWithInheritance(internalFolder, externalFolder) {
|
|
111
99
|
async function rreaddir(dir, allFiles = []) {
|
|
112
100
|
const files = (await fs.readdir(dir)).map((f) => join(dir, f));
|