const userModel = require('../models/user.js');
const yapi = require('../yapi.js');
const baseController = require('./base.js');
const request = require('request');
const common = require('../utils/commons.js');

const interfaceModel = require('../models/interface.js');
const groupModel = require('../models/group.js');
const projectModel = require('../models/project.js');
const avatarModel = require('../models/avatar.js');

const jwt = require('jsonwebtoken');

class userController extends baseController {
    constructor(ctx) {
        super(ctx);
        this.Model = yapi.getInst(userModel);
    }
    /**
     * 用户登录接口
     * @interface /user/login
     * @method POST
     * @category user
     * @foldnumber 10
     * @param {String} email email名称,不能为空
     * @param  {String} password 密码,不能为空
     * @returns {Object}
     * @example ./api/user/login.json
     */
    async login(ctx) {   //登录
        let userInst = yapi.getInst(userModel); //创建user实体
        let email = ctx.request.body.email;
        let password = ctx.request.body.password;

        if (!email) {
            return ctx.body = yapi.commons.resReturn(null, 400, 'email不能为空');
        }
        if (!password) {
            return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空');
        }

        let result = await userInst.findByEmail(email);


        if (!result) {
            return ctx.body = yapi.commons.resReturn(null, 404, '该用户不存在');
        } else if (yapi.commons.generatePassword(password, result.passsalt) === result.password) {
            this.setLoginCookie(result._id, result.passsalt);

            return ctx.body = yapi.commons.resReturn({
                username: result.username,
                role: result.role,
                uid: result._id,
                email: result.email,
                add_time: result.add_time,
                up_time: result.up_time,
                server_ip: yapi.WEBCONFIG.server_ip,
                type: 'site',
                study: result.study
            }, 0, 'logout success...');
        } else {
            return ctx.body = yapi.commons.resReturn(null, 405, '密码错误');
        }
    }

    /**
     * 退出登录接口
     * @interface /user/logout
     * @method GET
     * @category user
     * @foldnumber 10
     * @returns {Object}
     * @example ./api/user/logout.json
     */

    async logout(ctx) {
        ctx.cookies.set('_yapi_token', null);
        ctx.cookies.set('_yapi_uid', null);
        ctx.body = yapi.commons.resReturn('ok');
    }

    /**
     * 退出登录接口
     * @interface /user/up_study
     * @method GET
     * @category user
     * @foldnumber 10
     * @returns {Object}
     * @example
     */

    async upStudy(ctx) {
        let userInst = yapi.getInst(userModel); //创建user实体
        let data = {
            up_time: yapi.commons.time(),
            study: true
        };
        try {
            let result = await userInst.update(this.getUid(), data);
            ctx.body = yapi.commons.resReturn(result);
        } catch (e) {
            ctx.body = yapi.commons.resReturn(null, 401, e.message);
        }
    }


    /**
     *  第三方登录需要提供一个request方法和 token字段,暂时只支持qunar第三方
     * @return {email: String, username: String}
     */
    thirdQunarLogin() {
        return {
            request: (token) => {
                return new Promise((resolve, reject) => {
                    request('http://qsso.corp.qunar.com/api/verifytoken.php?token=' + token, function (error, response, body) {
                        if (!error && response.statusCode == 200) {
                            let result = JSON.parse(body);
                            if (result && result.ret === true) {
                                let ret = {
                                    email: result.userId + '@qunar.com',
                                    username: result.data.userInfo.name
                                };
                                resolve(ret);
                            } else {
                                reject(result);
                            }
                        }
                        reject(error);
                    });
                });
            },
            tokenField: 'token'
        };
    }

    async loginByToken(ctx) {
        //let config = this.thirdQunarLogin();
        try {
            let ret = await yapi.emitHook('third_login', ctx);
            let login = await this.handleThirdLogin(ret.email, ret.username);

            if (login === true) {
                yapi.commons.log('login success');
                ctx.redirect('/group');
            }
        } catch (e) {
            yapi.commons.log(e.message, 'error');
            ctx.redirect('/');
        }
    }

    async handleThirdLogin(email, username) {
        let user, data, passsalt;
        let userInst = yapi.getInst(userModel);

        try {
            user = await userInst.findByEmail(email);

            if (!user || !user._id) {
                passsalt = yapi.commons.randStr();
                data = {
                    username: username,
                    password: yapi.commons.generatePassword(passsalt, passsalt),
                    email: email,
                    passsalt: passsalt,
                    role: 'member',
                    add_time: yapi.commons.time(),
                    up_time: yapi.commons.time(),
                    type: 'third'
                };
                user = await userInst.save(data);
                await this.handlePrivateGroup(user._id, username, email);
                yapi.commons.sendMail({
                    to: email,
                    contents: `

亲爱的用户:

您好,感谢使用YApi平台,你的邮箱账号是:${email}

` }); } this.setLoginCookie(user._id, user.passsalt); return true; } catch (e) { console.error('third_login:', e.message); // eslint-disable-line return false; } } /** * 修改用户密码 * @interface /user/change_password * @method POST * @category user * @param {Number} uid 用户ID * @param {Number} [old_password] 旧密码, 非admin用户必须传 * @param {Number} password 新密码 * @return {Object} * @example ./api/user/change_password.json */ async changePassword(ctx) { let params = ctx.request.body; let userInst = yapi.getInst(userModel); if (!params.uid) { return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空'); } if (!params.password) { return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空'); } if (this.getRole() !== 'admin' && params.uid != this.getUid()) { return ctx.body = yapi.commons.resReturn(null, 402, '没有权限'); } if (this.getRole() !== 'admin') { if (!params.old_password) { return ctx.body = yapi.commons.resReturn(null, 400, '旧密码不能为空'); } let user = await userInst.findById(params.uid); if (yapi.commons.generatePassword(params.old_password, user.passsalt) !== user.password) { return ctx.body = yapi.commons.resReturn(null, 402, '旧密码错误'); } } let passsalt = yapi.commons.randStr(); let data = { up_time: yapi.commons.time(), password: yapi.commons.generatePassword(params.password, passsalt), passsalt: passsalt }; try { let result = await userInst.update(params.uid, data); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 401, e.message); } } async handlePrivateGroup(uid, username, email){ var groupInst = yapi.getInst(groupModel); await groupInst.save({ uid: uid, group_name: 'User-' + uid, add_time: yapi.commons.time(), up_time: yapi.commons.time(), type: 'private' }) } setLoginCookie(uid, passsalt) { let token = jwt.sign({ uid: uid }, passsalt, { expiresIn: '7 days' }); this.ctx.cookies.set('_yapi_token', token, { expires: yapi.commons.expireDate(7), httpOnly: true }); this.ctx.cookies.set('_yapi_uid', uid, { expires: yapi.commons.expireDate(7), httpOnly: true }); } /** * 用户注册接口 * @interface /user/reg * @method POST * @category user * @foldnumber 10 * @param {String} email email名称,不能为空 * @param {String} password 密码,不能为空 * @param {String} [username] 用户名 * @returns {Object} * @example ./api/user/login.json */ async reg(ctx) { //注册 let userInst = yapi.getInst(userModel); let params = ctx.request.body; //获取请求的参数,检查是否存在用户名和密码 params = yapi.commons.handleParams(params, { username: 'string', password: 'string', email: 'string' }); if (!params.email) { return ctx.body = yapi.commons.resReturn(null, 400, '邮箱不能为空'); } if (!params.password) { return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空'); } let checkRepeat = await userInst.checkRepeat(params.email);//然后检查是否已经存在该用户 if (checkRepeat > 0) { return ctx.body = yapi.commons.resReturn(null, 401, '该email已经注册'); } let passsalt = yapi.commons.randStr(); let data = { username: params.username, password: yapi.commons.generatePassword(params.password, passsalt),//加密 email: params.email, passsalt: passsalt, role: 'member', add_time: yapi.commons.time(), up_time: yapi.commons.time(), type: "site" }; if (!data.username) { data.username = data.email.substr(0, data.email.indexOf('@')); } try { let user = await userInst.save(data); this.setLoginCookie(user._id, user.passsalt); await this.handlePrivateGroup(user._id, user.username, user.email); ctx.body = yapi.commons.resReturn({ uid: user._id, email: user.email, username: user.username, add_time: user.add_time, up_time: user.up_time, role: 'member', type: user.type, study: false }); yapi.commons.sendMail({ to: user.email, contents: `

亲爱的用户:

您好,感谢使用YApi可视化接口平台,您的账号 ${params.email} 已经注册成功

` }); } catch (e) { ctx.body = yapi.commons.resReturn(null, 401, e.message); } } /** * 获取用户列表 * @interface /user/list * @method GET * @category user * @foldnumber 10 * @param {Number} [page] 分页页码 * @param {Number} [limit] 分页大小,默认为10条 * @returns {Object} * @example */ async list(ctx) { let page = ctx.request.query.page || 1, limit = ctx.request.query.limit || 10; const userInst = yapi.getInst(userModel); try { let user = await userInst.listWithPaging(page, limit); let count = await userInst.listCount(); return ctx.body = yapi.commons.resReturn({ count: count, total: Math.ceil(count / limit), list: user }); } catch (e) { return ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 获取用户个人信息 * @interface /user/find * @method GET * @param id 用户uid * @category user * @foldnumber 10 * @returns {Object} * @example */ async findById(ctx) { //根据id获取用户信息 try { let userInst = yapi.getInst(userModel); let id = ctx.request.query.id; if (!id) { return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空'); } let result = await userInst.findById(id); if (!result) { return ctx.body = yapi.commons.resReturn(null, 402, '不存在的用户'); } return ctx.body = yapi.commons.resReturn({ uid: result._id, username: result.username, email: result.email, role: result.role, type: result.type, add_time: result.add_time, up_time: result.up_time }); } catch (e) { return ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 删除用户,只有admin用户才有此权限 * @interface /user/del * @method POST * @param id 用户uid * @category user * @foldnumber 10 * @returns {Object} * @example */ async del(ctx) { //根据id删除一个用户 try { if (this.getRole() !== 'admin') { return ctx.body = yapi.commons.resReturn(null, 402, 'Without permission.'); } let userInst = yapi.getInst(userModel); let id = ctx.request.body.id; if (!id) { return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空'); } let result = await userInst.del(id); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 更新用户个人信息 * @interface /user/update * @method POST * @param uid 用户uid * @param [role] 用户角色,只有管理员有权限修改 * @param [username] String * @param [email] String * @category user * @foldnumber 10 * @returns {Object} * @example */ async update(ctx) { //更新用户信息 try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { username: 'string', email: 'string' }); if (this.getRole() !== 'admin' && params.uid != this.getUid()) { return ctx.body = yapi.commons.resReturn(null, 401, '没有权限'); } let userInst = yapi.getInst(userModel); let id = params.uid; if (!id) { return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空'); } let userData = await userInst.findById(id); if (!userData) { return ctx.body = yapi.commons.resReturn(null, 400, 'uid不存在'); } let data = { up_time: yapi.commons.time() }; params.username && (data.username = params.username); params.email && (data.email = params.email); if (data.email) { var checkRepeat = await userInst.checkRepeat(data.email);//然后检查是否已经存在该用户 if (checkRepeat > 0) { return ctx.body = yapi.commons.resReturn(null, 401, '该email已经注册'); } } let member = { uid: id, username: data.username || userData.username, email: data.email || userData.email } let groupInst = yapi.getInst(groupModel); await groupInst.updateMember(member) let projectInst = yapi.getInst(projectModel); await projectInst.updateMember(member) let result = await userInst.update(id, data); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 上传用户头像 * @interface /user/upload_avatar * @method POST * @param {*} basecode base64编码,通过h5 api传给后端 * @category user * @returns {Object} * @example */ async uploadAvatar(ctx) { try { let basecode = ctx.request.body.basecode; if(!basecode){ return ctx.body = yapi.commons.resReturn(null, 400, 'basecode不能为空') } let pngPrefix = 'data:image/png;base64,'; let jpegPrefix = 'data:image/jpeg;base64,'; let type; if(basecode.substr(0, pngPrefix.length ) === pngPrefix){ basecode = basecode.substr(pngPrefix.length); type = 'image/png'; }else if(basecode.substr(0, jpegPrefix.length ) === jpegPrefix){ basecode = basecode.substr(jpegPrefix.length); type = 'image/jpeg'; }else{ return ctx.body = yapi.commons.resReturn(null, 400, '仅支持jpeg和png格式的图片') } let strLength = basecode.length; if(parseInt(strLength-(strLength/8)*2) > 200000){ return ctx.body = yapi.commons.resReturn(null, 400, '图片大小不能超过200kb'); } let avatarInst = yapi.getInst(avatarModel); let result = await avatarInst.up(this.getUid(), basecode, type) ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 401, e.message); } } /** * 根据用户uid头像 * @interface /user/avatar * @method GET * @param {*} uid * @category user * @returns {Object} * @example */ async avatar(ctx) { try{ let uid = ctx.query.uid ? ctx.query.uid: this.getUid(); let avatarInst = yapi.getInst(avatarModel); let data = await avatarInst.get(uid); let dataBuffer, type; if(!data || !data.basecode){ dataBuffer = yapi.fs.readFileSync(yapi.path.join(yapi.WEBROOT, 'static/image/avatar.png')); type = 'image/png' }else{ type = data.type; dataBuffer = new Buffer(data.basecode, 'base64'); } ctx.set('Content-type', type); ctx.body = dataBuffer; }catch(err){ ctx.body = 'error:' + err.message } } /** * 模糊搜索用户名或者email * @interface /user/search * @method GET * @category user * @foldnumber 10 * @param {String} q * @return {Object} * @example ./api/user/search.json */ async search(ctx) { const { q } = ctx.request.query; if (!q) { return ctx.body = yapi.commons.resReturn(void 0, 400, 'No keyword.'); } if (!yapi.commons.validateSearchKeyword(q)) { return ctx.body = yapi.commons.resReturn(void 0, 400, 'Bad query.'); } let queryList = await this.Model.search(q); let rules = [ { key: '_id', alias: 'uid' }, 'username', 'email', 'role', { key: 'add_time', alias: 'addTime' }, { key: 'up_time', alias: 'upTime' } ]; let filteredRes = common.filterRes(queryList, rules); return ctx.body = yapi.commons.resReturn(filteredRes, 0, 'ok'); } /** * 根据路由id初始化项目数据 * @interface /user/project * @method GET * @category user * @foldnumber 10 * @param {String} type 可选group|interface|project * @param {Number} id * @return {Object} * @example */ async project(ctx) { let { id, type } = ctx.request.query; let result = {}; try { if (type === 'interface') { let interfaceInst = yapi.getInst(interfaceModel); let interfaceData = await interfaceInst.get(id) result.interface = interfaceData; type = 'project'; id = interfaceData.project_id; } if (type === 'project') { let projectInst = yapi.getInst(projectModel); let projectData = await projectInst.get(id); result.project = projectData.toObject(); let ownerAuth = await this.checkAuth(id, 'project', 'danger'), devAuth; if(ownerAuth){ result.project.role = 'owner' }else{ devAuth = await this.checkAuth(id, 'project', 'site'); if(devAuth){ result.project.role = 'dev' }else{ result.project.role = 'member' } } type = 'group'; id = projectData.group_id; } if (type === 'group') { let groupInst = yapi.getInst(groupModel); let groupData = await groupInst.get(id); result.group = groupData.toObject(); let ownerAuth = await this.checkAuth(id, 'group', 'danger'), devAuth; if(ownerAuth){ result.group.role = 'owner' }else{ devAuth = await this.checkAuth(id, 'group', 'site'); if(devAuth){ result.group.role = 'dev' }else{ result.group.role = 'member' } } } return ctx.body = yapi.commons.resReturn(result) } catch (e) { return ctx.body = yapi.commons.resReturn(result, 422, e.message) } } } module.exports = userController;