user.js 12.5 KB
/**
 * 用户controller
 * @author: leo <qi.li@yoho.cn>
 * @date: 2017/06/26
 */
'use strict';
const _ = require('lodash');
const UserModel = require('../models/user');
const request = require('request-promise');

const INVALID_SESSION = '用户SESSION信息缺失, 请重新验证';
const INVALID_PARAM = '参数错误!';
const GET_USER_INFO_SUCCESS = '获取用户信息成功';
const GET_USER_INFO_FAILED = '授权失败,请重新授权';
const OUT_OF_EXPIRED = '授权已过期';
const INVALID_REFERER = '无效的来源';
const USER_NOT_FOUNT = '未寻找到用户信息';
const WECHAT_LOGIN_URL_YOHOBOYS = 'http://www.yohoboys.com/yohonow/WechatAuthController/authorize?callbackurl=';
const DEFAULT_REDIRECT_URL = 'http://www.yoho.cn';
const config = global.yoho.config;
let siteUrl = config.siteUrl.indexOf('//') === 0 ? 'http:' + config.siteUrl : config.siteUrl;

const userController = {
    /**
     * 获取用户信息
     * @param req
     * @param res
     * @param next
     */
    userInfo(req, res, next) {
        const mobile = _.get(req.session, 'smsSend.mobile', '');

        if (!mobile) {
            res.json({
                code: 403,
                message: INVALID_SESSION
            });
        }


        req.ctx(UserModel).getUser(mobile)
            .then(result => {
                let userInfo = {};

                if (result.length) {
                    let user = result[0];

                    // 用户ID
                    _.set(req.session, 'user.id', user.id);
                    _.set(req.session, 'user.phone', user.user_phone);

                    res.json({
                        code: 200,
                        data: {
                            id: user.id,
                            name: user.user_name,
                            mobile: user.user_phone,
                            avatar: user.user_avatar
                        },
                        message: GET_USER_INFO_SUCCESS
                    });
                } else {
                    let name = '用户' + mobile.substr(7);
                    let avatar = 'http://img12.static.yhbimg.com/' +
                        'imserver/2016/11/17/11/02bc3c3de856432175c01d937342a1f2ce.jpg';

                    userInfo = {
                        name,
                        avatar,
                        mobile
                    };

                    req.ctx(UserModel).createUser(userInfo)
                        .then((id) => {

                            // 用户ID
                            _.set(req.session, 'user.id', id);
                            _.set(req.session, 'user.phone', mobile);

                            res.json({
                                code: 200,
                                data: _.assign(userInfo, {id}),
                                message: GET_USER_INFO_SUCCESS
                            });
                        })
                        .catch(next);
                }
            })
            .catch(next);
    },

    /**
     * 获取微信用户信息(直接调用)
     * @param req
     * @param res
     */
    newWechatUserInfo(req, res) {
        res.json({
            message: '获取用户信息成功'
        });
    },

    /**
     * 授权后跳转回调方法,获取授权信息,保存到数据库
     * @param req
     * @param res
     * @param next
     */
    async newWechatUserCallback(req, res) {
        let {code = 10005, state} = req.query;

        // console.log(req.session);
        try {
            if (code.toString().length > 5 && state === _.get(req.session, 'user.wechatState', '')) {
                let appId = config.wechatLogin.appID;
                let appSecret = config.wechatLogin.appSecret;
                let WECHAT_GET_TOKEN = 'https://api.weixin.qq.com/sns/oauth2/access_token';
                let WECHAT_GET_USERINFO = 'https://api.weixin.qq.com/sns/userinfo';

                // console.log(WECHAT_GET_TOKEN + '?appid=' + appId + '&secret=' + appSecret + '&code=' + code + '&grant_type=authorization_code');

                let tokenResult = await request({
                    url: WECHAT_GET_TOKEN,
                    qs: {
                        appid: appId,
                        secret: appSecret,
                        code: code,
                        grant_type: 'authorization_code'
                    },
                    json: true
                });

                // console.log('newWechatCallback', tokenResult);

                if (!tokenResult.errcode) {
                    let access_token = tokenResult.access_token;
                    let union_id = tokenResult.unionid || tokenResult.openid;
                    let userInfo = await request({
                        url: WECHAT_GET_USERINFO,
                        qs: {
                            access_token: access_token,
                            openid: union_id,
                            lang: 'zh_CN'
                        },
                        json: true
                    });

                    let userInfoStr = JSON.stringify(userInfo);

                    // console.log('userInfoStr:', userInfoStr);

                    let referer = `${siteUrl}/passport/user/wechatCallback`;
                    let note = referer.indexOf('?') > 0 ? '&' : '?';
                    let redirectUrl = referer + note + 'wechatUserInfo=' + userInfoStr;

                    res.redirect(redirectUrl);

                } else {
                    res.send({
                        code: 400,
                        message: '获取授权信息失败'
                    });
                }
            }
        } catch (err) {
            res.send(err);
        }
    },

    /**
     * 跳转微信授权(原生的)
     * @param req
     * @param res
     */
    newWechatLogin(req, res) {
        const referer = req.get('Referer') || 'http://www.yoho.cn';
        let appId = config.wechatLogin.appID;
        let scope = 'snsapi_userinfo';
        let state = Math.random().toString(36).substr(2, 15);
        let redirect_uri = encodeURIComponent(`${siteUrl}/passport/user/newWechatCallback`);
        let WECHAT_LOGIN_URL =
            `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;

        // console.log('WECHAT_LOGIN_URL:', WECHAT_LOGIN_URL);
        // console.log('referer', referer, referer.indexOf('yoho.cn'));
        if (referer && (referer.indexOf('yoho.cn') >= 0 || referer.indexOf('yohobuy.com') >= 0)) {
            _.set(req.session, 'user.wechatReferer', referer);
            _.set(req.session, 'user.wechatState', state);

            // console.log(req.session);
            res.redirect(WECHAT_LOGIN_URL);
        } else {
            res.json({
                code: 200,
                message: INVALID_REFERER
            });
        }
    },

    /**
     * 获取微信用户信息(yohoboys)
     * @param req
     * @param res
     */
    wechatUserInfo(req, res) {
        const union_id = req.query.union_id;

        if (!union_id) {
            return res.json({
                code: 403,
                message: INVALID_PARAM
            });
        }

        let session_union_id = _.get(req.session, 'user.union_id', '0');

        // session_union_id = union_id;// 临时用,要删!!!!

        if (union_id === session_union_id) { // 判断传过来的union_id和session中保存的union_id是否相同
            return req.ctx(UserModel).getWechatUser(union_id)
                .then(result => { // 获取用户的uid
                    if (result && result.length > 0) {
                        return res.json({
                            code: 200,
                            uid: result[0].id,
                            union_id: _.get(req.session, 'user.union_id', '0'),
                            head_img: _.get(req.session, 'user.head_img', ''),
                            user_name: _.get(req.session, 'user.user_name', '')
                        });
                    } else {
                        return res.json({
                            code: 204,
                            message: USER_NOT_FOUNT
                        });
                    }

                });
        } else {
            return res.json({
                code: 203,
                message: OUT_OF_EXPIRED
            });
        }
    },

    /**
     * 跳转微信授权(yohoboys)
     * @param req
     * @param res
     */
    wechatUserLogin(req, res) {
        const referer = req.get('Referer');
        let redirect_url = `${siteUrl}/passport/user/wechatCallback`;

        if (referer && (referer.indexOf('yoho.cn') || referer.indexOf('yhurl.com'))) {
            _.set(req.session, 'npnp', referer);
            res.redirect(WECHAT_LOGIN_URL_YOHOBOYS + encodeURIComponent(redirect_url));
        } else {
            res.json({
                code: 401,
                message: INVALID_REFERER
            });
        }
    },

    /**
     * 授权后跳转回调方法,获取授权信息,保存到数据库
     * @param req
     * @param res
     */
    wechatUserCallback(req, res, next) {
        let wechatUserInfo;

        try {
            wechatUserInfo = JSON.parse(req.query.wechatUserInfo);
        } catch (err) {
            wechatUserInfo = {};
        }


        // console.log('wechatUserCallBack:', wechatUserInfo);
        let user_name = '',
            head_img = '',
            union_id = '';


        if (wechatUserInfo && wechatUserInfo.nickname) {
            user_name = wechatUserInfo.nickname;
            head_img = wechatUserInfo.headimgurl;
            union_id = wechatUserInfo.unionid || wechatUserInfo.openid;

            _.set(req.session, 'user.union_id', union_id);
            _.set(req.session, 'user.head_img', head_img);
            _.set(req.session, 'user.user_name', user_name);

            // console.log(req.session);

            return req.ctx(UserModel).getWechatUser(union_id)
                .then(result => {
                    if (result.length > 0) { // 发现数据库有用户信息,则更新用户头像及昵称
                        return req.ctx(UserModel).modifyWechatUser(union_id, user_name, head_img)
                            .then(() => {
                                return Promise.resolve();
                            });
                    } else {
                        return req.ctx(UserModel).createWechatUser(union_id, user_name, head_img, 1)
                            .then(c_result => { // 发现数据库没有用户信息,则插入用户信息
                                if (c_result) {
                                    return Promise.resolve();
                                } else {
                                    return Promise.reject({code: 301, message: GET_USER_INFO_FAILED});
                                }
                            });
                    }
                })
                .then(() => { // 处理完毕后跳转回活动页面
                    let referer = _.get(req.session, 'user.wechatReferer', DEFAULT_REDIRECT_URL);
                    let note = referer.indexOf('?') >= 0 ? '&' : '?';

                    referer += note + 'union_id=' + union_id;
                    res.redirect(referer);
                }, (result) => {
                    res.json(result);
                }).catch(next);
        } else {
            res.json({
                code: 301,
                message: GET_USER_INFO_FAILED
            });
        }
    },

    /**
     * 通过用户的union_id更新用户的手机号码
     * @param req
     * @param res
     * @returns {Promise.<void>}
     */
    async updateUserMobileByUnionId(req, res) {
        let {unionId, phone, force = 0, token} = req.body;
        let regPhone = /^1[3-9][0-9]{9}$/g;

        if (!unionId || !phone || (!force && !token)) {
            return res.json({
                code: 400,
                message: INVALID_PARAM
            });
        } else if (!phone.match(regPhone)) {
            return res.json({
                code: 400,
                message: '手机号码格式错误'
            });
        }

        let session_token = req.session.shoesToken;
        let result = {};

        console.log(token, session_token);

        if (token === session_token) {
            result = await req.ctx(UserModel).updateUserMobileByUnionId(unionId, phone, force);
        } else {
            result = {
                code: 205,
                message: '保存手机号失败,请重新扫码后再试'
            };
        }


        return res.json(result);

    }
};

module.exports = userController;