q-koa 13.4.0 → 13.4.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/core/app.js CHANGED
@@ -159,6 +159,14 @@ class APP {
159
159
  ) {
160
160
  return ctx.ERROR('error')
161
161
  }
162
+
163
+ if (
164
+ ctx.request.header['user-agent'] &&
165
+ ctx.request.header['user-agent'].includes('Apache-HttpClient')
166
+ ) {
167
+ throw new Error(`error`)
168
+ }
169
+
162
170
  if (this.config.blackList.includes(ip)) {
163
171
  return ctx.ERROR('error')
164
172
  }
@@ -483,9 +491,12 @@ class APP {
483
491
  if (initFileConfig) {
484
492
  this.initFile(appName)
485
493
  }
486
-
487
494
  await this.initPlugin(appName)
488
- this.app[appName].event = new EventEmitter()
495
+
496
+ const initEvent = _.get(this.app[appName], 'appConfig.initEvent', false)
497
+ if (initEvent) {
498
+ this.app[appName].event = new EventEmitter()
499
+ }
489
500
 
490
501
  const cacheConfig = _.get(this.app[appName], 'appConfig.cache', {
491
502
  max: 100,
@@ -592,7 +603,7 @@ class APP {
592
603
  const folderResult = await fsPromise.readdir(
593
604
  path.resolve(pluginDir, folder)
594
605
  )
595
- folderResult.forEach((filename) => {
606
+ for (const filename of folderResult) {
596
607
  const extname = path.extname(filename)
597
608
  if (extname === '.js') {
598
609
  const n = path.basename(filename, extname)
@@ -807,7 +818,7 @@ class APP {
807
818
  }
808
819
  }
809
820
  }
810
- })
821
+ }
811
822
  }
812
823
  }
813
824
  const start = moment().valueOf()
@@ -836,19 +847,33 @@ class APP {
836
847
  }
837
848
 
838
849
  initModel(appName) {
850
+ const modelList = Object.keys(this.app[appName].model)
851
+
852
+ const include = modelList.reduce((a, b) => {
853
+ return {
854
+ ...a,
855
+ [b]: [],
856
+ }
857
+ }, {})
858
+ this.app[appName] = _.defaultsDeep(
859
+ {
860
+ include,
861
+ },
862
+ this.app[appName]
863
+ )
839
864
  for (let i = 0; i < Object.keys(this.app[appName].model).length; i++) {
840
865
  const model = Object.keys(this.app[appName].model)[i]
841
866
 
842
- if (!this.app[appName].include || !this.app[appName].include[model]) {
843
- this.app[appName] = _.defaultsDeep(
844
- {
845
- include: {
846
- [model]: [],
847
- },
848
- },
849
- this.app[appName]
850
- )
851
- }
867
+ // if (!this.app[appName].include || !this.app[appName].include[model]) {
868
+ // this.app[appName] = _.defaultsDeep(
869
+ // {
870
+ // include: {
871
+ // [model]: [],
872
+ // },
873
+ // },
874
+ // this.app[appName]
875
+ // )
876
+ // }
852
877
  const db = this.app[appName].attributes[model]
853
878
 
854
879
  const list = Object.keys(db)
@@ -1374,6 +1399,11 @@ class APP {
1374
1399
  app[appName].cache.get(modelName)
1375
1400
  ? app[appName].cache.get(modelName)
1376
1401
  : await model.findAll({
1402
+ ...(myInclude[j].attributes
1403
+ ? {
1404
+ attributes: myInclude[j].attributes,
1405
+ }
1406
+ : {}),
1377
1407
  where: {
1378
1408
  id: idList,
1379
1409
  ...myInclude[j].where,
@@ -1394,6 +1424,11 @@ class APP {
1394
1424
  const idList = rows.map((r) => r.id).filter((item) => item)
1395
1425
  if (idList.length) {
1396
1426
  const list = await model.findAll({
1427
+ ...(myInclude[j].attributes
1428
+ ? {
1429
+ attributes: myInclude[j].attributes,
1430
+ }
1431
+ : {}),
1397
1432
  where: {
1398
1433
  [controller + '_id']: idList,
1399
1434
  ...myInclude[j].where,
package/core/config.js CHANGED
@@ -66,6 +66,7 @@ module.exports = {
66
66
  'weixin/mp_login',
67
67
  'log/create',
68
68
  'log/upsert',
69
+ 'auto/minute',
69
70
  ].every((item) => {
70
71
  return !ctx.request.url.includes(item)
71
72
  })
@@ -214,8 +214,8 @@ exports.scan = async (ctx) => {
214
214
  })
215
215
  }
216
216
 
217
- app.event.removeAllListeners()
218
- app.event.on('scan', sendMessage)
217
+ app.event && app.event.removeAllListeners()
218
+ app.event && app.event.on('scan', sendMessage)
219
219
  } else {
220
220
  throw new Error('这是一个websocket url')
221
221
  }
@@ -224,8 +224,8 @@ exports.channel = async (ctx) => {
224
224
  })
225
225
  }
226
226
 
227
- app.event.removeAllListeners()
228
- app.event.on(channelId, sendMessage)
227
+ app.event && app.event.removeAllListeners()
228
+ app.event && app.event.on(channelId, sendMessage)
229
229
  } else {
230
230
  throw new Error('这是一个websocket url')
231
231
  }
@@ -442,6 +442,7 @@ exports.verify = async (ctx) => {
442
442
  const expressFn = async ({ app, express_number: _express_number }) => {
443
443
  const appConfig = getConfig(app)
444
444
  const { app_code, express_mobile } = await appConfig.getObject('express')
445
+
445
446
  const express_number = _express_number.replace(/\t/, '').trim()
446
447
 
447
448
  const lastFour = express_mobile
@@ -3,7 +3,6 @@ const path = require('path')
3
3
  const fsPromise = require('fs/promises')
4
4
  const { VM } = require('vm2')
5
5
  const axios = require('axios')
6
- const cheerio = require('cheerio')
7
6
  const { lodash, getAppByCtx, getConfig, Sequelize, moment } = require('q-koa')
8
7
  const LRU = require('lru-cache')
9
8
  const cache = new LRU({
@@ -584,7 +583,6 @@ exports.sandbox = async (ctx) => {
584
583
  const vm = new VM({
585
584
  sandbox: {
586
585
  axios,
587
- cheerio,
588
586
  module,
589
587
  setTimeout,
590
588
  sleep: (time) =>
@@ -603,7 +601,6 @@ exports.onlineChat = async (ctx) => {
603
601
  sandbox: {
604
602
  send: (data) => ws.send(JSON.stringify(data)),
605
603
  axios,
606
- cheerio,
607
604
  },
608
605
  })
609
606
  vm.run(code)
@@ -1,5 +1,5 @@
1
1
  const { getConfig, lodash, Sequelize } = require('q-koa')
2
- const { formatLiteralObj } = require('../../utils')
2
+ const { formatLiteralObj, filterFunction } = require('../../utils')
3
3
  const formatPostFunction = (str) => `eval(${str})`
4
4
  const nodeVm = require('vm')
5
5
  const axios = require('axios')
@@ -84,9 +84,7 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
84
84
  .map((i) => (i.toJSON ? i.toJSON() : i))
85
85
  .filter((c) => {
86
86
  const target = data && data.where ? data.where : {}
87
- return Object.keys(target).every((key) => {
88
- return c[key] === target[key]
89
- })
87
+ return filterFunction(target, c)
90
88
  })
91
89
  .map((c) => {
92
90
  return pick.length > 0
@@ -4,6 +4,7 @@ const {
4
4
  getConfig,
5
5
  moment,
6
6
  ServiceError,
7
+ getUserByCtx,
7
8
  } = require('q-koa')
8
9
 
9
10
  const axios = require('axios')
@@ -93,6 +94,7 @@ exports.mp_getPhone = async (ctx) => {
93
94
  (!exist.mp_user.appid || exist.mp_user.appid === app_id)
94
95
 
95
96
  if (mobileExist) {
97
+ app.service.log.push({ app, message: `系统已存在该手机号${phoneNumber}` })
96
98
  return ctx.ERROR('系统已存在该手机号')
97
99
  }
98
100
 
@@ -1144,6 +1146,50 @@ exports.mp_pay = async (ctx) => {
1144
1146
  })
1145
1147
  }
1146
1148
 
1149
+ exports.b2b_pay = async (ctx) => {
1150
+ const { app, appName } = getAppByCtx(ctx)
1151
+ const appConfig = getConfig(app)
1152
+ const { is_dev } = await appConfig.getObject('base')
1153
+ const { name, _out_trade_no, order_id, price, prefix, code, type, is_admin } =
1154
+ ctx.request.body
1155
+
1156
+ const { app_id, app_secrect } = await appConfig.getObject('weixin_mp')
1157
+ const {
1158
+ mchId: mchid,
1159
+ app_key,
1160
+ key,
1161
+ pay_key: _pay_key,
1162
+ } = await appConfig.getObject('weixin_pay')
1163
+
1164
+ const pay_key = _pay_key || key || appName
1165
+
1166
+ const weixinMp = new WeixinMp({
1167
+ appid: app_id,
1168
+ secrect: app_secrect,
1169
+ })
1170
+ weixinMp.init()
1171
+ const out_trade_no = _out_trade_no
1172
+ ? _out_trade_no
1173
+ : prefix
1174
+ ? `${pay_key}_${prefix}-${order_id}_${type}`
1175
+ : `${pay_key}_${order_id}_${type}`
1176
+
1177
+ const res = await weixinMp.b2bPay({
1178
+ mchid,
1179
+ app_key,
1180
+ code,
1181
+ data: {
1182
+ out_trade_no,
1183
+ description: name,
1184
+ amount: {
1185
+ order_amount: is_admin || is_dev ? 1 : Math.round(price * 100),
1186
+ },
1187
+ },
1188
+ })
1189
+
1190
+ ctx.SUCCESS(res)
1191
+ }
1192
+
1147
1193
  exports.mp_pay_new = async (ctx) => {
1148
1194
  const { app, appName } = getAppByCtx(ctx)
1149
1195
  const {
@@ -13,6 +13,76 @@ const fsPromise = require('fs/promises')
13
13
  const WeixinMp = require('../../services/weixinMP')
14
14
  const OSS = require('ali-oss')
15
15
 
16
+ exports.b2b_refund = async ({
17
+ ctx,
18
+ id,
19
+ prefix = '',
20
+ total_fee,
21
+ refund_fee,
22
+ price,
23
+ pay_type = 'B2B-WEIXIN',
24
+ type = '',
25
+ config = 'weixin_mp',
26
+ pay_config = 'weixin_pay',
27
+ out_trade_no: _out_trade_no,
28
+ out_refund_no: _out_refund_no,
29
+ refund_from = 1,
30
+ ...rest
31
+ }) => {
32
+ if (!ctx) throw new Error('?ctx')
33
+ const { app, appName } = getAppByCtx(ctx)
34
+ const appConfig = getConfig(app)
35
+ const { app_id, app_secrect } = await appConfig.getObject(config)
36
+ const { mchId: mchid, key, app_key } = await appConfig.getObject(pay_config)
37
+
38
+ const weixinMp = new WeixinMp({
39
+ appid: app_id,
40
+ secrect: app_secrect,
41
+ })
42
+ weixinMp.init()
43
+
44
+ const orderModel = prefix ? `${prefix}_order` : 'order'
45
+ const out_trade_no =
46
+ _out_trade_no ||
47
+ (prefix ? `${key}_${prefix}-${id}_${pay_type}` : `${key}_${id}_${pay_type}`)
48
+ const orderDetail = await app.model[orderModel].findOne({
49
+ where: {
50
+ id,
51
+ },
52
+ include: app.model.order_refund_record,
53
+ })
54
+
55
+ if (!orderDetail) throw new Error('不存在该订单')
56
+
57
+ const refundRecords = lodash.get(orderDetail, 'order_refund_records', [])
58
+ const refundNumber = refundRecords.length + 1
59
+ const out_refund_no =
60
+ _out_refund_no || [`${prefix}-${id}`, type, refundNumber].join('_')
61
+
62
+ console.log({
63
+ mchid,
64
+ app_key,
65
+ data: {
66
+ out_trade_no: out_trade_no,
67
+ out_refund_no,
68
+ refund_amount: Math.round((refund_fee || price) * 100),
69
+ refund_from,
70
+ },
71
+ })
72
+ const res = await weixinMp.b2bRefund({
73
+ mchid,
74
+ app_key,
75
+ data: {
76
+ out_trade_no: out_trade_no,
77
+ out_refund_no,
78
+ refund_amount: Math.round((refund_fee || price) * 100),
79
+ refund_from,
80
+ },
81
+ })
82
+
83
+ return res
84
+ }
85
+
16
86
  exports.refund = async ({
17
87
  ctx,
18
88
  id,
@@ -1,6 +1,6 @@
1
1
  const util = require('util')
2
2
  const axios = require('axios')
3
-
3
+ const crypto = require('crypto')
4
4
  const { lodash, ServiceError } = require('q-koa')
5
5
  const getAccessTokenUrl =
6
6
  'https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s'
@@ -82,6 +82,14 @@ const createActivityUrl =
82
82
  const setUpdatableMsgUrl =
83
83
  'https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=%s'
84
84
 
85
+ const b2bRefundUrl =
86
+ 'https://api.weixin.qq.com/retail/B2b/refund?access_token=%s&pay_sig=%s'
87
+
88
+ const b2bCheckRefundUrl =
89
+ 'https://api.weixin.qq.com/retail/B2b/getrefund?access_token=%s&pay_sig=%s'
90
+
91
+ const b2bCheckOrderUrl =
92
+ 'https://api.weixin.qq.com/retail/B2b/getorder?access_token=%s&pay_sig=%s'
85
93
  const fsPromise = require('fs/promises')
86
94
  const LRU = require('lru-cache')
87
95
  const request = require('request')
@@ -90,7 +98,9 @@ const cache = new LRU({
90
98
  maxAge: 1000 * 60 * 60,
91
99
  })
92
100
  const uuid = require('node-uuid')
93
-
101
+ const hmacSha256 = (data, secret) => {
102
+ return crypto.createHmac('sha256', secret).update(data).digest('hex')
103
+ }
94
104
  const uploadPromise = (options) => {
95
105
  return new Promise((resolve, reject) => {
96
106
  request.post(
@@ -998,6 +1008,115 @@ module.exports = class Singleton {
998
1008
  return result
999
1009
  }
1000
1010
 
1011
+ async b2bPay({
1012
+ uri = 'requestCommonPayment',
1013
+ data,
1014
+ app_key,
1015
+ code,
1016
+ env = 0,
1017
+ mchid,
1018
+ }) {
1019
+ const weixinLoginUrl = `https://api.weixin.qq.com/sns/jscode2session?appid=${this.config.appid}&secret=${this.config.secrect}&js_code=${code}&grant_type=authorization_code`
1020
+
1021
+ const weixinResult = await axios.get(weixinLoginUrl).then((res) => res.data)
1022
+
1023
+ const { session_key } = weixinResult
1024
+
1025
+ const signData = {
1026
+ mchid,
1027
+ env,
1028
+ ...data,
1029
+ }
1030
+
1031
+ const signature = hmacSha256(JSON.stringify(signData), session_key)
1032
+ const paySig = hmacSha256(`${uri}&${JSON.stringify(signData)}`, app_key)
1033
+
1034
+ return {
1035
+ signData: JSON.stringify(signData),
1036
+ mode: 'retail_pay_goods',
1037
+ signature,
1038
+ paySig,
1039
+ }
1040
+ }
1041
+
1042
+ async b2bRefund({ mchid, app_key, data }) {
1043
+ const requestUrl = b2bRefundUrl
1044
+
1045
+ const access_token = await this.getAccessToken()
1046
+
1047
+ const uri = requestUrl.split('api.weixin.qq.com')[1].split('?')[0]
1048
+
1049
+ const signData = {
1050
+ mchid,
1051
+ ...data,
1052
+ }
1053
+
1054
+ const pay_sig = hmacSha256(`${uri}&${JSON.stringify(signData)}`, app_key)
1055
+
1056
+ const url = util.format(requestUrl, access_token, pay_sig)
1057
+ const result = await axios.post(url, signData).then((res) => res.data)
1058
+ if (result.errcode) {
1059
+ if (result.errcode === 40001) {
1060
+ cache.reset()
1061
+ return await this.b2bRefund({ mchid, app_key, data })
1062
+ }
1063
+ throw new Error(`${result.errcode};${result.errmsg}`)
1064
+ }
1065
+ return result
1066
+ }
1067
+
1068
+ async b2bCheckRefund({ mchid, app_key, data }) {
1069
+ const requestUrl = b2bCheckRefundUrl
1070
+
1071
+ const access_token = await this.getAccessToken()
1072
+
1073
+ const uri = requestUrl.split('api.weixin.qq.com')[1].split('?')[0]
1074
+
1075
+ const signData = {
1076
+ mchid,
1077
+ ...data,
1078
+ }
1079
+
1080
+ const pay_sig = hmacSha256(`${uri}&${JSON.stringify(signData)}`, app_key)
1081
+
1082
+ const url = util.format(requestUrl, access_token, pay_sig)
1083
+ const result = await axios.post(url, signData).then((res) => res.data)
1084
+ if (result.errcode) {
1085
+ if (result.errcode === 40001) {
1086
+ cache.reset()
1087
+ return await this.b2bCheckRefund({ mchid, app_key, data })
1088
+ }
1089
+ throw new Error(`${result.errcode};${result.errmsg}`)
1090
+ }
1091
+ return result
1092
+ }
1093
+
1094
+ async b2bCheckOrder({ mchid, app_key, data }) {
1095
+ const requestUrl = b2bCheckOrderUrl
1096
+
1097
+ const access_token = await this.getAccessToken()
1098
+
1099
+ const uri = requestUrl.split('api.weixin.qq.com')[1].split('?')[0]
1100
+
1101
+ const signData = {
1102
+ mchid,
1103
+ ...data,
1104
+ }
1105
+
1106
+ const pay_sig = hmacSha256(`${uri}&${JSON.stringify(signData)}`, app_key)
1107
+
1108
+ const url = util.format(requestUrl, access_token, pay_sig)
1109
+ const result = await axios.post(url, signData).then((res) => res.data)
1110
+ if (result.errcode) {
1111
+ if (result.errcode === 40001) {
1112
+ cache.reset()
1113
+ return await this.b2bCheckOrder({ mchid, app_key, data })
1114
+ }
1115
+ throw new Error(`${result.errcode};${result.errmsg}`)
1116
+ }
1117
+ return result
1118
+ }
1119
+
1001
1120
  getConfig() {
1002
1121
  return this.config
1003
1122
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q-koa",
3
- "version": "13.4.0",
3
+ "version": "13.4.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {