├── .gitignore ├── .npmignore ├── README.md ├── dist ├── apis.js ├── apis.js.map ├── duoshuo.js ├── duoshuo.js.map ├── rules.js └── rules.js.map ├── examples └── index.js ├── libs ├── apis.js ├── duoshuo.js └── rules.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime* 2 | node_* 3 | *.DS_* 4 | thumb 5 | psd -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.sublime* 2 | node_* 3 | *.DS_* 4 | thumb 5 | psd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![duoshuo](http://ww1.sinaimg.cn/large/61ff0de3gw1e78kmsw0q0j200z00z0si.jpg) duoshuo.com apis ![npm](https://badge.fury.io/js/duoshuo.png) 2 | --- 3 | 4 | a duoshuo SDK in Node.js 5 | 6 | ### How to install 7 | 8 | ```bash 9 | $ npm install duoshuo 10 | ``` 11 | 12 | ### Example 13 | 14 | ```js 15 | var Duoshuo = require('duoshuo') 16 | 17 | var duoshuo = new Duoshuo({ 18 | short_name: 'abc', // 站点申请的多说二级域名。 19 | secret: 'xxx' // 站点密钥 20 | }) 21 | 22 | // Auth 23 | duoshuo 24 | .auth(code) 25 | .then(function(access_token){ 26 | console.log(access_token) 27 | }) 28 | .catch(function(err){ 29 | console.error(err) 30 | }) 31 | 32 | // 通过duoshuo.auth获得的access_token 33 | var access_token = 'xxxxxxxxxxxxxxxxxx' 34 | var client = duoshuo.getClient(access_token) 35 | 36 | // Join local user to duoshuo.com 37 | client.join({ 38 | user: {}, 39 | }).then(function(user) { 40 | console.log(user) 41 | }).catch(function(err){ 42 | console.log(err) 43 | }) 44 | 45 | // Fetch top articles 46 | client.tops({ 47 | range: 'daily' // 获取本日,详见:http://dev.duoshuo.com/docs/50398b4b8551ece011000023 48 | num_items: 10 // 获取10篇 49 | }).then(function(err, threads) { 50 | console.log(threads) 51 | }) 52 | 53 | // Push comments to duoshuo.com 54 | client.comment({ 55 | message: '我的一条新匿名评论' 56 | }).then(function(err, comment) { 57 | console.log(comment) 58 | }) 59 | ``` 60 | 61 | ### Tests 62 | 63 | ```bash 64 | $ npm test 65 | ``` 66 | -------------------------------------------------------------------------------- /dist/apis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 接口参数请参考官方文档 4 | * http://dev.duoshuo.com/docs 5 | * 6 | **/ 7 | 'use strict'; 8 | 9 | Object.defineProperty(exports, '__esModule', { 10 | value: true 11 | }); 12 | exports['default'] = { 13 | token: { 14 | method: 'post', 15 | url: 'oauth2/access_token', 16 | callback: defaultCallback 17 | }, 18 | userProfile: { 19 | method: 'get', 20 | url: 'users/profile.json', 21 | callback: defaultCallback 22 | }, 23 | join: { 24 | method: 'post', 25 | url: 'sites/join.json', 26 | callback: defaultCallback 27 | }, 28 | threads: { 29 | method: 'get', 30 | url: 'threads/counts.json', 31 | callback: defaultCallback 32 | }, 33 | comments: { 34 | method: 'post', 35 | url: 'posts/create.json', 36 | callback: defaultCallback 37 | }, 38 | tops: { 39 | method: 'get', 40 | url: 'sites/listTopThreads.json', 41 | callback: defaultCallback 42 | } 43 | }; 44 | 45 | function defaultCallback(err, res, body, next) { 46 | if (err) return next(err); 47 | 48 | if (res.statusCode !== 200) return next(new Error(res.statusCode), res); 49 | 50 | if (body.code !== 0) return next(new Error(body.errorMessage), res); 51 | 52 | return next(err, body); 53 | } 54 | module.exports = exports['default']; 55 | //# sourceMappingURL=apis.js.map -------------------------------------------------------------------------------- /dist/apis.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../libs/apis.js"],"names":[],"mappings":";;;;;;;;;;;qBAMe;AACb,OAAK,EAAE;AACL,UAAM,EAAE,MAAM;AACd,OAAG,EAAE,qBAAqB;AAC1B,YAAQ,EAAE,eAAe;GAC1B;AACD,aAAW,EAAE;AACX,UAAM,EAAE,KAAK;AACb,OAAG,EAAE,oBAAoB;AACzB,YAAQ,EAAE,eAAe;GAC1B;AACD,MAAI,EAAE;AACJ,UAAM,EAAE,MAAM;AACd,OAAG,EAAE,iBAAiB;AACtB,YAAQ,EAAE,eAAe;GAC1B;AACD,SAAO,EAAE;AACP,UAAM,EAAE,KAAK;AACb,OAAG,EAAE,qBAAqB;AAC1B,YAAQ,EAAE,eAAe;GAC1B;AACD,UAAQ,EAAE;AACR,UAAM,EAAE,MAAM;AACd,OAAG,EAAE,mBAAmB;AACxB,YAAQ,EAAE,eAAe;GAC1B;AACD,MAAI,EAAE;AACJ,UAAM,EAAE,KAAK;AACb,OAAG,EAAE,2BAA2B;AAChC,YAAQ,EAAE,eAAe;GAC1B;CACF;;AAED,SAAS,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE;AAC7C,MAAI,GAAG,EACL,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;;AAElB,MAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EACxB,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAA;;AAE7C,MAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EACjB,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,CAAA;;AAEhD,SAAO,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;CACvB","file":"apis.js","sourcesContent":["/**\n *\n * 接口参数请参考官方文档\n * http://dev.duoshuo.com/docs\n *\n **/\nexport default {\n token: {\n method: 'post',\n url: 'oauth2/access_token',\n callback: defaultCallback\n },\n userProfile: {\n method: 'get',\n url: 'users/profile.json',\n callback: defaultCallback\n },\n join: {\n method: 'post',\n url: 'sites/join.json',\n callback: defaultCallback\n },\n threads: {\n method: 'get',\n url: 'threads/counts.json',\n callback: defaultCallback\n },\n comments: {\n method: 'post',\n url: 'posts/create.json',\n callback: defaultCallback\n },\n tops: {\n method: 'get',\n url: 'sites/listTopThreads.json',\n callback: defaultCallback\n }\n}\n\nfunction defaultCallback(err, res, body, next) {\n if (err) \n return next(err)\n\n if (res.statusCode !== 200) \n return next(new Error(res.statusCode), res)\n\n if (body.code !== 0) \n return next(new Error(body.errorMessage), res)\n\n return next(err, body)\n}\n"]} -------------------------------------------------------------------------------- /dist/duoshuo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | var _sdk = require('sdk'); 14 | 15 | var _sdk2 = _interopRequireDefault(_sdk); 16 | 17 | var _apis = require('./apis'); 18 | 19 | var _apis2 = _interopRequireDefault(_apis); 20 | 21 | var _rules = require('./rules'); 22 | 23 | var _rules2 = _interopRequireDefault(_rules); 24 | 25 | var Duoshuo = (function () { 26 | function Duoshuo(config) { 27 | _classCallCheck(this, Duoshuo); 28 | 29 | if (!config.short_name) return; 30 | 31 | this.config = config; 32 | this.host = 'api.duoshuo.com'; 33 | this.sdk = new _sdk2['default']('https://' + this.host, _apis2['default'], (0, _rules2['default'])(config)); 34 | } 35 | 36 | _createClass(Duoshuo, [{ 37 | key: 'auth', 38 | 39 | /** 40 | * 41 | * Duoshuo#auth 42 | * 使用 `code` 换取 `access_token` 与用户 ID 43 | * 44 | **/ 45 | value: function auth(code) { 46 | var query = { 47 | form: { 48 | code: code, 49 | client_id: this.config.short_name 50 | } 51 | }; 52 | 53 | return this.sdk.token(query); 54 | } 55 | }, { 56 | key: 'signin', 57 | 58 | /** 59 | * 60 | * Duoshuo#signin() 61 | * Signin middleware: `Express/Connect` 等框架可直接使用此 middleware 62 | * 63 | **/ 64 | value: function signin() { 65 | var _this = this; 66 | 67 | return function (req, res, next) { 68 | _this.auth(req.query.code).then(function (result) { 69 | res.locals.duoshuo = result; 70 | return next(); 71 | })['catch'](next); 72 | }; 73 | } 74 | }, { 75 | key: 'getClient', 76 | 77 | /** 78 | * 79 | * Duoshuo#getClient 80 | * 获取一个 duoshuoClient 实例 81 | * 82 | **/ 83 | value: function getClient(access_token) { 84 | if (!access_token) return; 85 | 86 | return new duoshuoClient(this.sdk, access_token); 87 | } 88 | }]); 89 | 90 | return Duoshuo; 91 | })(); 92 | 93 | exports['default'] = Duoshuo; 94 | 95 | /** 96 | * 97 | * duoshuoClient 98 | * 构造一个 duoshuoClient 实例, 99 | * duoshuoClient 用于在拥有 `access_token` 的情况下访问多说接口 100 | **/ 101 | 102 | var duoshuoClient = (function () { 103 | function duoshuoClient(sdk, access_token) { 104 | _classCallCheck(this, duoshuoClient); 105 | 106 | this.access_token = access_token; 107 | this.init(sdk); 108 | } 109 | 110 | _createClass(duoshuoClient, [{ 111 | key: 'init', 112 | value: function init(sdk) { 113 | var _this2 = this; 114 | 115 | // Init build-in method 116 | ['get', 'post', 'put', 'delete'].forEach(function (method) { 117 | _this2[method] = function (url, params) { 118 | var data = params; 119 | var key = ({ 120 | 'get': 'qs', 121 | 'post': 'form' 122 | })[method]; 123 | 124 | if (!key) key = {}; 125 | 126 | key.access_token = _this2.access_token; 127 | 128 | // Todo: rewrited to return a Promise 129 | return sdk[method](url, data); 130 | }; 131 | }); 132 | 133 | // Init custom api and inject `access_token` 134 | Object.keys(_apis2['default']).forEach(function (key) { 135 | if (key === 'token') return; 136 | 137 | _this2[key] = function (params) { 138 | var method = _apis2['default'][key].method; 139 | var data = {}; 140 | var qsKey = ({ 141 | 'get': 'qs', 142 | 'post': 'form' 143 | })[method]; 144 | 145 | data[qsKey] = params[qsKey] || params; 146 | data[qsKey].access_token = _this2.access_token; 147 | 148 | return sdk[key](data); 149 | }; 150 | }); 151 | } 152 | }]); 153 | 154 | return duoshuoClient; 155 | })(); 156 | 157 | module.exports = exports['default']; 158 | //# sourceMappingURL=duoshuo.js.map -------------------------------------------------------------------------------- /dist/duoshuo.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../libs/duoshuo.js"],"names":[],"mappings":"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","file":"duoshuo.js","sourcesContent":["import SDK from 'sdk'\nimport apis from './apis'\nimport rules from './rules'\n\nexport default class Duoshuo {\n constructor(config) {\n if (!config.short_name) \n return\n\n this.config = config\n this.host = 'api.duoshuo.com'\n this.sdk = new SDK(`https://${ this.host }`, apis, rules(config))\n }\n\n /**\n *\n * Duoshuo#auth\n * 使用 `code` 换取 `access_token` 与用户 ID\n *\n **/\n auth(code) {\n const query = {\n form: {\n code,\n client_id: this.config.short_name\n }\n }\n\n return this.sdk.token(query)\n }\n\n /**\n *\n * Duoshuo#signin()\n * Signin middleware: `Express/Connect` 等框架可直接使用此 middleware\n *\n **/\n signin() {\n return (req, res, next) => {\n this\n .auth(req.query.code)\n .then(result => {\n res.locals.duoshuo = result\n return next()\n })\n .catch(next)\n }\n }\n\n /**\n *\n * Duoshuo#getClient\n * 获取一个 duoshuoClient 实例\n *\n **/\n getClient(access_token) {\n if (!access_token) \n return\n\n return new duoshuoClient(this.sdk, access_token)\n }\n}\n\n/**\n *\n * duoshuoClient\n * 构造一个 duoshuoClient 实例,\n * duoshuoClient 用于在拥有 `access_token` 的情况下访问多说接口\n **/\nclass duoshuoClient {\n constructor(sdk, access_token) {\n this.access_token = access_token\n this.init(sdk)\n }\n\n init(sdk) {\n // Init build-in method\n ['get','post','put','delete'].forEach(method => {\n this[method] = (url, params) => {\n let data = params\n let key = {\n 'get': 'qs',\n 'post': 'form'\n }[method]\n\n if (!key)\n key = {}\n\n key.access_token = this.access_token\n\n // Todo: rewrited to return a Promise\n return sdk[method](url, data)\n }\n })\n\n // Init custom api and inject `access_token`\n Object.keys(apis).forEach(key => {\n if (key === 'token') \n return\n\n this[key] = params => {\n let method = apis[key].method\n let data = {}\n let qsKey = {\n 'get': 'qs',\n 'post': 'form'\n }[method]\n\n data[qsKey] = params[qsKey] || params\n data[qsKey].access_token = this.access_token\n\n return sdk[key](data)\n }\n })\n }\n}\n"]} -------------------------------------------------------------------------------- /dist/rules.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports["default"] = function (_ref) { 8 | var short_name = _ref.short_name; 9 | 10 | return { 11 | get: { 12 | qs: { 13 | short_name: short_name 14 | } 15 | }, 16 | post: { 17 | form: { 18 | short_name: short_name 19 | } 20 | } 21 | }; 22 | }; 23 | 24 | module.exports = exports["default"]; 25 | //# sourceMappingURL=rules.js.map -------------------------------------------------------------------------------- /dist/rules.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../libs/rules.js"],"names":[],"mappings":";;;;;;qBAAe,UAAS,IAAc,EAAE;MAAd,UAAU,GAAZ,IAAc,CAAZ,UAAU;;AAClC,SAAO;AACL,OAAG,EAAE;AACH,QAAE,EAAE;AACF,kBAAU,EAAV,UAAU;OACX;KACF;AACD,QAAI,EAAE;AACJ,UAAI,EAAE;AACJ,kBAAU,EAAV,UAAU;OACX;KACF;GACF,CAAA;CACF","file":"rules.js","sourcesContent":["export default function({ short_name }) {\n return {\n get: {\n qs: {\n short_name\n }\n },\n post: {\n form: {\n short_name\n }\n }\n }\n}\n"]} -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | var Duoshuo = require('../index') 2 | var duoshuo = new Duoshuo({ 3 | short_name: 'abc', // 站点申请的多说二级域名。 4 | secret: 'xxx' // 站点密钥 5 | }) 6 | 7 | // 通过 duoshuo.auth 获得的 access_token 8 | var access_token = 'xxxxxxxxxxxxxxxxxx' 9 | 10 | duoshuo 11 | .getClient(access_token) 12 | .get('abc/def.json') 13 | .then(function({ body }){ 14 | console.log(body) 15 | }) -------------------------------------------------------------------------------- /libs/apis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 接口参数请参考官方文档 4 | * http://dev.duoshuo.com/docs 5 | * 6 | **/ 7 | export default { 8 | token: { 9 | method: 'post', 10 | url: 'oauth2/access_token', 11 | callback: defaultCallback 12 | }, 13 | userProfile: { 14 | method: 'get', 15 | url: 'users/profile.json', 16 | callback: defaultCallback 17 | }, 18 | join: { 19 | method: 'post', 20 | url: 'sites/join.json', 21 | callback: defaultCallback 22 | }, 23 | threads: { 24 | method: 'get', 25 | url: 'threads/counts.json', 26 | callback: defaultCallback 27 | }, 28 | comments: { 29 | method: 'post', 30 | url: 'posts/create.json', 31 | callback: defaultCallback 32 | }, 33 | tops: { 34 | method: 'get', 35 | url: 'sites/listTopThreads.json', 36 | callback: defaultCallback 37 | } 38 | } 39 | 40 | function defaultCallback(err, res, body, next) { 41 | if (err) 42 | return next(err) 43 | 44 | if (res.statusCode !== 200) 45 | return next(new Error(res.statusCode), res) 46 | 47 | if (body.code !== 0) 48 | return next(new Error(body.errorMessage), res) 49 | 50 | return next(err, body) 51 | } 52 | -------------------------------------------------------------------------------- /libs/duoshuo.js: -------------------------------------------------------------------------------- 1 | import SDK from 'sdk' 2 | import apis from './apis' 3 | import rules from './rules' 4 | 5 | export default class Duoshuo { 6 | constructor(config) { 7 | if (!config.short_name) 8 | return 9 | 10 | this.config = config 11 | this.host = 'api.duoshuo.com' 12 | this.sdk = new SDK(`https://${ this.host }`, apis, rules(config)) 13 | } 14 | 15 | /** 16 | * 17 | * Duoshuo#auth 18 | * 使用 `code` 换取 `access_token` 与用户 ID 19 | * 20 | **/ 21 | auth(code) { 22 | const query = { 23 | form: { 24 | code, 25 | client_id: this.config.short_name 26 | } 27 | } 28 | 29 | return this.sdk.token(query) 30 | } 31 | 32 | /** 33 | * 34 | * Duoshuo#signin() 35 | * Signin middleware: `Express/Connect` 等框架可直接使用此 middleware 36 | * 37 | **/ 38 | signin() { 39 | return (req, res, next) => { 40 | this 41 | .auth(req.query.code) 42 | .then(result => { 43 | res.locals.duoshuo = result 44 | return next() 45 | }) 46 | .catch(next) 47 | } 48 | } 49 | 50 | /** 51 | * 52 | * Duoshuo#getClient 53 | * 获取一个 duoshuoClient 实例 54 | * 55 | **/ 56 | getClient(access_token) { 57 | if (!access_token) 58 | return 59 | 60 | return new duoshuoClient(this.sdk, access_token) 61 | } 62 | } 63 | 64 | /** 65 | * 66 | * duoshuoClient 67 | * 构造一个 duoshuoClient 实例, 68 | * duoshuoClient 用于在拥有 `access_token` 的情况下访问多说接口 69 | **/ 70 | class duoshuoClient { 71 | constructor(sdk, access_token) { 72 | this.access_token = access_token 73 | this.init(sdk) 74 | } 75 | 76 | init(sdk) { 77 | // Init build-in method 78 | ['get','post','put','delete'].forEach(method => { 79 | this[method] = (url, params) => { 80 | let data = params 81 | let key = { 82 | 'get': 'qs', 83 | 'post': 'form' 84 | }[method] 85 | 86 | if (!key) 87 | key = {} 88 | 89 | key.access_token = this.access_token 90 | 91 | // Todo: rewrited to return a Promise 92 | return sdk[method](url, data) 93 | } 94 | }) 95 | 96 | // Init custom api and inject `access_token` 97 | Object.keys(apis).forEach(key => { 98 | if (key === 'token') 99 | return 100 | 101 | this[key] = params => { 102 | let method = apis[key].method 103 | let data = {} 104 | let qsKey = { 105 | 'get': 'qs', 106 | 'post': 'form' 107 | }[method] 108 | 109 | data[qsKey] = params[qsKey] || params 110 | data[qsKey].access_token = this.access_token 111 | 112 | return sdk[key](data) 113 | } 114 | }) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /libs/rules.js: -------------------------------------------------------------------------------- 1 | export default function({ short_name }) { 2 | return { 3 | get: { 4 | qs: { 5 | short_name 6 | } 7 | }, 8 | post: { 9 | form: { 10 | short_name 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "duoshuo", 3 | "version": "0.4.0", 4 | "description": "a duoshuo SDK in Node.js", 5 | "main": "dist/duoshuo.js", 6 | "scripts": { 7 | "build": "node_modules/.bin/babel libs --out-dir dist --source-maps --watch", 8 | "test": "node_modules/mocha/bin/mocha test/test.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/turingou/duoshuo" 13 | }, 14 | "keywords": [ 15 | "duoshuo", 16 | "social-network", 17 | "bbs", 18 | "forum" 19 | ], 20 | "author": "turing ", 21 | "contributors": [ 22 | { 23 | "name": "turing", 24 | "email": "o.u.turing@gmail.com" 25 | }, 26 | { 27 | "name": "shen2", 28 | "email": "zhenyupku@gmail.com" 29 | } 30 | ], 31 | "maintainers": [ 32 | { 33 | "name": "turing", 34 | "email": "o.u.turing@gmail.com" 35 | }, 36 | { 37 | "name": "shen2", 38 | "email": "zhenyupku@gmail.com" 39 | } 40 | ], 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/turingou/duoshuo/issues" 44 | }, 45 | "dependencies": { 46 | "sdk": "0.4.0" 47 | }, 48 | "devDependencies": { 49 | "babel": "^5.6.23", 50 | "mocha": "^2.2.5", 51 | "should": "^7.0.2" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var should = require("should") 2 | 3 | var Duoshuo = require('../index') 4 | var duoshuo = new Duoshuo({ 5 | short_name: 'demo-shortname' // 这里必须是一个真实的 token 6 | }) 7 | 8 | describe('API', function() { 9 | describe('#auth', function() { 10 | it('无效的 Code 必须被忽略', function(done) { 11 | duoshuo 12 | .auth('fakecode') 13 | .then(function(token) { 14 | var code = token.code 15 | var error = token.errorMessage 16 | code.should.equal(2) 17 | error.should.equal('Code不存在') 18 | done() 19 | }) 20 | }) 21 | }) 22 | describe('#userProfile', function() { 23 | it('获取用户信息逻辑', function(done) { 24 | }) 25 | }) 26 | describe('#join', function() { 27 | it('将本地用户同步到远程数据库', function(done) { 28 | }) 29 | }) 30 | describe('#threads', function() { 31 | it('将帖子数据同步到远程数据库', function(done) { 32 | }) 33 | }) 34 | describe('#comments', function() { 35 | it('将评论同步到数据库', function(done) { 36 | }) 37 | }) 38 | describe('#tops', function() { 39 | it('获取热点数据', function(done) { 40 | }) 41 | }) 42 | }) 43 | --------------------------------------------------------------------------------