@waline/vercel 1.36.5 → 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/development.js +1 -0
- package/index.js +4 -3
- package/package.json +2 -2
- package/src/config/adapter.js +8 -5
- package/src/config/config.js +3 -3
- package/src/controller/article.js +2 -2
- package/src/controller/comment.js +24 -21
- package/src/controller/oauth.js +7 -4
- package/src/controller/rest.js +1 -1
- package/src/controller/user.js +9 -8
- package/src/controller/verification.js +3 -2
- package/src/extend/think.js +33 -19
- package/src/logic/base.js +25 -23
- 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 +1 -1
- package/src/service/markdown/highlight.js +1 -1
- package/src/service/markdown/utils.js +5 -5
- package/src/service/markdown/xss.js +5 -10
- package/src/service/notify.js +56 -54
- package/src/service/storage/base.js +1 -1
- package/src/service/storage/cloudbase.js +9 -7
- package/src/service/storage/github.js +24 -18
- package/src/service/storage/leancloud.js +33 -26
- package/src/service/storage/mongodb.js +10 -6
- package/src/service/storage/mysql.js +4 -4
- package/src/service/storage/postgresql.js +5 -5
package/src/logic/comment.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const Base = require('./base.js');
|
|
2
2
|
|
|
3
|
-
module.exports = class extends Base {
|
|
3
|
+
module.exports = class CommentLogic extends Base {
|
|
4
4
|
checkAdmin() {
|
|
5
5
|
const { userInfo } = this.ctx.state;
|
|
6
6
|
|
|
@@ -117,7 +117,7 @@ module.exports = class extends Base {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
switch (type) {
|
|
120
|
-
case 'recent':
|
|
120
|
+
case 'recent': {
|
|
121
121
|
this.rules = {
|
|
122
122
|
count: {
|
|
123
123
|
int: { max: 50 },
|
|
@@ -125,14 +125,16 @@ module.exports = class extends Base {
|
|
|
125
125
|
},
|
|
126
126
|
};
|
|
127
127
|
break;
|
|
128
|
+
}
|
|
128
129
|
|
|
129
|
-
case 'count':
|
|
130
|
+
case 'count': {
|
|
130
131
|
this.rules = {
|
|
131
132
|
url: {
|
|
132
133
|
array: true,
|
|
133
134
|
},
|
|
134
135
|
};
|
|
135
136
|
break;
|
|
137
|
+
}
|
|
136
138
|
|
|
137
139
|
case 'list': {
|
|
138
140
|
const { userInfo } = this.ctx.state;
|
|
@@ -153,7 +155,7 @@ module.exports = class extends Base {
|
|
|
153
155
|
break;
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
default:
|
|
158
|
+
default: {
|
|
157
159
|
this.rules = {
|
|
158
160
|
path: {
|
|
159
161
|
string: true,
|
|
@@ -173,6 +175,7 @@ module.exports = class extends Base {
|
|
|
173
175
|
},
|
|
174
176
|
};
|
|
175
177
|
break;
|
|
178
|
+
}
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
|
package/src/logic/db.js
CHANGED
package/src/logic/token.js
CHANGED
|
@@ -34,8 +34,8 @@ module.exports = class extends Base {
|
|
|
34
34
|
* @apiSuccess (200) {Number} errno 0
|
|
35
35
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
36
36
|
*/
|
|
37
|
-
postAction() {
|
|
38
|
-
|
|
37
|
+
async postAction() {
|
|
38
|
+
await this.useCaptchaCheck();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
package/src/middleware/plugin.js
CHANGED
|
@@ -3,7 +3,7 @@ const compose = require('koa-compose');
|
|
|
3
3
|
module.exports = () => async (ctx, next) => {
|
|
4
4
|
const middlewares = think.getPluginMiddlewares();
|
|
5
5
|
|
|
6
|
-
if (!think.isArray(middlewares) ||
|
|
6
|
+
if (!think.isArray(middlewares) || middlewares.length === 0) {
|
|
7
7
|
return next();
|
|
8
8
|
}
|
|
9
9
|
|
package/src/service/akismet.js
CHANGED
|
@@ -2,6 +2,7 @@ const Akismet = require('akismet');
|
|
|
2
2
|
|
|
3
3
|
const DEFAULT_KEY = '70542d86693e';
|
|
4
4
|
|
|
5
|
+
// oxlint-disable-next-line func-names
|
|
5
6
|
module.exports = function (comment, blog) {
|
|
6
7
|
let { AKISMET_KEY, SITE_URL } = process.env;
|
|
7
8
|
|
|
@@ -13,14 +14,18 @@ module.exports = function (comment, blog) {
|
|
|
13
14
|
return Promise.resolve(false);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
// oxlint-disable-next-line func-names
|
|
16
18
|
return new Promise(function (resolve, reject) {
|
|
17
19
|
const akismet = Akismet.client({ blog, apiKey: AKISMET_KEY });
|
|
18
20
|
|
|
21
|
+
// oxlint-disable-next-line func-names
|
|
19
22
|
akismet.verifyKey(function (err, verifyKey) {
|
|
20
23
|
if (err) {
|
|
21
|
-
|
|
24
|
+
reject(err);
|
|
25
|
+
return;
|
|
22
26
|
} else if (!verifyKey) {
|
|
23
|
-
|
|
27
|
+
reject(new Error('Akismet API_KEY verify failed!'));
|
|
28
|
+
return;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
akismet.checkComment(
|
|
@@ -30,9 +35,11 @@ module.exports = function (comment, blog) {
|
|
|
30
35
|
comment_author: comment.nick,
|
|
31
36
|
comment_content: comment.comment,
|
|
32
37
|
},
|
|
38
|
+
// oxlint-disable-next-line func-names
|
|
33
39
|
function (err, spam) {
|
|
34
40
|
if (err) {
|
|
35
|
-
|
|
41
|
+
reject(err);
|
|
42
|
+
return;
|
|
36
43
|
}
|
|
37
44
|
resolve(spam);
|
|
38
45
|
},
|
package/src/service/avatar.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const escapeHtml = (unsafeHTML) =>
|
|
2
2
|
unsafeHTML
|
|
3
|
-
.
|
|
4
|
-
.
|
|
5
|
-
.
|
|
6
|
-
.
|
|
7
|
-
.
|
|
3
|
+
.replaceAll('&', '&')
|
|
4
|
+
.replaceAll('<', '<')
|
|
5
|
+
.replaceAll('>', '>')
|
|
6
|
+
.replaceAll('"', '"')
|
|
7
|
+
.replaceAll("'", ''');
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
10
|
escapeHtml,
|
|
@@ -28,16 +28,11 @@ DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
const sanitize = (content) =>
|
|
31
|
-
DOMPurify.sanitize(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
FORBID_ATTR: ['autoplay', 'style'],
|
|
37
|
-
},
|
|
38
|
-
think.config('domPurify') || {},
|
|
39
|
-
),
|
|
40
|
-
);
|
|
31
|
+
DOMPurify.sanitize(content, {
|
|
32
|
+
FORBID_TAGS: ['form', 'input', 'style'],
|
|
33
|
+
FORBID_ATTR: ['autoplay', 'style'],
|
|
34
|
+
...think.config('domPurify'),
|
|
35
|
+
});
|
|
41
36
|
|
|
42
37
|
module.exports = {
|
|
43
38
|
sanitize,
|
package/src/service/notify.js
CHANGED
|
@@ -4,7 +4,7 @@ const FormData = require('form-data');
|
|
|
4
4
|
const nodemailer = require('nodemailer');
|
|
5
5
|
const nunjucks = require('nunjucks');
|
|
6
6
|
|
|
7
|
-
module.exports = class extends think.Service {
|
|
7
|
+
module.exports = class NotifyService extends think.Service {
|
|
8
8
|
constructor(controller) {
|
|
9
9
|
super(controller);
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@ module.exports = class extends think.Service {
|
|
|
20
20
|
config.service = SMTP_SERVICE;
|
|
21
21
|
} else {
|
|
22
22
|
config.host = SMTP_HOST;
|
|
23
|
-
config.port = parseInt(SMTP_PORT);
|
|
23
|
+
config.port = Number.parseInt(SMTP_PORT, 10);
|
|
24
24
|
config.secure = SMTP_SECURE && SMTP_SECURE !== 'false';
|
|
25
25
|
}
|
|
26
26
|
this.transporter = nodemailer.createTransport(config);
|
|
@@ -28,7 +28,9 @@ module.exports = class extends think.Service {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
async sleep(second) {
|
|
31
|
-
return new Promise((resolve) =>
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
setTimeout(resolve, second * 1000);
|
|
33
|
+
});
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
async mail({ to, title, content }, self, parent) {
|
|
@@ -43,7 +45,7 @@ module.exports = class extends think.Service {
|
|
|
43
45
|
site: {
|
|
44
46
|
name: SITE_NAME,
|
|
45
47
|
url: SITE_URL,
|
|
46
|
-
postUrl: SITE_URL
|
|
48
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
47
49
|
},
|
|
48
50
|
};
|
|
49
51
|
|
|
@@ -71,7 +73,7 @@ module.exports = class extends think.Service {
|
|
|
71
73
|
site: {
|
|
72
74
|
name: SITE_NAME,
|
|
73
75
|
url: SITE_URL,
|
|
74
|
-
postUrl: SITE_URL
|
|
76
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
75
77
|
},
|
|
76
78
|
};
|
|
77
79
|
|
|
@@ -107,8 +109,8 @@ module.exports = class extends think.Service {
|
|
|
107
109
|
|
|
108
110
|
const QYWX_AM_AY = QYWX_AM.split(',');
|
|
109
111
|
const comment = self.comment
|
|
110
|
-
.
|
|
111
|
-
.
|
|
112
|
+
.replaceAll(/<a href="(.*?)">(.*?)<\/a>/g, '\n[$2] $1\n')
|
|
113
|
+
.replaceAll(/<[^>]+>/g, '');
|
|
112
114
|
const postName = self.url;
|
|
113
115
|
|
|
114
116
|
const data = {
|
|
@@ -121,7 +123,7 @@ module.exports = class extends think.Service {
|
|
|
121
123
|
site: {
|
|
122
124
|
name: SITE_NAME,
|
|
123
125
|
url: SITE_URL,
|
|
124
|
-
postUrl: SITE_URL
|
|
126
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
125
127
|
},
|
|
126
128
|
};
|
|
127
129
|
|
|
@@ -136,7 +138,7 @@ module.exports = class extends think.Service {
|
|
|
136
138
|
title = this.controller.locale(title, data);
|
|
137
139
|
const desp = this.controller.locale(contentWechat, data);
|
|
138
140
|
|
|
139
|
-
content = desp.
|
|
141
|
+
content = desp.replaceAll('\n', '<br/>');
|
|
140
142
|
|
|
141
143
|
const querystring = new URLSearchParams();
|
|
142
144
|
|
|
@@ -146,11 +148,7 @@ module.exports = class extends think.Service {
|
|
|
146
148
|
let baseUrl = 'https://qyapi.weixin.qq.com';
|
|
147
149
|
|
|
148
150
|
if (QYWX_PROXY) {
|
|
149
|
-
|
|
150
|
-
baseUrl = `http://${QYWX_PROXY}`;
|
|
151
|
-
} else {
|
|
152
|
-
baseUrl = `http://${QYWX_PROXY}:${QYWX_PROXY_PORT}`;
|
|
153
|
-
}
|
|
151
|
+
baseUrl = `http://${QYWX_PROXY}${QYWX_PROXY_PORT ? `:${QYWX_PROXY_PORT}` : ''}`;
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
const { access_token } = await fetch(`${baseUrl}/cgi-bin/gettoken?${querystring.toString()}`, {
|
|
@@ -191,7 +189,9 @@ module.exports = class extends think.Service {
|
|
|
191
189
|
return false;
|
|
192
190
|
}
|
|
193
191
|
|
|
194
|
-
const comment = self.comment
|
|
192
|
+
const comment = self.comment
|
|
193
|
+
.replaceAll(/<a href="(.*?)">(.*?)<\/a>/g, '')
|
|
194
|
+
.replaceAll(/<[^>]+>/g, '');
|
|
195
195
|
|
|
196
196
|
const data = {
|
|
197
197
|
self: {
|
|
@@ -202,7 +202,7 @@ module.exports = class extends think.Service {
|
|
|
202
202
|
site: {
|
|
203
203
|
name: SITE_NAME,
|
|
204
204
|
url: SITE_URL,
|
|
205
|
-
postUrl: SITE_URL
|
|
205
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
206
206
|
},
|
|
207
207
|
};
|
|
208
208
|
|
|
@@ -229,13 +229,13 @@ module.exports = class extends think.Service {
|
|
|
229
229
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
230
230
|
},
|
|
231
231
|
body: postBody,
|
|
232
|
-
}).then((resp) =>
|
|
233
|
-
|
|
232
|
+
}).then((resp) =>
|
|
233
|
+
resp.json().then((json) => {
|
|
234
234
|
think.logger.debug(`qq notify response: ${JSON.stringify(json)}`);
|
|
235
235
|
|
|
236
236
|
return json;
|
|
237
|
-
})
|
|
238
|
-
|
|
237
|
+
}),
|
|
238
|
+
);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
async telegram(self, parent) {
|
|
@@ -248,23 +248,19 @@ module.exports = class extends think.Service {
|
|
|
248
248
|
let commentLink = '';
|
|
249
249
|
const href = self.comment.match(/<a href="(.*?)">(.*?)<\/a>/g);
|
|
250
250
|
|
|
251
|
-
if (href
|
|
251
|
+
if (href != null) {
|
|
252
252
|
for (let i = 0; i < href.length; i++) {
|
|
253
253
|
href[i] =
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
'](' +
|
|
257
|
-
href[i].replace(/<a href="(.*?)">(.*?)<\/a>/g, '$1') +
|
|
258
|
-
') ';
|
|
259
|
-
commentLink = commentLink + href[i];
|
|
254
|
+
`[Link: ${href[i].replaceAll(/<a href="(.*?)">(.*?)<\/a>/g, '$2')}](${href[i].replaceAll(/<a href="(.*?)">(.*?)<\/a>/g, '$1')}) `;
|
|
255
|
+
commentLink += href[i];
|
|
260
256
|
}
|
|
261
257
|
}
|
|
262
258
|
if (commentLink !== '') {
|
|
263
|
-
commentLink = `\n
|
|
259
|
+
commentLink = `\n${commentLink}\n`;
|
|
264
260
|
}
|
|
265
261
|
const comment = self.comment
|
|
266
|
-
.
|
|
267
|
-
.
|
|
262
|
+
.replaceAll(/<a href="(.*?)">(.*?)<\/a>/g, '[Link:$2]')
|
|
263
|
+
.replaceAll(/<[^>]+>/g, '');
|
|
268
264
|
|
|
269
265
|
const contentTG =
|
|
270
266
|
think.config('TGTemplate') ||
|
|
@@ -291,7 +287,7 @@ module.exports = class extends think.Service {
|
|
|
291
287
|
site: {
|
|
292
288
|
name: SITE_NAME,
|
|
293
289
|
url: SITE_URL,
|
|
294
|
-
postUrl: SITE_URL
|
|
290
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
295
291
|
},
|
|
296
292
|
};
|
|
297
293
|
|
|
@@ -308,7 +304,7 @@ module.exports = class extends think.Service {
|
|
|
308
304
|
}).then((resp) => resp.json());
|
|
309
305
|
|
|
310
306
|
if (!resp.ok) {
|
|
311
|
-
console.log(
|
|
307
|
+
console.log(`Telegram Notification Failed:${JSON.stringify(resp)}`);
|
|
312
308
|
}
|
|
313
309
|
}
|
|
314
310
|
|
|
@@ -334,27 +330,29 @@ module.exports = class extends think.Service {
|
|
|
334
330
|
site: {
|
|
335
331
|
name: SITE_NAME,
|
|
336
332
|
url: SITE_URL,
|
|
337
|
-
postUrl: SITE_URL
|
|
333
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
338
334
|
},
|
|
339
335
|
};
|
|
340
336
|
|
|
341
337
|
title = this.controller.locale(title, data);
|
|
342
338
|
content = this.controller.locale(content, data);
|
|
343
339
|
|
|
344
|
-
const form = new
|
|
340
|
+
const form = new URLSearchParams();
|
|
345
341
|
|
|
346
|
-
if (topic) form.
|
|
347
|
-
if (template) form.
|
|
348
|
-
if (channel) form.
|
|
349
|
-
if (webhook) form.
|
|
350
|
-
if (callbackUrl) form.
|
|
351
|
-
if (title) form.
|
|
352
|
-
if (content) form.
|
|
342
|
+
if (topic) form.set('topic', topic);
|
|
343
|
+
if (template) form.set('template', template);
|
|
344
|
+
if (channel) form.set('channel', channel);
|
|
345
|
+
if (webhook) form.set('webhook', webhook);
|
|
346
|
+
if (callbackUrl) form.set('callbackUrl', callbackUrl);
|
|
347
|
+
if (title) form.set('title', title);
|
|
348
|
+
if (content) form.set('content', content);
|
|
353
349
|
|
|
354
350
|
return fetch(`http://www.pushplus.plus/send/${PUSH_PLUS_KEY}`, {
|
|
355
351
|
method: 'POST',
|
|
356
|
-
headers:
|
|
357
|
-
|
|
352
|
+
headers: {
|
|
353
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
354
|
+
},
|
|
355
|
+
body: form.toString(),
|
|
358
356
|
}).then((resp) => resp.json());
|
|
359
357
|
}
|
|
360
358
|
|
|
@@ -371,7 +369,7 @@ module.exports = class extends think.Service {
|
|
|
371
369
|
site: {
|
|
372
370
|
name: SITE_NAME,
|
|
373
371
|
url: SITE_URL,
|
|
374
|
-
postUrl: SITE_URL
|
|
372
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
375
373
|
},
|
|
376
374
|
};
|
|
377
375
|
|
|
@@ -406,7 +404,7 @@ module.exports = class extends think.Service {
|
|
|
406
404
|
return false;
|
|
407
405
|
}
|
|
408
406
|
|
|
409
|
-
self.comment = self.comment.
|
|
407
|
+
self.comment = self.comment.replaceAll(/(<([^>]+)>)/gi, '');
|
|
410
408
|
|
|
411
409
|
const data = {
|
|
412
410
|
self,
|
|
@@ -414,7 +412,7 @@ module.exports = class extends think.Service {
|
|
|
414
412
|
site: {
|
|
415
413
|
name: SITE_NAME,
|
|
416
414
|
url: SITE_URL,
|
|
417
|
-
postUrl: SITE_URL
|
|
415
|
+
postUrl: `${SITE_URL}${self.url}#${self.objectId}`,
|
|
418
416
|
},
|
|
419
417
|
};
|
|
420
418
|
|
|
@@ -447,13 +445,13 @@ module.exports = class extends think.Service {
|
|
|
447
445
|
};
|
|
448
446
|
|
|
449
447
|
const sign = (timestamp, secret) => {
|
|
450
|
-
const signStr = timestamp
|
|
448
|
+
const signStr = `${timestamp}\n${secret}`;
|
|
451
449
|
|
|
452
450
|
return crypto.createHmac('sha256', signStr).update('').digest('base64');
|
|
453
451
|
};
|
|
454
452
|
|
|
455
453
|
if (LARK_SECRET) {
|
|
456
|
-
const timestamp = parseInt(
|
|
454
|
+
const timestamp = Number.parseInt(Date.now() / 1000, 10);
|
|
457
455
|
|
|
458
456
|
signData = { timestamp: timestamp, sign: sign(timestamp, LARK_SECRET) };
|
|
459
457
|
}
|
|
@@ -470,10 +468,10 @@ module.exports = class extends think.Service {
|
|
|
470
468
|
}).then((resp) => resp.json());
|
|
471
469
|
|
|
472
470
|
if (resp.status !== 200) {
|
|
473
|
-
console.log(
|
|
471
|
+
console.log(`Lark Notification Failed:${JSON.stringify(resp)}`);
|
|
474
472
|
}
|
|
475
473
|
|
|
476
|
-
console.log(
|
|
474
|
+
console.log(`FeiShu Notification Success:${JSON.stringify(resp)}`);
|
|
477
475
|
}
|
|
478
476
|
|
|
479
477
|
async run(comment, parent, disableAuthorNotify = false) {
|
|
@@ -503,12 +501,16 @@ module.exports = class extends think.Service {
|
|
|
503
501
|
const discord = await this.discord({ title, content }, comment, parent);
|
|
504
502
|
const lark = await this.lark({ title, content }, comment, parent);
|
|
505
503
|
|
|
506
|
-
if (
|
|
504
|
+
if (
|
|
505
|
+
[wechat, qq, telegram, qywxAmWechat, pushplus, discord, lark].every((item) =>
|
|
506
|
+
think.isEmpty(item),
|
|
507
|
+
)
|
|
508
|
+
) {
|
|
507
509
|
mailList.push({ to: AUTHOR, title, content });
|
|
508
510
|
}
|
|
509
511
|
}
|
|
510
512
|
|
|
511
|
-
const disallowList = this.controller.ctx.state.oauthServices.map(({ name }) =>
|
|
513
|
+
const disallowList = this.controller.ctx.state.oauthServices.map(({ name }) => `mail.${name}`);
|
|
512
514
|
const fakeMail = new RegExp(`@(${disallowList.join('|')})$`, 'i');
|
|
513
515
|
|
|
514
516
|
if (
|
|
@@ -530,8 +532,8 @@ module.exports = class extends think.Service {
|
|
|
530
532
|
const response = await this.mail(mail, comment, parent);
|
|
531
533
|
|
|
532
534
|
console.log('Notification mail send success: %s', response);
|
|
533
|
-
} catch (
|
|
534
|
-
console.log('Mail send fail:',
|
|
535
|
+
} catch (err) {
|
|
536
|
+
console.log('Mail send fail:', err);
|
|
535
537
|
}
|
|
536
538
|
}
|
|
537
539
|
}
|
|
@@ -27,14 +27,14 @@ module.exports = class extends Base {
|
|
|
27
27
|
collections[tableName] = true;
|
|
28
28
|
|
|
29
29
|
return db.collection(tableName);
|
|
30
|
-
} catch (
|
|
31
|
-
if (
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (err.code === 'DATABASE_COLLECTION_NOT_EXIST') {
|
|
32
32
|
await db.createCollection(tableName);
|
|
33
33
|
collections[tableName] = true;
|
|
34
34
|
|
|
35
35
|
return db.collection(tableName);
|
|
36
36
|
}
|
|
37
|
-
throw
|
|
37
|
+
throw err;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -46,7 +46,7 @@ module.exports = class extends Base {
|
|
|
46
46
|
const filter = {};
|
|
47
47
|
const parseKey = (k) => (k === 'objectId' ? '_id' : k);
|
|
48
48
|
|
|
49
|
-
for (
|
|
49
|
+
for (const k in where) {
|
|
50
50
|
if (k === '_complex') {
|
|
51
51
|
continue;
|
|
52
52
|
}
|
|
@@ -62,12 +62,14 @@ module.exports = class extends Base {
|
|
|
62
62
|
const handler = where[k][0].toUpperCase();
|
|
63
63
|
|
|
64
64
|
switch (handler) {
|
|
65
|
-
case 'IN':
|
|
65
|
+
case 'IN': {
|
|
66
66
|
filter[parseKey(k)] = _.in(where[k][1]);
|
|
67
67
|
break;
|
|
68
|
-
|
|
68
|
+
}
|
|
69
|
+
case 'NOT IN': {
|
|
69
70
|
filter[parseKey(k)] = _.nin(where[k][1]);
|
|
70
71
|
break;
|
|
72
|
+
}
|
|
71
73
|
case 'LIKE': {
|
|
72
74
|
const first = where[k][1][0];
|
|
73
75
|
const last = where[k][1].slice(-1);
|
|
@@ -152,7 +154,7 @@ module.exports = class extends Base {
|
|
|
152
154
|
async select(where, options = {}) {
|
|
153
155
|
let data = [];
|
|
154
156
|
let ret = [];
|
|
155
|
-
|
|
157
|
+
const offset = options.offset ?? 0;
|
|
156
158
|
|
|
157
159
|
do {
|
|
158
160
|
options.offset = offset + data.length;
|
|
@@ -63,11 +63,11 @@ class Github {
|
|
|
63
63
|
},
|
|
64
64
|
)
|
|
65
65
|
.then((resp) => resp.json())
|
|
66
|
-
.catch((
|
|
67
|
-
const isTooLarge =
|
|
66
|
+
.catch((err) => {
|
|
67
|
+
const isTooLarge = err.message.includes('"too_large"');
|
|
68
68
|
|
|
69
69
|
if (!isTooLarge) {
|
|
70
|
-
throw
|
|
70
|
+
throw err;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
return this.getLargeFile(filename);
|
|
@@ -140,11 +140,11 @@ module.exports = class extends Base {
|
|
|
140
140
|
|
|
141
141
|
async collection(tableName) {
|
|
142
142
|
const filename = path.join(this.basePath, tableName + '.csv');
|
|
143
|
-
const file = await this.git.get(filename).catch((
|
|
144
|
-
if (
|
|
143
|
+
const file = await this.git.get(filename).catch((err) => {
|
|
144
|
+
if (err.statusCode === 404) {
|
|
145
145
|
return '';
|
|
146
146
|
}
|
|
147
|
-
throw
|
|
147
|
+
throw err;
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
return new Promise((resolve, reject) => {
|
|
@@ -157,7 +157,9 @@ module.exports = class extends Base {
|
|
|
157
157
|
})
|
|
158
158
|
.on('error', reject)
|
|
159
159
|
.on('data', (row) => data.push(row))
|
|
160
|
-
.on('end', () =>
|
|
160
|
+
.on('end', () => {
|
|
161
|
+
resolve(data);
|
|
162
|
+
});
|
|
161
163
|
});
|
|
162
164
|
}
|
|
163
165
|
|
|
@@ -180,7 +182,7 @@ module.exports = class extends Base {
|
|
|
180
182
|
|
|
181
183
|
const filters = [];
|
|
182
184
|
|
|
183
|
-
for (
|
|
185
|
+
for (const k in where) {
|
|
184
186
|
if (k === '_complex') {
|
|
185
187
|
continue;
|
|
186
188
|
}
|
|
@@ -203,12 +205,14 @@ module.exports = class extends Base {
|
|
|
203
205
|
const handler = where[k][0].toUpperCase();
|
|
204
206
|
|
|
205
207
|
switch (handler) {
|
|
206
|
-
case 'IN':
|
|
208
|
+
case 'IN': {
|
|
207
209
|
filters.push((item) => where[k][1].includes(item[k]));
|
|
208
210
|
break;
|
|
209
|
-
|
|
211
|
+
}
|
|
212
|
+
case 'NOT IN': {
|
|
210
213
|
filters.push((item) => !where[k][1].includes(item[k]));
|
|
211
214
|
break;
|
|
215
|
+
}
|
|
212
216
|
case 'LIKE': {
|
|
213
217
|
const first = where[k][1][0];
|
|
214
218
|
const last = where[k][1].slice(-1);
|
|
@@ -224,12 +228,14 @@ module.exports = class extends Base {
|
|
|
224
228
|
filters.push((item) => reg.test(item[k]));
|
|
225
229
|
break;
|
|
226
230
|
}
|
|
227
|
-
case '!=':
|
|
231
|
+
case '!=': {
|
|
228
232
|
filters.push((item) => item[k] !== where[k][1]);
|
|
229
233
|
break;
|
|
230
|
-
|
|
234
|
+
}
|
|
235
|
+
case '>': {
|
|
231
236
|
filters.push((item) => item[k] >= where[k][1]);
|
|
232
237
|
break;
|
|
238
|
+
}
|
|
233
239
|
}
|
|
234
240
|
}
|
|
235
241
|
|
|
@@ -279,7 +285,7 @@ module.exports = class extends Base {
|
|
|
279
285
|
});
|
|
280
286
|
}
|
|
281
287
|
|
|
282
|
-
data = data.slice(limit
|
|
288
|
+
data = data.slice(limit ?? 0, offset ?? data.length);
|
|
283
289
|
if (field) {
|
|
284
290
|
field.push('id');
|
|
285
291
|
const fieldObj = {};
|
|
@@ -312,9 +318,9 @@ module.exports = class extends Base {
|
|
|
312
318
|
const counts = {};
|
|
313
319
|
|
|
314
320
|
// FIXME: The loop is weird @lizheming
|
|
315
|
-
//
|
|
321
|
+
// oxlint-disable-next-line typescript/prefer-for-of
|
|
316
322
|
for (let i = 0; i < data.length; i++) {
|
|
317
|
-
const key = group.map((field) => data[field]).join();
|
|
323
|
+
const key = group.map((field) => data[field]).join(',');
|
|
318
324
|
|
|
319
325
|
if (!counts[key]) {
|
|
320
326
|
counts[key] = { count: 0 };
|
|
@@ -333,7 +339,7 @@ module.exports = class extends Base {
|
|
|
333
339
|
// { access: { read = true, write = true } = { read: true, write: true } } = {}
|
|
334
340
|
) {
|
|
335
341
|
const instance = await this.collection(this.tableName);
|
|
336
|
-
const id = Math.random().toString(36).
|
|
342
|
+
const id = Math.random().toString(36).slice(2, 15);
|
|
337
343
|
|
|
338
344
|
instance.push({ ...data, id });
|
|
339
345
|
await this.save(this.tableName, instance, instance.sha);
|
|
@@ -364,8 +370,8 @@ module.exports = class extends Base {
|
|
|
364
370
|
async delete(where) {
|
|
365
371
|
const instance = await this.collection(this.tableName);
|
|
366
372
|
const deleteData = this.where(instance, where);
|
|
367
|
-
const deleteId = deleteData.map(({ id }) => id);
|
|
368
|
-
const data = instance.filter((data) => !deleteId.
|
|
373
|
+
const deleteId = new Set(deleteData.map(({ id }) => id));
|
|
374
|
+
const data = instance.filter((data) => !deleteId.has(data.id));
|
|
369
375
|
|
|
370
376
|
await this.save(this.tableName, data, instance.sha);
|
|
371
377
|
}
|