@waline/vercel 1.4.1 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waline/vercel",
3
- "version": "1.4.1",
3
+ "version": "1.6.1",
4
4
  "description": "vercel server for waline comment system",
5
5
  "repository": "https://github.com/walinejs/waline",
6
6
  "license": "MIT",
@@ -36,6 +36,7 @@ const {
36
36
  MAIL_TEMPLATE_ADMIN,
37
37
  QQ_TEMPLATE,
38
38
  TG_TEMPLATE,
39
+ WX_TEMPLATE,
39
40
  } = process.env;
40
41
 
41
42
  let storage = 'leancloud';
@@ -105,7 +106,7 @@ module.exports = {
105
106
  forbiddenWords,
106
107
  disallowIPList: [],
107
108
  secureDomains: SECURE_DOMAINS ? SECURE_DOMAINS.split(/\s*,\s*/) : undefined,
108
- disableUserAgent: !isFalse(DISABLE_USERAGENT),
109
+ disableUserAgent: DISABLE_USERAGENT && !isFalse(DISABLE_USERAGENT),
109
110
  avatarProxy,
110
111
  oauthUrl,
111
112
  markdown,
@@ -115,4 +116,5 @@ module.exports = {
115
116
  mailTemplateAdmin: MAIL_TEMPLATE_ADMIN,
116
117
  QQTemplate: QQ_TEMPLATE,
117
118
  TGTemplate: TG_TEMPLATE,
119
+ WXTemplate: WX_TEMPLATE,
118
120
  };
@@ -3,6 +3,8 @@ const routerREST = require('think-router-rest');
3
3
  const isDev = think.env === 'development';
4
4
  const isTcb = think.env === 'cloudbase';
5
5
  const isDeta = think.env === 'deta' || process.env.DETA_RUNTIME === 'true';
6
+ const isAliyunFC =
7
+ think.env === 'aliyun-fc' || Boolean(process.env.FC_RUNTIME_VERSION);
6
8
 
7
9
  module.exports = [
8
10
  {
@@ -15,7 +17,7 @@ module.exports = [
15
17
  options: {
16
18
  logRequest: isDev,
17
19
  sendResponseTime: isDev,
18
- requestTimeoutCallback: isTcb || isDeta ? false : () => {},
20
+ requestTimeoutCallback: isTcb || isDeta || isAliyunFC ? false : () => {},
19
21
  },
20
22
  },
21
23
 
@@ -4,6 +4,7 @@ const BaseRest = require('./rest');
4
4
  const akismet = require('../service/akismet');
5
5
  const { getMarkdownParser } = require('../service/markdown');
6
6
 
7
+ const markdownParser = getMarkdownParser();
7
8
  async function formatCmt(
8
9
  { ua, user_id, ...comment },
9
10
  users = [],
@@ -39,6 +40,7 @@ async function formatCmt(
39
40
  comment.mail ? comment.mail.toLowerCase() : comment.mail
40
41
  );
41
42
 
43
+ comment.comment = markdownParser(comment.comment);
42
44
  return comment;
43
45
  }
44
46
 
@@ -49,8 +51,6 @@ module.exports = class extends BaseRest {
49
51
  `storage/${this.config('storage')}`,
50
52
  'Comment'
51
53
  );
52
-
53
- this.parser = getMarkdownParser();
54
54
  }
55
55
 
56
56
  async getAction() {
@@ -154,13 +154,33 @@ module.exports = class extends BaseRest {
154
154
  offset: Math.max((page - 1) * pageSize, 0),
155
155
  });
156
156
 
157
+ const userModel = this.service(
158
+ `storage/${this.config('storage')}`,
159
+ 'Users'
160
+ );
161
+ const user_ids = Array.from(
162
+ new Set(comments.map(({ user_id }) => user_id).filter((v) => v))
163
+ );
164
+
165
+ let users = [];
166
+ if (user_ids.length) {
167
+ users = await userModel.select(
168
+ { objectId: ['IN', user_ids] },
169
+ {
170
+ field: ['display_name', 'email', 'url', 'type', 'avatar'],
171
+ }
172
+ );
173
+ }
174
+
157
175
  return this.success({
158
176
  page,
159
177
  totalPages: Math.ceil(count / pageSize),
160
178
  pageSize,
161
179
  spamCount,
162
180
  waitingCount,
163
- data: comments,
181
+ data: await Promise.all(
182
+ comments.map((cmt) => formatCmt(cmt, users, this.config()))
183
+ ),
164
184
  });
165
185
  }
166
186
 
@@ -248,17 +268,14 @@ module.exports = class extends BaseRest {
248
268
  rid,
249
269
  ua,
250
270
  url,
271
+ comment,
251
272
  ip: this.ctx.ip,
252
273
  insertedAt: new Date(),
253
- comment: this.parser(comment),
254
274
  user_id: this.ctx.state.userInfo.objectId,
255
275
  };
256
276
 
257
277
  if (pid) {
258
- data.comment = data.comment.replace(
259
- '<p>',
260
- `<p><a class="at" href="#${pid}">@${at}</a>: `
261
- );
278
+ data.comment = `[@${at}](#${pid}): ` + data.comment;
262
279
  }
263
280
 
264
281
  think.logger.debug('Post Comment initial Data:', data);
@@ -91,6 +91,81 @@ module.exports = class extends think.Service {
91
91
  });
92
92
  }
93
93
 
94
+ async qywxAmWechat({ title, content }, self, parent) {
95
+ const { QYWX_AM, SITE_NAME, SITE_URL } = process.env;
96
+ if (!QYWX_AM) {
97
+ return false;
98
+ }
99
+
100
+ const QYWX_AM_AY = QYWX_AM.split(',');
101
+ const comment = self.comment
102
+ .replace(/<a href="(.*?)">(.*?)<\/a>/g, '\n[$2] $1\n')
103
+ .replace(/<[^>]+>/g, '');
104
+ const postName = self.url;
105
+
106
+ const data = {
107
+ self: {
108
+ ...self,
109
+ comment,
110
+ },
111
+ postName,
112
+ parent,
113
+ site: {
114
+ name: SITE_NAME,
115
+ url: SITE_URL,
116
+ postUrl: SITE_URL + self.url + '#' + self.objectId,
117
+ },
118
+ };
119
+ const contentWechat =
120
+ think.config('WXTemplate') ||
121
+ `💬 {{site.name|safe}}的文章《{{postName}}》有新评论啦
122
+ 【评论者昵称】:{{self.nick}}
123
+ 【评论者邮箱】:{{self.mail}}
124
+ 【内容】:{{self.comment}}
125
+ <a href='{{site.postUrl}}'>查看详情</a>`;
126
+
127
+ title = nunjucks.renderString(title, data);
128
+ const desp = nunjucks.renderString(contentWechat, data);
129
+ content = desp.replace(/\n/g, '<br/>');
130
+
131
+ const { access_token } = await request({
132
+ uri: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`,
133
+ qs: {
134
+ corpid: `${QYWX_AM_AY[0]}`,
135
+ corpsecret: `${QYWX_AM_AY[1]}`,
136
+ },
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ json: true,
141
+ });
142
+ return request({
143
+ url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${access_token}`,
144
+ body: {
145
+ touser: `${QYWX_AM_AY[2]}`,
146
+ agentid: `${QYWX_AM_AY[3]}`,
147
+ msgtype: 'mpnews',
148
+ mpnews: {
149
+ articles: [
150
+ {
151
+ title,
152
+ thumb_media_id: `${QYWX_AM_AY[4]}`,
153
+ author: `Waline Comment`,
154
+ content_source_url: `${data.site.postUrl}`,
155
+ content: `${content}`,
156
+ digest: `${desp}`,
157
+ },
158
+ ],
159
+ },
160
+ },
161
+ method: 'POST',
162
+ json: true,
163
+ headers: {
164
+ 'Content-Type': 'application/json',
165
+ },
166
+ });
167
+ }
168
+
94
169
  async qq(self, parent) {
95
170
  const { QMSG_KEY, QQ_ID, SITE_NAME, SITE_URL } = process.env;
96
171
  if (!QMSG_KEY) {
@@ -212,7 +287,7 @@ module.exports = class extends think.Service {
212
287
  ? parent && parent.mail.toLowerCase() === AUTHOR.toLowerCase()
213
288
  : false;
214
289
 
215
- const title = mailSubjectAdmin || '{{site.name}} 上有新评论了';
290
+ const title = mailSubjectAdmin || '{{site.name | safe}} 上有新评论了';
216
291
  const content =
217
292
  mailTemplateAdmin ||
218
293
  `
@@ -230,12 +305,18 @@ module.exports = class extends think.Service {
230
305
 
231
306
  if (!isAuthorComment && !disableAuthorNotify) {
232
307
  const wechat = await this.wechat({ title, content }, comment, parent);
308
+ const qywxAmWechat = await this.qywxAmWechat(
309
+ { title, content },
310
+ comment,
311
+ parent
312
+ );
233
313
  const qq = await this.qq(comment, parent);
234
314
  const telegram = await this.telegram(comment, parent);
235
315
  if (
236
316
  think.isEmpty(wechat) &&
237
317
  think.isEmpty(qq) &&
238
318
  think.isEmpty(telegram) &&
319
+ think.isEmpty(qywxAmWechat) &&
239
320
  !isReplyAuthor
240
321
  ) {
241
322
  mailList.push({ to: AUTHOR, title, content });
@@ -250,7 +331,8 @@ module.exports = class extends think.Service {
250
331
  mailList.push({
251
332
  to: parent.mail,
252
333
  title:
253
- mailSubject || '{{parent.nick}},『{{site.name}}』上的评论收到了回复',
334
+ mailSubject ||
335
+ '{{parent.nick | safe}},『{{site.name | safe}}』上的评论收到了回复',
254
336
  content:
255
337
  mailTemplate ||
256
338
  `
@@ -115,8 +115,9 @@ module.exports = class extends Base {
115
115
  async select(where, options = {}) {
116
116
  let data = [];
117
117
  let ret = [];
118
+ let offset = options.offset || 0;
118
119
  do {
119
- options.offset = (options.offset || 0) + data.length;
120
+ options.offset = offset + data.length;
120
121
  ret = await this._select(where, options);
121
122
  data = data.concat(ret);
122
123
  } while (ret.length === 100);
@@ -16,7 +16,8 @@ module.exports = class extends Base {
16
16
  const parseKey = (k) => (k === 'objectId' ? '_id' : k);
17
17
  for (const k in where) {
18
18
  if (think.isString(where[k])) {
19
- _where[parseKey(k)] = k === 'objectId' ? this.db.ObjectId(where[k]) : where[k];
19
+ _where[parseKey(k)] =
20
+ k === 'objectId' ? this.db.ObjectId(where[k]) : where[k];
20
21
  continue;
21
22
  }
22
23
  if (where[k] === undefined) {
@@ -100,8 +101,9 @@ module.exports = class extends Base {
100
101
  async select(where, options = {}) {
101
102
  let data = [];
102
103
  let ret = [];
104
+ let offset = options.offset || 0;
103
105
  do {
104
- options.offset = (options.offset || 0) + data.length;
106
+ options.offset = offset + data.length;
105
107
  ret = await this._select(where, options);
106
108
  data = data.concat(ret);
107
109
  } while (ret.length === 1000);
@@ -88,8 +88,9 @@ module.exports = class extends Base {
88
88
  async select(where, options = {}) {
89
89
  let data = [];
90
90
  let ret = [];
91
+ let offset = options.offset || 0;
91
92
  do {
92
- options.offset = (options.offset || 0) + data.length;
93
+ options.offset = offset + data.length;
93
94
  ret = await this._select(where, options);
94
95
  data = data.concat(ret);
95
96
  } while (ret.length === 100);