├── .eslintignore ├── .eslintrc ├── test ├── fixtures │ └── apps │ │ ├── wechat-api-test-redis-multi-clients │ │ ├── package.json │ │ ├── config │ │ │ ├── plugin.unittest.js │ │ │ └── config.unittest.js │ │ └── app │ │ │ └── router.js │ │ └── wechat-api-test-reids-single-client │ │ ├── package.json │ │ ├── config │ │ ├── plugin.unittest.js │ │ └── config.unittest.js │ │ └── app │ │ └── router.js ├── travis │ └── compose │ │ └── docker-compose.yml ├── wechat-api-redis-multi-clients.test.js └── wechat-api-redis-single-client.test.js ├── .gitignore ├── History.md ├── app.js ├── appveyor.yml ├── config └── config.default.js ├── .autod.conf.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── LICENSE ├── package.json ├── .travis.yml ├── app └── extend │ └── application.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-redis-multi-clients/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat-api-test", 3 | "version": "0.0.1" 4 | } -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-reids-single-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat-api-test", 3 | "version": "0.0.1" 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | .DS_Store 8 | *.swp 9 | yarn.lock 10 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-redis-multi-clients/config/plugin.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // redis 4 | exports.redis = { 5 | enable: true, 6 | package: 'egg-redis', 7 | }; 8 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-reids-single-client/config/plugin.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // redis 4 | exports.redis = { 5 | enable: true, 6 | package: 'egg-redis', 7 | }; 8 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | v1.0.0 / 2017-07-17 3 | ================== 4 | 5 | * test: add travis env for test 6 | * docs: update config 7 | * test: remove runtime nodejs-6 8 | * feat: first implement 9 | -------------------------------------------------------------------------------- /test/travis/compose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | redis: 4 | image: redis:3.2-alpine 5 | restart: always 6 | ports: 7 | - 6379:6379 8 | redis-foo: 9 | image: redis:3.2-alpine 10 | restart: always 11 | ports: 12 | - 6380:6379 -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | 5 | module.exports = app => { 6 | const { appId, appSecret } = app.config.wechatApi || {}; 7 | assert(appId && appSecret, 8 | '[egg-wechat-api] Must set `appId` and `appSecret` and in wechat-api\'s config'); 9 | }; 10 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '6' 4 | - nodejs_version: '8' 5 | 6 | install: 7 | - ps: Install-Product node $env:nodejs_version 8 | - npm i npminstall && node_modules\.bin\npminstall 9 | 10 | test_script: 11 | - node --version 12 | - npm --version 13 | - npm run test 14 | 15 | build: off 16 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * egg-wechat-api default config 5 | * @member Config#wechatApi 6 | * @property {String} SOME_KEY - some description 7 | */ 8 | exports.wechatApi = { 9 | default: { 10 | }, 11 | app: true, 12 | agent: false, 13 | 14 | // wechat 15 | appId: '', 16 | appSecret: '', 17 | 18 | // adapter 19 | adapter: 'redis', 20 | redisInstance: '', 21 | }; 22 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-redis-multi-clients/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | 5 | app.get('/', async function() { 6 | const { wechatApi } = app; 7 | 8 | try { 9 | const ticket = await wechatApi.getTicket(); 10 | this.status = 200; 11 | this.body = ticket; 12 | 13 | } catch (error) { 14 | this.status = 500; 15 | this.body = error; 16 | } 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-reids-single-client/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | 5 | app.get('/', async function() { 6 | const { wechatApi } = app; 7 | 8 | try { 9 | const ticket = await wechatApi.getTicket(); 10 | this.status = 200; 11 | this.body = ticket; 12 | 13 | } catch (error) { 14 | this.status = 500; 15 | this.body = error; 16 | } 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | devdep: [ 12 | 'egg', 13 | 'egg-ci', 14 | 'egg-bin', 15 | 'autod', 16 | 'autod-egg', 17 | 'eslint', 18 | 'eslint-config-egg', 19 | 'supertest', 20 | 'webstorm-disable-index', 21 | ], 22 | exclude: [ 23 | './test/fixtures', 24 | './docs', 25 | './coverage', 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-reids-single-client/config/config.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = '123456'; 4 | 5 | exports.redis = { 6 | client: { 7 | port: 6379, 8 | host: '127.0.0.1', 9 | password: null, 10 | family: 4, 11 | db: 0, 12 | }, 13 | }; 14 | 15 | exports.wechatApi = { 16 | default: { 17 | }, 18 | app: true, 19 | agent: false, 20 | 21 | // wechat 22 | appId: process.env.WECHAT_API_APP_ID, 23 | appSecret: process.env.WECHAT_API_APP_SECRET, 24 | }; 25 | -------------------------------------------------------------------------------- /test/fixtures/apps/wechat-api-test-redis-multi-clients/config/config.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = '123456'; 4 | 5 | exports.redis = { 6 | clients: { 7 | foo: { 8 | port: 6379, 9 | host: '127.0.0.1', 10 | password: null, 11 | db: 0, 12 | }, 13 | bar: { 14 | port: 6380, 15 | host: '127.0.0.1', 16 | password: null, 17 | db: 0, 18 | }, 19 | }, 20 | }; 21 | 22 | exports.wechatApi = { 23 | default: { 24 | }, 25 | app: true, 26 | agent: false, 27 | 28 | // wechat 29 | appId: process.env.WECHAT_API_APP_ID, 30 | appSecret: process.env.WECHAT_API_APP_SECRET, 31 | redisInstance: process.env.REDIS_INSTANCE, 32 | }; 33 | -------------------------------------------------------------------------------- /test/wechat-api-redis-multi-clients.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const request = require('supertest'); 4 | const mm = require('egg-mock'); 5 | 6 | describe('test/wechat-api-redis-multi-clients.test.js', () => { 7 | let app; 8 | before(() => { 9 | app = mm.app({ 10 | baseDir: 'apps/wechat-api-test-redis-multi-clients', 11 | }); 12 | 13 | return app.ready(); 14 | }); 15 | 16 | after(() => app.close()); 17 | afterEach(mm.restore); 18 | 19 | it('should return { ticket, expireTime } with code 200 GET /', () => { 20 | return request(app.callback()) 21 | .get('/') 22 | .expect(200) 23 | .expect(({ body }) => { 24 | if (!body.ticket) throw new Error('no ticket'); 25 | if (!body.expireTime) throw new Error('no expireTime'); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/wechat-api-redis-single-client.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const request = require('supertest'); 4 | const mm = require('egg-mock'); 5 | 6 | describe('test/wechat-api-redis-single-client.test.js', () => { 7 | let app; 8 | before(() => { 9 | app = mm.app({ 10 | baseDir: 'apps/wechat-api-test-reids-single-client', 11 | }); 12 | 13 | return app.ready(); 14 | }); 15 | 16 | after(() => app.close()); 17 | afterEach(mm.restore); 18 | 19 | it('should return { ticket, expireTime } with code 200 GET /', () => { 20 | return request(app.callback()) 21 | .get('/') 22 | .expect(200) 23 | .expect(({ body }) => { 24 | if (!body.ticket) throw new Error('no ticket'); 25 | if (!body.expireTime) throw new Error('no expireTime'); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ##### Checklist 12 | 13 | 14 | - [ ] `npm test` passes 15 | - [ ] tests and/or benchmarks are included 16 | - [ ] documentation is changed or added 17 | - [ ] commit message follows commit guidelines 18 | 19 | ##### Affected core subsystem(s) 20 | 21 | 22 | 23 | ##### Description of change 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Alibaba Group Holding Limited and other contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg-wechat-api", 3 | "version": "1.2.2", 4 | "description": "wechat-api for egg", 5 | "eggPlugin": { 6 | "name": "wechatApi", 7 | "dependencies": [] 8 | }, 9 | "keywords": [ 10 | "egg", 11 | "eggPlugin", 12 | "egg-plugin" 13 | ], 14 | "dependencies": { 15 | "co-wechat-api": "^3.7.0" 16 | }, 17 | "devDependencies": { 18 | "autod": "^3.0.1", 19 | "autod-egg": "^1.1.0", 20 | "egg": "^2.9.1", 21 | "egg-bin": "^4.7.1", 22 | "egg-ci": "^1.8.0", 23 | "egg-mock": "^3.17.2", 24 | "egg-redis": "^2.0.0", 25 | "eslint": "^5.0.1", 26 | "eslint-config-egg": "^7.0.0", 27 | "supertest": "^3.1.0", 28 | "webstorm-disable-index": "^1.2.0" 29 | }, 30 | "engines": { 31 | "node": ">=6.0.0" 32 | }, 33 | "scripts": { 34 | "test": "npm run lint -- --fix && npm run pkgfiles && npm run test-local", 35 | "test-local": "egg-bin test", 36 | "cov": "egg-bin cov", 37 | "lint": "eslint .", 38 | "ci": "npm run pkgfiles --check && npm run lint && npm run cov", 39 | "pkgfiles": "egg-bin pkgfiles", 40 | "autod": "autod" 41 | }, 42 | "files": [ 43 | "app", 44 | "config", 45 | "app.js" 46 | ], 47 | "ci": { 48 | "version": "6, 8" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/eggjs-community/egg-wechat-api.git" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/eggjs/egg/issues" 56 | }, 57 | "homepage": "https://github.com/eggjs-community/egg-wechat-api#readme", 58 | "author": "thonatos", 59 | "license": "MIT" 60 | } 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: node_js 3 | node_js: 4 | - '8' 5 | install: 6 | - npm i npminstall && npminstall 7 | script: 8 | - npm run ci 9 | after_script: 10 | - npminstall codecov && codecov 11 | before_script: 12 | - docker-compose -f test/travis/compose/docker-compose.yml up -d 13 | services: 14 | - docker 15 | env: 16 | global: 17 | - REDIS_INSTANCE=foo 18 | - secure: BDtJIXVcqAHFwJfVseQ1YWFcsoUkgKm4Cytw7qCc9qZswMFDMbxs4rdUlKX+lvZVj6++Z/z4sPohou+70TKkd7TcIX4yut4op0d/3FbP0azrVCtMo3xkzpU9Q7szez8IasvknkQ9I+zRMNE0xTOSDU6PDVmyOaDuxtRYvHg7acNlHMDSYA8yPPKtMNvnbJhKC7EjU7yaeseKJAorsl1A7lTd4r8NP5NbYdbXqE2aw9QLT684GdXixpeo6dQJqPAiJ0WkaGIJmxttbfCbJ4SwBLIEYTJ40YCig2MndhAlMntwy5Oob4qLTalbf5JRAWM9gIW9Po+JcJQ0tq8SnbO+2ipO8YxC6zuAcpwkX++iZGy3fQFmIPcmTL9ilM+NDFlmw8bTrQgdwtSBOwib+WxvlhJPLjnmqBSX6sdEwL0yiqu29ggL8+Zw20n5hjYsu6lQyyX5WEBVRtyC4lixqVvURq79GuwHUF7/+VF3dKGyKIiQCXybHO5zuG2cxaY25cwsThuos3BIgJeaBRH45ePeVz/BUduM1UiDvk8eRZufUSGSu++DyPuAc8Z9zmrDPuiunzLn9smMSaUTbFgNjdDHWhT5l8BKU0sewSv8NjdLf0kyUPiaKTe09eJHntVPOEe/x761GH69gAkUkM5BS/D0YD5zBw2rcJx5Yp8Vb4r8XhY= 19 | - secure: vDBVlX6+ejXnYNNVTzmLE9fdLcVIexi0BvaMnrNgCvrwX7lxebOUxwwdQB61lNysy+7SM3Ea8zFsRX2mzTIKZ6QqHgjcPqC38CNIP+3lkGFu6d/ptA3cwaixDGv+5+CGzz6D6HQbvi9YAjwarwjPbF4CjE2Xi2CSkhUfyrzVXJ5CjX2eh1QV33n4EGv5RxAOVgpYTRskLEWNoLLnZVXEyt7SxHdiZexYWNco1MnFBo7l2YRA6u43X2qv60LNpHvrIkmyS2w5Han+VcKcaXlLiRiBMC6EiM8M2EMozw27FxSjn/PrSBAw7NjJGJxwqbOjHSI5suNsyhjycWliOctZC+tZAvoV7dHr84NoA49IYLXfEvY+GCR3/c2H9xU0ST4bt8MGVI3hs5B3DeiA0Ww9roTWI6Cvy95uccEUNXM71TBFgcn5vZKFYwwpVdPRYBFzRNfm7j7cbGy1T+bA9baWE51jY1xQetXPcCPhse79e6u1SDg+fJkDxukgQH6dGlNjLOuCbzN8YVKaSoOep8iqFOyra8Nu5Pez4UeESHYBOAUFqOuweKTllgiMcEg7ibeQqgpuD+ceYe+b4szyQr1ytWvaf8oL9lkCwMtuQ4pzqkz4Cq2BKf9NaaVl2NDXe3cW45otZ3M9qtmrJmGd5v0SYpt2pW2QgFSzqsQ3YDLnoqU= 20 | -------------------------------------------------------------------------------- /app/extend/application.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WechatApi = require('co-wechat-api'); 4 | const WECHAT = Symbol('Application#wechat'); 5 | 6 | module.exports = { 7 | get wechatApi() { 8 | if (!this[WECHAT]) { 9 | this[WECHAT] = createClient(this); 10 | return this[WECHAT]; 11 | } 12 | return this[WECHAT]; 13 | }, 14 | }; 15 | 16 | function createClient(app) { 17 | const config = app.config.wechatApi; 18 | const { 19 | appId, 20 | appSecret 21 | } = config; 22 | 23 | if (!appId || !appSecret) { 24 | app.logger.error('[egg-wechat-api] must set `appId` and `appSecret` in plugin\'s config.'); 25 | return null; 26 | } 27 | 28 | let adapter; 29 | if (config.adapter === 'redis') { 30 | adapter = config.redisInstance ? app.redis && app.redis.get(config.redisInstance) : app.redis; 31 | } 32 | 33 | if (config.adapter === 'tair') { 34 | adapter = app.tair; 35 | } 36 | 37 | if (!adapter) { 38 | app.logger.error('[egg-wechat-api] adapter is ready ?'); 39 | return null; 40 | } 41 | 42 | async function getTicketToken(type) { 43 | const raw = await adapter.get(`wechat_${type}`); 44 | return JSON.parse(config.adapter === 'tair' ? raw.data : raw); 45 | } 46 | 47 | async function saveTicketToken(type, _ticketToken) { 48 | await adapter.set(`wechat_${type}`, JSON.stringify(_ticketToken)); 49 | } 50 | 51 | async function getAccessToken() { 52 | const token = await adapter.get('wechat_access_token'); 53 | return JSON.parse(config.adapter === 'tair' ? token.data : token); 54 | } 55 | 56 | async function saveAccessToken(token) { 57 | await adapter.set('wechat_access_token', JSON.stringify(token)); 58 | } 59 | 60 | const api = new WechatApi(appId, appSecret, getAccessToken, saveAccessToken); 61 | api.registerTicketHandle(getTicketToken, saveTicketToken); 62 | return api; 63 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # egg-wechat-api 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![build status][travis-image]][travis-url] 5 | [![Test coverage][codecov-image]][codecov-url] 6 | [![David deps][david-image]][david-url] 7 | [![Known Vulnerabilities][snyk-image]][snyk-url] 8 | [![npm download][download-image]][download-url] 9 | 10 | [npm-image]: https://img.shields.io/npm/v/egg-wechat-api.svg?style=flat-square 11 | [npm-url]: https://npmjs.org/package/egg-wechat-api 12 | [travis-image]: https://img.shields.io/travis/eggjs-community/egg-wechat-api.svg?style=flat-square 13 | [travis-url]: https://travis-ci.org/eggjs-community/egg-wechat-api 14 | [codecov-image]: https://img.shields.io/codecov/c/github/eggjs-community/egg-wechat-api.svg?style=flat-square 15 | [codecov-url]: https://codecov.io/github/eggjs-community/egg-wechat-api?branch=master 16 | [david-image]: https://img.shields.io/david/eggjs-community/egg-wechat-api.svg?style=flat-square 17 | [david-url]: https://david-dm.org/eggjs-community/egg-wechat-api 18 | [snyk-image]: https://snyk.io/test/npm/egg-wechat-api/badge.svg?style=flat-square 19 | [snyk-url]: https://snyk.io/test/npm/egg-wechat-api 20 | [download-image]: https://img.shields.io/npm/dm/egg-wechat-api.svg?style=flat-square 21 | [download-url]: https://npmjs.org/package/egg-wechat-api 22 | 23 | 26 | 27 | egg plugin for [wechat-api](https://github.com/node-webot/co-wechat-api) 28 | 29 | ## Install 30 | 31 | ```bash 32 | $ npm i egg-wechat-api --save 33 | ``` 34 | 35 | ## Prerequisite 36 | 37 | Node.js >= 7.x 38 | 39 | ## Usage 40 | 41 | - [co-wechat-api](https://github.com/node-webot/co-wechat-api) 42 | 43 | ## Dependencies 44 | 45 | - egg 46 | - [egg-redis](https://github.com/eggjs/egg-redis) 47 | - other 48 | - [co-wechat-api](https://github.com/node-webot/co-wechat-api) 49 | 50 | ## Configuration 51 | 52 | ```js 53 | // {app_root}/config/plugin.js 54 | exports.wechatApi = { 55 | enable: true, 56 | package: 'egg-wechat-api', 57 | }; 58 | ``` 59 | > if redis is single client 60 | 61 | ```js 62 | // {app_root}/config/config.default.js 63 | exports.wechatApi = { 64 | appId: '', 65 | appSecret: '', 66 | }; 67 | ``` 68 | > if redis is multi clients 69 | 70 | ```js 71 | // {app_root}/config/config.default.js 72 | exports.wechatApi = { 73 | appId: '', 74 | appSecret: '', 75 | redisInstance: '', // select instance of redis 76 | }; 77 | ``` 78 | 79 | > __Redis is required !__ 80 | 81 | see [config/config.default.js](config/config.default.js) for more detail. 82 | 83 | ## Example 84 | 85 | 86 | 87 | ``` 88 | 'use strict'; 89 | 90 | module.exports = app => { 91 | 92 | app.get('/', function* () { 93 | 94 | const { wechatApi } = app; 95 | 96 | try { 97 | const ticket = yield wechatApi.getTicket(); 98 | this.status = 200; 99 | this.body = ticket; 100 | 101 | } catch (error) { 102 | this.status = 500; 103 | this.body = error; 104 | } 105 | }); 106 | 107 | }; 108 | ``` 109 | 110 | ## Questions & Suggestions 111 | 112 | Please open an issue [here](https://github.com/eggjs/egg/issues). 113 | 114 | ## License 115 | 116 | [MIT](LICENSE) 117 | --------------------------------------------------------------------------------