q-koa 13.1.7 → 13.1.9

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/core/app.js CHANGED
@@ -22,7 +22,7 @@ const util = require('util')
22
22
  const jwt = require('jsonwebtoken')
23
23
  const verify = util.promisify(jwt.verify)
24
24
  const fsExtra = require('fs-extra')
25
- const { getObject, getAppConfig } = require('./file/utils')
25
+ const { getObject, getAppConfig, formatLiteralObj } = require('./file/utils')
26
26
 
27
27
  const restc = require('./restc')
28
28
  const APP_DIR = 'app'
@@ -288,6 +288,18 @@ class APP {
288
288
  )} server is running at http://localhost:${this.port}`
289
289
  )
290
290
  if (is_dev) {
291
+ const db_name = _.get(this.app[appName], 'sequelize.config.database')
292
+ this.app[appName].model.setting.update(
293
+ {
294
+ value: db_name,
295
+ },
296
+ {
297
+ where: {
298
+ code: 'db_name',
299
+ },
300
+ }
301
+ )
302
+
291
303
  console.log(
292
304
  `first app is http://localhost:3001/${appName}/setting/findOne`
293
305
  )
@@ -1157,57 +1169,6 @@ class APP {
1157
1169
 
1158
1170
  if (where) {
1159
1171
  if (fn === 'findAndCountAll') {
1160
- const $lt = {
1161
- check: (param) => typeof param === 'string',
1162
- result: (param, key) => {
1163
- return {
1164
- [key]: Sequelize.literal(param[key]),
1165
- }
1166
- },
1167
- }
1168
- const $in = {
1169
- check: (param) => typeof param === 'string',
1170
- result: (param, key) => {
1171
- return {
1172
- [key]: [Sequelize.literal(param[key])],
1173
- }
1174
- },
1175
- }
1176
- const $between = {
1177
- check: (param) =>
1178
- Array.isArray(param) &&
1179
- param.every((p) => p.includes('now()')),
1180
- result: (param, key) => {
1181
- return {
1182
- [key]: param[key].map(Sequelize.literal),
1183
- }
1184
- },
1185
- }
1186
- const mapper = {
1187
- $between,
1188
- notBetween: $between,
1189
- $lt,
1190
- $lte: $lt,
1191
- $gt: $lt,
1192
- $gte: $lt,
1193
- $in,
1194
- $notIn: $in,
1195
- }
1196
- const formatObj = (target) => {
1197
- for (const key of Object.keys(mapper)) {
1198
- if (Object.hasOwnProperty.call(target, key)) {
1199
- if (mapper[key].check(target[key])) {
1200
- return mapper[key].result(target, key)
1201
- } else {
1202
- return target
1203
- }
1204
- } else {
1205
- continue
1206
- }
1207
- }
1208
- return target
1209
- }
1210
-
1211
1172
  if (
1212
1173
  where.hasOwnProperty('id') &&
1213
1174
  typeof where.id === 'string' &&
@@ -1222,7 +1183,7 @@ class APP {
1222
1183
 
1223
1184
  const formatWhere = _.mapValues(where, (item) => {
1224
1185
  if (!_.isObject(item)) return item
1225
- return formatObj(item)
1186
+ return formatLiteralObj(item)
1226
1187
  })
1227
1188
  _where = _.cloneDeep(formatWhere)
1228
1189
  } else {
@@ -1282,12 +1243,12 @@ class APP {
1282
1243
  return {
1283
1244
  ...item,
1284
1245
  where: {
1285
- ...item.where,
1286
1246
  ...(includeWhere[item.model.getName()]
1287
1247
  ? {
1288
1248
  ...includeWhere[item.model.getName()],
1289
1249
  }
1290
1250
  : {}),
1251
+ ...item.where,
1291
1252
  },
1292
1253
  }
1293
1254
  })
@@ -2091,6 +2052,7 @@ APP.Validator = Validator
2091
2052
  APP.ServiceError = ServiceError
2092
2053
  APP.TransactionError = TransactionError
2093
2054
  APP.moment = moment
2055
+ APP.utils = require('./file/utils')
2094
2056
  APP.is_dev = is_dev
2095
2057
 
2096
2058
  global.moment = moment
@@ -309,7 +309,9 @@ exports.getTable = async (ctx) => {
309
309
  return ctx.SUCCESS(app.cache.get(`${_model}-table`))
310
310
  }
311
311
 
312
- const model = app.config[_model].model || _model
312
+ const model = (app.config[_model] && app.config[_model].model) || _model
313
+
314
+ if (!app.config[model]) return ctx.SUCCESS(null)
313
315
 
314
316
  const _result = await app.sequelize.getQueryInterface().describeTable(model)
315
317
 
@@ -1,4 +1,5 @@
1
- const { getConfig, lodash, Sequelize } = require('q-koa')
1
+ const { getConfig, lodash } = require('q-koa')
2
+ const { formatLiteralObj } = require('../../utils')
2
3
  const formatPostFunction = (str) => `eval(${str})`
3
4
  const nodeVm = require('vm')
4
5
  const axios = require('axios')
@@ -33,6 +34,7 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
33
34
  excludeInclude,
34
35
  autoInclude = true,
35
36
  is_cache = false,
37
+ defaultValue,
36
38
  } = route
37
39
 
38
40
  if (url.includes('http')) {
@@ -134,8 +136,14 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
134
136
 
135
137
  if (app.controller[model] && app.controller[model][fn]) {
136
138
  return app.controller[model][fn](ctx, data).then((result) => {
137
- if (!result && process.env.NODE_ENV !== 'production') {
139
+ if (
140
+ result === undefined &&
141
+ process.env.NODE_ENV !== 'production'
142
+ ) {
138
143
  console.error(`需要在控制器${fn}中返回`)
144
+ return {
145
+ [item]: defaultValue || result,
146
+ }
139
147
  }
140
148
  return {
141
149
  [item]: result,
@@ -208,49 +216,15 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
208
216
  data &&
209
217
  lodash.isObject(data) &&
210
218
  data.hasOwnProperty('where')
211
- ? Object.keys(data).reduce((a, b) => {
212
- return {
213
- ...a,
214
- ...(b === 'where'
215
- ? {
216
- [b]: Object.keys(data[b]).reduce((_a, _b) => {
217
- return {
218
- ..._a,
219
- ...(['$gt', '$lt'].some((i) =>
220
- data[b][_b].hasOwnProperty(i)
221
- )
222
- ? {
223
- [_b]: data[b][_b],
224
- ...(typeof data[b][_b].$gt ===
225
- 'string' &&
226
- data[b][_b].hasOwnProperty('$gt')
227
- ? {
228
- [_b]: {
229
- $gt: Sequelize.literal(
230
- data[b][_b].$gt
231
- ),
232
- },
233
- }
234
- : {}),
235
- ...(typeof data[b][_b].$lt ===
236
- 'string' &&
237
- data[b][_b].hasOwnProperty('$lt')
238
- ? {
239
- [_b]: {
240
- $lt: Sequelize.literal(
241
- data[b][_b].$lt
242
- ),
243
- },
244
- }
245
- : {}),
246
- }
247
- : { [_b]: data[b][_b] }),
248
- }
249
- }, {}),
250
- }
251
- : { [b]: data[b] }),
219
+ ? lodash.mapValues(data, (value, key) => {
220
+ if (key === 'where') {
221
+ return lodash.mapValues(data.where, (item) => {
222
+ if (!lodash.isObject(item)) return item
223
+ return formatLiteralObj(item)
224
+ })
252
225
  }
253
- }, {})
226
+ return value
227
+ })
254
228
  : data
255
229
  // console.log('formatData', data, '-->', formatData)
256
230
  return app.model[model][fn]({
@@ -6,7 +6,20 @@ module.exports = {
6
6
  availableSort: false,
7
7
  order: [],
8
8
  referenceSelect: [],
9
- select: ['id', 'code', 'name', 'is_front', 'is_cache', 'is_control', 'extra'],
9
+ select: [
10
+ 'id',
11
+ 'code',
12
+ 'name',
13
+ 'is_front',
14
+ 'is_cache',
15
+ 'is_control',
16
+ {
17
+ key: 'extra',
18
+ extra: {
19
+ list: ['is_admin', 'is_purchase', 'is_custom', 'is_supply'],
20
+ },
21
+ },
22
+ ],
10
23
  excludes: [],
11
24
  limit: 20,
12
25
  defaultOrder: [],
@@ -4,6 +4,7 @@ const {
4
4
  getConfig,
5
5
  lodash,
6
6
  moment,
7
+ sleep,
7
8
  } = require('q-koa')
8
9
  const { Pay } = require('@sigodenjs/wechatpay')
9
10
  const WXPay = require('weixin-pay-fork')
@@ -480,13 +481,23 @@ exports.handleUserMessage = async ({ app, result }) => {
480
481
  secrect: app_secrect,
481
482
  })
482
483
  weixinMp.init()
484
+ const touser = result.FromUserName
485
+ await weixinMp.handleTyping({
486
+ touser,
487
+ is_typing: true,
488
+ })
489
+ await sleep(3)
483
490
  await weixinMp.handleMessage({
484
- touser: result.FromUserName,
491
+ touser,
485
492
  msgtype: 'text',
486
493
  text: {
487
494
  content: `你说${result.Content},是吗?`,
488
495
  },
489
496
  })
497
+ await weixinMp.handleTyping({
498
+ touser,
499
+ is_typing: false,
500
+ })
490
501
  }
491
502
  }
492
503
 
@@ -20,6 +20,8 @@ const sendMessageUrl =
20
20
  'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s'
21
21
  const handleMessageUrl =
22
22
  'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s'
23
+ const handleTypingUrl =
24
+ 'https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=%s'
23
25
  const uploadFile =
24
26
  'https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s'
25
27
  const serviceMarketUrl =
@@ -558,6 +560,24 @@ module.exports = class Singleton {
558
560
  return result
559
561
  }
560
562
 
563
+ async handleTyping({ touser, is_typing = true }) {
564
+ const options = {
565
+ touser,
566
+ command: is_typing ? 'Typing' : 'CancelTyping',
567
+ }
568
+ const access_token = await this.getAccessToken()
569
+ const url = util.format(handleTypingUrl, access_token)
570
+ const result = await axios.post(url, options).then((res) => res.data)
571
+ if (result.errcode) {
572
+ if (result.errcode === 40001) {
573
+ cache.reset()
574
+ return await this.handleTyping(options)
575
+ }
576
+ throw new Error(`${result.errcode};${result.errmsg}`)
577
+ }
578
+ return result
579
+ }
580
+
561
581
  async uploadFile(imgUrl) {
562
582
  if (!imgUrl || !imgUrl.includes('//')) throw new Error('检查imgUrl是否链接')
563
583
 
@@ -1,5 +1,7 @@
1
1
  const { lodash } = require('q-koa')
2
+ const Sequelize = require('sequelize')
2
3
  const md5 = require('md5')
4
+ const moment = require('moment')
3
5
 
4
6
  const findConfig = (type) => (item) =>
5
7
  item.key === type ||
@@ -205,3 +207,124 @@ exports.signResult = (params, salt) => {
205
207
  var signStr = paramArray.join('&')
206
208
  return md5(signStr)
207
209
  }
210
+
211
+ function isDateTime(str) {
212
+ const dateRegex = /^[\u4e00-\u9fa5]{4}-[\u4e00-\u9fa5]{2}-[\u4e00-\u9fa5]{2}$/
213
+ return dateRegex.test(str)
214
+ }
215
+
216
+ const $lt = {
217
+ check: (param) => typeof param === 'string',
218
+ result: (param, key) => {
219
+ return {
220
+ [key]: Sequelize.literal(param[key]),
221
+ }
222
+ },
223
+ }
224
+ const $in = {
225
+ check: (param) => typeof param === 'string',
226
+ result: (param, key) => {
227
+ return {
228
+ [key]: [Sequelize.literal(param[key])],
229
+ }
230
+ },
231
+ }
232
+ const $between = {
233
+ check: (param) =>
234
+ Array.isArray(param) && param.every((p) => typeof param === 'string'),
235
+ result: (param, key) => {
236
+ return {
237
+ [key]: param[key].map(Sequelize.literal),
238
+ }
239
+ },
240
+ }
241
+ const mapper = {
242
+ $between,
243
+ notBetween: $between,
244
+ $lt,
245
+ $lte: $lt,
246
+ $gt: $lt,
247
+ $gte: $lt,
248
+ $in,
249
+ $notIn: $in,
250
+ }
251
+
252
+ exports.formatLiteralObj = (target) => {
253
+ for (const key of Object.keys(mapper)) {
254
+ if (Object.hasOwnProperty.call(target, key)) {
255
+ if (mapper[key].check(target[key])) {
256
+ return mapper[key].result(target, key)
257
+ } else {
258
+ return target
259
+ }
260
+ } else {
261
+ continue
262
+ }
263
+ }
264
+ return target
265
+ }
266
+
267
+ exports.filterFunction = (target, data) => {
268
+ if (!target) {
269
+ console.error(`target为null`)
270
+ return false
271
+ }
272
+ return Object.keys(target).every((key) => {
273
+ if (key.includes('.')) {
274
+ return lodash.get(data, key) === target[key]
275
+ }
276
+ if (typeof target[key] === 'boolean') {
277
+ return Boolean(data[key]) === target[key]
278
+ }
279
+ if (Array.isArray(target[key])) {
280
+ return target[key].includes(data[key])
281
+ }
282
+ if (lodash.isObject(target[key])) {
283
+ if (Object.prototype.hasOwnProperty.call(target[key], '$gt')) {
284
+ if (key.endsWith('time') || key.endsWith('_at')) {
285
+ return moment(data[key]).diff(moment(target[key].$gt), 'seconds') > 0
286
+ }
287
+ return data[key] > target[key].$gt
288
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$gte')) {
289
+ if (key.endsWith('time') || key.endsWith('_at')) {
290
+ return moment(data[key]).diff(moment(target[key].$gt), 'seconds') >= 0
291
+ }
292
+ return data[key] >= target[key].$gte
293
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$lt')) {
294
+ if (key.endsWith('time') || key.endsWith('_at')) {
295
+ return moment(target[key].$gt).diff(moment(data[key]), 'seconds') < 0
296
+ }
297
+ return data[key] < target[key].$lt
298
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$lte')) {
299
+ if (key.endsWith('time') || key.endsWith('_at')) {
300
+ return moment(target[key].$gt).diff(moment(data[key]), 'seconds') <= 0
301
+ }
302
+ return data[key] <= target[key].$lte
303
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$notIn')) {
304
+ return !target[key].$notIn.includes(data[key])
305
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$in')) {
306
+ return target[key].$in.includes(data[key])
307
+ } else if (
308
+ Object.prototype.hasOwnProperty.call(target[key], '$between')
309
+ ) {
310
+ if (
311
+ !Array.isArray(target[key].$between) ||
312
+ target[key].$between.length !== 2
313
+ ) {
314
+ throw new Error(`$between example : [2,5]`)
315
+ }
316
+ const min = target[key].$between[0]
317
+ const max = target[key].$between[1]
318
+ return data[key] >= min && data[key] <= max
319
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$ne')) {
320
+ return data[key] !== target[key].$ne
321
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$neq')) {
322
+ return data[key] !== target[key].$neq
323
+ } else if (Object.prototype.hasOwnProperty.call(target[key], '$eq')) {
324
+ return data[key] === target[key].$eq
325
+ }
326
+ return data[key] === target[key]
327
+ }
328
+ return data[key] === target[key]
329
+ })
330
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q-koa",
3
- "version": "13.1.7",
3
+ "version": "13.1.9",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {