Merge branch 'develop' into feature/personal
Showing
9 changed files
with
1 additions
and
928 deletions
@@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
8 | const utils = '../../../utils'; | 8 | const utils = '../../../utils'; |
9 | const helpers = global.yoho.helpers; | 9 | const helpers = global.yoho.helpers; |
10 | const _ = require('lodash'); | 10 | const _ = require('lodash'); |
11 | -const camelCase = require('../../../library/camel-case'); | 11 | +const camelCase = global.yoho.camelCase; |
12 | const productProcess = require(`${utils}/product-process`); | 12 | const productProcess = require(`${utils}/product-process`); |
13 | const url = require('url'); | 13 | const url = require('url'); |
14 | const queryString = require('querystring'); | 14 | const queryString = require('querystring'); |
library/api.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 接口公共方法 | ||
3 | - * @author: xuqi<qi.xu@yoho.cn> | ||
4 | - * @date: 2016/4/25 | ||
5 | - */ | ||
6 | - | ||
7 | -'use strict'; | ||
8 | -const rp = require('request-promise'); | ||
9 | -const qs = require('querystring'); | ||
10 | -const md5 = require('md5'); | ||
11 | -const _ = require('lodash'); | ||
12 | -const log = require('./logger'); | ||
13 | -const cache = require('./cache'); | ||
14 | -const Timer = require('./timer'); | ||
15 | -const sign = require('./sign'); | ||
16 | -const config = require('../config/common'); | ||
17 | -const api = config.domains.api; | ||
18 | -const serviceApi = config.domains.service; | ||
19 | -const searchApi = config.domains.search; | ||
20 | - | ||
21 | -// 错误返回 | ||
22 | -const API_BAD_RETSULT = { | ||
23 | - code: 500, | ||
24 | - message: 'API result is not JSON string or null.' | ||
25 | -}; | ||
26 | - | ||
27 | -// 调用失败 | ||
28 | -const API_CALL_FAIL = { | ||
29 | - code: 500, | ||
30 | - message: 'Call API failed.' | ||
31 | -}; | ||
32 | - | ||
33 | -// all 方法错误的传参 | ||
34 | -const API_ALL_METHOD_ERROR = 'the parameters of api all method should be Array!'; | ||
35 | - | ||
36 | -// 获取缓存数据失败 | ||
37 | -const SLAVE_CACHE_FAIL = 'get slave cache fail'; | ||
38 | -const MASTER_CACHE_FAIL = 'get master cache fail'; | ||
39 | - | ||
40 | -// 获取缓存数据成功 | ||
41 | -const SLAVE_CACHE_SUCCESS = 'get slave cache success'; | ||
42 | -const MASTER_CACHE_SUCCESS = 'get master cache success'; | ||
43 | - | ||
44 | -class Http { | ||
45 | - | ||
46 | - constructor(baseUrl) { | ||
47 | - this.ApiUrl = baseUrl; | ||
48 | - } | ||
49 | - | ||
50 | - /** | ||
51 | - * 获取请求 ID | ||
52 | - */ | ||
53 | - _getReqId(options) { | ||
54 | - return md5(`${options.url}?${qs.stringify(options.qs || options.form)}`); | ||
55 | - } | ||
56 | - | ||
57 | - /** | ||
58 | - * 处理接口返回状态码 | ||
59 | - */ | ||
60 | - _handleDataCode(data, code, url) { | ||
61 | - let result = {}; | ||
62 | - | ||
63 | - code = code || 200; | ||
64 | - if (_.toNumber(data.code) === _.toNumber(code)) { | ||
65 | - _.unset(data, 'code'); | ||
66 | - _.forEach(data, (value, key) => { | ||
67 | - _.set(result, key, value); | ||
68 | - }); | ||
69 | - } else { | ||
70 | - log.error(`API: ${url} return code not ${code}`); | ||
71 | - } | ||
72 | - return result; | ||
73 | - } | ||
74 | - | ||
75 | - | ||
76 | - /** | ||
77 | - * 调用接口 | ||
78 | - */ | ||
79 | - _requestFromAPI(options, param, reqId) { | ||
80 | - const timer = new Timer(); | ||
81 | - const method = options.method || 'get'; | ||
82 | - | ||
83 | - timer.put('getApi');// 统计时间开始 | ||
84 | - return rp(options).then((result) => { | ||
85 | - const duration = timer.put('getApi');// 统计时间结束 | ||
86 | - | ||
87 | - // 数据校验 | ||
88 | - if (!result) { | ||
89 | - log.error(`error: ${API_BAD_RETSULT.message}`); | ||
90 | - return Promise.reject(API_BAD_RETSULT); | ||
91 | - } | ||
92 | - | ||
93 | - // 处理返回数据状态码 | ||
94 | - if (param && param.code) { | ||
95 | - result = this._handleDataCode(result, param.code, options.url); | ||
96 | - } | ||
97 | - | ||
98 | - // 写缓存, 否则返回 Slave 缓存服务器的数据 | ||
99 | - if (options.method === 'get' && config.useCache && | ||
100 | - param && param.cache) { | ||
101 | - const cacheTime = _.isNumber(param.cache) ? param.cache : 60; | ||
102 | - const catchErr = (err) => { | ||
103 | - log.error(`cache: ${err.toString()}`); | ||
104 | - }; | ||
105 | - | ||
106 | - reqId = reqId || this._getReqId(options); | ||
107 | - cache.set(`apiCache:${reqId}`, result, cacheTime).catch(catchErr); | ||
108 | - cache.setSlave(`apiCache:${reqId}`, result, 86400).catch(catchErr); // 二级缓存存储一天 | ||
109 | - } | ||
110 | - | ||
111 | - log.info(`use: ${duration}ms for ${method} api: ${options.url}?${qs.stringify(options.qs)} `); | ||
112 | - return result; | ||
113 | - }).catch((err)=> { | ||
114 | - const duration = timer.put('getApi');// 统计时间结束 | ||
115 | - | ||
116 | - log.error(`${method} api fail: use: ${duration}ms, code:${err.statusCode}, error: ${err.message}`); | ||
117 | - log.error(`API: ${options.url}?${qs.stringify(options.qs)}`); | ||
118 | - | ||
119 | - // 使用缓存的时候,读取二级缓存 | ||
120 | - if (config.useCache && param && param.cache) { | ||
121 | - return this._requestFromCache(options, true); | ||
122 | - } | ||
123 | - return Promise.resolve(API_CALL_FAIL); | ||
124 | - }); | ||
125 | - } | ||
126 | - | ||
127 | - /** | ||
128 | - * 读取缓存 | ||
129 | - * @param {[object]} options | ||
130 | - * @param {[boolean]} slave true: 读取二级缓存 | ||
131 | - * @param {[object]} param 请求API处理参数 | ||
132 | - * @return {[type]} | ||
133 | - */ | ||
134 | - _requestFromCache(options, slave, param) { | ||
135 | - const reqId = this._getReqId(options); | ||
136 | - const getCache = slave ? cache.getFromSlave : cache.get; | ||
137 | - | ||
138 | - log.info(`get ${slave ? 'slave' : 'master'} cache: ${reqId}, url: ${options.url}?${qs.stringify(options.qs)}`); | ||
139 | - return getCache(`apiCache:${reqId}`).then((result) => { | ||
140 | - if (!_.isNil(result)) { | ||
141 | - try { | ||
142 | - result = JSON.parse(result); | ||
143 | - } finally { | ||
144 | - log.info(slave ? SLAVE_CACHE_SUCCESS : MASTER_CACHE_SUCCESS); | ||
145 | - return result; | ||
146 | - } | ||
147 | - } | ||
148 | - | ||
149 | - // 读取缓存失败,并且不是二级缓存的时候,调用 API | ||
150 | - if (!slave) { | ||
151 | - return this._requestFromAPI(options, param, reqId); | ||
152 | - } | ||
153 | - }).catch(() => { | ||
154 | - log.error(slave ? SLAVE_CACHE_FAIL : MASTER_CACHE_FAIL); | ||
155 | - | ||
156 | - // 读取缓存失败,并且不是二级缓存的时候,调用 API | ||
157 | - if (!slave) { | ||
158 | - return this._requestFromAPI(options, param, reqId); | ||
159 | - } | ||
160 | - | ||
161 | - return Promise.resolve(API_CALL_FAIL); | ||
162 | - }); | ||
163 | - } | ||
164 | - | ||
165 | - /** | ||
166 | - * 使用 get 请求获取接口 | ||
167 | - * @param {[string]} url | ||
168 | - * @param {[object]} data | ||
169 | - * @param {[object]} param 数据处理参数 | ||
170 | - * @return {[type]} | ||
171 | - */ | ||
172 | - get(url, data, param) { | ||
173 | - const options = { | ||
174 | - url: `${this.ApiUrl}${url}`, | ||
175 | - qs: data.client_secret ? data : sign.apiSign(data), | ||
176 | - json: true, | ||
177 | - gzip: true, | ||
178 | - timeout: 3000 | ||
179 | - }; | ||
180 | - | ||
181 | - // 从缓存获取数据 | ||
182 | - if (config.useCache && param && param.catch) { | ||
183 | - return this._requestFromCache(options, false, param); | ||
184 | - } | ||
185 | - | ||
186 | - return this._requestFromAPI(options, param); | ||
187 | - } | ||
188 | - | ||
189 | - /** | ||
190 | - * 使用 post 请求获取接口 | ||
191 | - * @param {[string]} url | ||
192 | - * @param {[object]} data | ||
193 | - * @param {[object]} param 数据处理参数 | ||
194 | - * @return {[type]} | ||
195 | - */ | ||
196 | - post(url, data, param) { | ||
197 | - const options = { | ||
198 | - url: `${this.ApiUrl}${url}`, | ||
199 | - form: data.client_secret ? data : sign.apiSign(data), | ||
200 | - method: 'post', | ||
201 | - json: true, | ||
202 | - timeout: 3000 | ||
203 | - }; | ||
204 | - | ||
205 | - return this._requestFromAPI(options, param); | ||
206 | - } | ||
207 | - | ||
208 | - all(list) { | ||
209 | - if (_.isArray(list)) { | ||
210 | - return Promise.all(list); | ||
211 | - } else { | ||
212 | - return Promise.reject(Error(API_ALL_METHOD_ERROR)); | ||
213 | - } | ||
214 | - } | ||
215 | -} | ||
216 | - | ||
217 | -class API extends Http { | ||
218 | - constructor() { | ||
219 | - super(api); | ||
220 | - } | ||
221 | -} | ||
222 | - | ||
223 | -class ServiceAPI extends Http { | ||
224 | - constructor() { | ||
225 | - super(serviceApi); | ||
226 | - } | ||
227 | -} | ||
228 | - | ||
229 | -class SearchAPI extends Http { | ||
230 | - constructor() { | ||
231 | - super(searchApi); | ||
232 | - } | ||
233 | -} | ||
234 | - | ||
235 | -exports.API = API; | ||
236 | -exports.ServiceAPI = ServiceAPI; | ||
237 | -exports.SearchAPI = SearchAPI; |
library/cache.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 缓存封装 | ||
3 | - * 前期使用 memcache, 写方法的时候考虑一下如何转换为 redis | ||
4 | - * @author bikai kai.bi@yoho.cn | ||
5 | - * @date 2016/05/16 | ||
6 | - */ | ||
7 | -'use strict'; | ||
8 | -const Promise = require('bluebird'); | ||
9 | -const Memcached = require('memcached'); | ||
10 | -const _ = require('lodash'); | ||
11 | -const config = require('../config/common'); | ||
12 | - | ||
13 | -let master = new Memcached(config.memcache.master, config.memcache); | ||
14 | -let slave = new Memcached(config.memcache.slave, config.memcache); | ||
15 | - | ||
16 | -master = Promise.promisifyAll(master); | ||
17 | -slave = Promise.promisifyAll(slave); | ||
18 | - | ||
19 | -/** | ||
20 | - * 获取缓存 | ||
21 | - * @param {[string]} key 键 | ||
22 | - * @return {[type]} | ||
23 | - */ | ||
24 | -exports.get = (key) => { | ||
25 | - if (_.isString(key)) { | ||
26 | - return master.getAsync(key); | ||
27 | - } | ||
28 | - | ||
29 | - return Promise.resolve(); | ||
30 | -}; | ||
31 | - | ||
32 | -/** | ||
33 | - * 批量获取缓存 | ||
34 | - * @param {[array]} list 字符串数组 | ||
35 | - * @return {[type]} | ||
36 | - */ | ||
37 | -exports.getMulti = (list) => { | ||
38 | - if (_.isArray(list)) { | ||
39 | - return master.getMultiAsync(list); | ||
40 | - } | ||
41 | - return Promise.resolve(); | ||
42 | -}; | ||
43 | - | ||
44 | -/** | ||
45 | - * 获取缓存(从 Slave 服务器) | ||
46 | - * @param {[string]} key 键 | ||
47 | - * @return {[type]} | ||
48 | - */ | ||
49 | -exports.getFromSlave = (key) => { | ||
50 | - if (_.isString(key)) { | ||
51 | - return slave.getAsync(key); | ||
52 | - } | ||
53 | - return Promise.resolve(); | ||
54 | -}; | ||
55 | - | ||
56 | -/** | ||
57 | - * 批量获取缓存(从 Slave 服务器) | ||
58 | - * @param {[array]} list 字符串数组 | ||
59 | - * @return {[type]} | ||
60 | - */ | ||
61 | -exports.getMultiFromSlave = (list) => { | ||
62 | - if (_.isArray(list)) { | ||
63 | - return slave.getMultiAsync(list); | ||
64 | - } | ||
65 | - return Promise.resolve(); | ||
66 | -}; | ||
67 | - | ||
68 | -/** | ||
69 | - * 写缓存 | ||
70 | - * @param {[type]} key 键 | ||
71 | - * @param {[type]} value 值 | ||
72 | - * @param {[type]} lifetime 生命周期 | ||
73 | - * @return {[type]} | ||
74 | - */ | ||
75 | -exports.set = (key, value, lifetime) => { | ||
76 | - lifetime = lifetime || 86400; | ||
77 | - | ||
78 | - if (_.isObject(value)) { | ||
79 | - value = JSON.stringify(value); | ||
80 | - } | ||
81 | - | ||
82 | - if (_.isString(key)) { | ||
83 | - return master.setAsync(key, value, lifetime); | ||
84 | - } | ||
85 | - return Promise.resolve(); | ||
86 | -}; | ||
87 | - | ||
88 | -/** | ||
89 | - * 写缓存(到 Slave 服务器) | ||
90 | - * @param {[type]} key 键 | ||
91 | - * @param {[type]} value 值 | ||
92 | - * @param {[type]} lifetime 生命周期 | ||
93 | - * @return {[type]} | ||
94 | - */ | ||
95 | -exports.setSlave = (key, value, lifetime) => { | ||
96 | - lifetime = lifetime || 86400; | ||
97 | - | ||
98 | - if (_.isObject(value)) { | ||
99 | - value = JSON.stringify(value); | ||
100 | - } | ||
101 | - | ||
102 | - if (_.isString(key)) { | ||
103 | - return slave.setAsync(key, value, lifetime); | ||
104 | - } | ||
105 | - return Promise.resolve(); | ||
106 | -}; | ||
107 | - | ||
108 | -/** | ||
109 | - * 删除缓存 | ||
110 | - * @param {[string]} key 键 | ||
111 | - * @return {[type]} | ||
112 | - */ | ||
113 | -exports.del = (key) => { | ||
114 | - if (_.isString(key)) { | ||
115 | - return master.delAsync(key); | ||
116 | - } | ||
117 | - return Promise.resolve(); | ||
118 | -}; |
library/camel-case.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 对象键名驼峰化 | ||
3 | - * @author: Bi Kai<kai.bi@yoho.cn> | ||
4 | - * @date: 2016/05/09 | ||
5 | - */ | ||
6 | -'use strict'; | ||
7 | -const _ = require('lodash'); | ||
8 | - | ||
9 | -let camelCase, | ||
10 | - camelCaseObject, | ||
11 | - camelCaseArray; | ||
12 | - | ||
13 | -camelCaseObject = (obj) => { | ||
14 | - _.forEach(Object.keys(obj), (k) => { | ||
15 | - obj[k] = camelCase(obj[k]); | ||
16 | - if (/[_-]/.test(k)) { | ||
17 | - obj[_.camelCase(k)] = obj[k]; | ||
18 | - delete obj[k]; | ||
19 | - } | ||
20 | - }); | ||
21 | - return obj; | ||
22 | -}; | ||
23 | - | ||
24 | -camelCaseArray = (list) => { | ||
25 | - _.forEach(list, (k) => { | ||
26 | - k = camelCase(k); | ||
27 | - }); | ||
28 | - return list; | ||
29 | -}; | ||
30 | - | ||
31 | -camelCase = (data) => { | ||
32 | - if (_.isArray(data)) { | ||
33 | - data = camelCaseArray(data); | ||
34 | - } else if (_.isObject(data)) { | ||
35 | - data = camelCaseObject(data); | ||
36 | - } | ||
37 | - | ||
38 | - return data; | ||
39 | -}; | ||
40 | - | ||
41 | -module.exports = camelCase; |
library/cookie.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 获取 UID | ||
3 | - * @param {[object]} req | ||
4 | - * @return {[string]} | ||
5 | - */ | ||
6 | -'use strict'; | ||
7 | -const sign = require('./sign'); | ||
8 | - | ||
9 | -exports.getUid = (req) => { | ||
10 | - const cookie = req.cookies._UID; | ||
11 | - let _uid = 0; | ||
12 | - let cookieList; | ||
13 | - | ||
14 | - if (req.isApp) { | ||
15 | - return req.query.uid || 0; | ||
16 | - } | ||
17 | - | ||
18 | - if (cookie) { | ||
19 | - cookieList = cookie.split('::'); | ||
20 | - if (cookieList[1] && !isNaN(cookieList[1])) { | ||
21 | - _uid = cookieList[1]; | ||
22 | - } | ||
23 | - } | ||
24 | - | ||
25 | - // 校验 cookie 的 uid 有没有被修改 | ||
26 | - if (req.cookies._TOKEN !== sign.makeToken(_uid)) { | ||
27 | - _uid = 0; | ||
28 | - } | ||
29 | - | ||
30 | - return _uid; | ||
31 | -}; | ||
32 | - | ||
33 | -exports.getShoppingKey = (req) => { | ||
34 | - return req.cookies['_SPK'] ? req.cookies['_SPK'] : ''; // eslint-disable-line | ||
35 | -}; |
library/helpers.js
deleted
100644 → 0
1 | -/** | ||
2 | - * Handlebars helpers | ||
3 | - * bikai kai.bi@yoho.cn | ||
4 | - * 2016-05-10 | ||
5 | - */ | ||
6 | -'use strict'; | ||
7 | -const querystring = require('querystring'); | ||
8 | -const _ = require('lodash'); | ||
9 | -const moment = require('moment'); | ||
10 | -const config = require('../config/common'); | ||
11 | - | ||
12 | -/** | ||
13 | - * 七牛图片路径处理 | ||
14 | - * @param {[string]} url | ||
15 | - * @param {[string]} width | ||
16 | - * @param {[string]} height | ||
17 | - * @param {[string]} mode | ||
18 | - * @return {[string]} | ||
19 | - */ | ||
20 | -exports.image = (url, width, height, mode) => { | ||
21 | - mode = _.isNumber(mode) ? mode : 2; | ||
22 | - url = url || ''; | ||
23 | - return url.replace(/{width}/g, width).replace(/{height}/g, height).replace(/{mode}/g, mode); | ||
24 | -}; | ||
25 | - | ||
26 | -/** | ||
27 | - * 条件判断 | ||
28 | - * @param {[string]} v1 | ||
29 | - * @param {[string]} v2 | ||
30 | - * @param {[object]} options 上下文环境,一般不手动传 | ||
31 | - * @return {[boolen]} | ||
32 | - */ | ||
33 | -exports.isEqual = (v1, v2, _options) => { | ||
34 | - if (_.isEqual(v1, v2)) { | ||
35 | - return _options.fn(this); // eslint-disable-line | ||
36 | - } | ||
37 | - | ||
38 | - return _options.inverse(this); // eslint-disable-line | ||
39 | -}; | ||
40 | - | ||
41 | -/** | ||
42 | - * 站内地址格式化 | ||
43 | - * @param {[string]} uri 路径 | ||
44 | - * @param {[object]} qs 查询字符串 | ||
45 | - * @param {[string]} module 模块 | ||
46 | - * @return {[string]} | ||
47 | - */ | ||
48 | -exports.urlFormat = (uri, qs, module) => { | ||
49 | - const subDomain = '.yohobuy.com'; | ||
50 | - const subName = { | ||
51 | - default: config.siteUrl, | ||
52 | - guang: `//guang${subDomain}`, | ||
53 | - list: `//list${subDomain}`, | ||
54 | - search: `//search${subDomain}`, | ||
55 | - huodong: `//huodong${subDomain}`, | ||
56 | - activity: '//activity.yohobuy.com', | ||
57 | - index: config.siteUrl | ||
58 | - }; | ||
59 | - let url; | ||
60 | - | ||
61 | - module = module || 'default'; | ||
62 | - if (subName[module]) { | ||
63 | - url = subName[module]; | ||
64 | - } else { | ||
65 | - url = `//${module}${subDomain}`; // 规则没匹配到就把模块当作子域名 | ||
66 | - } | ||
67 | - | ||
68 | - url += uri; | ||
69 | - if (qs) { | ||
70 | - url += `?${querystring.stringify(qs)}`; | ||
71 | - } | ||
72 | - | ||
73 | - return url; | ||
74 | -}; | ||
75 | - | ||
76 | -/** | ||
77 | - * 站内地址格式化 | ||
78 | - * @param {[string]} uri 路径 | ||
79 | - * @param {[object]} qs 查询字符串 | ||
80 | - * @param {[string]} module 模块 | ||
81 | - * @return {[string]} | ||
82 | - */ | ||
83 | -exports.fakeUrlFormat = (uri, qs, module) => { | ||
84 | - const subDomain = 'http://localhost:6001'; | ||
85 | - const subName = { | ||
86 | - default: subDomain, | ||
87 | - guang: `${subDomain}`, | ||
88 | - list: `${subDomain}`, | ||
89 | - search: `${subDomain}`, | ||
90 | - huodong: `${subDomain}`, | ||
91 | - index: subDomain | ||
92 | - }; | ||
93 | - let url; | ||
94 | - | ||
95 | - module = module || 'default'; | ||
96 | - if (subName[module]) { | ||
97 | - url = subName[module]; | ||
98 | - } else { | ||
99 | - url = `//${module}${subDomain}`; // 规则没匹配到就把模块当作子域名 | ||
100 | - } | ||
101 | - | ||
102 | - url += uri; | ||
103 | - if (qs) { | ||
104 | - url += `?${querystring.stringify(qs)}`; | ||
105 | - } | ||
106 | - | ||
107 | - return url; | ||
108 | -}; | ||
109 | - | ||
110 | -/** | ||
111 | - * 大写转小写处理 | ||
112 | - * @param {[string]} str 转换字符 | ||
113 | - */ | ||
114 | -exports.lowerCase = (str) => { | ||
115 | - str = str || ''; | ||
116 | - return str.toLowerCase(); | ||
117 | -}; | ||
118 | - | ||
119 | -/** | ||
120 | - * 小写转大写处理 | ||
121 | - * @param {[string]} str 转换字符 | ||
122 | - */ | ||
123 | -exports.upperCase = (str) => { | ||
124 | - str = str || ''; | ||
125 | - return str.toUpperCase(); | ||
126 | -}; | ||
127 | - | ||
128 | -/** | ||
129 | - * 四舍五入 | ||
130 | - * @param {[type]} num 数字 | ||
131 | - * @param {[type]} precision 精度 | ||
132 | - * @return {[type]} | ||
133 | - */ | ||
134 | -exports.round = (num, precision) => { | ||
135 | - precision = _.isNumber(precision) ? precision : 2; | ||
136 | - num = _.isInteger(num) ? (+num).toFixed(precision) : _.round(num, precision); | ||
137 | - return num; | ||
138 | -}; | ||
139 | - | ||
140 | -/** | ||
141 | - * 时间格式化 | ||
142 | - * @param format 格式化token @see{http://momentjs.cn/docs/#/displaying/format/} | ||
143 | - * @param date 日期或者数字 | ||
144 | - * @return string | ||
145 | - * | ||
146 | - */ | ||
147 | -exports.dateFormat = (format, date) => { | ||
148 | - if (typeof format !== 'string' || typeof date === 'undefined') { | ||
149 | - return ''; | ||
150 | - } else { | ||
151 | - if (date instanceof Date) { | ||
152 | - return moment(date).format(format); | ||
153 | - } else { | ||
154 | - const d = moment.unix(date); | ||
155 | - | ||
156 | - return moment(d).utc().format(format); | ||
157 | - } | ||
158 | - } | ||
159 | -}; | ||
160 | - | ||
161 | -/** | ||
162 | - * 时间差格式化 | ||
163 | - * @param {[string]} format 格式化字符串 | ||
164 | - * @param {[number]} diff 相差值 | ||
165 | - * @param {[string]} type diff时间类型 默认ms | ||
166 | - * | ||
167 | - * Key Shorthand | ||
168 | - * years y | ||
169 | - * quarters Q | ||
170 | - * months M | ||
171 | - * weeks w | ||
172 | - * days d | ||
173 | - * hours h | ||
174 | - * minutes m | ||
175 | - * seconds s | ||
176 | - * milliseconds ms | ||
177 | - * | ||
178 | - * @example | ||
179 | - * let diff = 60 * 60 * 24 * (1.3) + 2; | ||
180 | - * | ||
181 | - * let s = helpers.dateDiffFormat('{d}天{h}小时', diff, 's'); | ||
182 | - * >>> 1天7小时 | ||
183 | - */ | ||
184 | -exports.dateDiffFormat = (format, diff, type) => { | ||
185 | - if (typeof format !== 'string' || typeof diff === 'undefined') { | ||
186 | - return ''; | ||
187 | - } else { | ||
188 | - type = type || 'ms'; | ||
189 | - const m = moment.duration(diff, type); | ||
190 | - | ||
191 | - format.match(/(\{.*?\})/g).forEach((s) => { | ||
192 | - format = format.replace(s, m.get(s.substring(1, s.length - 1))); | ||
193 | - }); | ||
194 | - | ||
195 | - return format; | ||
196 | - } | ||
197 | -}; | ||
198 | - | ||
199 | -/** | ||
200 | - * 验证邮箱是否合法 | ||
201 | - * | ||
202 | - * @param string email | ||
203 | - * @return boolean | ||
204 | - */ | ||
205 | -exports.verifyEmail = (email) => { | ||
206 | - if (!email) { | ||
207 | - return false; | ||
208 | - } | ||
209 | - | ||
210 | - const emailRegExp = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/; | ||
211 | - | ||
212 | - return emailRegExp.test(email); | ||
213 | -}; | ||
214 | - | ||
215 | -/** | ||
216 | - * 各国手机号规则 | ||
217 | - */ | ||
218 | -function areaMobileVerify(phone, area) { | ||
219 | - area = area || '86'; | ||
220 | - phone = phone.trim(); | ||
221 | - | ||
222 | - let verify = { | ||
223 | - 86: { | ||
224 | - name: '中国', | ||
225 | - match: /^1[3|4|5|8|7][0-9]{9}$/.test(phone) | ||
226 | - }, | ||
227 | - 852: { | ||
228 | - name: '中国香港', | ||
229 | - match: /^[9|6|5][0-9]{7}$/.test(phone) | ||
230 | - }, | ||
231 | - 853: { | ||
232 | - name: '中国澳门', | ||
233 | - match: /^[0-9]{8}$/.test(phone) | ||
234 | - }, | ||
235 | - 886: { | ||
236 | - name: '中国台湾', | ||
237 | - match: /^[0-9]{10}$/.test(phone) | ||
238 | - }, | ||
239 | - 65: { | ||
240 | - name: '新加坡', | ||
241 | - match: /^[9|8][0-9]{7}$/.test(phone) | ||
242 | - }, | ||
243 | - 60: { | ||
244 | - name: '马来西亚', | ||
245 | - match: /^1[1|2|3|4|6|7|9][0-9]{8}$/.test(phone) | ||
246 | - }, | ||
247 | - 1: { | ||
248 | - name: '加拿大&美国', | ||
249 | - match: /^[0-9]{10}$/.test(phone) | ||
250 | - }, | ||
251 | - 82: { | ||
252 | - name: '韩国', | ||
253 | - match: /^01[0-9]{9}$/.test(phone) | ||
254 | - }, | ||
255 | - 44: { | ||
256 | - name: '英国', | ||
257 | - match: /^7[7|8|9][0-9]{8}$/.test(phone) | ||
258 | - }, | ||
259 | - 81: { | ||
260 | - name: '日本', | ||
261 | - match: /^0[9|8|7][0-9]{9}$/.test(phone) | ||
262 | - }, | ||
263 | - 61: { | ||
264 | - name: '澳大利亚', | ||
265 | - match: /^[0-9]{11}$/.test(phone) | ||
266 | - } | ||
267 | - }; | ||
268 | - | ||
269 | - if (verify[area]) { | ||
270 | - return verify[area].match; | ||
271 | - } else { | ||
272 | - return false; | ||
273 | - } | ||
274 | -} | ||
275 | - | ||
276 | -/** | ||
277 | - * 验证国际手机号是否合法 | ||
278 | - */ | ||
279 | -exports.isAreaMobile = (areaMobile) => { | ||
280 | - if (!areaMobile) { | ||
281 | - return false; | ||
282 | - } | ||
283 | - | ||
284 | - let mobile = { | ||
285 | - area: '86', | ||
286 | - phone: '' | ||
287 | - }; | ||
288 | - | ||
289 | - let splitMobile = areaMobile.split('-'); | ||
290 | - | ||
291 | - if (splitMobile.length === 2) { | ||
292 | - mobile.area = splitMobile[0]; | ||
293 | - mobile.phone = splitMobile[1]; | ||
294 | - } else { | ||
295 | - mobile.phone = splitMobile[0]; | ||
296 | - } | ||
297 | - | ||
298 | - return areaMobileVerify(mobile.phone, mobile.area); | ||
299 | -}; | ||
300 | - | ||
301 | -/** | ||
302 | - * 验证手机是否合法 | ||
303 | - */ | ||
304 | -exports.verifyMobile = (phone) => { | ||
305 | - if (!phone) { | ||
306 | - return false; | ||
307 | - } | ||
308 | - | ||
309 | - return /^1[3|4|5|8|7][0-9]{9}$/.test(phone); | ||
310 | -}; | ||
311 | - | ||
312 | -/** | ||
313 | - * 组合国际手机号 | ||
314 | - */ | ||
315 | -exports.makeAreaMobile = (area, mobile) => { | ||
316 | - if (!area || area === '86') { | ||
317 | - return mobile; | ||
318 | - } | ||
319 | - | ||
320 | - return `${area}-${mobile}`; | ||
321 | -}; | ||
322 | - | ||
323 | -exports.isPassword = (pwd) => { | ||
324 | - if (!pwd) { | ||
325 | - return false; | ||
326 | - } | ||
327 | - | ||
328 | - let pwdRegexp = /^([a-zA-Z0-9\-\+_!@\#$%\^&\*\(\)\:\;\.=\[\]\\\',\?]){6,20}$/; | ||
329 | - | ||
330 | - return pwdRegexp.test(_.trim(pwd)); | ||
331 | -}; |
library/logger.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 日志工具类 | ||
3 | - * @author: hbomb<qiqi.zhou@yoho.cn> | ||
4 | - * @date: 2016/05/06 | ||
5 | - */ | ||
6 | -'use strict'; | ||
7 | - | ||
8 | -const winston = require('winston'); | ||
9 | -const config = require('../config/common'); | ||
10 | -const FileTransport = require('winston-daily-rotate-file'); | ||
11 | - | ||
12 | -require('influxdb-winston'); | ||
13 | - | ||
14 | -const logger = new (winston.Logger)({ | ||
15 | - transports: [ | ||
16 | - new (FileTransport)(config.loggers.infoFile), | ||
17 | - new (FileTransport)(config.loggers.errorFile), | ||
18 | - new (winston.transports.UdpTransport)(config.loggers.udp), | ||
19 | - new (winston.transports.Console)(config.loggers.console) | ||
20 | - ], | ||
21 | - exitOnError: false | ||
22 | -}); | ||
23 | - | ||
24 | -module.exports = logger; |
library/sign.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 签名 | ||
3 | - * @author: bikai | ||
4 | - * @date: 2016/5/6 | ||
5 | - */ | ||
6 | - | ||
7 | -'use strict'; | ||
8 | -const _ = require('lodash'); | ||
9 | -const md5 = require('md5'); | ||
10 | - | ||
11 | -const privateKey = { | ||
12 | - android: 'fd4ad5fcfa0de589ef238c0e7331b585', | ||
13 | - iphone: 'a85bb0674e08986c6b115d5e3a4884fa', | ||
14 | - ipad: 'ad9fcda2e679cf9229e37feae2cdcf80', | ||
15 | - web: '0ed29744ed318fd28d2c07985d3ba633', | ||
16 | - yoho: 'fd4ad5fcsa0de589af23234ks1923ks', | ||
17 | - h5: 'fd4ad5fcfa0de589ef238c0e7331b585' | ||
18 | -}; | ||
19 | - | ||
20 | -/** | ||
21 | - * 排序参数 | ||
22 | - * @param {Object} argument 需要排序的参数对象 | ||
23 | - * @return {Object} 排序之后的参数对象 | ||
24 | - */ | ||
25 | -const packageSort = argument => { | ||
26 | - const newObj = {}; | ||
27 | - | ||
28 | - for (const k of Object.keys(argument).sort()) { | ||
29 | - newObj[k] = argument[k]; | ||
30 | - } | ||
31 | - | ||
32 | - return newObj; | ||
33 | -}; | ||
34 | - | ||
35 | -/** | ||
36 | - * 生成签名 | ||
37 | - * @param {Object} argument 需要签名的数据 | ||
38 | - * @return {string} 生成的签名字符串 | ||
39 | - */ | ||
40 | -const makeSign = argument => { | ||
41 | - const qs = []; | ||
42 | - | ||
43 | - _.forEach(argument, (value, key) => { | ||
44 | - qs.push(`${key}=${_.trim(value)}`); | ||
45 | - }); | ||
46 | - | ||
47 | - return md5(qs.join('&')).toLowerCase(); | ||
48 | -}; | ||
49 | - | ||
50 | -// 生成API签名,调用后端接口的时候有私钥校验 | ||
51 | -exports.apiSign = (params) => { | ||
52 | - const clientType = params.client_type || 'web'; | ||
53 | - | ||
54 | - /* eslint-disable */ | ||
55 | - let sign = packageSort(Object.assign({ | ||
56 | - client_type: clientType, | ||
57 | - private_key: privateKey[clientType], | ||
58 | - app_version: '3.8.2', | ||
59 | - os_version: 'yohobuy:web', | ||
60 | - screen_size: '720x1280', | ||
61 | - v: '7' | ||
62 | - }, params)); | ||
63 | - /* eslint-enable */ | ||
64 | - | ||
65 | - sign = Object.assign(sign, { | ||
66 | - client_secret: makeSign(sign) | ||
67 | - }); | ||
68 | - delete sign.private_key; | ||
69 | - return sign; | ||
70 | -}; | ||
71 | - | ||
72 | -// 检查签名,APP 访问 H5 页面的时候需要检查 | ||
73 | -exports.checkSign = (params) => { | ||
74 | - const clientSecret = params.client_secret; | ||
75 | - | ||
76 | - let sortedParams; | ||
77 | - | ||
78 | - // 忽略部分参数 | ||
79 | - delete params.client_secret; | ||
80 | - delete params.q; | ||
81 | - delete params.debug_data; | ||
82 | - delete params['/api']; | ||
83 | - | ||
84 | - params.private_key = privateKey[params.client_type]; | ||
85 | - sortedParams = packageSort(params); | ||
86 | - | ||
87 | - return clientSecret === makeSign(sortedParams); | ||
88 | -}; | ||
89 | - | ||
90 | -// 检查签名,APP 访问 H5 页面的时候需要检查, 有可能不同于上边的签名方式 | ||
91 | -exports.webSign = (params) => { | ||
92 | - const webPrivateKey = 'yohobuyapp'; | ||
93 | - | ||
94 | - return params.key === md5(md5(webPrivateKey) + params.uid); | ||
95 | -}; | ||
96 | - | ||
97 | -exports.makeToken = (string) => { | ||
98 | - return md5(md5(string + '#@!@#')); | ||
99 | -}; |
library/timer.js
deleted
100644 → 0
1 | -/** | ||
2 | - * 计时类 | ||
3 | - * @example | ||
4 | - * let timer = new Timer(); | ||
5 | - * timer.put('profile'); | ||
6 | - * timer.put('proflie'); // console output: 12.14 | ||
7 | - * | ||
8 | - * @author: hbomb<qiqi.zhou@yoho.cn> | ||
9 | - * @date: 2016/05/07 | ||
10 | - */ | ||
11 | -'use strict'; | ||
12 | -class Timer { | ||
13 | - constructor() { | ||
14 | - this.timers = {}; | ||
15 | - } | ||
16 | - | ||
17 | - /** | ||
18 | - * 打点计时 | ||
19 | - */ | ||
20 | - put(label) { | ||
21 | - const labelTime = this.timers[label]; | ||
22 | - | ||
23 | - if (labelTime) { | ||
24 | - const duration = process.hrtime(labelTime); | ||
25 | - | ||
26 | - return this._round(duration[0], duration[1]); | ||
27 | - } else { | ||
28 | - this.timers[label] = process.hrtime(); | ||
29 | - } | ||
30 | - } | ||
31 | - | ||
32 | - /** | ||
33 | - * 格式化成毫秒 | ||
34 | - * @param {Number} value 纳秒 | ||
35 | - */ | ||
36 | - _round(seconds, nanoseconds) { | ||
37 | - return Math.round((seconds * 1e9 + nanoseconds) / 10000) / 100; | ||
38 | - } | ||
39 | - | ||
40 | -} | ||
41 | - | ||
42 | -module.exports = Timer; |
-
Please register or login to post a comment