@adaptivestone/framework 2.15.4 → 3.0.1
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 +9 -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 +1 -1
- package/types/Expand.d.ts +11 -0
- package/types/TFoldersConfig.d.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,75 @@
|
|
|
1
|
+
### 3.0.1
|
|
2
|
+
|
|
3
|
+
[UPDATE] update deps
|
|
4
|
+
[UPDATE] getUserByTokens more logs
|
|
5
|
+
|
|
6
|
+
### 3.0.0
|
|
7
|
+
|
|
8
|
+
[BREAKING] Mongoose v6. Than a lot of changes:[mongoDB drive changes](https://github.com/mongodb/node-mongodb-native/blob/4.0/docs/CHANGES_4.0.0.md), [Mongoose changes](https://mongoosejs.com/docs/migrating_to_6.html).
|
|
9
|
+
Notable changes from migration
|
|
10
|
+
Removed `execPopulate()`[link](https://mongoosejs.com/docs/migrating_to_6.html#removed-execpopulate)
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
// Document#populate() now returns a promise and is now no longer chainable.
|
|
14
|
+
|
|
15
|
+
//Replace
|
|
16
|
+
await doc.populate('path1').populate('path2').execPopulate();
|
|
17
|
+
// with
|
|
18
|
+
await doc.populate(['path1', 'path2']);
|
|
19
|
+
//Replace
|
|
20
|
+
await doc
|
|
21
|
+
.populate('path1', 'select1')
|
|
22
|
+
.populate('path2', 'select2')
|
|
23
|
+
.execPopulate();
|
|
24
|
+
// with
|
|
25
|
+
await doc.populate([
|
|
26
|
+
{ path: 'path1', select: 'select1' },
|
|
27
|
+
{ path: 'path2', select: 'select2' },
|
|
28
|
+
]);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
[REMOVED] removed deprecated router handler string not allowed anymore. Use functions by itself
|
|
32
|
+
[REMOVED] removed deprecated someSecretSalt() on user model (use this.saltSecret instead)
|
|
33
|
+
[REMOVED] removed deprecated validate() on abstract controller and as result validator dependency. Use request validators instead
|
|
34
|
+
[REMOVED] removed deprecated isUseControllerNameForRouting() on abstract controller. Use getExpressPath() instead
|
|
35
|
+
[REMOVED] removed deprecated Base.loadFilesWithInheritance please use getFilesPathWithInheritance that produce almost the same output
|
|
36
|
+
[BREAKING] Removed "success" field on Auth contreoller. Please use http status instead
|
|
37
|
+
[BREAKING] Auth controller - "error" error responce renamed to "message"
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
// Before
|
|
41
|
+
{
|
|
42
|
+
error: 'Some error';
|
|
43
|
+
}
|
|
44
|
+
// After
|
|
45
|
+
{
|
|
46
|
+
message: 'Some error';
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
[UPDATE] update deps
|
|
51
|
+
[UPDATE] winston console transport now using timestapms
|
|
52
|
+
[UPDATE] PrepareAppInfo middleware now a global one. Do not need to include it on every controller
|
|
53
|
+
[NEW] Request anso works with req.query, but req.body have bigger priority
|
|
54
|
+
|
|
55
|
+
### 2.18.0
|
|
56
|
+
|
|
57
|
+
[UPDATE] update deps
|
|
58
|
+
[UPDATE] replace body-parser with express.json
|
|
59
|
+
[NEW] role middleware
|
|
60
|
+
|
|
61
|
+
### 2.17.0
|
|
62
|
+
|
|
63
|
+
[UPDATE] update deps
|
|
64
|
+
[NEW] new env variable LOGGER_SENTRY_LEVEL (default=info)
|
|
65
|
+
[NEW] new env variable LOGGER_CONSOLE_ENABLE (default=true)
|
|
66
|
+
[BREAKING] on translation we changed i18next. Please convert files if you have plurals inside it https://i18next.github.io/i18next-v4-format-converter-web/
|
|
67
|
+
|
|
68
|
+
#### 2.16.0
|
|
69
|
+
|
|
70
|
+
[UPDATE] update deps
|
|
71
|
+
[NEW] begin adding type script definitions
|
|
72
|
+
|
|
1
73
|
#### 2.15.4
|
|
2
74
|
|
|
3
75
|
[UPDATE] update deps
|
package/README.md
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const AbstractCommand = require('../modules/AbstractCommand');
|
|
2
|
+
const ControllerManager = require('../controllers/index');
|
|
3
|
+
|
|
4
|
+
class Documentation extends AbstractCommand {
|
|
5
|
+
async run() {
|
|
6
|
+
const CM = new ControllerManager(this.app);
|
|
7
|
+
this.app.documentation = [];
|
|
8
|
+
await CM.initControllers({ folders: this.app.foldersConfig });
|
|
9
|
+
console.log(JSON.stringify(this.app.documentation));
|
|
10
|
+
return JSON.stringify(this.app.documentation);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = Documentation;
|
package/commands/DropIndex.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const AbstractCommand = require('../modules/AbstractCommand');
|
|
2
2
|
|
|
3
3
|
class DropIndex extends AbstractCommand {
|
|
4
|
+
static get description() {
|
|
5
|
+
return 'Drop indexes of model';
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
async run() {
|
|
5
9
|
if (!this.args.model) {
|
|
6
10
|
this.logger.error('Please provide model name as "--model=BestUserModel"');
|
|
@@ -5,6 +5,10 @@ const fs = require('fs').promises;
|
|
|
5
5
|
const AbstractCommand = require('../../modules/AbstractCommand');
|
|
6
6
|
|
|
7
7
|
class CreateMigration extends AbstractCommand {
|
|
8
|
+
static get description() {
|
|
9
|
+
return 'Create new migration';
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
async run() {
|
|
9
13
|
if (!this.args.name) {
|
|
10
14
|
return this.logger.error(
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
const AbstractCommand = require('../../modules/AbstractCommand');
|
|
3
3
|
|
|
4
4
|
class Migrate extends AbstractCommand {
|
|
5
|
+
static get description() {
|
|
6
|
+
return 'Run all pending migrations';
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
async run() {
|
|
6
10
|
const files = await this.getFilesPathWithInheritance(
|
|
7
11
|
`${__dirname}/../../migrations`,
|
package/config/http.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
port: process.env.HTTP_PORT || 3300,
|
|
3
3
|
hostname: process.env.HTTP_HOST || '0.0.0.0',
|
|
4
|
-
// if you
|
|
4
|
+
// if you want to use 'all' domains please copy this file to your app
|
|
5
5
|
// and set "corsDomains: '*'" (not a mistake, string instead of array)
|
|
6
6
|
corsDomains: ['http://localhost:3000'],
|
|
7
7
|
myDomain: process.env.HTTP_DOMAIN || 'http://localhost:3300',
|
package/config/i18n.js
CHANGED
|
@@ -4,6 +4,6 @@ module.exports = {
|
|
|
4
4
|
fallbackLng: 'en',
|
|
5
5
|
// https://github.com/i18next/i18next-http-middleware#detector-options
|
|
6
6
|
// in additional we have 'xLang' that detect language based on header 'xLang'
|
|
7
|
-
langDetectionOders: ['xLang'], // from
|
|
7
|
+
langDetectionOders: ['xLang'], // from order option
|
|
8
8
|
lookupQuerystring: 'lng', // string to detect language on query
|
|
9
9
|
};
|
package/config/log.js
CHANGED
|
@@ -4,9 +4,9 @@ module.exports = {
|
|
|
4
4
|
transport: 'winston-transport-sentry-node',
|
|
5
5
|
transportOptions: {
|
|
6
6
|
sentry: {
|
|
7
|
-
dsn: process.env.SENTRY_DSN,
|
|
7
|
+
dsn: process.env.LOGGER_SENTRY_DSN || process.env.SENTRY_DSN,
|
|
8
8
|
},
|
|
9
|
-
level: 'info',
|
|
9
|
+
level: process.env.LOGGER_SENTRY_LEVEL || 'info',
|
|
10
10
|
},
|
|
11
11
|
enable: process.env.LOGGER_SENTRY_ENABLE || false,
|
|
12
12
|
},
|
|
@@ -14,8 +14,9 @@ module.exports = {
|
|
|
14
14
|
transport: 'console',
|
|
15
15
|
transportOptions: {
|
|
16
16
|
level: process.env.LOGGER_CONSOLE_LEVEL || 'silly',
|
|
17
|
+
timestamp: true,
|
|
17
18
|
},
|
|
18
|
-
enable: true,
|
|
19
|
+
enable: process.env.LOGGER_CONSOLE_ENABLE || true,
|
|
19
20
|
},
|
|
20
21
|
],
|
|
21
22
|
};
|
package/controllers/Auth.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const yup = require('yup');
|
|
2
2
|
const AbstractController = require('../modules/AbstractController');
|
|
3
|
-
const PrepareAppInfo = require('../services/http/middleware/PrepareAppInfo');
|
|
4
3
|
const GetUserByToken = require('../services/http/middleware/GetUserByToken');
|
|
5
4
|
const RateLimiter = require('../services/http/middleware/RateLimiter');
|
|
6
5
|
|
|
@@ -74,33 +73,31 @@ class Auth extends AbstractController {
|
|
|
74
73
|
req.appInfo.request.password, // we do a request casting
|
|
75
74
|
);
|
|
76
75
|
if (!user) {
|
|
77
|
-
return res.status(400).json({
|
|
76
|
+
return res.status(400).json({ message: req.i18n.t('auth.errorUPValid') });
|
|
78
77
|
}
|
|
79
78
|
const { isAuthWithVefificationFlow } = this.app.getConfig('auth');
|
|
80
79
|
if (isAuthWithVefificationFlow && !user.isVerified) {
|
|
81
80
|
return res
|
|
82
81
|
.status(400)
|
|
83
|
-
.json({
|
|
82
|
+
.json({ message: req.i18n.t('email.notVerified'), notVerified: true });
|
|
84
83
|
}
|
|
85
84
|
const token = await user.generateToken();
|
|
86
85
|
|
|
87
|
-
return res
|
|
88
|
-
.status(200)
|
|
89
|
-
.json({ success: true, token, user: user.getPublic() });
|
|
86
|
+
return res.status(200).json({ token, user: user.getPublic() });
|
|
90
87
|
}
|
|
91
88
|
|
|
92
89
|
async postRegister(req, res) {
|
|
93
90
|
const User = req.appInfo.app.getModel('User');
|
|
94
91
|
let user = await User.getUserByEmail(req.appInfo.request.email);
|
|
95
92
|
if (user) {
|
|
96
|
-
return res.status(400).json({
|
|
93
|
+
return res.status(400).json({ message: req.i18n.t('email.registered') });
|
|
97
94
|
}
|
|
98
95
|
if (req.appInfo.request.nickName) {
|
|
99
96
|
user = await User.findOne({ 'name.nick': req.appInfo.request.nickName });
|
|
100
97
|
if (user) {
|
|
101
98
|
return res
|
|
102
99
|
.status(400)
|
|
103
|
-
.json({
|
|
100
|
+
.json({ message: req.i18n.t('auth.nicknameExists') });
|
|
104
101
|
}
|
|
105
102
|
}
|
|
106
103
|
|
|
@@ -120,16 +117,16 @@ class Auth extends AbstractController {
|
|
|
120
117
|
this.logger.error(e.message);
|
|
121
118
|
});
|
|
122
119
|
if (!answer) {
|
|
123
|
-
return res.status(500).json(
|
|
120
|
+
return res.status(500).json();
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
|
-
return res.status(201).json(
|
|
123
|
+
return res.status(201).json();
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
// eslint-disable-next-line class-methods-use-this
|
|
130
127
|
async postLogout(req, res) {
|
|
131
128
|
// todo remove token
|
|
132
|
-
return res.status(200).json(
|
|
129
|
+
return res.status(200).json();
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
async verifyUser(req, res) {
|
|
@@ -141,21 +138,19 @@ class Auth extends AbstractController {
|
|
|
141
138
|
);
|
|
142
139
|
} catch (e) {
|
|
143
140
|
return res.status(400).json({
|
|
144
|
-
|
|
145
|
-
error: req.i18n.t('email.alreadyVerifiedOrWrongToken'),
|
|
141
|
+
message: req.i18n.t('email.alreadyVerifiedOrWrongToken'),
|
|
146
142
|
});
|
|
147
143
|
}
|
|
148
144
|
this.logger.debug(`Verify user user is :${user}`);
|
|
149
145
|
if (!user) {
|
|
150
146
|
return res.status(400).json({
|
|
151
|
-
|
|
152
|
-
error: req.i18n.t('email.alreadyVerifiedOrWrongToken'),
|
|
147
|
+
message: req.i18n.t('email.alreadyVerifiedOrWrongToken'),
|
|
153
148
|
});
|
|
154
149
|
}
|
|
155
150
|
|
|
156
151
|
user.isVerified = true;
|
|
157
152
|
await user.save();
|
|
158
|
-
return res.status(200).json(
|
|
153
|
+
return res.status(200).json();
|
|
159
154
|
}
|
|
160
155
|
|
|
161
156
|
async sendPasswordRecoveryEmail(req, res) {
|
|
@@ -165,15 +160,13 @@ class Auth extends AbstractController {
|
|
|
165
160
|
if (!user) {
|
|
166
161
|
return res
|
|
167
162
|
.status(400)
|
|
168
|
-
.json({
|
|
163
|
+
.json({ message: req.i18n.t('auth.errorUExist') });
|
|
169
164
|
}
|
|
170
165
|
await user.sendPasswordRecoveryEmail(req.i18n);
|
|
171
|
-
return res.status(200).json(
|
|
166
|
+
return res.status(200).json();
|
|
172
167
|
} catch (e) {
|
|
173
168
|
this.logger.error(e.message);
|
|
174
|
-
return res
|
|
175
|
-
.status(400)
|
|
176
|
-
.json({ success: false, error: req.i18n.t('auth.errorUExist') });
|
|
169
|
+
return res.status(400).json({ message: req.i18n.t('auth.errorUExist') });
|
|
177
170
|
}
|
|
178
171
|
}
|
|
179
172
|
|
|
@@ -190,7 +183,7 @@ class Auth extends AbstractController {
|
|
|
190
183
|
if (!user) {
|
|
191
184
|
return res
|
|
192
185
|
.status(400)
|
|
193
|
-
.json({
|
|
186
|
+
.json({ message: req.i18n.t('password.wrongToken') });
|
|
194
187
|
}
|
|
195
188
|
|
|
196
189
|
this.logger.debug(`Password recovery user is :${user}`);
|
|
@@ -198,23 +191,21 @@ class Auth extends AbstractController {
|
|
|
198
191
|
user.password = req.appInfo.request.password;
|
|
199
192
|
user.isVerified = true;
|
|
200
193
|
await user.save();
|
|
201
|
-
return res.status(200).json(
|
|
194
|
+
return res.status(200).json();
|
|
202
195
|
}
|
|
203
196
|
|
|
204
197
|
async sendVerification(req, res) {
|
|
205
198
|
const User = this.app.getModel('User');
|
|
206
199
|
const user = await User.getUserByEmail(req.appInfo.request.email);
|
|
207
200
|
if (!user) {
|
|
208
|
-
return res
|
|
209
|
-
.status(400)
|
|
210
|
-
.json({ success: false, error: req.i18n.t('auth.errorUExist') });
|
|
201
|
+
return res.status(400).json({ message: req.i18n.t('auth.errorUExist') });
|
|
211
202
|
}
|
|
212
203
|
await user.sendVerificationEmail(req.i18n);
|
|
213
|
-
return res.status(200).json(
|
|
204
|
+
return res.status(200).json();
|
|
214
205
|
}
|
|
215
206
|
|
|
216
207
|
static get middleware() {
|
|
217
|
-
return new Map([['/*', [
|
|
208
|
+
return new Map([['/*', [GetUserByToken, RateLimiter]]]);
|
|
218
209
|
}
|
|
219
210
|
}
|
|
220
211
|
|
package/controllers/Auth.test.js
CHANGED
|
@@ -20,10 +20,8 @@ describe('auth', () => {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
it('can create user', async () => {
|
|
23
|
-
expect.assertions(
|
|
24
|
-
const { status
|
|
25
|
-
global.server.app.httpServer.express,
|
|
26
|
-
)
|
|
23
|
+
expect.assertions(1);
|
|
24
|
+
const { status } = await request(global.server.app.httpServer.express)
|
|
27
25
|
.post('/auth/register')
|
|
28
26
|
.send({
|
|
29
27
|
email: userEmail,
|
|
@@ -31,7 +29,6 @@ describe('auth', () => {
|
|
|
31
29
|
nickName: 'test',
|
|
32
30
|
});
|
|
33
31
|
expect(status).toBe(201);
|
|
34
|
-
expect(body.success).toBe(true);
|
|
35
32
|
});
|
|
36
33
|
|
|
37
34
|
it('can NOT create SAME user', async () => {
|
|
@@ -71,7 +68,7 @@ describe('auth', () => {
|
|
|
71
68
|
});
|
|
72
69
|
|
|
73
70
|
it('can login with normal creds and verifyed email', async () => {
|
|
74
|
-
expect.assertions(
|
|
71
|
+
expect.assertions(2);
|
|
75
72
|
|
|
76
73
|
const user = await global.server.app
|
|
77
74
|
.getModel('User')
|
|
@@ -88,14 +85,13 @@ describe('auth', () => {
|
|
|
88
85
|
password: userPassword,
|
|
89
86
|
});
|
|
90
87
|
expect(status).toBe(200);
|
|
91
|
-
expect(body.success).toBe(true);
|
|
92
88
|
expect(body.token).toBeDefined();
|
|
93
89
|
});
|
|
94
90
|
});
|
|
95
91
|
|
|
96
92
|
describe('isAuthWithVefificationFlow auth option', () => {
|
|
97
93
|
it('can login with normal creds and NOT verifyed email is option isAuthWithVefificationFlow is set', async () => {
|
|
98
|
-
expect.assertions(
|
|
94
|
+
expect.assertions(4);
|
|
99
95
|
|
|
100
96
|
const { status } = await request(global.server.app.httpServer.express)
|
|
101
97
|
.post('/auth/register')
|
|
@@ -129,7 +125,6 @@ describe('auth', () => {
|
|
|
129
125
|
expect(status).toBe(201);
|
|
130
126
|
expect(status2).toBe(400);
|
|
131
127
|
expect(status3).toBe(200);
|
|
132
|
-
expect(body.success).toBe(true);
|
|
133
128
|
expect(body.token).toBeDefined();
|
|
134
129
|
});
|
|
135
130
|
});
|
package/controllers/Home.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const AbstractController = require('../modules/AbstractController');
|
|
2
|
-
const PrepareAppInfo = require('../services/http/middleware/PrepareAppInfo');
|
|
3
2
|
const GetUserByToken = require('../services/http/middleware/GetUserByToken');
|
|
4
3
|
|
|
5
4
|
class Home extends AbstractController {
|
|
@@ -22,7 +21,7 @@ class Home extends AbstractController {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
static get middleware() {
|
|
25
|
-
return new Map([['/*', [
|
|
24
|
+
return new Map([['/*', [GetUserByToken]]]);
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
|
package/models/User.js
CHANGED
|
@@ -12,16 +12,6 @@ class User extends AbstractModel {
|
|
|
12
12
|
this.saltSecret = authConfig.saltSecret;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* @deprecated
|
|
17
|
-
*/
|
|
18
|
-
get someSecretSalt() {
|
|
19
|
-
this.logger.warn(
|
|
20
|
-
'someSecretSalt deprecatred and will be removed in future release. Please use "this.saltSecret" instead ',
|
|
21
|
-
);
|
|
22
|
-
return this.saltSecret;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
15
|
initHooks() {
|
|
26
16
|
this.mongooseSchema.pre('save', async function () {
|
|
27
17
|
if (this.isModified('password')) {
|
|
@@ -69,6 +59,7 @@ class User extends AbstractModel {
|
|
|
69
59
|
verificationTokens: [{ until: Date, token: String }],
|
|
70
60
|
passwordRecoveryTokens: [{ until: Date, token: String }],
|
|
71
61
|
permissions: [],
|
|
62
|
+
roles: [],
|
|
72
63
|
isVerified: { type: Boolean, default: false },
|
|
73
64
|
locale: { type: String, default: 'en' },
|
|
74
65
|
languages: [String],
|