q-koa 7.7.2

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.
Files changed (116) hide show
  1. package/core/app.js +1813 -0
  2. package/core/config.js +124 -0
  3. package/core/file/plugins/administrator/config.js +17 -0
  4. package/core/file/plugins/administrator/controller.js +264 -0
  5. package/core/file/plugins/administrator/model.js +53 -0
  6. package/core/file/plugins/administrator/validate.js +41 -0
  7. package/core/file/plugins/alipay/controller.js +68 -0
  8. package/core/file/plugins/alipay/validate.js +9 -0
  9. package/core/file/plugins/cache/service.js +16 -0
  10. package/core/file/plugins/cloudfunction/config.js +4 -0
  11. package/core/file/plugins/cloudfunction/model.js +15 -0
  12. package/core/file/plugins/common/controller.js +398 -0
  13. package/core/file/plugins/common/validate.js +47 -0
  14. package/core/file/plugins/douyin/config.js +3 -0
  15. package/core/file/plugins/douyin/controller.js +521 -0
  16. package/core/file/plugins/douyin/validate.js +40 -0
  17. package/core/file/plugins/douyin_user/config.js +15 -0
  18. package/core/file/plugins/douyin_user/model.js +72 -0
  19. package/core/file/plugins/good_sku/controller.js +80 -0
  20. package/core/file/plugins/h5_user/config.js +19 -0
  21. package/core/file/plugins/h5_user/model.js +71 -0
  22. package/core/file/plugins/lang/config.js +4 -0
  23. package/core/file/plugins/lang/model.js +15 -0
  24. package/core/file/plugins/language/config.js +5 -0
  25. package/core/file/plugins/language/model.js +54 -0
  26. package/core/file/plugins/log/config.js +25 -0
  27. package/core/file/plugins/log/controller.js +31 -0
  28. package/core/file/plugins/log/model.js +51 -0
  29. package/core/file/plugins/model/config.js +12 -0
  30. package/core/file/plugins/model/controller.js +69 -0
  31. package/core/file/plugins/model/model.js +169 -0
  32. package/core/file/plugins/model/service.js +218 -0
  33. package/core/file/plugins/model/validate.js +42 -0
  34. package/core/file/plugins/model_attributes/config.js +12 -0
  35. package/core/file/plugins/model_attributes/model.js +114 -0
  36. package/core/file/plugins/mp_user/config.js +19 -0
  37. package/core/file/plugins/mp_user/model.js +59 -0
  38. package/core/file/plugins/permission/config.js +15 -0
  39. package/core/file/plugins/permission/model.js +91 -0
  40. package/core/file/plugins/role/config.js +27 -0
  41. package/core/file/plugins/role/controller.js +26 -0
  42. package/core/file/plugins/role/model.js +58 -0
  43. package/core/file/plugins/role_permission/config.js +12 -0
  44. package/core/file/plugins/role_permission/controller.js +27 -0
  45. package/core/file/plugins/role_permission/model.js +24 -0
  46. package/core/file/plugins/routes/config.js +17 -0
  47. package/core/file/plugins/routes/controller.js +153 -0
  48. package/core/file/plugins/routes/model.js +70 -0
  49. package/core/file/plugins/routes/service.js +22 -0
  50. package/core/file/plugins/setting/afterExecute.js +14 -0
  51. package/core/file/plugins/setting/config.js +14 -0
  52. package/core/file/plugins/setting/controller.js +50 -0
  53. package/core/file/plugins/setting/model.js +118 -0
  54. package/core/file/plugins/setting/validate.js +42 -0
  55. package/core/file/plugins/system/controller.js +501 -0
  56. package/core/file/plugins/system/service.js +148 -0
  57. package/core/file/plugins/system/validate.js +40 -0
  58. package/core/file/plugins/todolist/config.js +31 -0
  59. package/core/file/plugins/todolist/model.js +69 -0
  60. package/core/file/plugins/toutiao/controller.js +201 -0
  61. package/core/file/plugins/toutiao_user/config.js +15 -0
  62. package/core/file/plugins/toutiao_user/model.js +66 -0
  63. package/core/file/plugins/user/afterExecute.js +38 -0
  64. package/core/file/plugins/user/config.js +9 -0
  65. package/core/file/plugins/user/controller.js +329 -0
  66. package/core/file/plugins/user/model.js +96 -0
  67. package/core/file/plugins/user/test.js +71 -0
  68. package/core/file/plugins/user/validate.js +44 -0
  69. package/core/file/plugins/video/config.js +3 -0
  70. package/core/file/plugins/video/controller.js +15 -0
  71. package/core/file/plugins/video/validate.js +12 -0
  72. package/core/file/plugins/weixin/config.js +3 -0
  73. package/core/file/plugins/weixin/controller.js +994 -0
  74. package/core/file/plugins/weixin/service.js +105 -0
  75. package/core/file/plugins/weixin/validate.js +111 -0
  76. package/core/file/services/aliSms.js +45 -0
  77. package/core/file/services/alipay.js +123 -0
  78. package/core/file/services/amap.js +95 -0
  79. package/core/file/services/card.js +24 -0
  80. package/core/file/services/config.js +38 -0
  81. package/core/file/services/douyin.js +151 -0
  82. package/core/file/services/email.js +45 -0
  83. package/core/file/services/express.js +37 -0
  84. package/core/file/services/geo.js +71 -0
  85. package/core/file/services/qqVideo.js +64 -0
  86. package/core/file/services/toutiao.js +102 -0
  87. package/core/file/services/weixin.js +79 -0
  88. package/core/file/services/weixinArticle.js +53 -0
  89. package/core/file/services/weixinCrypt.js +34 -0
  90. package/core/file/services/weixinMP.js +435 -0
  91. package/core/file/services/weixinPay.js +35 -0
  92. package/core/file/services/xml.js +33 -0
  93. package/core/file/task/shop/index.js +589 -0
  94. package/core/file/task/shop/static/562e45760a44632de6fa7219bab78cce.png +0 -0
  95. package/core/file/task/shop/static/d7aeaeb6bfd68f71a00a83c0f5548363.png +0 -0
  96. package/core/file/utils/index.js +61 -0
  97. package/core/middlewares.js +120 -0
  98. package/core/restc/.npminstall.done +1 -0
  99. package/core/restc/LICENSE +21 -0
  100. package/core/restc/README.md +48 -0
  101. package/core/restc/faas/index.html +1112 -0
  102. package/core/restc/faas/index.txt +31 -0
  103. package/core/restc/faas/install_production.sh +6 -0
  104. package/core/restc/index.d.ts +7 -0
  105. package/core/restc/index.js +9 -0
  106. package/core/restc/lib/express.js +7 -0
  107. package/core/restc/lib/hapi.js +17 -0
  108. package/core/restc/lib/hapiLegacy.js +15 -0
  109. package/core/restc/lib/index.js +46 -0
  110. package/core/restc/lib/koa.js +9 -0
  111. package/core/restc/lib/koa2.js +9 -0
  112. package/core/restc/lib/utils/gateway.js +51 -0
  113. package/core/restc/package.json +41 -0
  114. package/core/validator.js +15 -0
  115. package/index.js +1 -0
  116. package/package.json +65 -0
@@ -0,0 +1,398 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const crypto = require('crypto')
4
+ const { Random, lodash, getAppByCtx, getConfig } = require('multiple-quick-koa')
5
+ const Captchapng = require('captchapng')
6
+ const qr = require('qr-image')
7
+ const OSS = require('ali-oss')
8
+ const axios = require('axios')
9
+ const util = require('util')
10
+ const jwt = require('jsonwebtoken')
11
+
12
+ const Email = require('../../services/email')
13
+ const Geo = require('../../services/geo')
14
+
15
+ const annotationsReg = /(?:^|\n|\r)\s*\/\*[\s\S]*?\*\/\s*(?:\r|\n|$)/g
16
+ const apiReg = /@api(Name|Desc|Param|Route|Return)(\s+)(.*)\n/g
17
+
18
+ /**
19
+ * @apiRoute upload
20
+ * @apiName 上传
21
+ * @apiParam subject/string/付款名称
22
+ * @apiParam total_fee/string/支付金额
23
+ * @apiReturn {url}
24
+ */
25
+
26
+ exports.upload = async (ctx) => {
27
+ const { app, appName } = getAppByCtx(ctx)
28
+
29
+ if (!(ctx.request.files && ctx.request.files.file)) {
30
+ throw new Error('请选择上传文件')
31
+ }
32
+
33
+ const { file, option = 'url' } = ctx.request.files
34
+
35
+ const appConfig = getConfig(app)
36
+
37
+ const { site_host } = await appConfig.getObject('base')
38
+
39
+ const reader = fs.readFileSync(file.path)
40
+
41
+ const fsHash = crypto.createHash('md5')
42
+ fsHash.update(reader)
43
+ const md5 = fsHash.digest('hex')
44
+ const newFilename = `${md5}.${
45
+ file.name.split('.')[file.name.split('.').length - 1]
46
+ }`
47
+
48
+ const imgData = Buffer.from(reader).toString('base64')
49
+ // 转换为 data:image/jpeg;base64,***** 格式的字符串
50
+ const base64 = `data:${file.name.split('.')[1]};base64,${imgData}`
51
+
52
+ // const { dir, upload } = app.config.static;
53
+ const targetPath = `${path.resolve(
54
+ __dirname,
55
+ `${process.cwd()}/public/upload`
56
+ )}/${newFilename}`
57
+
58
+ const isExists = fs.existsSync(targetPath)
59
+ const responseData = lodash.pick(
60
+ {
61
+ url: `//${site_host || 'api.kuashou.com'}/upload/${newFilename}`,
62
+ base64,
63
+ card: imgData,
64
+ },
65
+ [option]
66
+ )
67
+ if (isExists) return ctx.SUCCESS(responseData)
68
+
69
+ fs.writeFileSync(targetPath, reader)
70
+ return ctx.SUCCESS(responseData)
71
+ }
72
+
73
+ exports.oss_upload = async (ctx) => {
74
+ const { app } = getAppByCtx(ctx)
75
+
76
+ if (
77
+ !(ctx.request.files && ctx.request.files.file) &&
78
+ !(ctx.request.body.url && ctx.request.body.filename)
79
+ ) {
80
+ ctx.status = 500
81
+ ctx.ERROR('请选择上传文件')
82
+ }
83
+
84
+ const appConfig = getConfig(app)
85
+
86
+ const {
87
+ accessKeyId,
88
+ accessKeySecret,
89
+ bucket,
90
+ region,
91
+ cdn_host,
92
+ oss_host,
93
+ } = await appConfig.getObject('oss')
94
+
95
+ if (!(accessKeyId && accessKeySecret && bucket && region)) {
96
+ throw new Error('没有配置oss设置')
97
+ }
98
+
99
+ const client = new OSS({
100
+ accessKeyId,
101
+ accessKeySecret,
102
+ bucket,
103
+ region,
104
+ secure: true,
105
+ })
106
+ let fileName
107
+ let imageData
108
+ if (ctx.request.files && ctx.request.files.file) {
109
+ const { file } = ctx.request.files
110
+ fileName = `${
111
+ String(new Date().getTime()).split('').reverse().join('') + Math.random()
112
+ }.${file.name.split('.')[file.name.split('.').length - 1]}`
113
+ imageData = file.path
114
+ } else {
115
+ const { url: imageUrl, filename: imageFileName } = ctx.request.body
116
+ fileName = imageFileName
117
+ const formatUrl = imageUrl.startsWith('//') ? 'http:' + imageUrl : imageUrl
118
+ try {
119
+ imageData = await axios
120
+ .get(formatUrl, {
121
+ responseType: 'arraybuffer',
122
+ })
123
+ .then((res) => res.data)
124
+ } catch (e) {
125
+ ctx.status = 500
126
+ ctx.ERROR('请求图片错误')
127
+ }
128
+ }
129
+ const result = await client.put(fileName, imageData)
130
+ if (result.res && result.res.status === 200) {
131
+ if (oss_host && cdn_host) {
132
+ const url = result.url.replace(oss_host, cdn_host)
133
+ return ctx.SUCCESS({
134
+ url,
135
+ })
136
+ } else {
137
+ const url = result.url
138
+ return ctx.SUCCESS({
139
+ url,
140
+ })
141
+ }
142
+ } else {
143
+ throw new Error(result.res.statusMessage)
144
+ }
145
+ }
146
+
147
+ exports.captcha = async (ctx) => {
148
+ const number = Random.string('number', 4)
149
+ const p = new Captchapng(80, 30, number) // width,height,numeric captcha
150
+ p.color(0, 0, 0, 0) // First color: background (red, green, blue, alpha)
151
+ p.color(80, 80, 80, 255) // Second color: paint (red, green, blue, alpha)
152
+
153
+ const img = p.getBase64()
154
+ ctx.SUCCESS({
155
+ img: `data:image/png;base64,${img}`,
156
+ result: number,
157
+ })
158
+ }
159
+
160
+ exports.email = async (ctx) => {
161
+ const email = new Email({
162
+ email: '40854@qq.com',
163
+ password: 'xszvtgcjjqogcahb',
164
+ })
165
+
166
+ const { to, subject, text, html } = ctx.request.body
167
+
168
+ await email.send({
169
+ to,
170
+ subject,
171
+ text,
172
+ html,
173
+ })
174
+
175
+ return ctx.SUCCESS()
176
+ }
177
+
178
+ exports.createQr = async (ctx) => {
179
+ const { app, appName } = getAppByCtx(ctx)
180
+
181
+ const { url } = ctx.request.query
182
+ const img = qr.image(url, {
183
+ size: 10,
184
+ })
185
+ ctx.type = 'image/png'
186
+ ctx.body = img
187
+ }
188
+
189
+ exports.channel = async (ctx) => {
190
+ const { app, appName } = getAppByCtx(ctx)
191
+
192
+ const channelId = ctx.query.channelId
193
+ if (ctx.ws) {
194
+ app.ws[channelId] = await ctx.ws()
195
+
196
+ const send = (data) => app.ws[channelId].send(JSON.stringify(data))
197
+ const sendMessage = (content) => {
198
+ console.log('收到信息了')
199
+ const { type, payload } = content
200
+ send({
201
+ type,
202
+ payload: payload.message,
203
+ })
204
+ }
205
+
206
+ app.event.removeAllListeners()
207
+ app.event.on(channelId, sendMessage)
208
+ } else {
209
+ throw new Error('这是一个websocket url')
210
+ }
211
+ }
212
+
213
+ exports.swagger = async (ctx) => {
214
+ const { app, appName } = getAppByCtx(ctx)
215
+ if (app.cache && app.cache.get('swagger'))
216
+ return ctx.SUCCESS(app.cache.get('swagger'))
217
+
218
+ const filePath = path.resolve(
219
+ __dirname,
220
+ `${process.cwd()}/app/${appName}/plugins`
221
+ )
222
+ const apis = []
223
+ const pathList = fs.readdirSync(filePath)
224
+ for (let i = 0; i < pathList.length; i++) {
225
+ const folder = pathList[i]
226
+ const isFolder = fs.lstatSync(path.resolve(filePath, folder)).isDirectory()
227
+ if (isFolder) {
228
+ const models = []
229
+ if (app.model[folder]) {
230
+ const result = await app.sequelize
231
+ .getQueryInterface()
232
+ .describeTable(folder)
233
+ Object.keys(result).forEach((attr) => {
234
+ models.push(lodash.merge(app.attributes[folder][attr], result[attr]))
235
+ // models[attr] = lodash.merge(app.attributes[folder][attr], result[attr]);
236
+ })
237
+ }
238
+
239
+ const controllers = []
240
+ const controllerFilePath = path.resolve(filePath, folder, 'controller.js')
241
+ const isControllerExist = fs.existsSync(controllerFilePath)
242
+ if (isControllerExist) {
243
+ const controllerFile = fs.readFileSync(controllerFilePath, 'utf-8')
244
+ const annotations = controllerFile.match(annotationsReg)
245
+
246
+ if (annotations) {
247
+ for (let j = 0; j < annotations.length; j++) {
248
+ const annotation = annotations[j]
249
+ let res
250
+ const obj = {}
251
+ while ((res = apiReg.exec(annotation))) {
252
+ res = res.map((item) => item.toLowerCase())
253
+ if (res[1] === 'param') {
254
+ const arr = res[3].split('/')
255
+ if (obj[res[1]]) {
256
+ obj[res[1]].push({
257
+ key: arr[0],
258
+ type: arr[1],
259
+ name: arr[2],
260
+ })
261
+ } else {
262
+ obj[res[1]] = []
263
+
264
+ obj[res[1]].push({
265
+ key: arr[0],
266
+ type: arr[1],
267
+ name: arr[2],
268
+ })
269
+ }
270
+ } else {
271
+ obj[res[1]] = res[3]
272
+ }
273
+ }
274
+ controllers.push(obj)
275
+ }
276
+ }
277
+ }
278
+ apis.push({
279
+ name: folder,
280
+ desc: lodash.get(app, `config.${folder}.name`, `${folder}`),
281
+ models,
282
+ controllers,
283
+ })
284
+ }
285
+ }
286
+ app.cache && app.cache.set('swagger', apis)
287
+ // console.log(dir)
288
+ ctx.SUCCESS(apis)
289
+ }
290
+
291
+ exports.getLocation = async (ctx) => {
292
+ const { app } = getAppByCtx(ctx)
293
+
294
+ const { provinceName, cityName, address } = ctx.request.body
295
+ if (!provinceName || !cityName || !address) {
296
+ return ctx.SUCCESS({
297
+ longitude: null,
298
+ latitude: null,
299
+ })
300
+ }
301
+ const appConfig = getConfig(app)
302
+ const { tencent_key } = await appConfig.getObject('map')
303
+
304
+ const geo = new Geo(tencent_key)
305
+ const addressName = address || `${provinceName}${cityName}`
306
+ const result = await geo.getToLngAndLat(addressName)
307
+
308
+ const { lng: longitude, lat: latitude } = result.location
309
+
310
+ return ctx.SUCCESS({
311
+ longitude,
312
+ latitude,
313
+ })
314
+ }
315
+
316
+ exports.getLngAndLat = async (ctx) => {
317
+ const { app } = getAppByCtx(ctx)
318
+
319
+ const { longitude, latitude } = ctx.request.body
320
+
321
+ const appConfig = getConfig(app)
322
+ const { tencent_key } = await appConfig.getObject('map')
323
+
324
+ const geo = new Geo(tencent_key)
325
+ const res = await geo.getToLoation({
326
+ longitude,
327
+ latitude,
328
+ })
329
+
330
+ return ctx.SUCCESS(res)
331
+ }
332
+
333
+ exports.syncModel = async (ctx) => {
334
+ const { app } = getAppByCtx(ctx)
335
+
336
+ const { model: _model } = ctx.request.body
337
+
338
+ let modellist = []
339
+ if (_model === 'all') {
340
+ modellist = Object.keys(app.model)
341
+ } else {
342
+ modellist = [_model]
343
+ }
344
+
345
+ for (let index = 0; index < modellist.length; index++) {
346
+ const model = modellist[index]
347
+ try {
348
+ const list = await app.model[model].findAll({
349
+ raw: true,
350
+ })
351
+
352
+ const result = await app.sequelize
353
+ .getQueryInterface()
354
+ .describeTable(model)
355
+
356
+ const idType = result.id.type
357
+
358
+ if (idType.includes('TINYINT')) {
359
+ if (idType.includes('UNSIGNED') && list.length >= 128) {
360
+ throw new Error('id超过类型')
361
+ } else if (!idType.includes('UNSIGNED') && list.length >= 256) {
362
+ throw new Error('id超过类型')
363
+ }
364
+ } else if (idType.includes('SMALLINT')) {
365
+ if (idType.includes('UNSIGNED') && list.length >= 32767) {
366
+ throw new Error('id超过类型')
367
+ } else if (!idType.includes('UNSIGNED') && list.length >= 65535) {
368
+ throw new Error('id超过类型')
369
+ }
370
+ } else if (idType.includes('MEDIUMINT')) {
371
+ if (idType.includes('UNSIGNED') && list.length >= 8388607) {
372
+ throw new Error('id超过类型')
373
+ } else if (!idType.includes('UNSIGNED') && list.length >= 16777215) {
374
+ throw new Error('id超过类型')
375
+ }
376
+ }
377
+
378
+ await app.model[model].sync({
379
+ force: true,
380
+ })
381
+
382
+ await app.model[model].bulkCreate(list)
383
+ } catch (e) {
384
+ console.log(`${model}出错,${e.message}`)
385
+ continue
386
+ }
387
+ }
388
+
389
+ ctx.SUCCESS('ok')
390
+ }
391
+
392
+ exports.verify = async (ctx) => {
393
+ const { app, appName } = getAppByCtx(ctx)
394
+ const { code } = ctx.request.body
395
+ const verify = util.promisify(jwt.verify)
396
+ const result = await verify(code, 'token')
397
+ ctx.SUCCESS(result)
398
+ }
@@ -0,0 +1,47 @@
1
+ const { Validator } = require('multiple-quick-koa');
2
+
3
+ exports.email = async (ctx) => {
4
+ const params = {
5
+ to: {
6
+ type: 'string',
7
+ required: true,
8
+ message: '请输入接收邮箱',
9
+ },
10
+ subject: {
11
+ type: 'string',
12
+ required: true,
13
+ message: '请输入邮件主题',
14
+ },
15
+ };
16
+ await new Validator(params).validate(ctx.request.body);
17
+ };
18
+
19
+ exports.sendMessage = async ctx => {
20
+ const params = {
21
+ mobile: {
22
+ type: 'string',
23
+ required: true,
24
+ validator: (rule, value) => {
25
+ return /^[1][1,2,3,4,5,7,8,9][0-9]{9}$/.test(value) ? Promise.resolve() : Promise.reject('请输入正确手机号');
26
+ }
27
+ },
28
+ };
29
+ await new Validator(params).validate(ctx.request.body);
30
+ }
31
+
32
+
33
+ exports.schedule = async (ctx) => {
34
+ const params = {
35
+ to: {
36
+ type: 'string',
37
+ required: true,
38
+ message: '请输入接收邮箱',
39
+ },
40
+ subject: {
41
+ type: 'string',
42
+ required: true,
43
+ message: '请输入邮件主题',
44
+ },
45
+ };
46
+ await new Validator(params).validate(ctx.request.body);
47
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ name: '抖音',
3
+ };