back-service.js 6.91 KB
/**
 * Created by TaoHuang on 2016/6/14.
 */

'use strict';

const Promise = require('bluebird');
const co = Promise.coroutine;
const _ = require('lodash');
const moment = require('moment');

const helpers = global.yoho.helpers;
const Api = require('./back-api');
const UserService = require('./user-service');
const CaptchaImgService = require('./captcha-img-service');

const PassportHelper = require('./passport-helper');
const backHelper = require('./back-helper');

const BACK_LEFT_BANNER_CODE = '3bbaf502c447a2ddad60879042e286d8'; // 找回密码左边的banner

module.exports = class extends global.yoho.BaseModel {
    constructor(ctx) {
        super(ctx);

        this.api = new Api(ctx);
        this.userService = new UserService(ctx);
        this.captchaService = new CaptchaImgService(ctx);
        this.passportHelper = new PassportHelper(ctx);

        /**
         * 验证邮件验证码
         */
        this.checkEmailCodeAsync = this.api.checkEmailCodeAsync.bind(this.api);

        // 弱密码重置
        this.modPwdByCodeAsync = this.api.modPwdByCodeAsync.bind(this.api);
    }

    /**
     * 验证手机和邮箱输入正确性
     */
    validateEmailOrMobileAsync(userInput, areaCode) {
        let that = this;

        return new Promise(function(resolve, rejected) {
            let result = {type: 'email', area: '', phone: ''};

            if (that.passportHelper.validator.isEmail(userInput)) {
                result.type = 'email';
                result.area = '';
                result.phone = userInput;

                resolve(result);
            } else if (that.passportHelper.validator.isMobile(userInput)) {
                result.type = 'mobile';
                result.area = areaCode;
                result.phone = userInput;

                resolve(result);
            } else {
                rejected('输入信息出错!');
            }

        });

    }

    /**
     * 查找用户
     */
    findUserAsync(type, phone, area) {
        return co(function* () {
            const MESSAGE = {
                mobile: '您输入的手机号码尚未注册!',
                email: '您输入的邮件账户尚未注册!',
                ok: '验证成功'
            };

            const findBy = {
                email: this.userService.findByEmailAsync.bind(this.userService),
                mobile: _.rearg(this.userService.findByMobileAsync.bind(this.userService), [1, 0]) // 交换参数
            };

            const OK = {code: 200, message: MESSAGE.ok};

            const user = yield findBy[type](phone, area);

            if (_.isEmpty(user)) {
                return {
                    code: 402,
                    message: MESSAGE[type]
                };
            }

            return OK;
        }).bind(this)();
    }

    /**
     * 发送验证码到用户
     */
    async sendCodeToUserAsync(type, mobile, areaCode, id, captcha) {
        let sendTo = {
            email: this.api.sendCodeToEmailAsync.bind(this.api),
            mobile: this.api.sendCodeToMobileAsync.bind(this.api)
        };

        let result = await sendTo[type](mobile, areaCode, id, captcha);
        let captchaNeeded = await this.captchaService.try();

        _.set(result, 'data.needCaptcha', captchaNeeded);

        return result;
    }

    /**
     * 发送找回手机号短信
     */
    async sendCodeToMobileAsync(areaCode, mobile, id, captcha) {
        let result = await this.api.sendCodeToMobileAsync(mobile, areaCode, id, captcha);

        let captchaNeeded = await this.captchaService.try();

        _.set(result, 'data.needCaptcha', captchaNeeded);

        return result;
    }

    /**
     * 获得首页的数据
     */
    indexPageDataAsync() {
        let that = this;

        return co(function* () {
            let banner = yield that.passportHelper.getLeftBannerAsync(BACK_LEFT_BANNER_CODE);
            let countryList = that.passportHelper.getCountry();

            return {
                back: {
                    coverHref: banner.url,
                    coverImg: banner.img,
                    countryCode: 86,
                    countryName: '中国',
                    captchaUrl: helpers.urlFormat('/passport/imagesNode', {t: moment().unix()}),
                    countryList: countryList
                }
            };
        })();
    }

    /**
     * 验证手机验证码
     */
    verifyCodyByMobileAsync(area, mobile, mobileCode) {
        const ERR = {
            code: 400,
            message: '验证码错误!',
            data: helpers.urlFormat('/passport/back/index')
        };

        return this.api.validateMobileCodeAsync(mobile, mobileCode, area)
            .then(result => {
                if (!(result.code && result.code === 200)) {
                    return ERR;
                }

                let data = {
                    mobile: mobile,
                    area: area,
                    token: result.data.token,
                    createdAt: moment().unix()
                };

                data.code = new Buffer(backHelper.makeToken(data)).toString('base64');

                return {
                    code: 200,
                    message: '验证成功',
                    data: helpers.urlFormat('/passport/back/backcode', data)
                };
            });

    }

    /**
     * 手机 token 合法性验证
     */
    authRequest(data, token) {
        if (!backHelper.validateToken(data, token)) {
            return {};
        }

        let existTime = moment.duration(60, 'minutes').asSeconds();
        let isExpired = (moment().unix() - data.createdAt) > existTime;

        if (isExpired) {
            return {};
        } else {
            return data;
        }
    }

    /**
     * 更新密码接口
     */
    updatePwdAsync(emailToken, mobileToken, newPassword) {
        return co(function* () {
            let result = {type: 'mobile', status: false};
            const ERR = {type: 'unknown', status: false};

            if (!_.isEmpty(mobileToken)) {
                if (!mobileToken.mobile || mobileToken.uid) {
                    return ERR;
                }

                let mobile = mobileToken.mobile;
                let area = mobileToken.area;
                let token = mobileToken.token;
                let modifyStatus = yield this.api.modifyPasswordByMobileAsyncAes(mobile, token, newPassword, area);

                if (!modifyStatus.code || modifyStatus.code !== 200) {
                    return ERR;
                }

                result.type = 'mobile';
                result.status = true;
            } else {
                let modifyStatus = yield this.api.modifyPasswordByEmailCodeAsyncAes(emailToken, newPassword);

                if (!modifyStatus.code || modifyStatus.code !== 200) {
                    return ERR;
                }

                result.type = 'email';
                result.status = true;
            }

            return result;
        }).bind(this)();
    }
};