user.js 9.27 KB
/**
 * Created by Tommy Huang on 18/03/21.
 */

const config = require('config-lite')({
  config_basedir: __dirname,
  config_dir: 'config'
})
const moment = require('moment')
const axios = require('axios')
const jwt = require('jsonwebtoken')
const Helper = require('./helper')

const User = require('../models').User
const Redis = require('../models/redis')

exports.get = async function(req, res) {
  try {
    const expires = Date.now() + 2592000000
    var userToken
    if (process.env.NODE_ENV !== 'production') {
      let userId = 'oLP-es_k21Xzv-HgFMXTNFLlUMPY'
      let user = await User.findOne({
        where: {id: userId}
      })
      userToken = jwt.sign({
        iss: 'qicaidai',
        userId: user.id, 
        exp: expires
      }, config.jwt.key)
      res.json({
        success: 1,
        token: userToken,
        user: {
          id: user.id,
          username: user.username,
          name: user.name,          
          headimgurl: user.headimgurl,
          phone: user.phone || '',
          needPhoneBind: !user.phoneBinded,
          needIdBind: !user.idBinded,
          needSetPassword: !user.password
        }
      })
      return
    }
    const code = req.query.code
    let userId, user, token, info, refreshToken
    userId = req.user.userId || ''
    console.log('userId:', userId)
    if (userId) {
      user = await User.findOne({
        where: {id: userId}
      })
    }
    if (user && user.refreshToken) {
      let tokenResult = await Helper.refreshUserWxToken(user.refreshToken)
      if (!tokenResult) throw new Error('刷新微信授权失败')
      userId = user.id
      token = tokenResult.access_token
      refreshToken = user.refreshToken
    } else if (code) {
      let ticketResult = await Helper.getUserWxAccessTokenInfo(code)
      if (!ticketResult) throw new Error('获取微信授权失败')
      userId = ticketResult.openid
      token = ticketResult.access_token
      refreshToken = ticketResult.refresh_token
    } else {
      throw new Error('非法参数')
    }
    info = await Helper.getUserWxInfo(token, userId)
    if (!info) throw new Error('拉取微信信息失败')
    if (!user) {
      user = await User.findOne({
        where: {id: info.openid}
      })
    }
    if (user) {
      await user.update({
        username: info.nickname,
        headimgurl: info.headimgurl,
        refreshToken: refreshToken
      })
    } else {
      user = await User.create({
        id: info.openid,
        username: info.nickname,
        headimgurl: info.headimgurl,
        refreshToken: refreshToken
      })
    }
    console.log(user.id)
    userToken = jwt.sign({
      iss: 'qicaidai',
      userId: user.id, 
      exp: expires
    }, config.jwt.key)
    res.json({
      success: 1,
      token: userToken,
      user: {
        id: user.id,
        name: user.name,
        username: info.nickname,
        headimgurl: info.headimgurl,
        phone: user.phone || '',
        needPhoneBind: !user.phoneBinded,
        needIdBind: !user.idBinded,
        needSetPassword: !user.password        
      }
    })
  } catch (e) {
    console.log(e)
    res.json({
      success: 0,
      redirect: config.entryURL,
      msg: `获取用户信息失败:${e.message}`
    })
  }
}

exports.getVerificationCode = async function(req, res) {
  try {
    const phone = req.query.phone
    const id = req.query.userId
    const idFromToken = req.user.userId
    const reg =  /^1[0-9]{10}$/
    if (!id)  throw new Error('参数错误')
    if (idFromToken !== id) throw new Error('token check fail')
    if (!reg.test(phone)) throw new Error('手机号码不正确')
    let [user, userByPhone ] = await Promise.all([
      User.findOne({where: {id: id}}),
      User.findOne({where: {phone: phone, phoneBinded: true}})
    ])
    if (userByPhone) throw new Error('该号码已注册')    
    if (!user) throw new Error('用户不存在')
    let date = moment().format('YYYY-MM-DD')
    let timesKey = `sms_${phone}_${date}`
    let frequencyKey = `fqy_${phone}_${date}`
    let [timesData, frequencyData] = await Promise.all([Redis.get(timesKey), Redis.get(frequencyKey)])
    if (frequencyData) throw new Error('获取验证码太频繁')
    if (timesData >= 6) throw new Error('今日获取验证码数量已达上限')
    let times = parseInt(timesData) || 0
    let [timeResult, frequencyResult] = await Promise.all([
      Redis.sendCommand("set", [timesKey, times + 1, 'ex', 86400]),
      Redis.sendCommand("set", [frequencyKey, 'exist', 'ex', 60])
    ])
    let send = await Helper.sendVerificationCode(phone)
    if (!send.success) throw new Error(send.msg)
    await user.update({
      verificationCode: send.code,
      phone: phone,
      codeTime: moment().format()
    })
    res.json({
      success: 1
    })
  } catch (e) {
    res.json({
      success: 0,
      msg: `获取验证码失败:${e.message}`
    })
  }
}

exports.bindPhone = async function(req, res) {
  try {
    const id = req.body.userId
    const idFromToken = req.user.userId
    const phone = req.body.phone
    const code = req.body.verificationCode
    if (!id || !phone || !code)  throw new Error('参数错误')
    if (idFromToken !== id) throw new Error('token check fail')
    let user = await User.findOne({
      where: {id: id}
    })
    if (!user) throw new Error('用户不存在')
    if (user.phone !== phone) throw new Error('修改手机号后请重新获取验证码')
    if (user.verificationCode !== code) throw new Error('验证码不正确')
    let codeTime = moment(user.codeTime).add(5, 'minutes')
    if (moment().isAfter(codeTime)) throw new Error('验证码已过期')
    const update = await user.update({
      phoneBinded: true
    })
    res.json({
      success: 1,
      phone: phone
    })
  } catch (e) {
    console.log(e)
    res.json({
      success: 0,
      msg: `绑定失败:${e.message}`
    })
  }
}

exports.bindId = async function(req, res) {
  try {
    const idFromToken = req.user.userId
    const id = req.body.userId
    const name = req.body.name || ''
    const idNo = req.body.idNo || ''
    if (!id || req.files.length !== 2 || !name || !idNo)  throw new Error('参数错误')
    if (idFromToken !== id) throw new Error('token check fail')
    const [user, idUsed] = await Promise.all([
      User.findOne({where: {id: id}}),
      User.findOne({where: {idNo: idNo}})      
    ])
    if (!user) throw new Error('用户不存在')
    if (user.idBinded) throw new Error('您已绑定过身份信息')
    if (idUsed) throw new Error('该身份证已被绑定过')
    var idFront, idBack
    req.files.forEach(file => {
      if (file.fieldname === 'idFront') {
        idFront = file
      } else if (file.fieldname === 'idBack') {
        idBack = file
      }
    })
    if (!idFront || !idBack) throw new Error('照片上传错误')
    if (idFront.size >= 2000000) {
      const compressed = await Helper.imageCompression(idFront.buffer, 1000)
      idFront = {
        buffer: compressed,
        mimetype: idFront.mimetype
      }
    }
    if (idBack.size >= 2000000) {
      const compressed = await Helper.imageCompression(idBack.buffer, 1000)
      idBack = {
        buffer: compressed,
        mimetype: idBack.mimetype
      }
    }
    const auth = Helper.tencentCloudAuthorization()
    const [frontResData, backResData] = await Promise.all([
      Helper.getIdORCResult(idFront.buffer, 0, auth),
      Helper.getIdORCResult(idBack.buffer, 1, auth)      
    ])
    if (frontResData.code !== 0 || backResData.code !== 0) throw new Error('身份证识别失败,请上传更清晰的照片')
    if (frontResData.data.name !== name || frontResData.data.id !== idNo) throw new Error('身份证识别失败,请上传更清晰的照片')
    let [update, frontSave, backSave] = await Promise.all([
      user.update({
        idBinded: true,
        name: frontResData.data.name,
        gender: frontResData.data.sex,
        nation: frontResData.data.nation,
        birth: frontResData.data.birth,
        address: frontResData.data.address,
        idNo: frontResData.data.id,
        authority: backResData.data.authority,
        validDate: backResData.data.valid_date,
      }),
      Helper.writeFile(`${config.img.idImg}/${frontResData.data.id}-Front.${idFront.mimetype.split('/')[1]}`, idFront.buffer),
      Helper.writeFile(`${config.img.idImg}/${frontResData.data.id}-Back.${idBack.mimetype.split('/')[1]}`, idBack.buffer)
    ])
    res.json({
      success: 1,
      name: frontResData.data.name
    })
  } catch (e) {
    console.log(e)
    res.json({
      success: 0,
      msg: e.message
    })
  }
}

exports.setPassword = async function(req, res) {
  try {
    const idFromToken = req.user.userId
    const id = req.body.userId
    const password = req.body.password || ''
    if (!id || !password)  throw new Error('参数错误')
    if (idFromToken !== id) throw new Error('token check fail')
    if (password.length !== 6) throw new Error('密码至少为6')
    const user = await User.findOne({where: {id: id}})
    if (!user) throw new Error('用户不存在')
    if (user.password) throw new Error('您已设置过密码')
    let savedPasswd = await Helper.buildPassword(password)
    let update = await user.update({
      password: savedPasswd
    })
    res.json({
      success: 1,
    })
  } catch (e) {
    console.log(e)
    res.json({
      success: 0,
      msg: `${e.message}`
    })
  }
}