@waline/vercel 1.36.4 → 1.37.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/__tests__/xss.spec.js +8 -19
- package/development.js +1 -0
- package/index.js +4 -3
- package/package.json +17 -18
- package/src/config/adapter.js +9 -11
- package/src/config/config.js +4 -12
- package/src/config/extend.js +0 -6
- package/src/config/middleware.js +2 -5
- package/src/controller/article.js +5 -12
- package/src/controller/comment.js +33 -53
- package/src/controller/db.js +3 -9
- package/src/controller/oauth.js +8 -8
- package/src/controller/rest.js +1 -1
- package/src/controller/user/password.js +3 -12
- package/src/controller/user.js +18 -45
- package/src/controller/verification.js +3 -2
- package/src/extend/think.js +33 -23
- package/src/logic/base.js +31 -47
- package/src/logic/comment.js +7 -4
- package/src/logic/db.js +1 -1
- package/src/logic/token.js +2 -2
- package/src/middleware/dashboard.js +1 -0
- package/src/middleware/plugin.js +1 -1
- package/src/service/akismet.js +10 -3
- package/src/service/avatar.js +2 -4
- package/src/service/markdown/highlight.js +1 -1
- package/src/service/markdown/mathCommon.js +2 -8
- package/src/service/markdown/mathjax.js +1 -2
- package/src/service/markdown/utils.js +5 -5
- package/src/service/markdown/xss.js +5 -10
- package/src/service/notify.js +111 -135
- package/src/service/storage/base.js +2 -7
- package/src/service/storage/cloudbase.js +9 -7
- package/src/service/storage/github.js +39 -42
- package/src/service/storage/leancloud.js +41 -54
- package/src/service/storage/mongodb.js +11 -8
- package/src/service/storage/mysql.js +7 -13
- package/src/service/storage/postgresql.js +7 -11
- package/src/service/storage/deta.js +0 -310
package/__tests__/xss.spec.js
CHANGED
|
@@ -3,8 +3,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
3
3
|
|
|
4
4
|
import { sanitize } from '../src/service/markdown/xss';
|
|
5
5
|
|
|
6
|
-
const parser = (content) =>
|
|
7
|
-
sanitize(new MarkdownIt({ html: true }).render(content));
|
|
6
|
+
const parser = (content) => sanitize(new MarkdownIt({ html: true }).render(content));
|
|
8
7
|
|
|
9
8
|
describe('XSS test', () => {
|
|
10
9
|
it('Should render', () => {
|
|
@@ -36,20 +35,16 @@ Waline is a good framework. :money:
|
|
|
36
35
|
});
|
|
37
36
|
|
|
38
37
|
it('Should protect', () => {
|
|
39
|
-
expect(parser(`<img src="x" onerror="alert('img')">`)).toEqual(
|
|
40
|
-
'<img src="x">',
|
|
41
|
-
);
|
|
38
|
+
expect(parser(`<img src="x" onerror="alert('img')">`)).toEqual('<img src="x">');
|
|
42
39
|
expect(parser('<script>alert("hello world")</script>')).toEqual('');
|
|
43
40
|
|
|
44
41
|
expect(
|
|
45
|
-
parser(
|
|
46
|
-
'<p>Waline is <iframe//src=jaVa	script:alert(3)></iframe>awesome</p>',
|
|
47
|
-
),
|
|
42
|
+
parser('<p>Waline is <iframe//src=jaVa	script:alert(3)></iframe>awesome</p>'),
|
|
48
43
|
).toEqual('<p>Waline is awesome</p>');
|
|
49
44
|
|
|
50
|
-
expect(
|
|
51
|
-
|
|
52
|
-
)
|
|
45
|
+
expect(parser('<p>Waline is <iframe//src=jaVa	script:alert(3)>awesome</p>')).toEqual(
|
|
46
|
+
'<p>Waline is </p>',
|
|
47
|
+
);
|
|
53
48
|
});
|
|
54
49
|
|
|
55
50
|
it('Should resolve unmatching html tags', () => {
|
|
@@ -78,11 +73,7 @@ Waline is a good framework. :money:
|
|
|
78
73
|
expect(parser('[link](https://example.com)')).toEqual(
|
|
79
74
|
'<p><a href="https://example.com" target="_blank" rel="nofollow noreferrer noopener">link</a></p>\n',
|
|
80
75
|
);
|
|
81
|
-
expect(
|
|
82
|
-
parser(
|
|
83
|
-
'<p><a href="https://example.com" rel="opener prefetch">link</a></p>',
|
|
84
|
-
),
|
|
85
|
-
).toEqual(
|
|
76
|
+
expect(parser('<p><a href="https://example.com" rel="opener prefetch">link</a></p>')).toEqual(
|
|
86
77
|
'<p><a href="https://example.com" rel="nofollow noreferrer noopener" target="_blank">link</a></p>',
|
|
87
78
|
);
|
|
88
79
|
});
|
|
@@ -94,9 +85,7 @@ Waline is a good framework. :money:
|
|
|
94
85
|
|
|
95
86
|
it('Should forbid style', () => {
|
|
96
87
|
expect(
|
|
97
|
-
parser(
|
|
98
|
-
'<div style="position:fixed;top:0;left:0;width:100vh;height:100vh;">广告文字</div>',
|
|
99
|
-
),
|
|
88
|
+
parser('<div style="position:fixed;top:0;left:0;width:100vh;height:100vh;">广告文字</div>'),
|
|
100
89
|
).toEqual('<div>广告文字</div>');
|
|
101
90
|
expect(
|
|
102
91
|
parser(
|
package/development.js
CHANGED
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('node:path');
|
|
|
4
4
|
const Application = require('thinkjs');
|
|
5
5
|
const Loader = require('thinkjs/lib/loader');
|
|
6
6
|
|
|
7
|
-
module.exports = function (configParams = {}) {
|
|
7
|
+
module.exports = function main(configParams = {}) {
|
|
8
8
|
const { env, ...config } = configParams;
|
|
9
9
|
|
|
10
10
|
const app = new Application({
|
|
@@ -20,10 +20,11 @@ module.exports = function (configParams = {}) {
|
|
|
20
20
|
|
|
21
21
|
loader.loadAll('worker');
|
|
22
22
|
|
|
23
|
+
// oxlint-disable-next-line func-names
|
|
23
24
|
return function (req, res) {
|
|
24
|
-
for (const
|
|
25
|
+
for (const key in config) {
|
|
25
26
|
// fix https://github.com/walinejs/waline/issues/2649 with alias model config name
|
|
26
|
-
think.config(
|
|
27
|
+
think.config(key === 'model' ? 'customModel' : key, config[key]);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
return think
|
package/package.json
CHANGED
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waline/vercel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.37.0",
|
|
4
4
|
"description": "vercel server for waline comment system",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"vercel",
|
|
6
|
+
"blog",
|
|
8
7
|
"comment",
|
|
9
|
-
"
|
|
8
|
+
"vercel",
|
|
9
|
+
"waline"
|
|
10
10
|
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "lizheming <i@imnerd.org>",
|
|
11
13
|
"repository": {
|
|
12
14
|
"url": "https://github.com/walinejs/waline",
|
|
13
15
|
"directory": "packages/server"
|
|
14
16
|
},
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"provenance": true
|
|
19
|
+
},
|
|
17
20
|
"scripts": {
|
|
18
21
|
"dev": "node development.js 9090"
|
|
19
22
|
},
|
|
20
23
|
"dependencies": {
|
|
21
|
-
"@cloudbase/node-sdk": "^3.
|
|
24
|
+
"@cloudbase/node-sdk": "^3.18.0",
|
|
22
25
|
"@koa/cors": "^5.0.0",
|
|
23
26
|
"@mdit/plugin-katex": "0.23.4-cjs.0",
|
|
24
27
|
"@mdit/plugin-mathjax": "0.23.4-cjs.0",
|
|
25
28
|
"@mdit/plugin-sub": "0.22.5-cjs.0",
|
|
26
29
|
"@mdit/plugin-sup": "0.22.5-cjs.0",
|
|
27
30
|
"akismet": "^2.0.7",
|
|
28
|
-
"
|
|
29
|
-
"dompurify": "^3.3.0",
|
|
30
|
-
"dy-node-ip2region": "^1.0.1",
|
|
31
|
+
"dompurify": "^3.3.1",
|
|
31
32
|
"fast-csv": "^5.0.5",
|
|
32
33
|
"form-data": "^4.0.5",
|
|
34
|
+
"ip2region": "^2.3.0",
|
|
33
35
|
"jsdom": "^19.0.0",
|
|
34
|
-
"jsonwebtoken": "^9.0.
|
|
36
|
+
"jsonwebtoken": "^9.0.3",
|
|
35
37
|
"koa-compose": "^4.1.0",
|
|
36
38
|
"leancloud-storage": "^4.15.2",
|
|
37
|
-
"markdown-it": "^14.1.
|
|
39
|
+
"markdown-it": "^14.1.1",
|
|
38
40
|
"markdown-it-emoji": "^3.0.0",
|
|
39
41
|
"mathjax-full": "^3.2.2",
|
|
40
|
-
"nodemailer": "^
|
|
42
|
+
"nodemailer": "^8.0.1",
|
|
41
43
|
"nunjucks": "^3.2.4",
|
|
42
44
|
"phpass": "^0.1.1",
|
|
43
45
|
"prismjs": "^1.30.0",
|
|
@@ -52,16 +54,13 @@
|
|
|
52
54
|
"think-mongo": "^2.2.1",
|
|
53
55
|
"think-router-rest": "^1.0.5",
|
|
54
56
|
"thinkjs": "4.0.0-alpha.0",
|
|
55
|
-
"ua-parser-js": "^2.0.
|
|
57
|
+
"ua-parser-js": "^2.0.9"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
58
|
-
"dotenv": "17.2.
|
|
60
|
+
"dotenv": "17.2.4",
|
|
59
61
|
"think-watcher": "3.0.4"
|
|
60
62
|
},
|
|
61
63
|
"engines": {
|
|
62
64
|
"node": ">=20"
|
|
63
|
-
},
|
|
64
|
-
"publishConfig": {
|
|
65
|
-
"provenance": true
|
|
66
65
|
}
|
|
67
66
|
}
|
package/src/config/adapter.js
CHANGED
|
@@ -6,9 +6,10 @@ const Postgresql = require('think-model-postgresql');
|
|
|
6
6
|
let Sqlite;
|
|
7
7
|
|
|
8
8
|
try {
|
|
9
|
+
// oxlint-disable-next-line node/global-require
|
|
9
10
|
Sqlite = require('think-model-sqlite');
|
|
10
11
|
} catch (err) {
|
|
11
|
-
//
|
|
12
|
+
// oxlint-disable-next-line typescript/no-extraneous-class
|
|
12
13
|
Sqlite = class {};
|
|
13
14
|
console.log(err);
|
|
14
15
|
}
|
|
@@ -65,11 +66,11 @@ if (MONGO_AUTHSOURCE) mongoOpt.authSource = MONGO_AUTHSOURCE;
|
|
|
65
66
|
if (MONGO_DB) {
|
|
66
67
|
type = 'mongo';
|
|
67
68
|
for (const envKeys in process.env) {
|
|
68
|
-
if (
|
|
69
|
+
if (envKeys.includes('MONGO_OPT_')) {
|
|
69
70
|
const key = envKeys
|
|
70
71
|
.slice(10)
|
|
71
72
|
.toLocaleLowerCase()
|
|
72
|
-
.
|
|
73
|
+
.replaceAll(/_([a-z])/g, (_, b) => b.toUpperCase());
|
|
73
74
|
|
|
74
75
|
mongoOpt[key] = process.env[envKeys];
|
|
75
76
|
}
|
|
@@ -88,7 +89,9 @@ exports.model = {
|
|
|
88
89
|
type,
|
|
89
90
|
common: {
|
|
90
91
|
logSql: true,
|
|
91
|
-
logger: (msg) =>
|
|
92
|
+
logger: (msg) => {
|
|
93
|
+
think.logger.info(msg);
|
|
94
|
+
},
|
|
92
95
|
},
|
|
93
96
|
|
|
94
97
|
mongo: {
|
|
@@ -97,11 +100,7 @@ exports.model = {
|
|
|
97
100
|
? JSON.parse(MONGO_HOST)
|
|
98
101
|
: MONGO_HOST
|
|
99
102
|
: '127.0.0.1',
|
|
100
|
-
port: MONGO_PORT
|
|
101
|
-
? MONGO_PORT.startsWith('[')
|
|
102
|
-
? JSON.parse(MONGO_PORT)
|
|
103
|
-
: MONGO_PORT
|
|
104
|
-
: 27017,
|
|
103
|
+
port: MONGO_PORT ? (MONGO_PORT.startsWith('[') ? JSON.parse(MONGO_PORT) : MONGO_PORT) : 27017,
|
|
105
104
|
user: MONGO_USER,
|
|
106
105
|
password: MONGO_PASSWORD,
|
|
107
106
|
database: MONGO_DB,
|
|
@@ -118,8 +117,7 @@ exports.model = {
|
|
|
118
117
|
connectionLimit: 1,
|
|
119
118
|
prefix: PG_PREFIX || POSTGRES_PREFIX || 'wl_',
|
|
120
119
|
ssl:
|
|
121
|
-
(PG_SSL || POSTGRES_SSL)
|
|
122
|
-
POSTGRES_URL?.includes('sslmode=require')
|
|
120
|
+
(PG_SSL || POSTGRES_SSL) === 'true' || POSTGRES_URL?.includes('sslmode=require')
|
|
123
121
|
? {
|
|
124
122
|
rejectUnauthorized: false,
|
|
125
123
|
}
|
package/src/config/config.js
CHANGED
|
@@ -21,7 +21,6 @@ const {
|
|
|
21
21
|
DISABLE_REGION,
|
|
22
22
|
AVATAR_PROXY,
|
|
23
23
|
GITHUB_TOKEN,
|
|
24
|
-
DETA_PROJECT_KEY,
|
|
25
24
|
OAUTH_URL,
|
|
26
25
|
|
|
27
26
|
MARKDOWN_CONFIG = '{}',
|
|
@@ -74,9 +73,6 @@ if (LEAN_KEY) {
|
|
|
74
73
|
} else if (think.env === 'cloudbase' || TCB_ENV) {
|
|
75
74
|
storage = 'cloudbase';
|
|
76
75
|
jwtKey = jwtKey || TENCENTCLOUD_SECRETKEY || TCB_KEY || TCB_ENV;
|
|
77
|
-
} else if (DETA_PROJECT_KEY) {
|
|
78
|
-
storage = 'deta';
|
|
79
|
-
jwtKey = jwtKey || DETA_PROJECT_KEY;
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
if (think.env === 'cloudbase' && storage === 'sqlite') {
|
|
@@ -85,8 +81,7 @@ if (think.env === 'cloudbase' && storage === 'sqlite') {
|
|
|
85
81
|
|
|
86
82
|
const forbiddenWords = FORBIDDEN_WORDS ? FORBIDDEN_WORDS.split(/\s*,\s*/) : [];
|
|
87
83
|
|
|
88
|
-
const isFalse = (content) =>
|
|
89
|
-
content && ['0', 'false'].includes(content.toLowerCase());
|
|
84
|
+
const isFalse = (content) => content && ['0', 'false'].includes(content.toLowerCase());
|
|
90
85
|
|
|
91
86
|
const markdown = {
|
|
92
87
|
config: JSON.parse(MARKDOWN_CONFIG),
|
|
@@ -105,7 +100,7 @@ if (isFalse(MARKDOWN_HIGHLIGHT)) markdown.config.highlight = false;
|
|
|
105
100
|
let avatarProxy = '';
|
|
106
101
|
|
|
107
102
|
if (AVATAR_PROXY) {
|
|
108
|
-
avatarProxy =
|
|
103
|
+
avatarProxy = isFalse(AVATAR_PROXY) ? '' : AVATAR_PROXY;
|
|
109
104
|
}
|
|
110
105
|
|
|
111
106
|
const oauthUrl = OAUTH_URL || 'https://oauth.lithub.cc';
|
|
@@ -116,13 +111,10 @@ module.exports = {
|
|
|
116
111
|
jwtKey,
|
|
117
112
|
forbiddenWords,
|
|
118
113
|
disallowIPList: [],
|
|
119
|
-
secureDomains: SECURE_DOMAINS ? SECURE_DOMAINS.split(/\s*,\s*/) :
|
|
114
|
+
secureDomains: SECURE_DOMAINS ? SECURE_DOMAINS.split(/\s*,\s*/) : null,
|
|
120
115
|
disableUserAgent: DISABLE_USERAGENT && !isFalse(DISABLE_USERAGENT),
|
|
121
116
|
disableRegion: DISABLE_REGION && !isFalse(DISABLE_REGION),
|
|
122
|
-
levels:
|
|
123
|
-
!LEVELS || isFalse(LEVELS)
|
|
124
|
-
? false
|
|
125
|
-
: LEVELS.split(/\s*,\s*/).map((v) => Number(v)),
|
|
117
|
+
levels: !LEVELS || isFalse(LEVELS) ? false : LEVELS.split(/\s*,\s*/).map(Number),
|
|
126
118
|
|
|
127
119
|
audit: COMMENT_AUDIT && !isFalse(COMMENT_AUDIT),
|
|
128
120
|
avatarProxy,
|
package/src/config/extend.js
CHANGED
|
@@ -3,8 +3,6 @@ const Mongo = require('think-mongo');
|
|
|
3
3
|
|
|
4
4
|
const { isNetlify, netlifyFunctionPrefix } = require('./netlify');
|
|
5
5
|
|
|
6
|
-
const isDeta = think.env === 'deta' || process.env.DETA_RUNTIME === 'true';
|
|
7
|
-
|
|
8
6
|
module.exports = [
|
|
9
7
|
Model(think.app),
|
|
10
8
|
Mongo(think.app),
|
|
@@ -23,10 +21,6 @@ module.exports = [
|
|
|
23
21
|
return `${protocol}://${host}${netlifyFunctionPrefix}`;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
if (isDeta) {
|
|
27
|
-
return `https://${host}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
24
|
return `${protocol}://${host}`;
|
|
31
25
|
},
|
|
32
26
|
async webhook(type, data) {
|
package/src/config/middleware.js
CHANGED
|
@@ -5,9 +5,7 @@ const { isNetlify, netlifyFunctionPrefix } = require('./netlify.js');
|
|
|
5
5
|
|
|
6
6
|
const isDev = think.env === 'development';
|
|
7
7
|
const isTcb = think.env === 'cloudbase';
|
|
8
|
-
const
|
|
9
|
-
const isAliyunFC =
|
|
10
|
-
think.env === 'aliyun-fc' || Boolean(process.env.FC_RUNTIME_VERSION);
|
|
8
|
+
const isAliyunFC = think.env === 'aliyun-fc' || Boolean(process.env.FC_RUNTIME_VERSION);
|
|
11
9
|
|
|
12
10
|
module.exports = [
|
|
13
11
|
{
|
|
@@ -26,8 +24,7 @@ module.exports = [
|
|
|
26
24
|
options: {
|
|
27
25
|
logRequest: isDev,
|
|
28
26
|
sendResponseTime: isDev,
|
|
29
|
-
requestTimeoutCallback:
|
|
30
|
-
isTcb || isDeta || isAliyunFC || isNetlify ? false : () => {},
|
|
27
|
+
requestTimeoutCallback: isTcb || isAliyunFC || isNetlify ? false : () => {},
|
|
31
28
|
},
|
|
32
29
|
},
|
|
33
30
|
|
|
@@ -11,14 +11,14 @@ module.exports = class extends BaseRest {
|
|
|
11
11
|
const { deprecated } = this.ctx.state;
|
|
12
12
|
|
|
13
13
|
// path is required
|
|
14
|
-
if (!Array.isArray(path) ||
|
|
14
|
+
if (!Array.isArray(path) || path.length === 0) {
|
|
15
15
|
return this.jsonOrSuccess(0);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const resp = await this.modelInstance.select({ url: ['IN', path] });
|
|
19
19
|
|
|
20
20
|
if (think.isEmpty(resp)) {
|
|
21
|
-
const counters =
|
|
21
|
+
const counters = Array(path.length).fill(
|
|
22
22
|
type.length === 1 && deprecated
|
|
23
23
|
? 0
|
|
24
24
|
: type.reduce((o, field) => {
|
|
@@ -38,9 +38,7 @@ module.exports = class extends BaseRest {
|
|
|
38
38
|
// - single path and multiple type: [{[type]: 0}]
|
|
39
39
|
// - multiple path and single type: [{[type]: 0}]
|
|
40
40
|
// - multiple path and multiple type: [{[type]: 0}]
|
|
41
|
-
return this.jsonOrSuccess(
|
|
42
|
-
path.length === 1 && deprecated ? counters[0] : counters,
|
|
43
|
-
);
|
|
41
|
+
return this.jsonOrSuccess(path.length === 1 && deprecated ? counters[0] : counters);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
const respObj = resp.reduce((o, n) => {
|
|
@@ -89,17 +87,12 @@ module.exports = class extends BaseRest {
|
|
|
89
87
|
|
|
90
88
|
const ret = await this.modelInstance.update(
|
|
91
89
|
(counter) => ({
|
|
92
|
-
[type]:
|
|
93
|
-
action === 'desc'
|
|
94
|
-
? (counter[type] || 1) - 1
|
|
95
|
-
: (counter[type] || 0) + 1,
|
|
90
|
+
[type]: action === 'desc' ? (counter[type] || 1) - 1 : (counter[type] || 0) + 1,
|
|
96
91
|
updatedAt: new Date(),
|
|
97
92
|
}),
|
|
98
93
|
{ objectId: ['IN', resp.map(({ objectId }) => objectId)] },
|
|
99
94
|
);
|
|
100
95
|
|
|
101
|
-
return this.jsonOrSuccess(
|
|
102
|
-
deprecated ? ret[0][type] : [{ [type]: ret[0][type] }],
|
|
103
|
-
);
|
|
96
|
+
return this.jsonOrSuccess(deprecated ? ret[0][type] : [{ [type]: ret[0][type] }]);
|
|
104
97
|
}
|
|
105
98
|
};
|
|
@@ -4,12 +4,13 @@ const { getMarkdownParser } = require('../service/markdown/index.js');
|
|
|
4
4
|
|
|
5
5
|
const markdownParser = getMarkdownParser();
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// oxlint-disable-next-line max-statements
|
|
8
|
+
const formatCmt = async (
|
|
8
9
|
{ ua, ip, ...comment },
|
|
9
10
|
users = [],
|
|
10
11
|
{ avatarProxy, deprecated },
|
|
11
12
|
loginUser,
|
|
12
|
-
) {
|
|
13
|
+
) => {
|
|
13
14
|
ua = think.uaParser(ua);
|
|
14
15
|
if (!think.config('disableUserAgent')) {
|
|
15
16
|
comment.browser = `${ua.browser.name || ''}${(ua.browser.version || '')
|
|
@@ -29,13 +30,11 @@ async function formatCmt(
|
|
|
29
30
|
comment.label = user.label;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
const avatarUrl = user?.avatar
|
|
33
|
-
? user.avatar
|
|
34
|
-
: await think.service('avatar').stringify(comment);
|
|
33
|
+
const avatarUrl = user?.avatar ? user.avatar : await think.service('avatar').stringify(comment);
|
|
35
34
|
|
|
36
35
|
comment.avatar =
|
|
37
36
|
avatarProxy && !avatarUrl.includes(avatarProxy)
|
|
38
|
-
? avatarProxy
|
|
37
|
+
? `${avatarProxy}?url=${encodeURIComponent(avatarUrl)}`
|
|
39
38
|
: avatarUrl;
|
|
40
39
|
|
|
41
40
|
const isAdmin = loginUser && loginUser.type === 'administrator';
|
|
@@ -69,7 +68,7 @@ async function formatCmt(
|
|
|
69
68
|
delete comment.updatedAt;
|
|
70
69
|
|
|
71
70
|
return comment;
|
|
72
|
-
}
|
|
71
|
+
};
|
|
73
72
|
|
|
74
73
|
module.exports = class extends BaseRest {
|
|
75
74
|
constructor(ctx) {
|
|
@@ -81,12 +80,12 @@ module.exports = class extends BaseRest {
|
|
|
81
80
|
const { type } = this.get();
|
|
82
81
|
|
|
83
82
|
const fnMap = {
|
|
84
|
-
recent: this
|
|
85
|
-
count: this
|
|
86
|
-
list: this
|
|
83
|
+
recent: this['getRecentCommentList'],
|
|
84
|
+
count: this['getCommentCount'],
|
|
85
|
+
list: this['getAdminCommentList'],
|
|
87
86
|
};
|
|
88
87
|
|
|
89
|
-
const fn = fnMap[type] || this
|
|
88
|
+
const fn = fnMap[type] || this['getCommentList'];
|
|
90
89
|
const data = await fn.call(this);
|
|
91
90
|
|
|
92
91
|
return this.jsonOrSuccess(data);
|
|
@@ -124,7 +123,7 @@ module.exports = class extends BaseRest {
|
|
|
124
123
|
|
|
125
124
|
if (
|
|
126
125
|
think.isArray(disallowIPList) &&
|
|
127
|
-
disallowIPList.length &&
|
|
126
|
+
disallowIPList.length > 0 &&
|
|
128
127
|
disallowIPList.includes(data.ip)
|
|
129
128
|
) {
|
|
130
129
|
think.logger.debug(`Comment IP ${data.ip} is in disallowIPList`);
|
|
@@ -144,9 +143,7 @@ module.exports = class extends BaseRest {
|
|
|
144
143
|
});
|
|
145
144
|
|
|
146
145
|
if (!think.isEmpty(duplicate)) {
|
|
147
|
-
think.logger.debug(
|
|
148
|
-
'The comment author had post same comment content before',
|
|
149
|
-
);
|
|
146
|
+
think.logger.debug('The comment author had post same comment content before');
|
|
150
147
|
|
|
151
148
|
return this.fail(this.locale('Duplicate Content'));
|
|
152
149
|
}
|
|
@@ -175,9 +172,9 @@ module.exports = class extends BaseRest {
|
|
|
175
172
|
think.logger.debug(`Comment initial status is ${data.status}`);
|
|
176
173
|
|
|
177
174
|
if (data.status === 'approved') {
|
|
178
|
-
const spam = await akismet(data, this.ctx.serverURL).catch((err) =>
|
|
179
|
-
console.log(err)
|
|
180
|
-
); // ignore akismet error
|
|
175
|
+
const spam = await akismet(data, this.ctx.serverURL).catch((err) => {
|
|
176
|
+
console.log(err);
|
|
177
|
+
}); // ignore akismet error
|
|
181
178
|
|
|
182
179
|
if (spam === true) {
|
|
183
180
|
data.status = 'spam';
|
|
@@ -255,9 +252,7 @@ module.exports = class extends BaseRest {
|
|
|
255
252
|
|
|
256
253
|
await notify.run(
|
|
257
254
|
{ ...cmtReturn, mail: resp.mail, rawComment: comment },
|
|
258
|
-
parentReturn
|
|
259
|
-
? { ...parentReturn, mail: parentComment.mail }
|
|
260
|
-
: undefined,
|
|
255
|
+
parentReturn ? { ...parentReturn, mail: parentComment.mail } : undefined,
|
|
261
256
|
);
|
|
262
257
|
}
|
|
263
258
|
|
|
@@ -280,7 +275,7 @@ module.exports = class extends BaseRest {
|
|
|
280
275
|
async putAction() {
|
|
281
276
|
const { userInfo } = this.ctx.state;
|
|
282
277
|
const isAdmin = userInfo.type === 'administrator';
|
|
283
|
-
|
|
278
|
+
const data = isAdmin ? this.post() : this.post('comment,like');
|
|
284
279
|
let oldData = await this.modelInstance.select({ objectId: this.id });
|
|
285
280
|
|
|
286
281
|
if (think.isEmpty(oldData) || think.isEmpty(data)) {
|
|
@@ -292,8 +287,7 @@ module.exports = class extends BaseRest {
|
|
|
292
287
|
const likeIncMax = this.config('LIKE_INC_MAX') || 1;
|
|
293
288
|
|
|
294
289
|
data.like =
|
|
295
|
-
(Number(oldData.like) || 0) +
|
|
296
|
-
(data.like ? Math.ceil(Math.random() * likeIncMax) : -1);
|
|
290
|
+
(Number(oldData.like) || 0) + (data.like ? Math.ceil(Math.random() * likeIncMax) : -1);
|
|
297
291
|
data.like = Math.max(data.like, 0);
|
|
298
292
|
}
|
|
299
293
|
|
|
@@ -325,11 +319,7 @@ module.exports = class extends BaseRest {
|
|
|
325
319
|
userInfo,
|
|
326
320
|
);
|
|
327
321
|
|
|
328
|
-
if (
|
|
329
|
-
oldData.status === 'waiting' &&
|
|
330
|
-
data.status === 'approved' &&
|
|
331
|
-
oldData.pid
|
|
332
|
-
) {
|
|
322
|
+
if (oldData.status === 'waiting' && data.status === 'approved' && oldData.pid) {
|
|
333
323
|
let pComment = await this.modelInstance.select({
|
|
334
324
|
objectId: oldData.pid,
|
|
335
325
|
});
|
|
@@ -390,7 +380,7 @@ module.exports = class extends BaseRest {
|
|
|
390
380
|
const { path: url, page, pageSize, sortBy } = this.get();
|
|
391
381
|
const where = { url };
|
|
392
382
|
|
|
393
|
-
if (think.isEmpty(userInfo)
|
|
383
|
+
if (think.isEmpty(userInfo)) {
|
|
394
384
|
where.status = ['NOT IN', ['waiting', 'spam']];
|
|
395
385
|
} else if (userInfo.type !== 'administrator') {
|
|
396
386
|
where._complex = {
|
|
@@ -462,9 +452,7 @@ module.exports = class extends BaseRest {
|
|
|
462
452
|
rootComments.forEach(({ objectId }) => {
|
|
463
453
|
rootIds[objectId] = true;
|
|
464
454
|
});
|
|
465
|
-
comments = comments.filter(
|
|
466
|
-
(cmt) => rootIds[cmt.objectId] || rootIds[cmt.rid],
|
|
467
|
-
);
|
|
455
|
+
comments = comments.filter((cmt) => rootIds[cmt.objectId] || rootIds[cmt.rid]);
|
|
468
456
|
} else {
|
|
469
457
|
comments = await this.modelInstance.select(
|
|
470
458
|
{ ...where, rid: undefined },
|
|
@@ -488,12 +476,10 @@ module.exports = class extends BaseRest {
|
|
|
488
476
|
}
|
|
489
477
|
|
|
490
478
|
const userModel = this.getModel('Users');
|
|
491
|
-
const user_ids =
|
|
492
|
-
new Set(comments.map(({ user_id }) => user_id).filter((v) => v)),
|
|
493
|
-
);
|
|
479
|
+
const user_ids = [...new Set(comments.map(({ user_id }) => user_id).filter((v) => v))];
|
|
494
480
|
let users = [];
|
|
495
481
|
|
|
496
|
-
if (user_ids.length) {
|
|
482
|
+
if (user_ids.length > 0) {
|
|
497
483
|
users = await userModel.select(
|
|
498
484
|
{ objectId: ['IN', user_ids] },
|
|
499
485
|
{
|
|
@@ -508,14 +494,12 @@ module.exports = class extends BaseRest {
|
|
|
508
494
|
_complex: {},
|
|
509
495
|
};
|
|
510
496
|
|
|
511
|
-
if (user_ids.length) {
|
|
497
|
+
if (user_ids.length > 0) {
|
|
512
498
|
countWhere._complex.user_id = ['IN', user_ids];
|
|
513
499
|
}
|
|
514
|
-
const mails =
|
|
515
|
-
new Set(comments.map(({ mail }) => mail).filter((v) => v)),
|
|
516
|
-
);
|
|
500
|
+
const mails = [...new Set(comments.map(({ mail }) => mail).filter((v) => v))];
|
|
517
501
|
|
|
518
|
-
if (mails.length) {
|
|
502
|
+
if (mails.length > 0) {
|
|
519
503
|
countWhere._complex.mail = ['IN', mails];
|
|
520
504
|
}
|
|
521
505
|
if (!think.isEmpty(countWhere._complex)) {
|
|
@@ -629,13 +613,11 @@ module.exports = class extends BaseRest {
|
|
|
629
613
|
});
|
|
630
614
|
|
|
631
615
|
const userModel = this.getModel('Users');
|
|
632
|
-
const user_ids =
|
|
633
|
-
new Set(comments.map(({ user_id }) => user_id).filter((v) => v)),
|
|
634
|
-
);
|
|
616
|
+
const user_ids = [...new Set(comments.map(({ user_id }) => user_id).filter((v) => v))];
|
|
635
617
|
|
|
636
618
|
let users = [];
|
|
637
619
|
|
|
638
|
-
if (user_ids.length) {
|
|
620
|
+
if (user_ids.length > 0) {
|
|
639
621
|
users = await userModel.select(
|
|
640
622
|
{ objectId: ['IN', user_ids] },
|
|
641
623
|
{
|
|
@@ -668,7 +650,7 @@ module.exports = class extends BaseRest {
|
|
|
668
650
|
const { userInfo } = this.ctx.state;
|
|
669
651
|
const where = {};
|
|
670
652
|
|
|
671
|
-
if (think.isEmpty(userInfo)
|
|
653
|
+
if (think.isEmpty(userInfo)) {
|
|
672
654
|
where.status = ['NOT IN', ['waiting', 'spam']];
|
|
673
655
|
} else {
|
|
674
656
|
where._complex = {
|
|
@@ -700,13 +682,11 @@ module.exports = class extends BaseRest {
|
|
|
700
682
|
});
|
|
701
683
|
|
|
702
684
|
const userModel = this.getModel('Users');
|
|
703
|
-
const user_ids =
|
|
704
|
-
new Set(comments.map(({ user_id }) => user_id).filter((v) => v)),
|
|
705
|
-
);
|
|
685
|
+
const user_ids = [...new Set(comments.map(({ user_id }) => user_id).filter((v) => v))];
|
|
706
686
|
|
|
707
687
|
let users = [];
|
|
708
688
|
|
|
709
|
-
if (user_ids.length) {
|
|
689
|
+
if (user_ids.length > 0) {
|
|
710
690
|
users = await userModel.select(
|
|
711
691
|
{ objectId: ['IN', user_ids] },
|
|
712
692
|
{
|
|
@@ -730,9 +710,9 @@ module.exports = class extends BaseRest {
|
|
|
730
710
|
async getCommentCount() {
|
|
731
711
|
const { url } = this.get();
|
|
732
712
|
const { userInfo } = this.ctx.state;
|
|
733
|
-
const where = Array.isArray(url) && url.length ? { url: ['IN', url] } : {};
|
|
713
|
+
const where = Array.isArray(url) && url.length > 0 ? { url: ['IN', url] } : {};
|
|
734
714
|
|
|
735
|
-
if (think.isEmpty(userInfo)
|
|
715
|
+
if (think.isEmpty(userInfo)) {
|
|
736
716
|
where.status = ['NOT IN', ['waiting', 'spam']];
|
|
737
717
|
} else {
|
|
738
718
|
where._complex = {
|
package/src/controller/db.js
CHANGED
|
@@ -38,15 +38,9 @@ module.exports = class extends BaseRest {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (storage === 'mysql') {
|
|
41
|
-
if (item.insertedAt)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'YYYY-MM-DD HH:mm:ss',
|
|
45
|
-
);
|
|
46
|
-
if (item.createdAt)
|
|
47
|
-
item.createdAt = think.datetime(item.createdAt, 'YYYY-MM-DD HH:mm:ss');
|
|
48
|
-
if (item.updatedAt)
|
|
49
|
-
item.updatedAt = think.datetime(item.updatedAt, 'YYYY-MM-DD HH:mm:ss');
|
|
41
|
+
if (item.insertedAt) item.insertedAt = think.datetime(item.insertedAt, 'YYYY-MM-DD HH:mm:ss');
|
|
42
|
+
if (item.createdAt) item.createdAt = think.datetime(item.createdAt, 'YYYY-MM-DD HH:mm:ss');
|
|
43
|
+
if (item.updatedAt) item.updatedAt = think.datetime(item.updatedAt, 'YYYY-MM-DD HH:mm:ss');
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
delete item.objectId;
|
package/src/controller/oauth.js
CHANGED
|
@@ -10,8 +10,7 @@ module.exports = class extends think.Controller {
|
|
|
10
10
|
const { code, oauth_verifier, oauth_token, type, redirect } = this.get();
|
|
11
11
|
const { oauthUrl } = this.config();
|
|
12
12
|
|
|
13
|
-
const hasCode =
|
|
14
|
-
type === 'twitter' ? oauth_token && oauth_verifier : Boolean(code);
|
|
13
|
+
const hasCode = type === 'twitter' ? oauth_token && oauth_verifier : Boolean(code);
|
|
15
14
|
|
|
16
15
|
if (!hasCode) {
|
|
17
16
|
const { serverURL } = this.ctx;
|
|
@@ -20,12 +19,13 @@ module.exports = class extends think.Controller {
|
|
|
20
19
|
type,
|
|
21
20
|
});
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
this.redirect(
|
|
24
23
|
think.buildUrl(`${oauthUrl}/${type}`, {
|
|
25
24
|
redirect: redirectUrl,
|
|
26
25
|
state: this.ctx.state.token || '',
|
|
27
26
|
}),
|
|
28
27
|
);
|
|
28
|
+
return;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -65,7 +65,8 @@ module.exports = class extends think.Controller {
|
|
|
65
65
|
const token = jwt.sign(userBySocial[0].objectId, this.config('jwtKey'));
|
|
66
66
|
|
|
67
67
|
if (redirect) {
|
|
68
|
-
|
|
68
|
+
this.redirect(think.buildUrl(redirect, { token }));
|
|
69
|
+
return;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
return this.success();
|
|
@@ -85,7 +86,8 @@ module.exports = class extends think.Controller {
|
|
|
85
86
|
objectId: current.objectId,
|
|
86
87
|
});
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
this.redirect('/ui/profile');
|
|
90
|
+
return;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
// when user has not login, then we create account by the social type!
|
|
@@ -109,8 +111,6 @@ module.exports = class extends think.Controller {
|
|
|
109
111
|
// and then generate token!
|
|
110
112
|
const token = jwt.sign(user.objectId, this.config('jwtKey'));
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
redirect + (redirect.includes('?') ? '&' : '?') + 'token=' + token,
|
|
114
|
-
);
|
|
114
|
+
this.redirect(redirect + (redirect.includes('?') ? '&' : '?') + 'token=' + token);
|
|
115
115
|
}
|
|
116
116
|
};
|