@waline/vercel 1.15.2 → 1.17.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/package.json +6 -5
- package/src/config/config.js +2 -0
- package/src/controller/comment.js +33 -4
- package/src/controller/user.js +32 -2
- package/src/extend/think.js +46 -0
- package/src/logic/base.js +17 -0
- package/src/logic/user.js +24 -0
- package/src/service/storage/leancloud.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waline/vercel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "vercel server for waline comment system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"waline",
|
|
@@ -20,20 +20,21 @@
|
|
|
20
20
|
"akismet": "^2.0.7",
|
|
21
21
|
"deta": "^1.1.0",
|
|
22
22
|
"dompurify": "^2.3.6",
|
|
23
|
+
"dy-node-ip2region": "^1.0.1",
|
|
23
24
|
"fast-csv": "^4.3.6",
|
|
24
25
|
"jsdom": "^19.0.0",
|
|
25
26
|
"jsonwebtoken": "^8.5.1",
|
|
26
27
|
"katex": "^0.15.3",
|
|
27
28
|
"leancloud-storage": "^4.12.2",
|
|
28
|
-
"markdown-it": "^
|
|
29
|
-
"markdown-it-emoji": "^2.0.
|
|
29
|
+
"markdown-it": "^13.0.1",
|
|
30
|
+
"markdown-it-emoji": "^2.0.2",
|
|
30
31
|
"markdown-it-sub": "^1.0.0",
|
|
31
32
|
"markdown-it-sup": "^1.0.0",
|
|
32
33
|
"mathjax-full": "^3.2.0",
|
|
33
|
-
"nodemailer": "^6.7.
|
|
34
|
+
"nodemailer": "^6.7.4",
|
|
34
35
|
"nunjucks": "^3.2.3",
|
|
35
36
|
"phpass": "^0.1.1",
|
|
36
|
-
"prismjs": "^1.
|
|
37
|
+
"prismjs": "^1.28.0",
|
|
37
38
|
"request": "^2.88.2",
|
|
38
39
|
"request-promise-native": "^1.0.9",
|
|
39
40
|
"speakeasy": "^2.0.0",
|
package/src/config/config.js
CHANGED
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
TCB_KEY,
|
|
15
15
|
SECURE_DOMAINS,
|
|
16
16
|
DISABLE_USERAGENT,
|
|
17
|
+
DISABLE_REGION,
|
|
17
18
|
AVATAR_PROXY,
|
|
18
19
|
GITHUB_TOKEN,
|
|
19
20
|
DETA_PROJECT_KEY,
|
|
@@ -106,6 +107,7 @@ module.exports = {
|
|
|
106
107
|
disallowIPList: [],
|
|
107
108
|
secureDomains: SECURE_DOMAINS ? SECURE_DOMAINS.split(/\s*,\s*/) : undefined,
|
|
108
109
|
disableUserAgent: DISABLE_USERAGENT && !isFalse(DISABLE_USERAGENT),
|
|
110
|
+
disableRegion: DISABLE_REGION && !isFalse(DISABLE_REGION),
|
|
109
111
|
levels:
|
|
110
112
|
!LEVELS || isFalse(LEVELS)
|
|
111
113
|
? false
|
|
@@ -5,7 +5,7 @@ const { getMarkdownParser } = require('../service/markdown');
|
|
|
5
5
|
|
|
6
6
|
const markdownParser = getMarkdownParser();
|
|
7
7
|
async function formatCmt(
|
|
8
|
-
{ ua, user_id, ...comment },
|
|
8
|
+
{ ua, user_id, ip, ...comment },
|
|
9
9
|
users = [],
|
|
10
10
|
{ avatarProxy },
|
|
11
11
|
loginUser
|
|
@@ -25,6 +25,7 @@ async function formatCmt(
|
|
|
25
25
|
comment.mail = user.email;
|
|
26
26
|
comment.link = user.url;
|
|
27
27
|
comment.type = user.type;
|
|
28
|
+
comment.label = user.label;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const avatarUrl =
|
|
@@ -41,8 +42,13 @@ async function formatCmt(
|
|
|
41
42
|
delete comment.mail;
|
|
42
43
|
} else {
|
|
43
44
|
comment.orig = comment.comment;
|
|
45
|
+
comment.ip = ip;
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
// administrator can always show region
|
|
49
|
+
if (isAdmin || !think.config('disableRegion')) {
|
|
50
|
+
comment.addr = await think.ip2region(ip, { depth: isAdmin ? 3 : 1 });
|
|
51
|
+
}
|
|
46
52
|
comment.comment = markdownParser(comment.comment);
|
|
47
53
|
return comment;
|
|
48
54
|
}
|
|
@@ -88,6 +94,7 @@ module.exports = class extends BaseRest {
|
|
|
88
94
|
'pid',
|
|
89
95
|
'rid',
|
|
90
96
|
'ua',
|
|
97
|
+
'ip',
|
|
91
98
|
'user_id',
|
|
92
99
|
'sticky',
|
|
93
100
|
],
|
|
@@ -106,7 +113,14 @@ module.exports = class extends BaseRest {
|
|
|
106
113
|
users = await userModel.select(
|
|
107
114
|
{ objectId: ['IN', user_ids] },
|
|
108
115
|
{
|
|
109
|
-
field: [
|
|
116
|
+
field: [
|
|
117
|
+
'display_name',
|
|
118
|
+
'email',
|
|
119
|
+
'url',
|
|
120
|
+
'type',
|
|
121
|
+
'avatar',
|
|
122
|
+
'label',
|
|
123
|
+
],
|
|
110
124
|
}
|
|
111
125
|
);
|
|
112
126
|
}
|
|
@@ -186,7 +200,14 @@ module.exports = class extends BaseRest {
|
|
|
186
200
|
users = await userModel.select(
|
|
187
201
|
{ objectId: ['IN', user_ids] },
|
|
188
202
|
{
|
|
189
|
-
field: [
|
|
203
|
+
field: [
|
|
204
|
+
'display_name',
|
|
205
|
+
'email',
|
|
206
|
+
'url',
|
|
207
|
+
'type',
|
|
208
|
+
'avatar',
|
|
209
|
+
'label',
|
|
210
|
+
],
|
|
190
211
|
}
|
|
191
212
|
);
|
|
192
213
|
}
|
|
@@ -235,6 +256,7 @@ module.exports = class extends BaseRest {
|
|
|
235
256
|
'pid',
|
|
236
257
|
'rid',
|
|
237
258
|
'ua',
|
|
259
|
+
'ip',
|
|
238
260
|
'user_id',
|
|
239
261
|
'sticky',
|
|
240
262
|
],
|
|
@@ -307,7 +329,14 @@ module.exports = class extends BaseRest {
|
|
|
307
329
|
users = await userModel.select(
|
|
308
330
|
{ objectId: ['IN', user_ids] },
|
|
309
331
|
{
|
|
310
|
-
field: [
|
|
332
|
+
field: [
|
|
333
|
+
'display_name',
|
|
334
|
+
'email',
|
|
335
|
+
'url',
|
|
336
|
+
'type',
|
|
337
|
+
'avatar',
|
|
338
|
+
'label',
|
|
339
|
+
],
|
|
311
340
|
}
|
|
312
341
|
);
|
|
313
342
|
}
|
package/src/controller/user.js
CHANGED
|
@@ -11,6 +11,26 @@ module.exports = class extends BaseRest {
|
|
|
11
11
|
);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
async getAction() {
|
|
15
|
+
const { page, pageSize } = this.get();
|
|
16
|
+
|
|
17
|
+
const count = await this.modelInstance.count({});
|
|
18
|
+
const users = await this.modelInstance.select(
|
|
19
|
+
{},
|
|
20
|
+
{
|
|
21
|
+
desc: 'insertedAt',
|
|
22
|
+
limit: pageSize,
|
|
23
|
+
offset: Math.max((page - 1) * pageSize, 0),
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
return this.success({
|
|
27
|
+
page,
|
|
28
|
+
totalPages: Math.ceil(count / pageSize),
|
|
29
|
+
pageSize,
|
|
30
|
+
data: users,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
14
34
|
async postAction() {
|
|
15
35
|
const data = this.post();
|
|
16
36
|
const resp = await this.modelInstance.select({
|
|
@@ -92,12 +112,20 @@ module.exports = class extends BaseRest {
|
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
async putAction() {
|
|
95
|
-
const { display_name, url, avatar, password } = this.post();
|
|
115
|
+
const { display_name, url, avatar, password, type, label } = this.post();
|
|
96
116
|
const { objectId } = this.ctx.state.userInfo;
|
|
97
117
|
const twoFactorAuth = this.post('2fa');
|
|
98
118
|
|
|
99
119
|
const updateData = {};
|
|
100
120
|
|
|
121
|
+
if (this.id && type) {
|
|
122
|
+
updateData.type = type;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (think.isString(label)) {
|
|
126
|
+
updateData.label = label;
|
|
127
|
+
}
|
|
128
|
+
|
|
101
129
|
if (display_name) {
|
|
102
130
|
updateData.display_name = display_name;
|
|
103
131
|
}
|
|
@@ -130,7 +158,9 @@ module.exports = class extends BaseRest {
|
|
|
130
158
|
return this.success();
|
|
131
159
|
}
|
|
132
160
|
|
|
133
|
-
await this.modelInstance.update(updateData, {
|
|
161
|
+
await this.modelInstance.update(updateData, {
|
|
162
|
+
objectId: this.id || objectId,
|
|
163
|
+
});
|
|
134
164
|
|
|
135
165
|
return this.success();
|
|
136
166
|
}
|
package/src/extend/think.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
const ip2region = require('dy-node-ip2region');
|
|
2
|
+
const helper = require('think-helper');
|
|
1
3
|
const preventMessage = 'PREVENT_NEXT_PROCESS';
|
|
2
4
|
|
|
5
|
+
const regionSearch = ip2region.create();
|
|
6
|
+
|
|
3
7
|
module.exports = {
|
|
4
8
|
prevent() {
|
|
5
9
|
throw new Error(preventMessage);
|
|
@@ -18,4 +22,46 @@ module.exports = {
|
|
|
18
22
|
|
|
19
23
|
return -1;
|
|
20
24
|
},
|
|
25
|
+
promiseAllQueue(promises, taskNum) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const ret = [];
|
|
28
|
+
let index = 0;
|
|
29
|
+
let count = 0;
|
|
30
|
+
|
|
31
|
+
function runTask() {
|
|
32
|
+
const idx = index;
|
|
33
|
+
index += 1;
|
|
34
|
+
if (index > promises.length) {
|
|
35
|
+
return Promise.resolve();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return promises[idx].then((data) => {
|
|
39
|
+
ret[idx] = data;
|
|
40
|
+
count += 1;
|
|
41
|
+
if (count === promises.length) {
|
|
42
|
+
resolve(ret);
|
|
43
|
+
}
|
|
44
|
+
return runTask();
|
|
45
|
+
}, reject);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < taskNum; i++) {
|
|
49
|
+
runTask();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
async ip2region(ip, { depth = 1 }) {
|
|
54
|
+
if (!ip) return '';
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const search = helper.promisify(regionSearch.btreeSearch, regionSearch);
|
|
58
|
+
const { region } = await search(ip);
|
|
59
|
+
const [, , province, city, isp] = region.split('|');
|
|
60
|
+
const address = Array.from(new Set([province, city, isp]));
|
|
61
|
+
return address.slice(0, depth).join(' ');
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.log(e);
|
|
64
|
+
return '';
|
|
65
|
+
}
|
|
66
|
+
},
|
|
21
67
|
};
|
package/src/logic/base.js
CHANGED
|
@@ -8,6 +8,7 @@ module.exports = class extends think.Logic {
|
|
|
8
8
|
`storage/${this.config('storage')}`,
|
|
9
9
|
'Users'
|
|
10
10
|
);
|
|
11
|
+
this.id = this.getId();
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
async __before() {
|
|
@@ -89,4 +90,20 @@ module.exports = class extends think.Logic {
|
|
|
89
90
|
this.ctx.state.userInfo = userInfo;
|
|
90
91
|
this.ctx.state.token = token;
|
|
91
92
|
}
|
|
93
|
+
|
|
94
|
+
getId() {
|
|
95
|
+
const id = this.get('id');
|
|
96
|
+
|
|
97
|
+
if (id && (think.isString(id) || think.isNumber(id))) {
|
|
98
|
+
return id;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const last = decodeURIComponent(this.ctx.path.split('/').pop());
|
|
102
|
+
|
|
103
|
+
if (last !== this.resource && /^([a-z0-9]+,?)*$/i.test(last)) {
|
|
104
|
+
return last;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
92
109
|
};
|
package/src/logic/user.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
const Base = require('./base');
|
|
2
2
|
|
|
3
3
|
module.exports = class extends Base {
|
|
4
|
+
getAction() {
|
|
5
|
+
const { userInfo } = this.ctx.state;
|
|
6
|
+
if (think.isEmpty(userInfo) || userInfo.type !== 'administrator') {
|
|
7
|
+
return this.fail();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
this.rules = {
|
|
11
|
+
page: {
|
|
12
|
+
int: true,
|
|
13
|
+
default: 1,
|
|
14
|
+
},
|
|
15
|
+
pageSize: {
|
|
16
|
+
int: { max: 100 },
|
|
17
|
+
default: 10,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
4
22
|
/**
|
|
5
23
|
* @api {POST} /user user register
|
|
6
24
|
* @apiGroup User
|
|
@@ -30,9 +48,15 @@ module.exports = class extends Base {
|
|
|
30
48
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
31
49
|
*/
|
|
32
50
|
putAction() {
|
|
51
|
+
// you need login to update yourself profile
|
|
33
52
|
const { userInfo } = this.ctx.state;
|
|
34
53
|
if (think.isEmpty(userInfo)) {
|
|
35
54
|
return this.fail();
|
|
36
55
|
}
|
|
56
|
+
|
|
57
|
+
// you should be a administrator to update otherself info
|
|
58
|
+
if (this.id && userInfo.type !== 'administrator') {
|
|
59
|
+
return this.fail();
|
|
60
|
+
}
|
|
37
61
|
}
|
|
38
62
|
};
|