@azteam/express 1.2.117 → 1.2.120
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/package.json +1 -1
- package/src/AdminController.js +52 -53
- package/src/ApiServer.js +40 -28
- package/src/Controller.js +30 -0
- package/src/constant.js +0 -8
- package/src/index.js +3 -1
- package/src/middleware/etagMiddleware.js +1 -2
package/package.json
CHANGED
package/src/AdminController.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {NOT_EXISTS} from '@azteam/error';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import {REQUEST_TYPE, USER_LEVEL} from './constant';
|
|
4
|
+
import {paginateMiddleware, roleMiddleware, validateMiddleware} from './middleware';
|
|
5
|
+
import {rulesID} from './validate';
|
|
6
|
+
import Controller from './Controller';
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
class Controller {
|
|
9
|
+
class AdminController extends Controller {
|
|
8
10
|
constructor(pathName, repository, options = {}) {
|
|
9
|
-
|
|
10
|
-
this.repository = repository;
|
|
11
|
-
|
|
12
|
-
this.options = {
|
|
11
|
+
super(pathName, repository, {
|
|
13
12
|
roles: {
|
|
14
13
|
READ: 1,
|
|
15
14
|
CREATE: 2,
|
|
16
15
|
UPDATE: 3,
|
|
17
16
|
DELETE: 4,
|
|
18
|
-
RESTORE: 5
|
|
17
|
+
RESTORE: 5
|
|
19
18
|
}, // system roles
|
|
20
19
|
|
|
20
|
+
paginateOptions: {},
|
|
21
21
|
rulesCreate: {},
|
|
22
22
|
rulesModify: {},
|
|
23
23
|
|
|
24
24
|
guardResponse: {},
|
|
25
25
|
allowResponse: {},
|
|
26
|
-
|
|
27
|
-
...options
|
|
28
|
-
}
|
|
26
|
+
|
|
27
|
+
...options
|
|
28
|
+
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
getPaginate() {
|
|
32
32
|
return {
|
|
33
|
-
path:
|
|
33
|
+
path: '/public',
|
|
34
34
|
method: [
|
|
35
35
|
roleMiddleware([this.options.roles.READ], USER_LEVEL.ADMIN),
|
|
36
|
-
paginateMiddleware(paginateOptions),
|
|
36
|
+
paginateMiddleware(this.options.paginateOptions),
|
|
37
37
|
async function(req, res) {
|
|
38
38
|
const paginateData = await this.repository.find(req.query, req.paginate);
|
|
39
39
|
|
|
40
40
|
return res.success(paginateData, this.options.guardResponse, this.options.allowResponse);
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
getPaginateTrash() {
|
|
47
47
|
return {
|
|
48
|
-
path:
|
|
48
|
+
path: '/trash',
|
|
49
49
|
method: [
|
|
50
50
|
roleMiddleware([this.options.roles.READ], USER_LEVEL.ADMIN),
|
|
51
|
-
paginateMiddleware(paginateOptions),
|
|
51
|
+
paginateMiddleware(this.options.paginateOptions),
|
|
52
52
|
async function(req, res) {
|
|
53
53
|
const paginateData = await this.repository.findTrash(req.query, req.paginate);
|
|
54
54
|
|
|
55
55
|
return res.success(paginateData, this.options.guardResponse, this.options.allowResponse);
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
};
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
getOne() {
|
|
62
62
|
return {
|
|
63
|
-
path:
|
|
63
|
+
path: '/public/:id',
|
|
64
64
|
method: [
|
|
65
65
|
roleMiddleware([this.options.roles.READ], USER_LEVEL.ADMIN),
|
|
66
66
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
@@ -68,15 +68,15 @@ class Controller {
|
|
|
68
68
|
const item = await this.repository.findOneById(req.params.id);
|
|
69
69
|
if (!item) return res.error(NOT_EXISTS);
|
|
70
70
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
71
|
-
}
|
|
72
|
-
]
|
|
73
|
-
}
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
74
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
getOneTrash() {
|
|
78
78
|
return {
|
|
79
|
-
path:
|
|
79
|
+
path: '/trash/:id',
|
|
80
80
|
method: [
|
|
81
81
|
roleMiddleware([this.options.roles.READ], USER_LEVEL.ADMIN),
|
|
82
82
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
@@ -84,43 +84,43 @@ class Controller {
|
|
|
84
84
|
const item = await this.repository.findOneTrashById(req.params.id);
|
|
85
85
|
if (!item) return res.error(NOT_EXISTS);
|
|
86
86
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
87
|
-
}
|
|
88
|
-
]
|
|
89
|
-
}
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
90
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
beforeCreate(data) {
|
|
95
95
|
return data;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
postCreate() {
|
|
99
99
|
return {
|
|
100
|
-
path:
|
|
100
|
+
path: '/public',
|
|
101
101
|
method: [
|
|
102
102
|
roleMiddleware([this.options.roles.CREATE], USER_LEVEL.ADMIN),
|
|
103
103
|
validateMiddleware(REQUEST_TYPE.BODY, this.options.rulesCreate),
|
|
104
104
|
async function(req, res) {
|
|
105
105
|
|
|
106
|
-
const data = this.
|
|
106
|
+
const data = this.beforeCreate(req.body);
|
|
107
107
|
|
|
108
108
|
const item = await this.repository.createByUser(req.user.id, data);
|
|
109
109
|
|
|
110
110
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
beforeModify(item) {
|
|
118
118
|
return item;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
putModify() {
|
|
122
122
|
return {
|
|
123
|
-
path:
|
|
123
|
+
path: '/public/:id',
|
|
124
124
|
method: [
|
|
125
125
|
roleMiddleware([this.options.roles.UPDATE], USER_LEVEL.ADMIN),
|
|
126
126
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
@@ -130,19 +130,19 @@ class Controller {
|
|
|
130
130
|
let item = await this.options.roles.findOneById(req.params.id);
|
|
131
131
|
if (!item) return res.error(NOT_EXISTS);
|
|
132
132
|
|
|
133
|
-
item = await this.
|
|
133
|
+
item = await this.beforeModify(item);
|
|
134
134
|
|
|
135
135
|
item = await this.options.roles.modifyByUser(req.user.id, item, req.body);
|
|
136
136
|
|
|
137
137
|
return res.success(item, this.options.guardResponse, this.options.allowResponse);
|
|
138
|
-
}
|
|
139
|
-
]
|
|
140
|
-
}
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
};
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
delete() {
|
|
144
144
|
return {
|
|
145
|
-
path:
|
|
145
|
+
path: '/public/:id',
|
|
146
146
|
method: [
|
|
147
147
|
roleMiddleware([this.options.roles.DELETE], USER_LEVEL.ADMIN),
|
|
148
148
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
@@ -152,14 +152,14 @@ class Controller {
|
|
|
152
152
|
|
|
153
153
|
await this.repository.deleteByUser(req.user.id, item);
|
|
154
154
|
return res.success(true);
|
|
155
|
-
}
|
|
156
|
-
]
|
|
157
|
-
}
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
postRestore() {
|
|
161
161
|
return {
|
|
162
|
-
path:
|
|
162
|
+
path: '/trash/:id',
|
|
163
163
|
method: [
|
|
164
164
|
roleMiddleware([this.options.roles.RESTORE], USER_LEVEL.ADMIN),
|
|
165
165
|
validateMiddleware(REQUEST_TYPE.PARAMS, rulesID),
|
|
@@ -169,11 +169,10 @@ class Controller {
|
|
|
169
169
|
|
|
170
170
|
await this.repository.restoreByUser(req.user.id, item);
|
|
171
171
|
return res.success(true);
|
|
172
|
-
}
|
|
173
|
-
]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
},
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
};
|
|
175
|
+
}
|
|
177
176
|
}
|
|
178
177
|
|
|
179
|
-
export default
|
|
178
|
+
export default AdminController;
|
package/src/ApiServer.js
CHANGED
|
@@ -9,8 +9,7 @@ import morgan from 'morgan';
|
|
|
9
9
|
import cors from 'cors';
|
|
10
10
|
import _ from 'lodash';
|
|
11
11
|
import 'express-async-errors';
|
|
12
|
-
import {
|
|
13
|
-
import { errorCatch, ErrorException, NOT_FOUND, UNKNOWN } from '@azteam/error';
|
|
12
|
+
import {errorCatch, ErrorException, NOT_FOUND, UNKNOWN} from '@azteam/error';
|
|
14
13
|
|
|
15
14
|
function omitItem(item, guard) {
|
|
16
15
|
if (item.toJSON) {
|
|
@@ -33,7 +32,7 @@ class ApiServer {
|
|
|
33
32
|
httpOnly: true,
|
|
34
33
|
signed: true,
|
|
35
34
|
sameSite: 'Lax'
|
|
36
|
-
}
|
|
35
|
+
};
|
|
37
36
|
|
|
38
37
|
this.middlewares = [];
|
|
39
38
|
this.controllers = [];
|
|
@@ -114,8 +113,8 @@ class ApiServer {
|
|
|
114
113
|
}));
|
|
115
114
|
|
|
116
115
|
app.use(methodOverride());
|
|
117
|
-
app.use(bodyParser.urlencoded({
|
|
118
|
-
app.use(bodyParser.json({
|
|
116
|
+
app.use(bodyParser.urlencoded({limit: '5mb', extended: true}));
|
|
117
|
+
app.use(bodyParser.json({limit: '5mb'}));
|
|
119
118
|
|
|
120
119
|
app.set('trust proxy', 1);
|
|
121
120
|
|
|
@@ -128,11 +127,11 @@ class ApiServer {
|
|
|
128
127
|
if (
|
|
129
128
|
!origin || !WHITE_LIST.length ||
|
|
130
129
|
WHITE_LIST.some(re => origin.endsWith(re))) {
|
|
131
|
-
callback(null, true)
|
|
130
|
+
callback(null, true);
|
|
132
131
|
} else {
|
|
133
132
|
callback(new Error(`${origin} Not allowed by CORS`));
|
|
134
133
|
}
|
|
135
|
-
}
|
|
134
|
+
}
|
|
136
135
|
}));
|
|
137
136
|
|
|
138
137
|
if (this.debug) {
|
|
@@ -150,13 +149,13 @@ class ApiServer {
|
|
|
150
149
|
ip: req.ip,
|
|
151
150
|
device: req.get('X-DEVICE') || req.get('User-Agent'),
|
|
152
151
|
device_id: req.get('X-DEVICE-ID') || 'web',
|
|
153
|
-
os: req.get('X-OS') || 'web'
|
|
154
|
-
}
|
|
152
|
+
os: req.get('X-OS') || 'web'
|
|
153
|
+
};
|
|
155
154
|
|
|
156
155
|
|
|
157
156
|
res.error = function(code, errors = []) {
|
|
158
157
|
throw new ErrorException(code, errors);
|
|
159
|
-
}
|
|
158
|
+
};
|
|
160
159
|
|
|
161
160
|
res.success = function(data = {}, guard = [], allows = []) {
|
|
162
161
|
if (data) {
|
|
@@ -176,7 +175,7 @@ class ApiServer {
|
|
|
176
175
|
'metadata_disable',
|
|
177
176
|
'metadata_keywords',
|
|
178
177
|
'metadata_description',
|
|
179
|
-
'metadata_image_url'
|
|
178
|
+
'metadata_image_url'
|
|
180
179
|
];
|
|
181
180
|
}
|
|
182
181
|
|
|
@@ -200,7 +199,7 @@ class ApiServer {
|
|
|
200
199
|
return res.json({
|
|
201
200
|
success: true,
|
|
202
201
|
data,
|
|
203
|
-
options: req.resOptions
|
|
202
|
+
options: req.resOptions
|
|
204
203
|
});
|
|
205
204
|
};
|
|
206
205
|
|
|
@@ -210,7 +209,7 @@ class ApiServer {
|
|
|
210
209
|
domain: COOKIE_OPTIONS.domain
|
|
211
210
|
});
|
|
212
211
|
});
|
|
213
|
-
}
|
|
212
|
+
};
|
|
214
213
|
|
|
215
214
|
res.addCookie = function(data) {
|
|
216
215
|
_.map(data, (value, key) => {
|
|
@@ -221,7 +220,7 @@ class ApiServer {
|
|
|
221
220
|
expires: new Date(Date.now() + maxAge)
|
|
222
221
|
});
|
|
223
222
|
});
|
|
224
|
-
}
|
|
223
|
+
};
|
|
225
224
|
next();
|
|
226
225
|
});
|
|
227
226
|
|
|
@@ -231,19 +230,32 @@ class ApiServer {
|
|
|
231
230
|
|
|
232
231
|
const msg = [];
|
|
233
232
|
_.map(this.controllers, (obj) => {
|
|
234
|
-
const controller = obj.controller;
|
|
235
|
-
_.map(controller, (item, key) => {
|
|
236
|
-
item.path = obj.version.startsWith('v') ? `/${obj.version}${item.path}` : item.path;
|
|
237
|
-
|
|
238
|
-
msg.push({
|
|
239
|
-
controller: obj.name,
|
|
240
|
-
version: obj.version,
|
|
241
|
-
type: item.type,
|
|
242
|
-
method: key,
|
|
243
|
-
path: item.path,
|
|
244
|
-
});
|
|
245
233
|
|
|
246
|
-
|
|
234
|
+
const {name, controller, version} = obj;
|
|
235
|
+
|
|
236
|
+
const listPublicMethod = obj.controller.publicMethod();
|
|
237
|
+
|
|
238
|
+
_.map(listPublicMethod, (methodName) => {
|
|
239
|
+
|
|
240
|
+
const matches = methodName.match(/get|post|put|patch|delete/);
|
|
241
|
+
if (matches) {
|
|
242
|
+
const type = matches[0];
|
|
243
|
+
const item = controller[methodName]();
|
|
244
|
+
|
|
245
|
+
item.path = controller.pathName ? `/${controller.pathName}${item.path}` : item.path;
|
|
246
|
+
|
|
247
|
+
item.path = version.startsWith('v') ? `/${version}${item.path}` : item.path;
|
|
248
|
+
|
|
249
|
+
msg.push({
|
|
250
|
+
controller: name,
|
|
251
|
+
version,
|
|
252
|
+
type,
|
|
253
|
+
method: methodName,
|
|
254
|
+
path: item.path
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
app[type](item.path, ...item.method);
|
|
258
|
+
}
|
|
247
259
|
});
|
|
248
260
|
});
|
|
249
261
|
|
|
@@ -268,7 +280,7 @@ class ApiServer {
|
|
|
268
280
|
this.callbackError(error);
|
|
269
281
|
}
|
|
270
282
|
|
|
271
|
-
return res.status(error.status).json({
|
|
283
|
+
return res.status(error.status).json({success: false, errors: error.errors});
|
|
272
284
|
});
|
|
273
285
|
|
|
274
286
|
const server = http.Server(app);
|
|
@@ -324,4 +336,4 @@ class ApiServer {
|
|
|
324
336
|
}
|
|
325
337
|
}
|
|
326
338
|
|
|
327
|
-
export default ApiServer;
|
|
339
|
+
export default ApiServer;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Controller {
|
|
2
|
+
constructor(pathName = '', repository = null, options = {}) {
|
|
3
|
+
this.pathName = pathName;
|
|
4
|
+
this.repository = repository;
|
|
5
|
+
|
|
6
|
+
this.options = {
|
|
7
|
+
...options
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
publicMethod() {
|
|
12
|
+
let child = this;
|
|
13
|
+
let result = [];
|
|
14
|
+
|
|
15
|
+
while (Object.getPrototypeOf(child.__proto__)) {
|
|
16
|
+
|
|
17
|
+
const data = Object.getOwnPropertyNames(Object.getPrototypeOf(child));
|
|
18
|
+
|
|
19
|
+
result = [
|
|
20
|
+
...result,
|
|
21
|
+
...data.filter((methodName) => methodName.match(/^get|post|put|patch|delete/))
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
child = child.__proto__;
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default Controller;
|
package/src/constant.js
CHANGED
package/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ApiServer from './ApiServer';
|
|
2
2
|
import SocketServer from './SocketServer';
|
|
3
3
|
|
|
4
|
+
import Controller from './Controller';
|
|
4
5
|
import AdminController from './AdminController';
|
|
5
6
|
|
|
6
7
|
|
|
@@ -12,5 +13,6 @@ export {
|
|
|
12
13
|
ApiServer,
|
|
13
14
|
SocketServer,
|
|
14
15
|
|
|
16
|
+
Controller,
|
|
15
17
|
AdminController,
|
|
16
|
-
}
|
|
18
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import etag from 'etag';
|
|
2
2
|
|
|
3
|
-
import { HTTP_GET } from '../constant';
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
function floorToMinute(time, minutes) {
|
|
@@ -11,7 +10,7 @@ function floorToMinute(time, minutes) {
|
|
|
11
10
|
|
|
12
11
|
export default function(mTimeout = 5) {
|
|
13
12
|
return async function(req, res, next) {
|
|
14
|
-
if (req.method ===
|
|
13
|
+
if (req.method === 'GET') {
|
|
15
14
|
const etag_hash = etag(req.url + floorToMinute(Math.floor(Date.now() / 1000), mTimeout));
|
|
16
15
|
if (req.headers['if-none-match'] === etag_hash) {
|
|
17
16
|
return res.status(304).send();
|