bind.js 13.5 KB
/**
 * 手机号绑定功能
 *
 * @author JiangFeng<jeff.jiang@yoho.cn>
 * @date 2016/06/21
 */

'use strict';

const helpers = global.yoho.helpers;
const RegService = require('../models/reg-service');
const BindService = require('../models/bind-service');
const AuthHelper = require('../models/auth-helper');
const _ = require('lodash');
const config = global.yoho.config;
const moment = require('moment');
const logger = global.yoho.logger;

const Sources = {
    qq: 'QQ',
    sina: '微博',
    alipay: '支付宝',
    wechat: '微信'
};

const bind = {
    indexPage: (req, res) => {
        // 如果没有originalUrl,判定为非法链接
        if (req.session.originalUrl !== 'true') {
            return res.redirect('//m.yohobuy.com');
        }
        let refer = req.get('Referer');

        if (refer) {
            res.cookie('refer', encodeURI(refer), {
                domain: 'yohobuy.com'
            });
        }

        let openId = req.query.openId;
        let sourceType = req.query.sourceType;
        let serviceUrl = _.get(req.app.locals.wap, 'clientService.new', false) ?
            helpers.urlFormat('/service/im') :
            'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';

        res.render('bind/index', {
            bindIndex: true, // js标识
            backUrl: helpers.urlFormat('/signin.html'), // 返回的URL链接
            showHeaderImg: true, // 控制显示头部图片
            isPassportPage: true, // 模板中模块标识
            sourceType: sourceType, // 第三方登录来源
            platform: Sources[sourceType],
            isWechatLogin: sourceType === 'wechat',
            openId: openId, // openId
            areaCode: '+86', // 默认区号
            countrys: RegService.getAreaData(), // 国别码
            serviceUrl: serviceUrl, // 在线客服
            module: 'passport',
            page: 'bind',
            title: '绑定手机号'
        });
    },

    codePage: (req, res) => {
        let openId = req.query.openId;
        let sourceType = req.query.sourceType;
        let areaCode = req.query.areaCode || '86';
        let isReg = req.query.isReg;
        let phoneNum = req.query.phoneNum;

        res.render('bind/code', {
            backUrl: helpers.urlFormat('/signin.html'),
            showHeaderImg: true,
            isPassportPage: true,
            sourceType: sourceType,
            openId: openId,
            isReg: isReg,
            areaCode: areaCode,
            phoneNum: phoneNum,
            relateCode: isReg === '3',
            bindCode: isReg !== '3',
            module: 'passport',
            page: isReg === '3' ? 'relate' : 'bind-code',
            title: '验证手机'
        });
    },

    bindCheck: (req, res, next) => {
        let phoneNum = req.body.phoneNum;
        let openId = req.body.openId;
        let areaCode = req.body.areaCode || '86';
        let sourceType = req.body.sourceType;
        let verify = req.body.verify || '';
        let testCode = req.body.yohobuy;

        if (_.isNumber(parseInt(phoneNum, 0)) && openId && areaCode && sourceType) {
            if (verify) {
                let captcha = _.get(req, 'session.captcha');

                logger.info(`captcha validate result${verify.toString() ===
                    captcha},user:${verify};server:${captcha}`);
                if ((captcha && verify.toString() === captcha) || (testCode === config.testCode)) {
                    BindService.bindCheck(phoneNum, openId, sourceType, areaCode).then(result => {
                        let data = {
                            code: result.code,
                            message: result.message,
                            data: {}
                        };

                        if (result.code === 200) {
                            let nextUrl = helpers.urlFormat('/passport/bind/code', {
                                isReg: result.data.is_register,  // esline-disable-line
                                openId: openId,
                                sourceType: sourceType,
                                areaCode: areaCode,
                                phoneNum: phoneNum
                            });

                            data.data.isReg = result.data.is_register;
                            data.data.next = nextUrl;

                            _.set(req.session, 'bind.area', areaCode);
                            _.set(req.session, 'bind.phoneNum', phoneNum);
                        } else {
                            data.data = result.data;
                        }

                        res.json(data);
                    }).catch(next);
                } else {
                    let jsonData = {
                        code: 400,
                        message: '请将图片旋转到正确方向'
                    };

                    if (req.session.captchaValidCount === 0) {
                        req.session.captcha = null; // 验证码 用过就扔
                        jsonData.changeCaptcha = true;
                    }

                    return res.json(jsonData);
                }

                _.set(req.session, 'captcha', null);
            }
        } else {
            res.json({
                code: 400,
                message: '',
                data: ''
            });
        }
    },

    // 防刷
    sendBefore: (req, res, next) => {
        let count = _.get(req.session, 'bind.count');
        let interval = _.get(req.session, 'bind.interval');

        let now = Date.now();

        // // 重发次数用完了, 会冻结5min
        // //      1. 过了冻结期, count 重设为 5次
        // //      2. 没过冻结期, end
        // // 没有用完, 判断是否请求太频繁
        let during = moment.duration(interval - now, 'ms').minutes();
        let message = `请${during}分钟后再试`;

        if (!count) {
            if (interval > now) {
                return res.json({
                    code: 400,
                    message: message,
                    during: Math.ceil((interval - now) / 1000)
                });
            } else {
                _.set(req.session, 'bind.count', 5);
            }
        } else if (interval > now) {
            return res.json({
                code: 429,
                message: message
            });
        }

        next();
    },

    sendBindMsg: (req, res, next) => {
        let phoneNum = _.get(req.session, 'bind.phoneNum');
        let areaCode = _.get(req.session, 'bind.area');

        if (req.xhr && _.isNumber(parseInt(phoneNum, 0)) && areaCode) {
            BindService.sendBindMsg(areaCode, phoneNum).then(result => {
                if (result && result.code) {

                    if (result.code === 200) {

                        _.set(req.session, 'bind.area', areaCode);
                        _.set(req.session, 'bind.phoneNum', phoneNum);

                        --req.session.bind.count;

                        if (!req.session.bind.count) {
                            _.set(req.session, 'bind.interval', Date.now() + 5 * 60 * 1000);
                        } else {
                            _.set(req.session, 'bind.interval', Date.now() + 60 * 1000);
                        }
                    }

                    res.json(result);
                } else {
                    res.json({ code: 400, message: '', data: '' });
                }
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    },

    checkBindMsg: (req, res, next) => {
        let phoneNum = req.body.phoneNum;
        let code = req.body.code;
        let areaCode = req.body.areaCode;

        if (_.isNumber(parseInt(phoneNum, 0)) && code && areaCode) {
            BindService.checkBindMsg(areaCode, phoneNum, code).then(result => {
                if (result && result.code) {
                    res.json(result);
                } else {
                    res.json({ code: 400, message: '', data: '' });
                }
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    },

    bindMobile: (req, res, next) => {
        let phoneNum = req.body.phoneNum;
        let openId = req.body.openId;
        let areaCode = req.body.areaCode || '86';
        let sourceType = req.body.sourceType;
        let code = req.body.code;
        let password = req.body.password || '';

        if (_.isNumber(parseInt(phoneNum, 0)) && openId && sourceType && areaCode && code) {
            BindService.checkBindCode(areaCode, phoneNum, code).then(result => {
                if (result && result.code && result.code === 200) {
                    return BindService.bindMobile(openId, sourceType, phoneNum, areaCode, password);
                } else {
                    return { code: 400, message: '短信验证码错误', data: '' };
                }
            }).then(result => {
                let refer = helpers.urlFormat('/passport/bind/success?type=bind');

                if (result && result.code && result.code === 200 && result.data.uid) {
                    return AuthHelper.syncUserSession(result.data.uid, req, res, result.data.session_key).then(() => {
                        result.data.refer = refer;
                        return result;
                    });
                } else {
                    return { code: 400, message: '绑定失败', data: '' };
                }

            }).then(result => {
                res.json(result);
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    },

    relateMobile: (req, res, next) => {
        let phoneNum = req.body.phoneNum;
        let openId = req.body.openId;
        let areaCode = req.body.areaCode || '86';
        let sourceType = req.body.sourceType;
        let code = req.body.code;

        if (_.isNumber(parseInt(phoneNum, 0)) && openId && areaCode && sourceType && code) {
            BindService.checkBindCode(areaCode, phoneNum, code).then(result => {
                if (result && result.code && result.code === 200) {
                    return BindService.relateMobile(openId, sourceType, phoneNum, areaCode);
                } else {
                    return { code: 400, message: '短信验证码错误', data: '' };
                }
            }).then(result => {
                let refer = helpers.urlFormat('/passport/bind/success', { sourceType: sourceType });

                if (result && result.code && result.code === 200 && result.data.uid) {
                    return AuthHelper.syncUserSession(result.data.uid, req, res, result.data.session_key).then(() => {
                        result.data.refer = refer;
                        return result;
                    });
                } else {
                    return { code: 400, message: '关联失败', data: '' };
                }

            }).then(result => {
                res.json(result);
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    },

    passwordPage: (req, res) => {
        let openId = req.query.openId;
        let sourceType = req.query.sourceType;
        let areaCode = req.query.areaCode || '86';
        let phoneNum = req.query.phoneNum;
        let code = req.query.code;

        res.render('bind/password', {
            module: 'passport',
            page: 'bind-password',
            bindPwd: true, // js标识
            backUrl: helpers.urlFormat('/signin.html'), // 返回的URL链接
            showHeaderImg: true, // 控制显示头部图片
            isPassportPage: true, // 模板中模块标识
            sourceType: sourceType, // 第三方登录来源
            openId: openId, // openId
            areaCode: areaCode, // 国别码
            phoneNum: phoneNum,   // 国别码
            code: code // 验证码
        });
    },

    successPage: (req, res) => {
        let refer = req.cookies.refer;
        let type = req.query.type;

        if (!refer || /signin|login/.test(refer)) {
            refer = helpers.urlFormat('/?go=1');
        }

        // 微信免单活动,判断来源地址 2.16.12.28 by jing.li@yoho.cn
        res.cookie('bindUrl', 'http://m.yohobuy.com/passport/bind/success?type=bind');

        res.render('bind/success', {
            isPassportPage: true,
            successTip: type === 'bind' ? '恭喜您,第三方账号绑定手机号码成功!' : '恭喜您,第三方账号关联手机号码成功!',
            goUrl: refer,
            module: 'passport',
            page: 'bind-success',
            title: '绑定手机号'
        });
    },

    changeCheck: (req, res, next) => {
        let phoneNum = req.body.phoneNum;
        let areaCode = req.body.areaCode;

        if (_.isNumber(parseInt(phoneNum, 0)) && areaCode) {
            BindService.changeCheck(phoneNum, areaCode).then(result => {
                res.json(result);
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    },

    changeMobile: (req, res, next) => {
        let uid = req.user.uid;
        let phoneNum = req.body.phoneNum;
        let areaCode = req.body.areaCode;
        let code = req.body.code;

        if (_.isNumber(parseInt(phoneNum, 0)) && uid && areaCode && code) {
            BindService.changeMobile(uid, phoneNum, areaCode, code).then(result => {
                res.json(result);
            }).catch(next);
        } else {
            res.json({ code: 400, message: '', data: '' });
        }
    }
};

module.exports = bind;