user.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. //
  7. class UserService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'user');
  10. this.redis = this.app.redis;
  11. this.model = this.ctx.model.User.User;
  12. this.bindEmailKey = 'bindEmail:';
  13. this.httpUtil = this.ctx.service.util.httpUtil;
  14. this.emailServiceUrl = _.get(this.app, 'config.httpPrefix.email');
  15. this.emailServiceConfig = _.get(this.app, 'config.emailConfig.config');
  16. this.bindPhoneKey = 'bindPhone:';
  17. this.smsServiceUrl = _.get(this.app, 'config.httpPrefix.sms');
  18. this.smsServiceConfig = _.get(this.app, 'config.smsConfig.config');
  19. this.phoneLoginKey = 'phoneLogin:';
  20. this.conenctCode = '&&';
  21. }
  22. async beforeCreate(data) {
  23. const openid = _.get(data, 'openid');
  24. const phone = _.get(data, 'phone');
  25. const shop = _.get(data, 'shop');
  26. if (!openid && phone) {
  27. const num = await this.model.count({ phone });
  28. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该手机号已注册');
  29. } else if (openid && shop) {
  30. const num = await this.model.count({ openid, shop });
  31. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该微信号已注册');
  32. } else throw new BusinessError(ErrorCode.BADPARAM, '参数不正确');
  33. return data;
  34. }
  35. async resetPwd({ id }, { password }) {
  36. const data = await this.model.findById(id);
  37. if (!data) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  38. data.password = { secret: password };
  39. await data.save();
  40. }
  41. /**
  42. * 登陆
  43. * @param {Object} body 登陆参数
  44. * @param body.phone 账户
  45. * @param body.password 密码
  46. */
  47. async login({ phone, password }) {
  48. const { populate } = this.getRefMods();
  49. let user = await this.model.findOne({ phone }, '+password').populate(populate);
  50. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  51. const { password: upwd, status } = user;
  52. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  53. if (password !== upwd.secret) throw new BusinessError(ErrorCode.BAD_PASSWORD);
  54. // // 使用redis存储,后续的任何操作进行token的校验
  55. // await this.setUserInRedis(user);
  56. user = JSON.parse(JSON.stringify(user));
  57. delete user.password;
  58. delete user.meta;
  59. delete user.__v;
  60. const token = this.ctx.service.util.jwt.encrypt(user);
  61. return token;
  62. }
  63. /**
  64. * 微信登录
  65. * @param {Object} body 登陆参数
  66. * @param body.openid 微信小程序的openid
  67. * @param body.shop 店铺id
  68. */
  69. async wxLogin({ openid, shop }) {
  70. const { populate } = this.getRefMods();
  71. const user = await this.model.findOne({ openid, shop }).populate(populate);
  72. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  73. const { status } = user;
  74. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  75. delete user.meta;
  76. delete user.__v;
  77. const token = this.ctx.service.util.jwt.encrypt(user);
  78. return token;
  79. }
  80. /**
  81. * 绑定邮箱验证码
  82. * @param {Object} body 请求体
  83. * @param body.id 用户id
  84. * @param body.email 用户要绑定的邮箱
  85. */
  86. async toBindEmail({ id, email }) {
  87. const code = _.random(100000, 999999);
  88. const value = `${email}${this.conenctCode}${code}`;
  89. await this.redis.set(`${this.bindEmailKey}${id}`, value, 'EX', 300);
  90. // 发邮件
  91. const data = { config: this.emailServiceConfig, template: 'bindEmail', receiver: email, params: { code } };
  92. const url = `${this.emailServiceUrl}/sendEmail`;
  93. await this.httpUtil.cpost(url, data);
  94. }
  95. async checkBindEmail({ code, id, email }) {
  96. const redisData = await this.redis.get(`${this.bindEmailKey}${id}`);
  97. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  98. const arr = redisData.split(this.conenctCode);
  99. const rEmail = _.head(arr);
  100. const rCode = _.last(arr);
  101. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  102. if (email !== rEmail) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的邮箱与接收验证码的邮箱不是同一个邮箱');
  103. await this.model.updateOne({ _id: id }, { email });
  104. await this.redis.del(`${this.bindEmailKey}${id}`);
  105. }
  106. /**
  107. * 绑定手机验证码
  108. * @param {Object} body 请求体
  109. * @param body.id 用户id
  110. * @param body.phone 用户要绑定的手机
  111. */
  112. async toBindPhone({ id, phone }) {
  113. const num = await this.model.count({ phone });
  114. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '手机号已被绑定');
  115. const code = _.random(100000, 999999);
  116. const value = `${phone}${this.conenctCode}${code}`;
  117. await this.redis.set(`${this.bindPhoneKey}${id}`, value, 'EX', 300);
  118. // 发短信
  119. const data = { config: this.smsServiceConfig, template: 'bind', phone, params: { code } };
  120. const url = `${this.smsServiceUrl}/sendMessage`;
  121. await this.httpUtil.cpost(url, data);
  122. }
  123. async checkBindPhone({ code, id, phone }) {
  124. const redisData = await this.redis.get(`${this.bindPhoneKey}${id}`);
  125. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  126. const arr = redisData.split(this.conenctCode);
  127. const rphone = _.head(arr);
  128. const rCode = _.last(arr);
  129. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  130. if (phone !== rphone) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的手机号与接收验证码的手机号不是同一个手机号');
  131. await this.model.updateOne({ _id: id }, { phone });
  132. await this.redis.del(`${this.bindPhoneKey}${id}`);
  133. }
  134. // 发送登陆验证码
  135. async toLoginByCode({ phone }) {
  136. const code = _.random(100000, 999999);
  137. const value = `${phone}${this.conenctCode}${code}`;
  138. await this.redis.set(`${this.phoneLoginKey}${phone}`, value, 'EX', 300);
  139. // 发短信
  140. const data = { config: this.smsServiceConfig, template: 'login', phone, params: { code } };
  141. const url = `${this.smsServiceUrl}/sendMessage`;
  142. await this.httpUtil.cpost(url, data);
  143. }
  144. // 检查登陆验证码,然后登陆
  145. async checkLoginCode({ phone, code }) {
  146. const redisData = await this.redis.get(`${this.phoneLoginKey}${phone}`);
  147. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  148. const arr = redisData.split(this.conenctCode);
  149. const rphone = _.head(arr);
  150. const rCode = _.last(arr);
  151. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  152. if (phone !== rphone) throw new BusinessError(ErrorCode.DATA_INVALID, '要登陆的手机号与接收验证码的手机号不是同一个手机号');
  153. const { populate } = this.getRefMods();
  154. const user = await this.model.findOne({ phone }).populate(populate);
  155. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  156. const { status } = user;
  157. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  158. delete user.meta;
  159. delete user.__v;
  160. const token = this.ctx.service.util.jwt.encrypt(user);
  161. return token;
  162. }
  163. /**
  164. * 删除用户
  165. * @param {Object} param 地址参数
  166. * @param {String} param.key 就是key
  167. * @param {String} param.target 操作对象
  168. */
  169. async delete({ key, target }) {
  170. const { opera_id, target: rt } = await this.ctx.service.util.user.getKeyData(key);
  171. const admin = _.get(this.ctx, 'admin');
  172. const _id = _.get(admin, '_id');
  173. if (opera_id !== _id) throw new BusinessError(ErrorCode.DATA_INVALID, '不是同一个操作人,操作无效');
  174. if (target !== rt) throw new BusinessError(ErrorCode.DATA_INVALID, '操作对象不是同一个数据,操作无效');
  175. await this.model.deleteOne({ _id: target });
  176. }
  177. async getUserIsLeader(id) {
  178. const user = await this.model.findById(id, { is_leader: 1 }).lean();
  179. if (!user) return false;
  180. const is_leader = _.get(user, 'is_leader', '1');
  181. return is_leader === '0';
  182. }
  183. async changeCacheToken() {
  184. const user_id = _.get(this.ctx, 'user._id');
  185. if (!user_id) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户信息');
  186. const user = await this.model.findById(user_id).lean();
  187. if (user) {
  188. delete user.meta;
  189. delete user.__v;
  190. if (!user.id) user.id = user_id;
  191. const token = this.ctx.service.util.jwt.encrypt(user);
  192. return token;
  193. }
  194. }
  195. }
  196. module.exports = UserService;