mongoose

mongoose

egg.js+mongodb+openstack 公有云计费系统(三)用户系统的搭建 (2)

Nodejslopo1983 发表了文章 • 0 个评论 • 1153 次浏览 • 2019-03-15 11:08 • 来自相关话题

A/SK 机制
?
控制器
?
/*************************************************************
*
*- Copyright (c) qiduo, 2018
*- FileName: AccesskeyController.js 安全认证 Accesskey接口
*- Author: 罗波 lopo1983@vip.qq.com
*- Version: 1.0
*- Date:2018-10-15
*- Descripttion:openstack geecp
*- Modules:
*
*- Extends
* - 1.egg_Controller
*----------------------------------------------------------
*
*- Function List :
*
*- StaticsList :
* - show 获取所有ak/sk
* - update 创建ak/sk 修改备注
* - destroy 删除ak/sk
*
*- History :
* <Author> <Date> <Desc>
*
**************************************************************/
'use strict';

const Controller = require('egg').Controller;

class AccesskeyController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Model} MODEL 公司表
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Account.Company;
}
/**
*
* @name 获取Accesskey列表
*
* @example
* - GET /user/accesskey/_id{ObjectId} HTTP/1.1
*
*/
async show() {
const ctx = this.ctx;
const result = await this.MODEL.getASK({ '_id': ctx.params.id });
ctx.body = result
}
/**
*
* @name 创建AK/SK|修改Info
*
* @param {String} info 必填 备注内容
* @param {ObjectId} id 必填 A/SK{ObjectId}
*
* @example
* - PUT /user/accesskey/user{ObjectId} HTTP/1.1 创建
* - PUT /user/accesskey/user{ObjectId} HTTP/1.1 修改
* body:{
* id:ak/sk{ObjectId}
* info:备注名称
* }
*
* @description info id 为必填参数
*
*/
async update() {
const ctx = this.ctx;
if (!!ctx.request.body.info) {
ctx.body = await this.MODEL.setInfo(ctx);
}
else {
ctx.body = await this.MODEL.createASK(ctx);
}
}
/**
*
* @name 删除AK/SK
*
* @param {ObjectId} id 必填 A/SK id
*
* @example
* PUT /user/accesskey/id{ObjectId} HTTP/1.1
* @description id 为必填参数
*
*/
async destroy() {
const ctx = this.ctx;
ctx.body = await this.MODEL.delASK(ctx);
}
/**
*
* @name ak/sk鉴权接口
*
* @param {ObjectId} uid 必填 用户uid
* @param {String} api_key 必填 accountKey
* @param {String} secret_key 必填 secretKey
*
* @example
* POST /user/authorization HTTP/1.1
*
* @description uid|api_key|secret_key 必填
*
*/
async authorization() {
const ctx = this.ctx;
const { uid, api_key, secret_key } = ctx.request.body;
ctx.body = await this.MODEL.apiToken({ uid, api_key, secret_key });
}
}

module.exports = AccesskeyController;

用户鉴权
控制器
'use strict';
const Controller = require('egg').Controller;
class ServiceJwtController extends Controller {
constructor(ctx) {
super(ctx);
this.MODELComp = ctx.model.Account.Company;
this.MODELAdmin = ctx.model.Account.Admin;
};
/**
* @name 用户token生成
*
* @param {action:string} 'api' 用于鉴权ak/sk生成token
* @param {String} compEmail 用户邮箱
* @param {String} compPhone 用户手机
* @param {String} compPassword 用户密码
*
* @description
*
* @example POST /user/sign/
*
* @return Object
*{
* "token": "",
* "info": {
* "_id": "5bcdd5e7f12ee030f44b6228",
* "compPhone": "13658157663",
* "compEmail": "64832897@qq.com",
* "compAuth": {
* "email": false,
* "phone": true
* },
* "compService": [],
* "updated": "2018-10-22T13:51:35.314Z",
* "compApi": []
* }
* }
*
**/
async sign() {
const ctx = this.ctx;
const {
body,
header
} = ctx.request;
try {
if (ctx.request.url.includes('admin')) {
ctx.body = await this.MODELAdmin.isLogin(ctx);
} else {
if (!['compEmail', 'compPhone'].map(e => Object.keys(body).includes(e)).reduce((a, b) => a + b)) {
ctx.body = {
code: 422,
message: '用户参数错误'
};
return
};
ctx.body = await this.MODELComp.isLogin(ctx);
}
} catch (error) {
console.log(error)
if (error.message === 'jwt expired') {
ctx.body = {
message: '用户鉴权失败,请重新登陆',
code: 401
}
} else {
ctx.body = {
message: !!error.errors ? `${error.errors.reduce((a, error) => { a.push(`${error.field} ${error.message}`); return a }, [])}` : error.message,
code: 422
}
}
}
}
}
module.exports = ServiceJwtControllerextend 扩展
简单用户划分
module.exports = {
isAdmin() {
console.log(this.url)
return this.state.user.group === 1 ? false : true;
},
};OpenStack 相关控制器
project
'use strict';

const Controller = require('egg').Controller;

class OPIdentityProjectsController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
}
/**
* @name project列表
*
* @param {String} ctx.query 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/projects
*
*/
async index() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.list(ctx.query);
ctx.body = datas;
}
/**
* @name 获取单一project信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/projects/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.show(ctx.params.id);
ctx.body = datas;
}
/**
* @name 创建project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/projects/
*/
async create() {
const { ctx, service } = this;
const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
const datas = await service.openstack.identity.projects.create(this.DUFn(bodys))
ctx.body = datas;
}
/**
* @name 更新project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - DELETE /openstack/projects/{ctx.params.id}
*/
async destroy() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.destroy(ctx.params.id);
ctx.body = datas;
}
/**
* @name 删除project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - PATCH /openstack/projects/{ctx.params.id}
*/
async update() {
const { ctx, service } = this;
const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
const datas = await service.openstack.identity.projects.update(ctx.params.id, this.DUFn(bodys))
ctx.body = datas;
}
/**
* @name 锁定不可操作项目
*
*/
checkID(idx) {
const ARR = ['c3513f27bbf24362b74d13e6afae2c37', '5d3b50c18fd44db4bc6abfdbbfcf6a3a', '5c7e341df8ff493c8ae7baf57c0129dd'];
return ARR.includes(idx);
}
}

module.exports = OPIdentityProjectsController;
region
'use strict';

const Controller = require('egg').Controller;

class identityUserRegionController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.Region
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @description
*
* @example GET /openstack/identity/region
*
*/
async index() {
const { ctx, service } = this;
const datas = await this.MODEL.getAll(this.auth.id, ctx.isAdmin());
ctx.body = datas;
}
}

module.exports = identityUserRegionController;user
'use strict';

const Controller = require('egg').Controller;

class identityUserController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.User
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @param {String} ctx.query.detail 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/user
*
*/
async index() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.list(ctx.query);
};
/**
* @name 获取单一用户信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/user/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.show(ctx.params.id);
// const result = await this.MODEL.getOne(this.auth.id);
// ctx.body = result;
};
/**
* @name 创建用户
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/user/
*/
async create() {
const ctx = this.ctx;
const result = await this.MODEL.createUser(this.auth.id)
ctx.body = result;
// const { ctx, service } = this;
// const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
// const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
// ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
};
/**
*
* @name 测试内部用token
*
*/
async testToken() {
const { ctx, service } = this;
ctx.body = await this.TKMODEL.getToken(this.auth.id)
};
}

module.exports = identityUserController; 查看全部
A/SK 机制
?
控制器
?
/*************************************************************
*
*- Copyright (c) qiduo, 2018
*- FileName: AccesskeyController.js 安全认证 Accesskey接口
*- Author: 罗波 lopo1983@vip.qq.com
*- Version: 1.0
*- Date:2018-10-15
*- Descripttion:openstack geecp
*- Modules:
*
*- Extends
* - 1.egg_Controller
*----------------------------------------------------------
*
*- Function List :
*
*- StaticsList :
* - show 获取所有ak/sk
* - update 创建ak/sk 修改备注
* - destroy 删除ak/sk
*
*- History :
* <Author> <Date> <Desc>
*
**************************************************************/
'use strict';

const Controller = require('egg').Controller;

class AccesskeyController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Model} MODEL 公司表
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Account.Company;
}
/**
*
* @name 获取Accesskey列表
*
* @example
* - GET /user/accesskey/_id{ObjectId} HTTP/1.1
*
*/
async show() {
const ctx = this.ctx;
const result = await this.MODEL.getASK({ '_id': ctx.params.id });
ctx.body = result
}
/**
*
* @name 创建AK/SK|修改Info
*
* @param {String} info 必填 备注内容
* @param {ObjectId} id 必填 A/SK{ObjectId}
*
* @example
* - PUT /user/accesskey/user{ObjectId} HTTP/1.1 创建
* - PUT /user/accesskey/user{ObjectId} HTTP/1.1 修改
* body:{
* id:ak/sk{ObjectId}
* info:备注名称
* }
*
* @description info id 为必填参数
*
*/
async update() {
const ctx = this.ctx;
if (!!ctx.request.body.info) {
ctx.body = await this.MODEL.setInfo(ctx);
}
else {
ctx.body = await this.MODEL.createASK(ctx);
}
}
/**
*
* @name 删除AK/SK
*
* @param {ObjectId} id 必填 A/SK id
*
* @example
* PUT /user/accesskey/id{ObjectId} HTTP/1.1
* @description id 为必填参数
*
*/
async destroy() {
const ctx = this.ctx;
ctx.body = await this.MODEL.delASK(ctx);
}
/**
*
* @name ak/sk鉴权接口
*
* @param {ObjectId} uid 必填 用户uid
* @param {String} api_key 必填 accountKey
* @param {String} secret_key 必填 secretKey
*
* @example
* POST /user/authorization HTTP/1.1
*
* @description uid|api_key|secret_key 必填
*
*/
async authorization() {
const ctx = this.ctx;
const { uid, api_key, secret_key } = ctx.request.body;
ctx.body = await this.MODEL.apiToken({ uid, api_key, secret_key });
}
}

module.exports = AccesskeyController;

用户鉴权
控制器
'use strict';
const Controller = require('egg').Controller;
class ServiceJwtController extends Controller {
constructor(ctx) {
super(ctx);
this.MODELComp = ctx.model.Account.Company;
this.MODELAdmin = ctx.model.Account.Admin;
};
/**
* @name 用户token生成
*
* @param {action:string} 'api' 用于鉴权ak/sk生成token
* @param {String} compEmail 用户邮箱
* @param {String} compPhone 用户手机
* @param {String} compPassword 用户密码
*
* @description
*
* @example POST /user/sign/
*
* @return Object
*{
* "token": "",
* "info": {
* "_id": "5bcdd5e7f12ee030f44b6228",
* "compPhone": "13658157663",
* "compEmail": "64832897@qq.com",
* "compAuth": {
* "email": false,
* "phone": true
* },
* "compService": [],
* "updated": "2018-10-22T13:51:35.314Z",
* "compApi": []
* }
* }
*
**/
async sign() {
const ctx = this.ctx;
const {
body,
header
} = ctx.request;
try {
if (ctx.request.url.includes('admin')) {
ctx.body = await this.MODELAdmin.isLogin(ctx);
} else {
if (!['compEmail', 'compPhone'].map(e => Object.keys(body).includes(e)).reduce((a, b) => a + b)) {
ctx.body = {
code: 422,
message: '用户参数错误'
};
return
};
ctx.body = await this.MODELComp.isLogin(ctx);
}
} catch (error) {
console.log(error)
if (error.message === 'jwt expired') {
ctx.body = {
message: '用户鉴权失败,请重新登陆',
code: 401
}
} else {
ctx.body = {
message: !!error.errors ? `${error.errors.reduce((a, error) => { a.push(`${error.field} ${error.message}`); return a }, [])}` : error.message,
code: 422
}
}
}
}
}
module.exports = ServiceJwtController
extend 扩展
简单用户划分
module.exports = {
isAdmin() {
console.log(this.url)
return this.state.user.group === 1 ? false : true;
},
};
OpenStack 相关控制器
project
'use strict';

const Controller = require('egg').Controller;

class OPIdentityProjectsController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
}
/**
* @name project列表
*
* @param {String} ctx.query 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/projects
*
*/
async index() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.list(ctx.query);
ctx.body = datas;
}
/**
* @name 获取单一project信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/projects/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.show(ctx.params.id);
ctx.body = datas;
}
/**
* @name 创建project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/projects/
*/
async create() {
const { ctx, service } = this;
const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
const datas = await service.openstack.identity.projects.create(this.DUFn(bodys))
ctx.body = datas;
}
/**
* @name 更新project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - DELETE /openstack/projects/{ctx.params.id}
*/
async destroy() {
const { ctx, service } = this;
const datas = await service.openstack.identity.projects.destroy(ctx.params.id);
ctx.body = datas;
}
/**
* @name 删除project
*
* @param {String} ctx.params.id 实例id
*
* @example
* - PATCH /openstack/projects/{ctx.params.id}
*/
async update() {
const { ctx, service } = this;
const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
const datas = await service.openstack.identity.projects.update(ctx.params.id, this.DUFn(bodys))
ctx.body = datas;
}
/**
* @name 锁定不可操作项目
*
*/
checkID(idx) {
const ARR = ['c3513f27bbf24362b74d13e6afae2c37', '5d3b50c18fd44db4bc6abfdbbfcf6a3a', '5c7e341df8ff493c8ae7baf57c0129dd'];
return ARR.includes(idx);
}
}

module.exports = OPIdentityProjectsController;
region
'use strict';

const Controller = require('egg').Controller;

class identityUserRegionController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.Region
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @description
*
* @example GET /openstack/identity/region
*
*/
async index() {
const { ctx, service } = this;
const datas = await this.MODEL.getAll(this.auth.id, ctx.isAdmin());
ctx.body = datas;
}
}

module.exports = identityUserRegionController;
user
'use strict';

const Controller = require('egg').Controller;

class identityUserController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.User
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @param {String} ctx.query.detail 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/user
*
*/
async index() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.list(ctx.query);
};
/**
* @name 获取单一用户信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/user/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.show(ctx.params.id);
// const result = await this.MODEL.getOne(this.auth.id);
// ctx.body = result;
};
/**
* @name 创建用户
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/user/
*/
async create() {
const ctx = this.ctx;
const result = await this.MODEL.createUser(this.auth.id)
ctx.body = result;
// const { ctx, service } = this;
// const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
// const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
// ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
};
/**
*
* @name 测试内部用token
*
*/
async testToken() {
const { ctx, service } = this;
ctx.body = await this.TKMODEL.getToken(this.auth.id)
};
}

module.exports = identityUserController;

egg.js+mongodb+openstack 公有云计费系统(二)用户系统的搭建

Nodejslopo1983 发表了文章 • 0 个评论 • 1204 次浏览 • 2019-03-14 00:13 • 来自相关话题

鉴于Openstack的特殊性 和项目需求,用户系统将分为 系统用户 管理员用户 openstack用户 大致3类
一 系统用户
表设计const crypto = require('crypto');
const Decimal = require('decimal');

module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const CompanySchema = new Schema({
// 公司名称
compName: {
type: String,
index: true
},
// 认证类型 [0/未认证,1/个人,2/企业]
compAuthType: {
type: Number,
default: 0,
get: v => NumToStr(['未认证', '个人', '企业'], v, true),
},
// 认证状态 [0/'未认证', 1/'已上传', 2/'认证中',3/ '认证未通过', 4/'已认证']
compAuthStatus: {
type: Number,
default: 0,
get: v => NumToStr(['未认证', '已上传', '认证中', '认证未通过', '已认证'], v, true),
},
// 认证证件信息相关
compLicense: {
type: Schema.Types.ObjectId,
ref: 'CompLicense',
},
// 关联绑定
compAuth: {
// 邮件绑定
email: {
type: Boolean,
default: false
},
// 手机绑定
phone: {
type: Boolean,
default: true
}
},
// 企业邮箱
compEmail: {
type: String,
required: [true, '企业邮箱不允许为空'],
unique: true,
},
compName: {
type: String,
},
// 企业联系电话
compPhone: {
type: String,
required: [true, '联系电话不允许为空'],
unique: true,
},
// 登陆密码
compPassword: {
type: String,
required: [true, '密码不能为空'],
minlength: [8, '密码应大于8位数'],
set: v => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
}
},
// 企业服务
compService: ,
// 企业产品
compProduct: ,
// 企业api 需求
compApi: [{
name: {
type: String,
},
IPWhiteList: [String]
}],
// 用户ak sk
compASK: ,
// 用户账户余额
compAccount: {
// 现金账户
cash: {
type: Number,
default: 0.00,
},
// 代理账户
agent: {
type: Number,
default: 0.00
},
// 代金券账户
other: {
type: Number,
default: 0.00
}
},
// 余额预警
compAccountWarnig: {
type: Number,
default: 0
},
// 客户编号
compNumer: {
type: String
},
// 公司客服经理
compMaster: {
type: String
},
// 用户代理等级 [1-5]
compAgent: {
type: Number,
default: 1,
get: v => NumToStr(['普通', '铜牌', '银牌', '金牌', '白金', '钻石'], v),
},
// 公司客户
compCustomer: [{
type: Schema.Types.ObjectId,
ref: 'Company',
}],
// 用户优惠券
compCoupon: {
type: Array
},
// 购物车ID
shoppingCart: {
type: Schema.Types.ObjectId,
ref: 'ShopCar',
},
// 签名系统状态 ['删除','正常','锁定'] 0,1,2
status: {
type: Number,
default: 1,
// get: v => NumToStr(['删除', '正常', '锁定'], v, true),
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
const isAdmin = (auth) => auth.group === 1 ? 0 : 1;
CompanySchema.statics = {
getAll: async function(queryMix) {
const {
querys,
select,
pages,
sort,
dates
} = queryMix;
const models = this.find({
'status': {
'$ne': 0
},
...querys,
...(!!pages && !!pages.marker && {
'_id': {
"$lt": pages.marker
}
}),
}, {
...select,
'compPassword': 0,
'compASK': 0
})
.limit(!!pages ? pages.limit : 10)
.sort({
'_id': -1,
...sort
});
return {
data: {
result: await models,
totalCount: await models.count()
}
};
},
getOne: async function(_id) {
const models = this.findOne({
_id,
'status': {
'$ne': 0
}
}, {
'compPassword': 0,
'compASK': 0
});
return {
data: await models
}
},
/**
* 账户余额操作
* @param {Number} money 金额
* @param {Object} auth admin鉴权
* @param {String} type 余额类型
* @param {String} method 类型 add + sub-
* @param {ObjectId} _id 公司id
*/
cashFN: async function(money, auth, type = 'cash', method = 'add', _id) {
try {
const {
compAccount,
compName
} = await this.findOne({
'_id': _id ? _id : auth.id
});
const nowCash = new Decimal(compAccount[type])[method](new Decimal(money)).toNumber();
let result;
if (type = 'cash') {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.cash': nowCash
});
} else if (type = 'agent') {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.agent': nowCash
});
} else {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.other': nowCash
});
};
if (auth.group === 1) await this.cashWarning(ctx, _id);
return result.ok === 1 ? `${compName}${method === 'add' ? `充值¥:${money}元成功!` : '购买成功'}` : `${compName}充值失败`;
} catch (error) {
return error
}
},
// 余额预警
cashWarning: async function (ctx, _id) {
const {
compAccount,
compAccountWarnig,
compName
} = await this.findOne({
_id
});
const cashCount = Object.values(compAccount).reduce((a, b) => a + b);
if (compAccountWarnig >= cashCount) return await ctx.helper.sendWarning(ctx, `您的现金账户余额不足¥:${compAccountWarnig},为了保证您业务的正常运行,请及时充值!`, _id, compName);
},
// 登陆获取token
isLogin: async function (ctx) {
return await ctx.service.mongo.adcq.isLogin(ctx, 'Company', 'compPassword', async (e) => {
let {
_id,
compPhone,
compEmail,
compName,
compAuth,
compService,
updated,
compApi
} = e;
const ProjectID = (await ctx.model.Openstack.Identity.User.getObjectID(_id)).default_project_id;
try {
const TOKEN = await ctx.service.apps.jwt.sign({
id: _id,
group: 1,
phone: compPhone,
compApi,
ProjectID
});
// await ctx.model.Token.addOne({ authToken: TOKEN, updateTime: new Date() });
return {
token: TOKEN,
info: {
_id,
compPhone,
compEmail,
compName,
compAuth,
compService,
updated,
compApi
}
}
} catch (error) {
return error
}
})
},
// ak/sk生成token
apiToken: async function (body) {
const {
uid,
api_key,
secret_key
} = body;
const userInfo = await this.findOne({
_id: uid
}, {
'compASK': 1,
'compApi': 1,
});
const isHave = userInfo.compASK.filter(e => e.ak == api_key && e.sk == secret_key).length;
if (isHave === 1) {
let {
_id,
compApi
} = userInfo;
return {
data: {
token: await ctx.service.apps.jwt.sign({
id: _id,
group: 3,
service: compApi,
}),
expiresIn: 60 * 60 * 24 * 30 * 1000
}
}
} else {
return {
code: 422,
message: '参数不正确'
}
}
},
// 获取ask 列表
getASK: async function (_id) {
try {
const result = await this.findOne(_id);
return {
data: result.compASK
}
} catch (error) {}
},
// 创建ask
createASK: async function (ctx) {
if ((await this.getASK({
'_id': ctx.state.user.id
})).data.length === 20) return {
message: '每一用户只允许创建20个ak/sk序列对!',
code: 422
};
const asks = {
_id: mongoose.Types.ObjectId(),
info: '',
ak: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 5)}`).digest('hex'),
sk: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 8)}`).digest('hex'),
createTime: new Date()
};
return {
data: (await this.findOneAndUpdate({
'_id': ctx.state.user.id
}, {
$push: {
'compASK': asks
}
})).compASK.pop()
}
},
// 设置ask 名称
setInfo: async function (ctx) {
const {
info
} = ctx.request.body;
const result = await this.update({
'_id': ctx.params.id,
'compASK._id': mongoose.Types.ObjectId(ctx.request.body.id)
}, {
'$set': {
'compASK.$.info': info
}
});
return result.n === 1 && {
data: {
_id: ctx.params.id,
info: info
}
}
},
// 删除ak
delASK: async function name(ctx) {
const result = await this.update({
'_id': ctx.state.user.id
}, {
"$pull": {
'compASK': {
'_id': mongoose.Types.ObjectId(ctx.params.id)
}
}
});
return result.n === 1 && {
data: ctx.params.id
};
},
// 锁定公司
lockfn: async function (ctx, type) {
return {
data: await this.findOneAndUpdate({
'_id': ctx.params.id
}, {
$set: {
'status': 2
}
})
}
},
// 是否已存在
isIn: async function (params) {
return await this.findOne({ ...params
})
},
// 获取公司详细
getComp: async function (auth) {
return (await this.findOne({ ...(!isAdmin(auth) && {
'_id': auth.id
})
}))
},
// 获取现金
getCash: async function (auth) {
return (await this.getComp(auth)).compAccount
},
// 获取优惠券
getCoupon: async function (auth) {
const coupon = (await this.getComp(auth)).compCoupon;
return {
coupon: coupon,
length: coupon.length
}
},
// 获取服务
getService: async function (auth) {
return (await this.getComp(auth)).compService
},
// 获取客户列表
getCustomerList: async function (auth) {
const List = (await this.findOne({
'_id': auth.id
})).compCustomer;
const result = await this.find({
_id: {
$in: List
}
}, 'compName compEmail compPhone created');
return result;
},
// 绑定邮箱
bindMail: async function (auth) {
const result = await this.update({
'_id': auth.id
}, {
'compAuth.emailAuth': true
}, {
upsert: true
});
return result.ok === 1 && true;
},
// 登陆注册找回密码 pipe
lrfAction: async function (body) {
const {
action,
compPhone: SmsPhone,
code: SmsCode
} = body;
delete body.action
if (action === 'changePsd') {
const isInUsers = await this.isIn({
'compPhone': body.compPhone
});
if (!isInUsers) return {
message: '对不起您还不是我们的客户,请先注册!'
};
}
const checkCode = await ctx.model.SmsCode.check({
SmsPhone,
SmsCode
});
delete body.code
if (checkCode !== true) return checkCode;
return this[action](body);
},
// 注册
regist: async function (body) {
const {
compEmail
} = body;
try {
const result = await this.create(body);
if (result._id) {
await ctx.service.sms.mail.sendMail({
to: compEmail,
html: 'regist',
});
await ctx.model.System.Ui.User.create({
'_comp': result._id
});
const datas = await ctx.model.Openstack.Identity.User.createUser(result._id);
return {
code: 201,
data: {
name: result._id,
}
}
};
} catch (error) {
return error
}
},
// 修改密码
changePsd: async function (body) {
const {
compPhone,
compPassword
} = body;
return await this.findOneAndUpdate({
'compPhone': compPhone
}, {
'compPassword': compPassword
})
},
// 绑定客户
bindCustomer: async function (_id, auth) {
return await this.findOneAndUpdate({
_id
}, {
$push: {
'compCustomer': auth.id
}
})
},
}
return mongoose.model('Company', CompanySchema);
}控制器/*************************************************************
*
*- Copyright (c) qiduo, 2018
*- FileName: USERController.js 用户基本信息相关
*- Author: 罗波 lopo1983@vip.qq.com
*- Version: 1.0
*- Date:2018-10-15
*- Descripttion:openstack geecp
*- Modules:
*
*- Extends
* - 1.egg_Controller
*----------------------------------------------------------
*
*- Function List :
*
*- StaticsList :
* - index 获取用户列表
* - isHave 检测用户是否存在
* - show 获取单一用户信息
* - create 用户注册
*
*- History :
* <Author> <Date> <Desc>
*
**************************************************************/
'use strict';

const Controller = require('egg').Controller;

class USERController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Model} MODEL 公司表
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Account.Company;
}
/**
*
* @name 获取用户列表
*
* @description Admin 用户可用 可使用queryParamFn 进行查询
*
* @example GET /user/
*
*/
async index() {
const ctx = this.ctx;
const { helper } = ctx;
const result = await this.MODEL.getAll(helper.queryParamFn(ctx.query));
ctx.body = result
}
/**
*
* @name 检测用户是否存在
*
* @param {String} compName 用户名称
* @param {String} compEmail 用户邮箱
* @param {String} compPhone 用户手机
*
* @description compName, compEmail, compPhone 三选一 或可多选
*
* @example GET /user/isIn/?@param = param
*
*/
async isHave() {
const ctx = this.ctx;
const { compName, compEmail, compPhone } = ctx.query;
const result = (await this.MODEL.isIn(this.DUFn({ compName, compEmail, compPhone }))) === null;
ctx.body = { data: `${!result}` }
}
/**
*
* @name 获取用户信息
* @param {ObjectId} id 必传 ctx.params.id 用户id
*
* @example GET /user/{id}
*/
async show() {
const ctx = this.ctx;
const result = await this.MODEL.getOne({ '_id': ctx.params.id });
ctx.body = result
}
/**
*
* @name 用户注册 body = ctx.request.body
* @param {String} action 必传 动作 regist changePsd
* @param {String} compEmail 必传 邮箱
* @param {String} compPhone 必传 手机号码
* @param {String} compPassword 必传 用户密码 `${SALT}${MD5}`
* @param {String} code 必传 手机验证码,120s次 mongodb.smscodes expiresIn_TTL_60*3
*
* @example POST /user/
*
* @description
* - 邮箱和手机均能登陆
* - compEmail, compPhone, compPassword, action, code 均为必选参数
*
*/
async create() {
const { ctx } = this;
const { compEmail, compPhone, compPassword, action, code } = ctx.request.body;
const result = await this.MODEL.lrfAction({ compEmail, compPhone, compPassword, action, code });
ctx.body = result
}
/**
* @name 修改用户信息
*
* @param {String} action 必传 修改的方法
* @param {action}
* - changePsd 修改密码
* - bindCustomer 绑定客户
* - lrfAction 找回密码
* -
*
* @example PUT /user/{ObjecId}
*/
async update() {
const { ctx } = this;
const bodys = ctx.request.body;
const { action } = bodys;
delete bodys.action;
const result = await this.MODEL[action](bodys)
}
}

module.exports = USERController;

二 管理员用户
表设计const crypto = require('crypto');
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const AdminSchema = new Schema({
// 用户名
adminName: {
type: String,
required: true,
unique: [true, '用户名已存在']
},
// 用户密码
adminPassword: {
type: String,
required: true,
set: v => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
}
},
// 用户权限组
adminGroup: {
type: Number,
required: true,
default: 2
},
// 用户真实姓名
adminRealName: {
type: String
},
// 用户头像
adminHeader: {
type: String,
default: ''
},
adminStaff: {
// type: Schema.Types.ObjectId,
// ref: 'Staff',
},
status: {
type: Number,
default: 1
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
AdminSchema.statics = {
isLogin: async function (ctx) {
return await ctx.service.mongo.adcq.isLogin(ctx, 'Admin', 'adminPassword', async (e) => {
let { _id, adminRealName, adminName, adminGroup, adminHeader, adminStaff } = e;
return {
token: await ctx.service.apps.jwt.sign({ id: _id, group: adminGroup }),
info: { _id, adminRealName, adminName, adminHeader, adminStaff }
}
})
}
}
return mongoose.model('Admin', AdminSchema)
}OpenStack 用户
表设计const crypto = require('crypto');
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const { ctx, helper, service } = app.createAnonymousContext();
const OSIdentityUserSchema = new Schema({
// The user ID.
id: String,
// The ID of the default project for the user.
default_project_id: String,
// user description
description: String,
// The ID of the domain.
domain_id: String,
// user emaill address
email: String,
// If the user is enabled, this value is true. If the user is disabled, this value is false.
enabled: Boolean,
// The links for the user resource.
links: {},
// user name
name: String,
// 密码
password: String,
// 角色ID
role: String,
// 同步状态
sync: Boolean
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSIdentityUserSchema.statics = {
createUser: async function(_id) {
const setPSDFn = (v = _id) => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
};
const password = setPSDFn();
try {
/****************************创建Project*********************************/
const PROJECT = await service.openstack.identity.projects.create({
name: _id,
'description': `comp_id:${_id} date:${new Date() -0 }`
});
const default_project_id = PROJECT.data.project.id;
// || PROJECT.data.error.code === 409
if (PROJECT.data.project) {
const DATAS = await service.openstack.identity.users.create({
'name': _id,
password,
default_project_id,
'description': `comp_id:${_id} date:${new Date()-0 }`
});
/******************************本地创建*******************************/
const result = await this.create({
...DATAS.data.user,
password,
default_project_id,
sync: true
});
/******************************分配角色*******************************/
if (!result.id) return;
await service.openstack.identity.roles.update(result.default_project_id, result.id, app.config.openstack.rolesID.default);
return result
}
} catch (error) {
return error
}
},
/**
* @name 获取一个
* @param {*} _id compid
* @param {*} select 选择的字段(BSON name/显示的名称 -name/不显示的名称)
*/
getOne: async function(_id, select) {
const MODEL = this.findOne({ name: _id }, !!select && select);
try {
const result = await MODEL;
return !!result ? result : await this.createUser(_id);
} catch (error) {
return error
}
},
// 获取ObjectID
getObjectID: async function(_id) {
const MODEL = this.findOne({ 'name': _id }, 'default_project_id -_id')
try {
return await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_Identity_user', OSIdentityUserSchema)
}service?
role'use strict';
const ServerIndex = require('../index')
//
class identityRolesService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':5000/identity/v3/'
};
// 获取Region列表
async list(parent_region_id) {
try {
const datas = await this.OSAJax(`${this.actions}`, { body: { parent_region_id } })
return {
data: {
result: datas.regions,
totalCount: datas.regions.length
}
};
} catch (error) {
return {
data: error
}
}

}
// 显示regions详情
async show(project_id, user_id) {
let datas
try {
datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles`)
} catch (error) {
datas = error
}
return datas
}
// 创建regions
async create(bodys) {
}
// 给用户赋予角色
async update(project_id, user_id, role_id) {
let datas;
try {
datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles/${role_id}`, { method: 'PUT' });
} catch (error) {
datas = error
}
return { data: datas }
}
// 删除regions
async destroy(id) {
}
}
module.exports = identityRolesService;project'use strict';
const ServerIndex = require('../index')
//
class identityProjectService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':5000/identity/v3/projects'
};
// 获取Projects列表
async list() {
const datas = await this.OSAJax(`${this.actions}`);
return {
data: {
'result': datas.projects,
'totalCount': datas.projects.length
}
};
}
// 显示Projects详情
async show(id) {
const datas = await this.OSAJax(`${this.actions}/${id}`);
return { data: datas };
}
// 创建Projects
async create(bodys) {
const datas = await this.OSAJax(this.actions, { body: { 'project': bodys }, method: 'POST' });
return { data: datas }
}
// 修改Projects
async update(id, bodys) {
const datas = await this.OSAJax(`${this.actions}/${id}`, { body: { 'project': bodys }, method: 'PATCH' });
return { data: datas }
}
// 删除Projects
async destroy(id) {
const datas = await this.OSAJax(`${this.actions}/${id}`, { method: 'DELETE' });
return { data: datas }
}
}
module.exports = identityProjectService;控制器'use strict';

const Controller = require('egg').Controller;

class identityUserController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.User
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @param {String} ctx.query.detail 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/user
*
*/
async index() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.list(ctx.query);
};
/**
* @name 获取单一用户信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/user/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.show(ctx.params.id);
// const result = await this.MODEL.getOne(this.auth.id);
// ctx.body = result;
};
/**
* @name 创建用户
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/user/
*/
async create() {
const ctx = this.ctx;
const result = await this.MODEL.createUser(this.auth.id)
ctx.body = result;
// const { ctx, service } = this;
// const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
// const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
// ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
};
/**
*
* @name 测试内部用token
*
*/
async testToken() {
const { ctx, service } = this;
ctx.body = await this.TKMODEL.getToken(this.auth.id)
};
}

module.exports = identityUserController;共用service
'use strict';
const Service = require('egg').Service;
//
class indexService extends Service {
constructor(ctx) {
super(ctx);
this.OPTokenMODEL = ctx.model.Openstack.Token;
this.OPUserMODEL = ctx.model.Openstack.Identity.User;
this.OBJKeySort = ctx.helper.OBJKeySort;
const {
uri
} = this.config.openstack;
this.uri = `${uri}`;
this.CurlOpt = async(method, full, token) => {
return {
'dataType': 'json',
'headers': {
...((!full && !token) && {
'X-Auth-Token': (await ctx.helper.TokenFn('openstack')).data
}) || !!token && {
'X-Auth-Token': token
},
'Content-Type': 'application/json',
},
'method': method,
...method !== 'DELETE' && {
'data': {}
},
'timeout': 60000
}
}
};
/**
* 基础库
*
* @param {Object} body 需要提交的参数
* @param {String} method GET POST DELETE PUT PATCH
* @param {String} params url 参数
* @param {Boolean} full 是否显示完整参数
* @param {String} _ucid 用户ID Optional
*/
async OSAJax(params, {
body = {},
method = "GET",
full = false,
status = false,
_ucid
} = {}) {
const ctx = this.ctx;
const opt = await this.CurlOpt(method, full, !!_ucid ? await this.getUserToken(_ucid) : false);
method !== 'DELETE' && Object.assign(opt.data, {...!!body ? body : ''
});
// console.log(opt)
// console.log({
// // 'getFullRES': full,
// // 'isAdmin': !!_ucid ? `No | _ucid:${_ucid}` : 'Yes',
// 'URI': `http://${this.uri}${!!params ? params : ''}`,
// // 'Method': method,
// // ...method !== 'DELETE' && {
// // 'Body': opt.data
// // },
// // '_': new Date()
// })
try {
const result = await ctx.curl(`${this.uri}${!!params ? params : ''}`, opt);
return !!full && result || !!status && result.status || result.data;
} catch (error) {
return error
}
};
// 获取普通用户token
async getUserToken(_id) {
const ctx = this.ctx;
return (await ctx.model.Openstack.Token.getToken(_id)).data
};
// 获取普通用户projectID
async getProject(_id) {
const ctx = this.ctx;
return _id !== 'admin' ? (await this.OPUserMODEL.getOne(_id, 'default_project_id'))['default_project_id'] : this.config.openstack.projectID.default
};
// 从支付订单创建相关实例
/**
*
* @param {*} _comp 公司id
* @param {*} model 数据库
* @param {*} bodys 内容
* +@param {String} _metadata 关联数据
* @param {*} time 开通时长
*/
async createFromOrder(_comp, model, bodys, time, payment) {
try {
const ctx = this.ctx;
const MODELS = ctx.model.Openstack;
const {
deleteUndefined: DUFn,
subtractMoment: TMFn
} = ctx.helper
let datas = {}
if (model === 'cds') {
const {
availability_zone,
snapshot_id,
backup_id,
imageRef,
size,
volume_type,
_metadata
} = bodys;
const BODYS = DUFn({
availability_zone,
snapshot_id,
backup_id,
imageRef,
size,
volume_type,
_metadata
});
datas = await MODELS.BlcokStorage.Volumes.createOne(
_comp, {
...BODYS,
'endTime': TMFn(time, 'month', 'add'),
payment
}
);
}
if (model === 'ecs') {
const {
availability_zone,
flavorRef,
name,
uuid,
imageRef,
server_password,
key_name,
security_groups,
_metadata
} = bodys;
const SERVERBODYS = DUFn({
availability_zone,
flavorRef,
name,
uuid,
imageRef,
server_password,
key_name,
security_groups,
_metadata
});
datas = await MODELS.Servers.Server.createServer(
_comp, {
...SERVERBODYS,
'endTime': TMFn(time, 'month', 'add'),
payment,
}
);
}
if (model === 'eip') {
const {
description,
_metadata
} = bodys;
const EIPBODYS = DUFn({
description,
_metadata
});
datas = await MODELS.Neutron.FloatingIP.createOne(
_comp, {
...EIPBODYS,
'endTime': TMFn(time, 'month', 'add'),
payment
})
}
return datas
} catch (error) {
console.log(error)
}
}
}
module.exports = indexService; 查看全部

鉴于Openstack的特殊性 和项目需求,用户系统将分为 系统用户 管理员用户 openstack用户 大致3类


一 系统用户
表设计
const crypto = require('crypto');
const Decimal = require('decimal');

module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const CompanySchema = new Schema({
// 公司名称
compName: {
type: String,
index: true
},
// 认证类型 [0/未认证,1/个人,2/企业]
compAuthType: {
type: Number,
default: 0,
get: v => NumToStr(['未认证', '个人', '企业'], v, true),
},
// 认证状态 [0/'未认证', 1/'已上传', 2/'认证中',3/ '认证未通过', 4/'已认证']
compAuthStatus: {
type: Number,
default: 0,
get: v => NumToStr(['未认证', '已上传', '认证中', '认证未通过', '已认证'], v, true),
},
// 认证证件信息相关
compLicense: {
type: Schema.Types.ObjectId,
ref: 'CompLicense',
},
// 关联绑定
compAuth: {
// 邮件绑定
email: {
type: Boolean,
default: false
},
// 手机绑定
phone: {
type: Boolean,
default: true
}
},
// 企业邮箱
compEmail: {
type: String,
required: [true, '企业邮箱不允许为空'],
unique: true,
},
compName: {
type: String,
},
// 企业联系电话
compPhone: {
type: String,
required: [true, '联系电话不允许为空'],
unique: true,
},
// 登陆密码
compPassword: {
type: String,
required: [true, '密码不能为空'],
minlength: [8, '密码应大于8位数'],
set: v => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
}
},
// 企业服务
compService: ,
// 企业产品
compProduct: ,
// 企业api 需求
compApi: [{
name: {
type: String,
},
IPWhiteList: [String]
}],
// 用户ak sk
compASK: ,
// 用户账户余额
compAccount: {
// 现金账户
cash: {
type: Number,
default: 0.00,
},
// 代理账户
agent: {
type: Number,
default: 0.00
},
// 代金券账户
other: {
type: Number,
default: 0.00
}
},
// 余额预警
compAccountWarnig: {
type: Number,
default: 0
},
// 客户编号
compNumer: {
type: String
},
// 公司客服经理
compMaster: {
type: String
},
// 用户代理等级 [1-5]
compAgent: {
type: Number,
default: 1,
get: v => NumToStr(['普通', '铜牌', '银牌', '金牌', '白金', '钻石'], v),
},
// 公司客户
compCustomer: [{
type: Schema.Types.ObjectId,
ref: 'Company',
}],
// 用户优惠券
compCoupon: {
type: Array
},
// 购物车ID
shoppingCart: {
type: Schema.Types.ObjectId,
ref: 'ShopCar',
},
// 签名系统状态 ['删除','正常','锁定'] 0,1,2
status: {
type: Number,
default: 1,
// get: v => NumToStr(['删除', '正常', '锁定'], v, true),
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
const isAdmin = (auth) => auth.group === 1 ? 0 : 1;
CompanySchema.statics = {
getAll: async function(queryMix) {
const {
querys,
select,
pages,
sort,
dates
} = queryMix;
const models = this.find({
'status': {
'$ne': 0
},
...querys,
...(!!pages && !!pages.marker && {
'_id': {
"$lt": pages.marker
}
}),
}, {
...select,
'compPassword': 0,
'compASK': 0
})
.limit(!!pages ? pages.limit : 10)
.sort({
'_id': -1,
...sort
});
return {
data: {
result: await models,
totalCount: await models.count()
}
};
},
getOne: async function(_id) {
const models = this.findOne({
_id,
'status': {
'$ne': 0
}
}, {
'compPassword': 0,
'compASK': 0
});
return {
data: await models
}
},
/**
* 账户余额操作
* @param {Number} money 金额
* @param {Object} auth admin鉴权
* @param {String} type 余额类型
* @param {String} method 类型 add + sub-
* @param {ObjectId} _id 公司id
*/
cashFN: async function(money, auth, type = 'cash', method = 'add', _id) {
try {
const {
compAccount,
compName
} = await this.findOne({
'_id': _id ? _id : auth.id
});
const nowCash = new Decimal(compAccount[type])[method](new Decimal(money)).toNumber();
let result;
if (type = 'cash') {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.cash': nowCash
});
} else if (type = 'agent') {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.agent': nowCash
});
} else {
result = await this.update({
'_id': _id ? _id : auth.id
}, {
'compAccount.other': nowCash
});
};
if (auth.group === 1) await this.cashWarning(ctx, _id);
return result.ok === 1 ? `${compName}${method === 'add' ? `充值¥:${money}元成功!` : '购买成功'}` : `${compName}充值失败`;
} catch (error) {
return error
}
},
// 余额预警
cashWarning: async function (ctx, _id) {
const {
compAccount,
compAccountWarnig,
compName
} = await this.findOne({
_id
});
const cashCount = Object.values(compAccount).reduce((a, b) => a + b);
if (compAccountWarnig >= cashCount) return await ctx.helper.sendWarning(ctx, `您的现金账户余额不足¥:${compAccountWarnig},为了保证您业务的正常运行,请及时充值!`, _id, compName);
},
// 登陆获取token
isLogin: async function (ctx) {
return await ctx.service.mongo.adcq.isLogin(ctx, 'Company', 'compPassword', async (e) => {
let {
_id,
compPhone,
compEmail,
compName,
compAuth,
compService,
updated,
compApi
} = e;
const ProjectID = (await ctx.model.Openstack.Identity.User.getObjectID(_id)).default_project_id;
try {
const TOKEN = await ctx.service.apps.jwt.sign({
id: _id,
group: 1,
phone: compPhone,
compApi,
ProjectID
});
// await ctx.model.Token.addOne({ authToken: TOKEN, updateTime: new Date() });
return {
token: TOKEN,
info: {
_id,
compPhone,
compEmail,
compName,
compAuth,
compService,
updated,
compApi
}
}
} catch (error) {
return error
}
})
},
// ak/sk生成token
apiToken: async function (body) {
const {
uid,
api_key,
secret_key
} = body;
const userInfo = await this.findOne({
_id: uid
}, {
'compASK': 1,
'compApi': 1,
});
const isHave = userInfo.compASK.filter(e => e.ak == api_key && e.sk == secret_key).length;
if (isHave === 1) {
let {
_id,
compApi
} = userInfo;
return {
data: {
token: await ctx.service.apps.jwt.sign({
id: _id,
group: 3,
service: compApi,
}),
expiresIn: 60 * 60 * 24 * 30 * 1000
}
}
} else {
return {
code: 422,
message: '参数不正确'
}
}
},
// 获取ask 列表
getASK: async function (_id) {
try {
const result = await this.findOne(_id);
return {
data: result.compASK
}
} catch (error) {}
},
// 创建ask
createASK: async function (ctx) {
if ((await this.getASK({
'_id': ctx.state.user.id
})).data.length === 20) return {
message: '每一用户只允许创建20个ak/sk序列对!',
code: 422
};
const asks = {
_id: mongoose.Types.ObjectId(),
info: '',
ak: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 5)}`).digest('hex'),
sk: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 8)}`).digest('hex'),
createTime: new Date()
};
return {
data: (await this.findOneAndUpdate({
'_id': ctx.state.user.id
}, {
$push: {
'compASK': asks
}
})).compASK.pop()
}
},
// 设置ask 名称
setInfo: async function (ctx) {
const {
info
} = ctx.request.body;
const result = await this.update({
'_id': ctx.params.id,
'compASK._id': mongoose.Types.ObjectId(ctx.request.body.id)
}, {
'$set': {
'compASK.$.info': info
}
});
return result.n === 1 && {
data: {
_id: ctx.params.id,
info: info
}
}
},
// 删除ak
delASK: async function name(ctx) {
const result = await this.update({
'_id': ctx.state.user.id
}, {
"$pull": {
'compASK': {
'_id': mongoose.Types.ObjectId(ctx.params.id)
}
}
});
return result.n === 1 && {
data: ctx.params.id
};
},
// 锁定公司
lockfn: async function (ctx, type) {
return {
data: await this.findOneAndUpdate({
'_id': ctx.params.id
}, {
$set: {
'status': 2
}
})
}
},
// 是否已存在
isIn: async function (params) {
return await this.findOne({ ...params
})
},
// 获取公司详细
getComp: async function (auth) {
return (await this.findOne({ ...(!isAdmin(auth) && {
'_id': auth.id
})
}))
},
// 获取现金
getCash: async function (auth) {
return (await this.getComp(auth)).compAccount
},
// 获取优惠券
getCoupon: async function (auth) {
const coupon = (await this.getComp(auth)).compCoupon;
return {
coupon: coupon,
length: coupon.length
}
},
// 获取服务
getService: async function (auth) {
return (await this.getComp(auth)).compService
},
// 获取客户列表
getCustomerList: async function (auth) {
const List = (await this.findOne({
'_id': auth.id
})).compCustomer;
const result = await this.find({
_id: {
$in: List
}
}, 'compName compEmail compPhone created');
return result;
},
// 绑定邮箱
bindMail: async function (auth) {
const result = await this.update({
'_id': auth.id
}, {
'compAuth.emailAuth': true
}, {
upsert: true
});
return result.ok === 1 && true;
},
// 登陆注册找回密码 pipe
lrfAction: async function (body) {
const {
action,
compPhone: SmsPhone,
code: SmsCode
} = body;
delete body.action
if (action === 'changePsd') {
const isInUsers = await this.isIn({
'compPhone': body.compPhone
});
if (!isInUsers) return {
message: '对不起您还不是我们的客户,请先注册!'
};
}
const checkCode = await ctx.model.SmsCode.check({
SmsPhone,
SmsCode
});
delete body.code
if (checkCode !== true) return checkCode;
return this[action](body);
},
// 注册
regist: async function (body) {
const {
compEmail
} = body;
try {
const result = await this.create(body);
if (result._id) {
await ctx.service.sms.mail.sendMail({
to: compEmail,
html: 'regist',
});
await ctx.model.System.Ui.User.create({
'_comp': result._id
});
const datas = await ctx.model.Openstack.Identity.User.createUser(result._id);
return {
code: 201,
data: {
name: result._id,
}
}
};
} catch (error) {
return error
}
},
// 修改密码
changePsd: async function (body) {
const {
compPhone,
compPassword
} = body;
return await this.findOneAndUpdate({
'compPhone': compPhone
}, {
'compPassword': compPassword
})
},
// 绑定客户
bindCustomer: async function (_id, auth) {
return await this.findOneAndUpdate({
_id
}, {
$push: {
'compCustomer': auth.id
}
})
},
}
return mongoose.model('Company', CompanySchema);
}
控制器
/*************************************************************
*
*- Copyright (c) qiduo, 2018
*- FileName: USERController.js 用户基本信息相关
*- Author: 罗波 lopo1983@vip.qq.com
*- Version: 1.0
*- Date:2018-10-15
*- Descripttion:openstack geecp
*- Modules:
*
*- Extends
* - 1.egg_Controller
*----------------------------------------------------------
*
*- Function List :
*
*- StaticsList :
* - index 获取用户列表
* - isHave 检测用户是否存在
* - show 获取单一用户信息
* - create 用户注册
*
*- History :
* <Author> <Date> <Desc>
*
**************************************************************/
'use strict';

const Controller = require('egg').Controller;

class USERController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Model} MODEL 公司表
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Account.Company;
}
/**
*
* @name 获取用户列表
*
* @description Admin 用户可用 可使用queryParamFn 进行查询
*
* @example GET /user/
*
*/
async index() {
const ctx = this.ctx;
const { helper } = ctx;
const result = await this.MODEL.getAll(helper.queryParamFn(ctx.query));
ctx.body = result
}
/**
*
* @name 检测用户是否存在
*
* @param {String} compName 用户名称
* @param {String} compEmail 用户邮箱
* @param {String} compPhone 用户手机
*
* @description compName, compEmail, compPhone 三选一 或可多选
*
* @example GET /user/isIn/?@param = param
*
*/
async isHave() {
const ctx = this.ctx;
const { compName, compEmail, compPhone } = ctx.query;
const result = (await this.MODEL.isIn(this.DUFn({ compName, compEmail, compPhone }))) === null;
ctx.body = { data: `${!result}` }
}
/**
*
* @name 获取用户信息
* @param {ObjectId} id 必传 ctx.params.id 用户id
*
* @example GET /user/{id}
*/
async show() {
const ctx = this.ctx;
const result = await this.MODEL.getOne({ '_id': ctx.params.id });
ctx.body = result
}
/**
*
* @name 用户注册 body = ctx.request.body
* @param {String} action 必传 动作 regist changePsd
* @param {String} compEmail 必传 邮箱
* @param {String} compPhone 必传 手机号码
* @param {String} compPassword 必传 用户密码 `${SALT}${MD5}`
* @param {String} code 必传 手机验证码,120s次 mongodb.smscodes expiresIn_TTL_60*3
*
* @example POST /user/
*
* @description
* - 邮箱和手机均能登陆
* - compEmail, compPhone, compPassword, action, code 均为必选参数
*
*/
async create() {
const { ctx } = this;
const { compEmail, compPhone, compPassword, action, code } = ctx.request.body;
const result = await this.MODEL.lrfAction({ compEmail, compPhone, compPassword, action, code });
ctx.body = result
}
/**
* @name 修改用户信息
*
* @param {String} action 必传 修改的方法
* @param {action}
* - changePsd 修改密码
* - bindCustomer 绑定客户
* - lrfAction 找回密码
* -
*
* @example PUT /user/{ObjecId}
*/
async update() {
const { ctx } = this;
const bodys = ctx.request.body;
const { action } = bodys;
delete bodys.action;
const result = await this.MODEL[action](bodys)
}
}

module.exports = USERController;

二 管理员用户
表设计
const crypto = require('crypto');
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const AdminSchema = new Schema({
// 用户名
adminName: {
type: String,
required: true,
unique: [true, '用户名已存在']
},
// 用户密码
adminPassword: {
type: String,
required: true,
set: v => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
}
},
// 用户权限组
adminGroup: {
type: Number,
required: true,
default: 2
},
// 用户真实姓名
adminRealName: {
type: String
},
// 用户头像
adminHeader: {
type: String,
default: ''
},
adminStaff: {
// type: Schema.Types.ObjectId,
// ref: 'Staff',
},
status: {
type: Number,
default: 1
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
AdminSchema.statics = {
isLogin: async function (ctx) {
return await ctx.service.mongo.adcq.isLogin(ctx, 'Admin', 'adminPassword', async (e) => {
let { _id, adminRealName, adminName, adminGroup, adminHeader, adminStaff } = e;
return {
token: await ctx.service.apps.jwt.sign({ id: _id, group: adminGroup }),
info: { _id, adminRealName, adminName, adminHeader, adminStaff }
}
})
}
}
return mongoose.model('Admin', AdminSchema)
}
OpenStack 用户
表设计
const crypto = require('crypto');
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const { ctx, helper, service } = app.createAnonymousContext();
const OSIdentityUserSchema = new Schema({
// The user ID.
id: String,
// The ID of the default project for the user.
default_project_id: String,
// user description
description: String,
// The ID of the domain.
domain_id: String,
// user emaill address
email: String,
// If the user is enabled, this value is true. If the user is disabled, this value is false.
enabled: Boolean,
// The links for the user resource.
links: {},
// user name
name: String,
// 密码
password: String,
// 角色ID
role: String,
// 同步状态
sync: Boolean
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSIdentityUserSchema.statics = {
createUser: async function(_id) {
const setPSDFn = (v = _id) => {
let pilipala = Math.random().toString(36).slice(2, 8);
let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
return `${pilipala}${bilibole}`;
};
const password = setPSDFn();
try {
/****************************创建Project*********************************/
const PROJECT = await service.openstack.identity.projects.create({
name: _id,
'description': `comp_id:${_id} date:${new Date() -0 }`
});
const default_project_id = PROJECT.data.project.id;
// || PROJECT.data.error.code === 409
if (PROJECT.data.project) {
const DATAS = await service.openstack.identity.users.create({
'name': _id,
password,
default_project_id,
'description': `comp_id:${_id} date:${new Date()-0 }`
});
/******************************本地创建*******************************/
const result = await this.create({
...DATAS.data.user,
password,
default_project_id,
sync: true
});
/******************************分配角色*******************************/
if (!result.id) return;
await service.openstack.identity.roles.update(result.default_project_id, result.id, app.config.openstack.rolesID.default);
return result
}
} catch (error) {
return error
}
},
/**
* @name 获取一个
* @param {*} _id compid
* @param {*} select 选择的字段(BSON name/显示的名称 -name/不显示的名称)
*/
getOne: async function(_id, select) {
const MODEL = this.findOne({ name: _id }, !!select && select);
try {
const result = await MODEL;
return !!result ? result : await this.createUser(_id);
} catch (error) {
return error
}
},
// 获取ObjectID
getObjectID: async function(_id) {
const MODEL = this.findOne({ 'name': _id }, 'default_project_id -_id')
try {
return await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_Identity_user', OSIdentityUserSchema)
}
service?
role
'use strict';
const ServerIndex = require('../index')
//
class identityRolesService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':5000/identity/v3/'
};
// 获取Region列表
async list(parent_region_id) {
try {
const datas = await this.OSAJax(`${this.actions}`, { body: { parent_region_id } })
return {
data: {
result: datas.regions,
totalCount: datas.regions.length
}
};
} catch (error) {
return {
data: error
}
}

}
// 显示regions详情
async show(project_id, user_id) {
let datas
try {
datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles`)
} catch (error) {
datas = error
}
return datas
}
// 创建regions
async create(bodys) {
}
// 给用户赋予角色
async update(project_id, user_id, role_id) {
let datas;
try {
datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles/${role_id}`, { method: 'PUT' });
} catch (error) {
datas = error
}
return { data: datas }
}
// 删除regions
async destroy(id) {
}
}
module.exports = identityRolesService;
project
'use strict';
const ServerIndex = require('../index')
//
class identityProjectService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':5000/identity/v3/projects'
};
// 获取Projects列表
async list() {
const datas = await this.OSAJax(`${this.actions}`);
return {
data: {
'result': datas.projects,
'totalCount': datas.projects.length
}
};
}
// 显示Projects详情
async show(id) {
const datas = await this.OSAJax(`${this.actions}/${id}`);
return { data: datas };
}
// 创建Projects
async create(bodys) {
const datas = await this.OSAJax(this.actions, { body: { 'project': bodys }, method: 'POST' });
return { data: datas }
}
// 修改Projects
async update(id, bodys) {
const datas = await this.OSAJax(`${this.actions}/${id}`, { body: { 'project': bodys }, method: 'PATCH' });
return { data: datas }
}
// 删除Projects
async destroy(id) {
const datas = await this.OSAJax(`${this.actions}/${id}`, { method: 'DELETE' });
return { data: datas }
}
}
module.exports = identityProjectService;
控制器
'use strict';

const Controller = require('egg').Controller;

class identityUserController extends Controller {
/**
* @name constructor
*
* @param {*} ctx
* @param {Function} DuFn 清理空字段函数
* @param {Object} auth 用户JWT
*
*/
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFn = ctx.helper.deleteUndefined;
this.MODEL = ctx.model.Openstack.Identity.User
this.TKMODEL = ctx.model.Openstack.Token
};
/**
*
* @name 用户列表
*
* @param {String} ctx.query.detail 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/user
*
*/
async index() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.list(ctx.query);
};
/**
* @name 获取单一用户信息
*
* @param {String} ctx.params.id 实例id
*
* @example GET /openstack/user/{ctx.params.id}
*
*/
async show() {
const { ctx, service } = this;
ctx.body = await service.openstack.identity.users.show(ctx.params.id);
// const result = await this.MODEL.getOne(this.auth.id);
// ctx.body = result;
};
/**
* @name 创建用户
*
* @param {String} ctx.params.id 实例id
*
* @example
* - POST /openstack/user/
*/
async create() {
const ctx = this.ctx;
const result = await this.MODEL.createUser(this.auth.id)
ctx.body = result;
// const { ctx, service } = this;
// const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
// const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
// ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
};
/**
*
* @name 测试内部用token
*
*/
async testToken() {
const { ctx, service } = this;
ctx.body = await this.TKMODEL.getToken(this.auth.id)
};
}

module.exports = identityUserController;
共用service
'use strict';
const Service = require('egg').Service;
//
class indexService extends Service {
constructor(ctx) {
super(ctx);
this.OPTokenMODEL = ctx.model.Openstack.Token;
this.OPUserMODEL = ctx.model.Openstack.Identity.User;
this.OBJKeySort = ctx.helper.OBJKeySort;
const {
uri
} = this.config.openstack;
this.uri = `${uri}`;
this.CurlOpt = async(method, full, token) => {
return {
'dataType': 'json',
'headers': {
...((!full && !token) && {
'X-Auth-Token': (await ctx.helper.TokenFn('openstack')).data
}) || !!token && {
'X-Auth-Token': token
},
'Content-Type': 'application/json',
},
'method': method,
...method !== 'DELETE' && {
'data': {}
},
'timeout': 60000
}
}
};
/**
* 基础库
*
* @param {Object} body 需要提交的参数
* @param {String} method GET POST DELETE PUT PATCH
* @param {String} params url 参数
* @param {Boolean} full 是否显示完整参数
* @param {String} _ucid 用户ID Optional
*/
async OSAJax(params, {
body = {},
method = "GET",
full = false,
status = false,
_ucid
} = {}) {
const ctx = this.ctx;
const opt = await this.CurlOpt(method, full, !!_ucid ? await this.getUserToken(_ucid) : false);
method !== 'DELETE' && Object.assign(opt.data, {...!!body ? body : ''
});
// console.log(opt)
// console.log({
// // 'getFullRES': full,
// // 'isAdmin': !!_ucid ? `No | _ucid:${_ucid}` : 'Yes',
// 'URI': `http://${this.uri}${!!params ? params : ''}`,
// // 'Method': method,
// // ...method !== 'DELETE' && {
// // 'Body': opt.data
// // },
// // '_': new Date()
// })
try {
const result = await ctx.curl(`${this.uri}${!!params ? params : ''}`, opt);
return !!full && result || !!status && result.status || result.data;
} catch (error) {
return error
}
};
// 获取普通用户token
async getUserToken(_id) {
const ctx = this.ctx;
return (await ctx.model.Openstack.Token.getToken(_id)).data
};
// 获取普通用户projectID
async getProject(_id) {
const ctx = this.ctx;
return _id !== 'admin' ? (await this.OPUserMODEL.getOne(_id, 'default_project_id'))['default_project_id'] : this.config.openstack.projectID.default
};
// 从支付订单创建相关实例
/**
*
* @param {*} _comp 公司id
* @param {*} model 数据库
* @param {*} bodys 内容
* +@param {String} _metadata 关联数据
* @param {*} time 开通时长
*/
async createFromOrder(_comp, model, bodys, time, payment) {
try {
const ctx = this.ctx;
const MODELS = ctx.model.Openstack;
const {
deleteUndefined: DUFn,
subtractMoment: TMFn
} = ctx.helper
let datas = {}
if (model === 'cds') {
const {
availability_zone,
snapshot_id,
backup_id,
imageRef,
size,
volume_type,
_metadata
} = bodys;
const BODYS = DUFn({
availability_zone,
snapshot_id,
backup_id,
imageRef,
size,
volume_type,
_metadata
});
datas = await MODELS.BlcokStorage.Volumes.createOne(
_comp, {
...BODYS,
'endTime': TMFn(time, 'month', 'add'),
payment
}
);
}
if (model === 'ecs') {
const {
availability_zone,
flavorRef,
name,
uuid,
imageRef,
server_password,
key_name,
security_groups,
_metadata
} = bodys;
const SERVERBODYS = DUFn({
availability_zone,
flavorRef,
name,
uuid,
imageRef,
server_password,
key_name,
security_groups,
_metadata
});
datas = await MODELS.Servers.Server.createServer(
_comp, {
...SERVERBODYS,
'endTime': TMFn(time, 'month', 'add'),
payment,
}
);
}
if (model === 'eip') {
const {
description,
_metadata
} = bodys;
const EIPBODYS = DUFn({
description,
_metadata
});
datas = await MODELS.Neutron.FloatingIP.createOne(
_comp, {
...EIPBODYS,
'endTime': TMFn(time, 'month', 'add'),
payment
})
}
return datas
} catch (error) {
console.log(error)
}
}
}
module.exports = indexService;

egg.js+mongodb+openstack 公有云计费系统(一)

Nodejslopo1983 发表了文章 • 0 个评论 • 1128 次浏览 • 2019-03-13 23:58 • 来自相关话题

本代码仅供学习 参考用 请勿做其他用途
?本项目结构
?
用户系统财务系统工单系统计费系统OpenStack (rocky)
?
OpenStack 功能
用户系统identity磁盘blcokStorage计算compute监控gnocchi网络 network
?
所需依赖
"dependencies": {
"egg": "^2.2.1",
"egg-scripts": "^2.5.0",
"lodash": "^4.17.11",
"xml2js": "^0.4.19"
},
"devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.0.0",
"baidu-aip-sdk": "^2.3.3",
"bce-sdk-js": "^0.2.9",
"decimal": "0.0.2",
"decimal.js": "^10.0.1",
"egg-bin": "^4.3.5",
"egg-ci": "^1.8.0",
"egg-cors": "^2.1.0",
"egg-jwt": "^3.1.2",
"egg-mock": "^3.14.0",
"egg-mongoose": "^3.1.0",
"egg-multipart": "^2.1.0",
"egg-validate": "^1.1.1",
"egg-wechat-api": "^1.2.2",
"eslint": "^4.11.0",
"eslint-config-egg": "^6.0.0",
"formstream": "^1.1.0",
"jpush-async": "^4.0.0-rc.1",
"koa-useragent": "^1.1.0",
"moment": "^2.22.2",
"nodemailer": "^4.6.8",
"request": "^2.88.0",
"request-promise-native": "^1.0.5",
"stream-to-array": "^2.3.0",
"stream-wormhole": "^1.1.0",
"webstorm-disable-index": "^1.2.0"
},
环境?
node 8.11?
mongodb4.x?
openstack(rocky)
?
注意:
?
1.本教程不会上传相关代码到GitHub ;
2.本教程需要熟悉egg.js mongoose ES6/7;
3.熟悉Async/await
? 查看全部

本代码仅供学习 参考用 请勿做其他用途


?本项目结构
?
  • 用户系统
  • 财务系统
  • 工单系统
  • 计费系统
  • OpenStack (rocky)

  • ?
    OpenStack 功能
  • 用户系统identity
  • 磁盘blcokStorage
  • 计算compute
  • 监控gnocchi
  • 网络 network

  • ?
    所需依赖
      "dependencies": {
    "egg": "^2.2.1",
    "egg-scripts": "^2.5.0",
    "lodash": "^4.17.11",
    "xml2js": "^0.4.19"
    },
    "devDependencies": {
    "autod": "^3.0.1",
    "autod-egg": "^1.0.0",
    "baidu-aip-sdk": "^2.3.3",
    "bce-sdk-js": "^0.2.9",
    "decimal": "0.0.2",
    "decimal.js": "^10.0.1",
    "egg-bin": "^4.3.5",
    "egg-ci": "^1.8.0",
    "egg-cors": "^2.1.0",
    "egg-jwt": "^3.1.2",
    "egg-mock": "^3.14.0",
    "egg-mongoose": "^3.1.0",
    "egg-multipart": "^2.1.0",
    "egg-validate": "^1.1.1",
    "egg-wechat-api": "^1.2.2",
    "eslint": "^4.11.0",
    "eslint-config-egg": "^6.0.0",
    "formstream": "^1.1.0",
    "jpush-async": "^4.0.0-rc.1",
    "koa-useragent": "^1.1.0",
    "moment": "^2.22.2",
    "nodemailer": "^4.6.8",
    "request": "^2.88.0",
    "request-promise-native": "^1.0.5",
    "stream-to-array": "^2.3.0",
    "stream-wormhole": "^1.1.0",
    "webstorm-disable-index": "^1.2.0"
    },

    环境?
    node 8.11?
    mongodb4.x?
    openstack(rocky)
    ?
    注意:
    ?
    1.本教程不会上传相关代码到GitHub ;
    2.本教程需要熟悉egg.js mongoose ES6/7;
    3.熟悉Async/await
    ?

    egg.js+mongodb+openstack 公有云计费系统(三)用户系统的搭建 (2)

    Nodejslopo1983 发表了文章 • 0 个评论 • 1153 次浏览 • 2019-03-15 11:08 • 来自相关话题

    A/SK 机制
    ?
    控制器
    ?
    /*************************************************************
    *
    *- Copyright (c) qiduo, 2018
    *- FileName: AccesskeyController.js 安全认证 Accesskey接口
    *- Author: 罗波 lopo1983@vip.qq.com
    *- Version: 1.0
    *- Date:2018-10-15
    *- Descripttion:openstack geecp
    *- Modules:
    *
    *- Extends
    * - 1.egg_Controller
    *----------------------------------------------------------
    *
    *- Function List :
    *
    *- StaticsList :
    * - show 获取所有ak/sk
    * - update 创建ak/sk 修改备注
    * - destroy 删除ak/sk
    *
    *- History :
    * <Author> <Date> <Desc>
    *
    **************************************************************/
    'use strict';

    const Controller = require('egg').Controller;

    class AccesskeyController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Model} MODEL 公司表
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Account.Company;
    }
    /**
    *
    * @name 获取Accesskey列表
    *
    * @example
    * - GET /user/accesskey/_id{ObjectId} HTTP/1.1
    *
    */
    async show() {
    const ctx = this.ctx;
    const result = await this.MODEL.getASK({ '_id': ctx.params.id });
    ctx.body = result
    }
    /**
    *
    * @name 创建AK/SK|修改Info
    *
    * @param {String} info 必填 备注内容
    * @param {ObjectId} id 必填 A/SK{ObjectId}
    *
    * @example
    * - PUT /user/accesskey/user{ObjectId} HTTP/1.1 创建
    * - PUT /user/accesskey/user{ObjectId} HTTP/1.1 修改
    * body:{
    * id:ak/sk{ObjectId}
    * info:备注名称
    * }
    *
    * @description info id 为必填参数
    *
    */
    async update() {
    const ctx = this.ctx;
    if (!!ctx.request.body.info) {
    ctx.body = await this.MODEL.setInfo(ctx);
    }
    else {
    ctx.body = await this.MODEL.createASK(ctx);
    }
    }
    /**
    *
    * @name 删除AK/SK
    *
    * @param {ObjectId} id 必填 A/SK id
    *
    * @example
    * PUT /user/accesskey/id{ObjectId} HTTP/1.1
    * @description id 为必填参数
    *
    */
    async destroy() {
    const ctx = this.ctx;
    ctx.body = await this.MODEL.delASK(ctx);
    }
    /**
    *
    * @name ak/sk鉴权接口
    *
    * @param {ObjectId} uid 必填 用户uid
    * @param {String} api_key 必填 accountKey
    * @param {String} secret_key 必填 secretKey
    *
    * @example
    * POST /user/authorization HTTP/1.1
    *
    * @description uid|api_key|secret_key 必填
    *
    */
    async authorization() {
    const ctx = this.ctx;
    const { uid, api_key, secret_key } = ctx.request.body;
    ctx.body = await this.MODEL.apiToken({ uid, api_key, secret_key });
    }
    }

    module.exports = AccesskeyController;

    用户鉴权
    控制器
    'use strict';
    const Controller = require('egg').Controller;
    class ServiceJwtController extends Controller {
    constructor(ctx) {
    super(ctx);
    this.MODELComp = ctx.model.Account.Company;
    this.MODELAdmin = ctx.model.Account.Admin;
    };
    /**
    * @name 用户token生成
    *
    * @param {action:string} 'api' 用于鉴权ak/sk生成token
    * @param {String} compEmail 用户邮箱
    * @param {String} compPhone 用户手机
    * @param {String} compPassword 用户密码
    *
    * @description
    *
    * @example POST /user/sign/
    *
    * @return Object
    *{
    * "token": "",
    * "info": {
    * "_id": "5bcdd5e7f12ee030f44b6228",
    * "compPhone": "13658157663",
    * "compEmail": "64832897@qq.com",
    * "compAuth": {
    * "email": false,
    * "phone": true
    * },
    * "compService": [],
    * "updated": "2018-10-22T13:51:35.314Z",
    * "compApi": []
    * }
    * }
    *
    **/
    async sign() {
    const ctx = this.ctx;
    const {
    body,
    header
    } = ctx.request;
    try {
    if (ctx.request.url.includes('admin')) {
    ctx.body = await this.MODELAdmin.isLogin(ctx);
    } else {
    if (!['compEmail', 'compPhone'].map(e => Object.keys(body).includes(e)).reduce((a, b) => a + b)) {
    ctx.body = {
    code: 422,
    message: '用户参数错误'
    };
    return
    };
    ctx.body = await this.MODELComp.isLogin(ctx);
    }
    } catch (error) {
    console.log(error)
    if (error.message === 'jwt expired') {
    ctx.body = {
    message: '用户鉴权失败,请重新登陆',
    code: 401
    }
    } else {
    ctx.body = {
    message: !!error.errors ? `${error.errors.reduce((a, error) => { a.push(`${error.field} ${error.message}`); return a }, [])}` : error.message,
    code: 422
    }
    }
    }
    }
    }
    module.exports = ServiceJwtControllerextend 扩展
    简单用户划分
    module.exports = {
    isAdmin() {
    console.log(this.url)
    return this.state.user.group === 1 ? false : true;
    },
    };OpenStack 相关控制器
    project
    'use strict';

    const Controller = require('egg').Controller;

    class OPIdentityProjectsController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    }
    /**
    * @name project列表
    *
    * @param {String} ctx.query 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/projects
    *
    */
    async index() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.list(ctx.query);
    ctx.body = datas;
    }
    /**
    * @name 获取单一project信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/projects/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.show(ctx.params.id);
    ctx.body = datas;
    }
    /**
    * @name 创建project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/projects/
    */
    async create() {
    const { ctx, service } = this;
    const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
    const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
    const datas = await service.openstack.identity.projects.create(this.DUFn(bodys))
    ctx.body = datas;
    }
    /**
    * @name 更新project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - DELETE /openstack/projects/{ctx.params.id}
    */
    async destroy() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.destroy(ctx.params.id);
    ctx.body = datas;
    }
    /**
    * @name 删除project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - PATCH /openstack/projects/{ctx.params.id}
    */
    async update() {
    const { ctx, service } = this;
    const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
    const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
    const datas = await service.openstack.identity.projects.update(ctx.params.id, this.DUFn(bodys))
    ctx.body = datas;
    }
    /**
    * @name 锁定不可操作项目
    *
    */
    checkID(idx) {
    const ARR = ['c3513f27bbf24362b74d13e6afae2c37', '5d3b50c18fd44db4bc6abfdbbfcf6a3a', '5c7e341df8ff493c8ae7baf57c0129dd'];
    return ARR.includes(idx);
    }
    }

    module.exports = OPIdentityProjectsController;
    region
    'use strict';

    const Controller = require('egg').Controller;

    class identityUserRegionController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.Region
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @description
    *
    * @example GET /openstack/identity/region
    *
    */
    async index() {
    const { ctx, service } = this;
    const datas = await this.MODEL.getAll(this.auth.id, ctx.isAdmin());
    ctx.body = datas;
    }
    }

    module.exports = identityUserRegionController;user
    'use strict';

    const Controller = require('egg').Controller;

    class identityUserController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.User
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @param {String} ctx.query.detail 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/user
    *
    */
    async index() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.list(ctx.query);
    };
    /**
    * @name 获取单一用户信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/user/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.show(ctx.params.id);
    // const result = await this.MODEL.getOne(this.auth.id);
    // ctx.body = result;
    };
    /**
    * @name 创建用户
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/user/
    */
    async create() {
    const ctx = this.ctx;
    const result = await this.MODEL.createUser(this.auth.id)
    ctx.body = result;
    // const { ctx, service } = this;
    // const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
    // const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
    // ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
    };
    /**
    *
    * @name 测试内部用token
    *
    */
    async testToken() {
    const { ctx, service } = this;
    ctx.body = await this.TKMODEL.getToken(this.auth.id)
    };
    }

    module.exports = identityUserController; 查看全部
    A/SK 机制
    ?
    控制器
    ?
    /*************************************************************
    *
    *- Copyright (c) qiduo, 2018
    *- FileName: AccesskeyController.js 安全认证 Accesskey接口
    *- Author: 罗波 lopo1983@vip.qq.com
    *- Version: 1.0
    *- Date:2018-10-15
    *- Descripttion:openstack geecp
    *- Modules:
    *
    *- Extends
    * - 1.egg_Controller
    *----------------------------------------------------------
    *
    *- Function List :
    *
    *- StaticsList :
    * - show 获取所有ak/sk
    * - update 创建ak/sk 修改备注
    * - destroy 删除ak/sk
    *
    *- History :
    * <Author> <Date> <Desc>
    *
    **************************************************************/
    'use strict';

    const Controller = require('egg').Controller;

    class AccesskeyController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Model} MODEL 公司表
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Account.Company;
    }
    /**
    *
    * @name 获取Accesskey列表
    *
    * @example
    * - GET /user/accesskey/_id{ObjectId} HTTP/1.1
    *
    */
    async show() {
    const ctx = this.ctx;
    const result = await this.MODEL.getASK({ '_id': ctx.params.id });
    ctx.body = result
    }
    /**
    *
    * @name 创建AK/SK|修改Info
    *
    * @param {String} info 必填 备注内容
    * @param {ObjectId} id 必填 A/SK{ObjectId}
    *
    * @example
    * - PUT /user/accesskey/user{ObjectId} HTTP/1.1 创建
    * - PUT /user/accesskey/user{ObjectId} HTTP/1.1 修改
    * body:{
    * id:ak/sk{ObjectId}
    * info:备注名称
    * }
    *
    * @description info id 为必填参数
    *
    */
    async update() {
    const ctx = this.ctx;
    if (!!ctx.request.body.info) {
    ctx.body = await this.MODEL.setInfo(ctx);
    }
    else {
    ctx.body = await this.MODEL.createASK(ctx);
    }
    }
    /**
    *
    * @name 删除AK/SK
    *
    * @param {ObjectId} id 必填 A/SK id
    *
    * @example
    * PUT /user/accesskey/id{ObjectId} HTTP/1.1
    * @description id 为必填参数
    *
    */
    async destroy() {
    const ctx = this.ctx;
    ctx.body = await this.MODEL.delASK(ctx);
    }
    /**
    *
    * @name ak/sk鉴权接口
    *
    * @param {ObjectId} uid 必填 用户uid
    * @param {String} api_key 必填 accountKey
    * @param {String} secret_key 必填 secretKey
    *
    * @example
    * POST /user/authorization HTTP/1.1
    *
    * @description uid|api_key|secret_key 必填
    *
    */
    async authorization() {
    const ctx = this.ctx;
    const { uid, api_key, secret_key } = ctx.request.body;
    ctx.body = await this.MODEL.apiToken({ uid, api_key, secret_key });
    }
    }

    module.exports = AccesskeyController;

    用户鉴权
    控制器
    'use strict';
    const Controller = require('egg').Controller;
    class ServiceJwtController extends Controller {
    constructor(ctx) {
    super(ctx);
    this.MODELComp = ctx.model.Account.Company;
    this.MODELAdmin = ctx.model.Account.Admin;
    };
    /**
    * @name 用户token生成
    *
    * @param {action:string} 'api' 用于鉴权ak/sk生成token
    * @param {String} compEmail 用户邮箱
    * @param {String} compPhone 用户手机
    * @param {String} compPassword 用户密码
    *
    * @description
    *
    * @example POST /user/sign/
    *
    * @return Object
    *{
    * "token": "",
    * "info": {
    * "_id": "5bcdd5e7f12ee030f44b6228",
    * "compPhone": "13658157663",
    * "compEmail": "64832897@qq.com",
    * "compAuth": {
    * "email": false,
    * "phone": true
    * },
    * "compService": [],
    * "updated": "2018-10-22T13:51:35.314Z",
    * "compApi": []
    * }
    * }
    *
    **/
    async sign() {
    const ctx = this.ctx;
    const {
    body,
    header
    } = ctx.request;
    try {
    if (ctx.request.url.includes('admin')) {
    ctx.body = await this.MODELAdmin.isLogin(ctx);
    } else {
    if (!['compEmail', 'compPhone'].map(e => Object.keys(body).includes(e)).reduce((a, b) => a + b)) {
    ctx.body = {
    code: 422,
    message: '用户参数错误'
    };
    return
    };
    ctx.body = await this.MODELComp.isLogin(ctx);
    }
    } catch (error) {
    console.log(error)
    if (error.message === 'jwt expired') {
    ctx.body = {
    message: '用户鉴权失败,请重新登陆',
    code: 401
    }
    } else {
    ctx.body = {
    message: !!error.errors ? `${error.errors.reduce((a, error) => { a.push(`${error.field} ${error.message}`); return a }, [])}` : error.message,
    code: 422
    }
    }
    }
    }
    }
    module.exports = ServiceJwtController
    extend 扩展
    简单用户划分
    module.exports = {
    isAdmin() {
    console.log(this.url)
    return this.state.user.group === 1 ? false : true;
    },
    };
    OpenStack 相关控制器
    project
    'use strict';

    const Controller = require('egg').Controller;

    class OPIdentityProjectsController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    }
    /**
    * @name project列表
    *
    * @param {String} ctx.query 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/projects
    *
    */
    async index() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.list(ctx.query);
    ctx.body = datas;
    }
    /**
    * @name 获取单一project信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/projects/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.show(ctx.params.id);
    ctx.body = datas;
    }
    /**
    * @name 创建project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/projects/
    */
    async create() {
    const { ctx, service } = this;
    const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
    const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
    const datas = await service.openstack.identity.projects.create(this.DUFn(bodys))
    ctx.body = datas;
    }
    /**
    * @name 更新project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - DELETE /openstack/projects/{ctx.params.id}
    */
    async destroy() {
    const { ctx, service } = this;
    const datas = await service.openstack.identity.projects.destroy(ctx.params.id);
    ctx.body = datas;
    }
    /**
    * @name 删除project
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - PATCH /openstack/projects/{ctx.params.id}
    */
    async update() {
    const { ctx, service } = this;
    const { name, is_domain, description, domain_id, enabled, parent_id, tags } = ctx.request.body;
    const bodys = { name, is_domain, description, domain_id, enabled, parent_id, tags };
    const datas = await service.openstack.identity.projects.update(ctx.params.id, this.DUFn(bodys))
    ctx.body = datas;
    }
    /**
    * @name 锁定不可操作项目
    *
    */
    checkID(idx) {
    const ARR = ['c3513f27bbf24362b74d13e6afae2c37', '5d3b50c18fd44db4bc6abfdbbfcf6a3a', '5c7e341df8ff493c8ae7baf57c0129dd'];
    return ARR.includes(idx);
    }
    }

    module.exports = OPIdentityProjectsController;
    region
    'use strict';

    const Controller = require('egg').Controller;

    class identityUserRegionController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.Region
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @description
    *
    * @example GET /openstack/identity/region
    *
    */
    async index() {
    const { ctx, service } = this;
    const datas = await this.MODEL.getAll(this.auth.id, ctx.isAdmin());
    ctx.body = datas;
    }
    }

    module.exports = identityUserRegionController;
    user
    'use strict';

    const Controller = require('egg').Controller;

    class identityUserController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.User
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @param {String} ctx.query.detail 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/user
    *
    */
    async index() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.list(ctx.query);
    };
    /**
    * @name 获取单一用户信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/user/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.show(ctx.params.id);
    // const result = await this.MODEL.getOne(this.auth.id);
    // ctx.body = result;
    };
    /**
    * @name 创建用户
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/user/
    */
    async create() {
    const ctx = this.ctx;
    const result = await this.MODEL.createUser(this.auth.id)
    ctx.body = result;
    // const { ctx, service } = this;
    // const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
    // const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
    // ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
    };
    /**
    *
    * @name 测试内部用token
    *
    */
    async testToken() {
    const { ctx, service } = this;
    ctx.body = await this.TKMODEL.getToken(this.auth.id)
    };
    }

    module.exports = identityUserController;

    egg.js+mongodb+openstack 公有云计费系统(二)用户系统的搭建

    Nodejslopo1983 发表了文章 • 0 个评论 • 1204 次浏览 • 2019-03-14 00:13 • 来自相关话题

    鉴于Openstack的特殊性 和项目需求,用户系统将分为 系统用户 管理员用户 openstack用户 大致3类
    一 系统用户
    表设计const crypto = require('crypto');
    const Decimal = require('decimal');

    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const ctx = app.createAnonymousContext();
    const {
    NumToStr
    } = ctx.helper;
    const CompanySchema = new Schema({
    // 公司名称
    compName: {
    type: String,
    index: true
    },
    // 认证类型 [0/未认证,1/个人,2/企业]
    compAuthType: {
    type: Number,
    default: 0,
    get: v => NumToStr(['未认证', '个人', '企业'], v, true),
    },
    // 认证状态 [0/'未认证', 1/'已上传', 2/'认证中',3/ '认证未通过', 4/'已认证']
    compAuthStatus: {
    type: Number,
    default: 0,
    get: v => NumToStr(['未认证', '已上传', '认证中', '认证未通过', '已认证'], v, true),
    },
    // 认证证件信息相关
    compLicense: {
    type: Schema.Types.ObjectId,
    ref: 'CompLicense',
    },
    // 关联绑定
    compAuth: {
    // 邮件绑定
    email: {
    type: Boolean,
    default: false
    },
    // 手机绑定
    phone: {
    type: Boolean,
    default: true
    }
    },
    // 企业邮箱
    compEmail: {
    type: String,
    required: [true, '企业邮箱不允许为空'],
    unique: true,
    },
    compName: {
    type: String,
    },
    // 企业联系电话
    compPhone: {
    type: String,
    required: [true, '联系电话不允许为空'],
    unique: true,
    },
    // 登陆密码
    compPassword: {
    type: String,
    required: [true, '密码不能为空'],
    minlength: [8, '密码应大于8位数'],
    set: v => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    }
    },
    // 企业服务
    compService: ,
    // 企业产品
    compProduct: ,
    // 企业api 需求
    compApi: [{
    name: {
    type: String,
    },
    IPWhiteList: [String]
    }],
    // 用户ak sk
    compASK: ,
    // 用户账户余额
    compAccount: {
    // 现金账户
    cash: {
    type: Number,
    default: 0.00,
    },
    // 代理账户
    agent: {
    type: Number,
    default: 0.00
    },
    // 代金券账户
    other: {
    type: Number,
    default: 0.00
    }
    },
    // 余额预警
    compAccountWarnig: {
    type: Number,
    default: 0
    },
    // 客户编号
    compNumer: {
    type: String
    },
    // 公司客服经理
    compMaster: {
    type: String
    },
    // 用户代理等级 [1-5]
    compAgent: {
    type: Number,
    default: 1,
    get: v => NumToStr(['普通', '铜牌', '银牌', '金牌', '白金', '钻石'], v),
    },
    // 公司客户
    compCustomer: [{
    type: Schema.Types.ObjectId,
    ref: 'Company',
    }],
    // 用户优惠券
    compCoupon: {
    type: Array
    },
    // 购物车ID
    shoppingCart: {
    type: Schema.Types.ObjectId,
    ref: 'ShopCar',
    },
    // 签名系统状态 ['删除','正常','锁定'] 0,1,2
    status: {
    type: Number,
    default: 1,
    // get: v => NumToStr(['删除', '正常', '锁定'], v, true),
    },
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    const isAdmin = (auth) => auth.group === 1 ? 0 : 1;
    CompanySchema.statics = {
    getAll: async function(queryMix) {
    const {
    querys,
    select,
    pages,
    sort,
    dates
    } = queryMix;
    const models = this.find({
    'status': {
    '$ne': 0
    },
    ...querys,
    ...(!!pages && !!pages.marker && {
    '_id': {
    "$lt": pages.marker
    }
    }),
    }, {
    ...select,
    'compPassword': 0,
    'compASK': 0
    })
    .limit(!!pages ? pages.limit : 10)
    .sort({
    '_id': -1,
    ...sort
    });
    return {
    data: {
    result: await models,
    totalCount: await models.count()
    }
    };
    },
    getOne: async function(_id) {
    const models = this.findOne({
    _id,
    'status': {
    '$ne': 0
    }
    }, {
    'compPassword': 0,
    'compASK': 0
    });
    return {
    data: await models
    }
    },
    /**
    * 账户余额操作
    * @param {Number} money 金额
    * @param {Object} auth admin鉴权
    * @param {String} type 余额类型
    * @param {String} method 类型 add + sub-
    * @param {ObjectId} _id 公司id
    */
    cashFN: async function(money, auth, type = 'cash', method = 'add', _id) {
    try {
    const {
    compAccount,
    compName
    } = await this.findOne({
    '_id': _id ? _id : auth.id
    });
    const nowCash = new Decimal(compAccount[type])[method](new Decimal(money)).toNumber();
    let result;
    if (type = 'cash') {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.cash': nowCash
    });
    } else if (type = 'agent') {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.agent': nowCash
    });
    } else {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.other': nowCash
    });
    };
    if (auth.group === 1) await this.cashWarning(ctx, _id);
    return result.ok === 1 ? `${compName}${method === 'add' ? `充值¥:${money}元成功!` : '购买成功'}` : `${compName}充值失败`;
    } catch (error) {
    return error
    }
    },
    // 余额预警
    cashWarning: async function (ctx, _id) {
    const {
    compAccount,
    compAccountWarnig,
    compName
    } = await this.findOne({
    _id
    });
    const cashCount = Object.values(compAccount).reduce((a, b) => a + b);
    if (compAccountWarnig >= cashCount) return await ctx.helper.sendWarning(ctx, `您的现金账户余额不足¥:${compAccountWarnig},为了保证您业务的正常运行,请及时充值!`, _id, compName);
    },
    // 登陆获取token
    isLogin: async function (ctx) {
    return await ctx.service.mongo.adcq.isLogin(ctx, 'Company', 'compPassword', async (e) => {
    let {
    _id,
    compPhone,
    compEmail,
    compName,
    compAuth,
    compService,
    updated,
    compApi
    } = e;
    const ProjectID = (await ctx.model.Openstack.Identity.User.getObjectID(_id)).default_project_id;
    try {
    const TOKEN = await ctx.service.apps.jwt.sign({
    id: _id,
    group: 1,
    phone: compPhone,
    compApi,
    ProjectID
    });
    // await ctx.model.Token.addOne({ authToken: TOKEN, updateTime: new Date() });
    return {
    token: TOKEN,
    info: {
    _id,
    compPhone,
    compEmail,
    compName,
    compAuth,
    compService,
    updated,
    compApi
    }
    }
    } catch (error) {
    return error
    }
    })
    },
    // ak/sk生成token
    apiToken: async function (body) {
    const {
    uid,
    api_key,
    secret_key
    } = body;
    const userInfo = await this.findOne({
    _id: uid
    }, {
    'compASK': 1,
    'compApi': 1,
    });
    const isHave = userInfo.compASK.filter(e => e.ak == api_key && e.sk == secret_key).length;
    if (isHave === 1) {
    let {
    _id,
    compApi
    } = userInfo;
    return {
    data: {
    token: await ctx.service.apps.jwt.sign({
    id: _id,
    group: 3,
    service: compApi,
    }),
    expiresIn: 60 * 60 * 24 * 30 * 1000
    }
    }
    } else {
    return {
    code: 422,
    message: '参数不正确'
    }
    }
    },
    // 获取ask 列表
    getASK: async function (_id) {
    try {
    const result = await this.findOne(_id);
    return {
    data: result.compASK
    }
    } catch (error) {}
    },
    // 创建ask
    createASK: async function (ctx) {
    if ((await this.getASK({
    '_id': ctx.state.user.id
    })).data.length === 20) return {
    message: '每一用户只允许创建20个ak/sk序列对!',
    code: 422
    };
    const asks = {
    _id: mongoose.Types.ObjectId(),
    info: '',
    ak: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 5)}`).digest('hex'),
    sk: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 8)}`).digest('hex'),
    createTime: new Date()
    };
    return {
    data: (await this.findOneAndUpdate({
    '_id': ctx.state.user.id
    }, {
    $push: {
    'compASK': asks
    }
    })).compASK.pop()
    }
    },
    // 设置ask 名称
    setInfo: async function (ctx) {
    const {
    info
    } = ctx.request.body;
    const result = await this.update({
    '_id': ctx.params.id,
    'compASK._id': mongoose.Types.ObjectId(ctx.request.body.id)
    }, {
    '$set': {
    'compASK.$.info': info
    }
    });
    return result.n === 1 && {
    data: {
    _id: ctx.params.id,
    info: info
    }
    }
    },
    // 删除ak
    delASK: async function name(ctx) {
    const result = await this.update({
    '_id': ctx.state.user.id
    }, {
    "$pull": {
    'compASK': {
    '_id': mongoose.Types.ObjectId(ctx.params.id)
    }
    }
    });
    return result.n === 1 && {
    data: ctx.params.id
    };
    },
    // 锁定公司
    lockfn: async function (ctx, type) {
    return {
    data: await this.findOneAndUpdate({
    '_id': ctx.params.id
    }, {
    $set: {
    'status': 2
    }
    })
    }
    },
    // 是否已存在
    isIn: async function (params) {
    return await this.findOne({ ...params
    })
    },
    // 获取公司详细
    getComp: async function (auth) {
    return (await this.findOne({ ...(!isAdmin(auth) && {
    '_id': auth.id
    })
    }))
    },
    // 获取现金
    getCash: async function (auth) {
    return (await this.getComp(auth)).compAccount
    },
    // 获取优惠券
    getCoupon: async function (auth) {
    const coupon = (await this.getComp(auth)).compCoupon;
    return {
    coupon: coupon,
    length: coupon.length
    }
    },
    // 获取服务
    getService: async function (auth) {
    return (await this.getComp(auth)).compService
    },
    // 获取客户列表
    getCustomerList: async function (auth) {
    const List = (await this.findOne({
    '_id': auth.id
    })).compCustomer;
    const result = await this.find({
    _id: {
    $in: List
    }
    }, 'compName compEmail compPhone created');
    return result;
    },
    // 绑定邮箱
    bindMail: async function (auth) {
    const result = await this.update({
    '_id': auth.id
    }, {
    'compAuth.emailAuth': true
    }, {
    upsert: true
    });
    return result.ok === 1 && true;
    },
    // 登陆注册找回密码 pipe
    lrfAction: async function (body) {
    const {
    action,
    compPhone: SmsPhone,
    code: SmsCode
    } = body;
    delete body.action
    if (action === 'changePsd') {
    const isInUsers = await this.isIn({
    'compPhone': body.compPhone
    });
    if (!isInUsers) return {
    message: '对不起您还不是我们的客户,请先注册!'
    };
    }
    const checkCode = await ctx.model.SmsCode.check({
    SmsPhone,
    SmsCode
    });
    delete body.code
    if (checkCode !== true) return checkCode;
    return this[action](body);
    },
    // 注册
    regist: async function (body) {
    const {
    compEmail
    } = body;
    try {
    const result = await this.create(body);
    if (result._id) {
    await ctx.service.sms.mail.sendMail({
    to: compEmail,
    html: 'regist',
    });
    await ctx.model.System.Ui.User.create({
    '_comp': result._id
    });
    const datas = await ctx.model.Openstack.Identity.User.createUser(result._id);
    return {
    code: 201,
    data: {
    name: result._id,
    }
    }
    };
    } catch (error) {
    return error
    }
    },
    // 修改密码
    changePsd: async function (body) {
    const {
    compPhone,
    compPassword
    } = body;
    return await this.findOneAndUpdate({
    'compPhone': compPhone
    }, {
    'compPassword': compPassword
    })
    },
    // 绑定客户
    bindCustomer: async function (_id, auth) {
    return await this.findOneAndUpdate({
    _id
    }, {
    $push: {
    'compCustomer': auth.id
    }
    })
    },
    }
    return mongoose.model('Company', CompanySchema);
    }控制器/*************************************************************
    *
    *- Copyright (c) qiduo, 2018
    *- FileName: USERController.js 用户基本信息相关
    *- Author: 罗波 lopo1983@vip.qq.com
    *- Version: 1.0
    *- Date:2018-10-15
    *- Descripttion:openstack geecp
    *- Modules:
    *
    *- Extends
    * - 1.egg_Controller
    *----------------------------------------------------------
    *
    *- Function List :
    *
    *- StaticsList :
    * - index 获取用户列表
    * - isHave 检测用户是否存在
    * - show 获取单一用户信息
    * - create 用户注册
    *
    *- History :
    * <Author> <Date> <Desc>
    *
    **************************************************************/
    'use strict';

    const Controller = require('egg').Controller;

    class USERController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Model} MODEL 公司表
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Account.Company;
    }
    /**
    *
    * @name 获取用户列表
    *
    * @description Admin 用户可用 可使用queryParamFn 进行查询
    *
    * @example GET /user/
    *
    */
    async index() {
    const ctx = this.ctx;
    const { helper } = ctx;
    const result = await this.MODEL.getAll(helper.queryParamFn(ctx.query));
    ctx.body = result
    }
    /**
    *
    * @name 检测用户是否存在
    *
    * @param {String} compName 用户名称
    * @param {String} compEmail 用户邮箱
    * @param {String} compPhone 用户手机
    *
    * @description compName, compEmail, compPhone 三选一 或可多选
    *
    * @example GET /user/isIn/?@param = param
    *
    */
    async isHave() {
    const ctx = this.ctx;
    const { compName, compEmail, compPhone } = ctx.query;
    const result = (await this.MODEL.isIn(this.DUFn({ compName, compEmail, compPhone }))) === null;
    ctx.body = { data: `${!result}` }
    }
    /**
    *
    * @name 获取用户信息
    * @param {ObjectId} id 必传 ctx.params.id 用户id
    *
    * @example GET /user/{id}
    */
    async show() {
    const ctx = this.ctx;
    const result = await this.MODEL.getOne({ '_id': ctx.params.id });
    ctx.body = result
    }
    /**
    *
    * @name 用户注册 body = ctx.request.body
    * @param {String} action 必传 动作 regist changePsd
    * @param {String} compEmail 必传 邮箱
    * @param {String} compPhone 必传 手机号码
    * @param {String} compPassword 必传 用户密码 `${SALT}${MD5}`
    * @param {String} code 必传 手机验证码,120s次 mongodb.smscodes expiresIn_TTL_60*3
    *
    * @example POST /user/
    *
    * @description
    * - 邮箱和手机均能登陆
    * - compEmail, compPhone, compPassword, action, code 均为必选参数
    *
    */
    async create() {
    const { ctx } = this;
    const { compEmail, compPhone, compPassword, action, code } = ctx.request.body;
    const result = await this.MODEL.lrfAction({ compEmail, compPhone, compPassword, action, code });
    ctx.body = result
    }
    /**
    * @name 修改用户信息
    *
    * @param {String} action 必传 修改的方法
    * @param {action}
    * - changePsd 修改密码
    * - bindCustomer 绑定客户
    * - lrfAction 找回密码
    * -
    *
    * @example PUT /user/{ObjecId}
    */
    async update() {
    const { ctx } = this;
    const bodys = ctx.request.body;
    const { action } = bodys;
    delete bodys.action;
    const result = await this.MODEL[action](bodys)
    }
    }

    module.exports = USERController;

    二 管理员用户
    表设计const crypto = require('crypto');
    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const AdminSchema = new Schema({
    // 用户名
    adminName: {
    type: String,
    required: true,
    unique: [true, '用户名已存在']
    },
    // 用户密码
    adminPassword: {
    type: String,
    required: true,
    set: v => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    }
    },
    // 用户权限组
    adminGroup: {
    type: Number,
    required: true,
    default: 2
    },
    // 用户真实姓名
    adminRealName: {
    type: String
    },
    // 用户头像
    adminHeader: {
    type: String,
    default: ''
    },
    adminStaff: {
    // type: Schema.Types.ObjectId,
    // ref: 'Staff',
    },
    status: {
    type: Number,
    default: 1
    },
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    AdminSchema.statics = {
    isLogin: async function (ctx) {
    return await ctx.service.mongo.adcq.isLogin(ctx, 'Admin', 'adminPassword', async (e) => {
    let { _id, adminRealName, adminName, adminGroup, adminHeader, adminStaff } = e;
    return {
    token: await ctx.service.apps.jwt.sign({ id: _id, group: adminGroup }),
    info: { _id, adminRealName, adminName, adminHeader, adminStaff }
    }
    })
    }
    }
    return mongoose.model('Admin', AdminSchema)
    }OpenStack 用户
    表设计const crypto = require('crypto');
    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const { ctx, helper, service } = app.createAnonymousContext();
    const OSIdentityUserSchema = new Schema({
    // The user ID.
    id: String,
    // The ID of the default project for the user.
    default_project_id: String,
    // user description
    description: String,
    // The ID of the domain.
    domain_id: String,
    // user emaill address
    email: String,
    // If the user is enabled, this value is true. If the user is disabled, this value is false.
    enabled: Boolean,
    // The links for the user resource.
    links: {},
    // user name
    name: String,
    // 密码
    password: String,
    // 角色ID
    role: String,
    // 同步状态
    sync: Boolean
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    OSIdentityUserSchema.statics = {
    createUser: async function(_id) {
    const setPSDFn = (v = _id) => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    };
    const password = setPSDFn();
    try {
    /****************************创建Project*********************************/
    const PROJECT = await service.openstack.identity.projects.create({
    name: _id,
    'description': `comp_id:${_id} date:${new Date() -0 }`
    });
    const default_project_id = PROJECT.data.project.id;
    // || PROJECT.data.error.code === 409
    if (PROJECT.data.project) {
    const DATAS = await service.openstack.identity.users.create({
    'name': _id,
    password,
    default_project_id,
    'description': `comp_id:${_id} date:${new Date()-0 }`
    });
    /******************************本地创建*******************************/
    const result = await this.create({
    ...DATAS.data.user,
    password,
    default_project_id,
    sync: true
    });
    /******************************分配角色*******************************/
    if (!result.id) return;
    await service.openstack.identity.roles.update(result.default_project_id, result.id, app.config.openstack.rolesID.default);
    return result
    }
    } catch (error) {
    return error
    }
    },
    /**
    * @name 获取一个
    * @param {*} _id compid
    * @param {*} select 选择的字段(BSON name/显示的名称 -name/不显示的名称)
    */
    getOne: async function(_id, select) {
    const MODEL = this.findOne({ name: _id }, !!select && select);
    try {
    const result = await MODEL;
    return !!result ? result : await this.createUser(_id);
    } catch (error) {
    return error
    }
    },
    // 获取ObjectID
    getObjectID: async function(_id) {
    const MODEL = this.findOne({ 'name': _id }, 'default_project_id -_id')
    try {
    return await MODEL
    } catch (error) {
    return error
    }
    }
    }
    return mongoose.model('openstack_Identity_user', OSIdentityUserSchema)
    }service?
    role'use strict';
    const ServerIndex = require('../index')
    //
    class identityRolesService extends ServerIndex {
    constructor(ctx) {
    super(ctx);
    this.actions = ':5000/identity/v3/'
    };
    // 获取Region列表
    async list(parent_region_id) {
    try {
    const datas = await this.OSAJax(`${this.actions}`, { body: { parent_region_id } })
    return {
    data: {
    result: datas.regions,
    totalCount: datas.regions.length
    }
    };
    } catch (error) {
    return {
    data: error
    }
    }

    }
    // 显示regions详情
    async show(project_id, user_id) {
    let datas
    try {
    datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles`)
    } catch (error) {
    datas = error
    }
    return datas
    }
    // 创建regions
    async create(bodys) {
    }
    // 给用户赋予角色
    async update(project_id, user_id, role_id) {
    let datas;
    try {
    datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles/${role_id}`, { method: 'PUT' });
    } catch (error) {
    datas = error
    }
    return { data: datas }
    }
    // 删除regions
    async destroy(id) {
    }
    }
    module.exports = identityRolesService;project'use strict';
    const ServerIndex = require('../index')
    //
    class identityProjectService extends ServerIndex {
    constructor(ctx) {
    super(ctx);
    this.actions = ':5000/identity/v3/projects'
    };
    // 获取Projects列表
    async list() {
    const datas = await this.OSAJax(`${this.actions}`);
    return {
    data: {
    'result': datas.projects,
    'totalCount': datas.projects.length
    }
    };
    }
    // 显示Projects详情
    async show(id) {
    const datas = await this.OSAJax(`${this.actions}/${id}`);
    return { data: datas };
    }
    // 创建Projects
    async create(bodys) {
    const datas = await this.OSAJax(this.actions, { body: { 'project': bodys }, method: 'POST' });
    return { data: datas }
    }
    // 修改Projects
    async update(id, bodys) {
    const datas = await this.OSAJax(`${this.actions}/${id}`, { body: { 'project': bodys }, method: 'PATCH' });
    return { data: datas }
    }
    // 删除Projects
    async destroy(id) {
    const datas = await this.OSAJax(`${this.actions}/${id}`, { method: 'DELETE' });
    return { data: datas }
    }
    }
    module.exports = identityProjectService;控制器'use strict';

    const Controller = require('egg').Controller;

    class identityUserController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.User
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @param {String} ctx.query.detail 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/user
    *
    */
    async index() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.list(ctx.query);
    };
    /**
    * @name 获取单一用户信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/user/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.show(ctx.params.id);
    // const result = await this.MODEL.getOne(this.auth.id);
    // ctx.body = result;
    };
    /**
    * @name 创建用户
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/user/
    */
    async create() {
    const ctx = this.ctx;
    const result = await this.MODEL.createUser(this.auth.id)
    ctx.body = result;
    // const { ctx, service } = this;
    // const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
    // const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
    // ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
    };
    /**
    *
    * @name 测试内部用token
    *
    */
    async testToken() {
    const { ctx, service } = this;
    ctx.body = await this.TKMODEL.getToken(this.auth.id)
    };
    }

    module.exports = identityUserController;共用service
    'use strict';
    const Service = require('egg').Service;
    //
    class indexService extends Service {
    constructor(ctx) {
    super(ctx);
    this.OPTokenMODEL = ctx.model.Openstack.Token;
    this.OPUserMODEL = ctx.model.Openstack.Identity.User;
    this.OBJKeySort = ctx.helper.OBJKeySort;
    const {
    uri
    } = this.config.openstack;
    this.uri = `${uri}`;
    this.CurlOpt = async(method, full, token) => {
    return {
    'dataType': 'json',
    'headers': {
    ...((!full && !token) && {
    'X-Auth-Token': (await ctx.helper.TokenFn('openstack')).data
    }) || !!token && {
    'X-Auth-Token': token
    },
    'Content-Type': 'application/json',
    },
    'method': method,
    ...method !== 'DELETE' && {
    'data': {}
    },
    'timeout': 60000
    }
    }
    };
    /**
    * 基础库
    *
    * @param {Object} body 需要提交的参数
    * @param {String} method GET POST DELETE PUT PATCH
    * @param {String} params url 参数
    * @param {Boolean} full 是否显示完整参数
    * @param {String} _ucid 用户ID Optional
    */
    async OSAJax(params, {
    body = {},
    method = "GET",
    full = false,
    status = false,
    _ucid
    } = {}) {
    const ctx = this.ctx;
    const opt = await this.CurlOpt(method, full, !!_ucid ? await this.getUserToken(_ucid) : false);
    method !== 'DELETE' && Object.assign(opt.data, {...!!body ? body : ''
    });
    // console.log(opt)
    // console.log({
    // // 'getFullRES': full,
    // // 'isAdmin': !!_ucid ? `No | _ucid:${_ucid}` : 'Yes',
    // 'URI': `http://${this.uri}${!!params ? params : ''}`,
    // // 'Method': method,
    // // ...method !== 'DELETE' && {
    // // 'Body': opt.data
    // // },
    // // '_': new Date()
    // })
    try {
    const result = await ctx.curl(`${this.uri}${!!params ? params : ''}`, opt);
    return !!full && result || !!status && result.status || result.data;
    } catch (error) {
    return error
    }
    };
    // 获取普通用户token
    async getUserToken(_id) {
    const ctx = this.ctx;
    return (await ctx.model.Openstack.Token.getToken(_id)).data
    };
    // 获取普通用户projectID
    async getProject(_id) {
    const ctx = this.ctx;
    return _id !== 'admin' ? (await this.OPUserMODEL.getOne(_id, 'default_project_id'))['default_project_id'] : this.config.openstack.projectID.default
    };
    // 从支付订单创建相关实例
    /**
    *
    * @param {*} _comp 公司id
    * @param {*} model 数据库
    * @param {*} bodys 内容
    * +@param {String} _metadata 关联数据
    * @param {*} time 开通时长
    */
    async createFromOrder(_comp, model, bodys, time, payment) {
    try {
    const ctx = this.ctx;
    const MODELS = ctx.model.Openstack;
    const {
    deleteUndefined: DUFn,
    subtractMoment: TMFn
    } = ctx.helper
    let datas = {}
    if (model === 'cds') {
    const {
    availability_zone,
    snapshot_id,
    backup_id,
    imageRef,
    size,
    volume_type,
    _metadata
    } = bodys;
    const BODYS = DUFn({
    availability_zone,
    snapshot_id,
    backup_id,
    imageRef,
    size,
    volume_type,
    _metadata
    });
    datas = await MODELS.BlcokStorage.Volumes.createOne(
    _comp, {
    ...BODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment
    }
    );
    }
    if (model === 'ecs') {
    const {
    availability_zone,
    flavorRef,
    name,
    uuid,
    imageRef,
    server_password,
    key_name,
    security_groups,
    _metadata
    } = bodys;
    const SERVERBODYS = DUFn({
    availability_zone,
    flavorRef,
    name,
    uuid,
    imageRef,
    server_password,
    key_name,
    security_groups,
    _metadata
    });
    datas = await MODELS.Servers.Server.createServer(
    _comp, {
    ...SERVERBODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment,
    }
    );
    }
    if (model === 'eip') {
    const {
    description,
    _metadata
    } = bodys;
    const EIPBODYS = DUFn({
    description,
    _metadata
    });
    datas = await MODELS.Neutron.FloatingIP.createOne(
    _comp, {
    ...EIPBODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment
    })
    }
    return datas
    } catch (error) {
    console.log(error)
    }
    }
    }
    module.exports = indexService; 查看全部

    鉴于Openstack的特殊性 和项目需求,用户系统将分为 系统用户 管理员用户 openstack用户 大致3类


    一 系统用户
    表设计
    const crypto = require('crypto');
    const Decimal = require('decimal');

    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const ctx = app.createAnonymousContext();
    const {
    NumToStr
    } = ctx.helper;
    const CompanySchema = new Schema({
    // 公司名称
    compName: {
    type: String,
    index: true
    },
    // 认证类型 [0/未认证,1/个人,2/企业]
    compAuthType: {
    type: Number,
    default: 0,
    get: v => NumToStr(['未认证', '个人', '企业'], v, true),
    },
    // 认证状态 [0/'未认证', 1/'已上传', 2/'认证中',3/ '认证未通过', 4/'已认证']
    compAuthStatus: {
    type: Number,
    default: 0,
    get: v => NumToStr(['未认证', '已上传', '认证中', '认证未通过', '已认证'], v, true),
    },
    // 认证证件信息相关
    compLicense: {
    type: Schema.Types.ObjectId,
    ref: 'CompLicense',
    },
    // 关联绑定
    compAuth: {
    // 邮件绑定
    email: {
    type: Boolean,
    default: false
    },
    // 手机绑定
    phone: {
    type: Boolean,
    default: true
    }
    },
    // 企业邮箱
    compEmail: {
    type: String,
    required: [true, '企业邮箱不允许为空'],
    unique: true,
    },
    compName: {
    type: String,
    },
    // 企业联系电话
    compPhone: {
    type: String,
    required: [true, '联系电话不允许为空'],
    unique: true,
    },
    // 登陆密码
    compPassword: {
    type: String,
    required: [true, '密码不能为空'],
    minlength: [8, '密码应大于8位数'],
    set: v => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    }
    },
    // 企业服务
    compService: ,
    // 企业产品
    compProduct: ,
    // 企业api 需求
    compApi: [{
    name: {
    type: String,
    },
    IPWhiteList: [String]
    }],
    // 用户ak sk
    compASK: ,
    // 用户账户余额
    compAccount: {
    // 现金账户
    cash: {
    type: Number,
    default: 0.00,
    },
    // 代理账户
    agent: {
    type: Number,
    default: 0.00
    },
    // 代金券账户
    other: {
    type: Number,
    default: 0.00
    }
    },
    // 余额预警
    compAccountWarnig: {
    type: Number,
    default: 0
    },
    // 客户编号
    compNumer: {
    type: String
    },
    // 公司客服经理
    compMaster: {
    type: String
    },
    // 用户代理等级 [1-5]
    compAgent: {
    type: Number,
    default: 1,
    get: v => NumToStr(['普通', '铜牌', '银牌', '金牌', '白金', '钻石'], v),
    },
    // 公司客户
    compCustomer: [{
    type: Schema.Types.ObjectId,
    ref: 'Company',
    }],
    // 用户优惠券
    compCoupon: {
    type: Array
    },
    // 购物车ID
    shoppingCart: {
    type: Schema.Types.ObjectId,
    ref: 'ShopCar',
    },
    // 签名系统状态 ['删除','正常','锁定'] 0,1,2
    status: {
    type: Number,
    default: 1,
    // get: v => NumToStr(['删除', '正常', '锁定'], v, true),
    },
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    const isAdmin = (auth) => auth.group === 1 ? 0 : 1;
    CompanySchema.statics = {
    getAll: async function(queryMix) {
    const {
    querys,
    select,
    pages,
    sort,
    dates
    } = queryMix;
    const models = this.find({
    'status': {
    '$ne': 0
    },
    ...querys,
    ...(!!pages && !!pages.marker && {
    '_id': {
    "$lt": pages.marker
    }
    }),
    }, {
    ...select,
    'compPassword': 0,
    'compASK': 0
    })
    .limit(!!pages ? pages.limit : 10)
    .sort({
    '_id': -1,
    ...sort
    });
    return {
    data: {
    result: await models,
    totalCount: await models.count()
    }
    };
    },
    getOne: async function(_id) {
    const models = this.findOne({
    _id,
    'status': {
    '$ne': 0
    }
    }, {
    'compPassword': 0,
    'compASK': 0
    });
    return {
    data: await models
    }
    },
    /**
    * 账户余额操作
    * @param {Number} money 金额
    * @param {Object} auth admin鉴权
    * @param {String} type 余额类型
    * @param {String} method 类型 add + sub-
    * @param {ObjectId} _id 公司id
    */
    cashFN: async function(money, auth, type = 'cash', method = 'add', _id) {
    try {
    const {
    compAccount,
    compName
    } = await this.findOne({
    '_id': _id ? _id : auth.id
    });
    const nowCash = new Decimal(compAccount[type])[method](new Decimal(money)).toNumber();
    let result;
    if (type = 'cash') {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.cash': nowCash
    });
    } else if (type = 'agent') {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.agent': nowCash
    });
    } else {
    result = await this.update({
    '_id': _id ? _id : auth.id
    }, {
    'compAccount.other': nowCash
    });
    };
    if (auth.group === 1) await this.cashWarning(ctx, _id);
    return result.ok === 1 ? `${compName}${method === 'add' ? `充值¥:${money}元成功!` : '购买成功'}` : `${compName}充值失败`;
    } catch (error) {
    return error
    }
    },
    // 余额预警
    cashWarning: async function (ctx, _id) {
    const {
    compAccount,
    compAccountWarnig,
    compName
    } = await this.findOne({
    _id
    });
    const cashCount = Object.values(compAccount).reduce((a, b) => a + b);
    if (compAccountWarnig >= cashCount) return await ctx.helper.sendWarning(ctx, `您的现金账户余额不足¥:${compAccountWarnig},为了保证您业务的正常运行,请及时充值!`, _id, compName);
    },
    // 登陆获取token
    isLogin: async function (ctx) {
    return await ctx.service.mongo.adcq.isLogin(ctx, 'Company', 'compPassword', async (e) => {
    let {
    _id,
    compPhone,
    compEmail,
    compName,
    compAuth,
    compService,
    updated,
    compApi
    } = e;
    const ProjectID = (await ctx.model.Openstack.Identity.User.getObjectID(_id)).default_project_id;
    try {
    const TOKEN = await ctx.service.apps.jwt.sign({
    id: _id,
    group: 1,
    phone: compPhone,
    compApi,
    ProjectID
    });
    // await ctx.model.Token.addOne({ authToken: TOKEN, updateTime: new Date() });
    return {
    token: TOKEN,
    info: {
    _id,
    compPhone,
    compEmail,
    compName,
    compAuth,
    compService,
    updated,
    compApi
    }
    }
    } catch (error) {
    return error
    }
    })
    },
    // ak/sk生成token
    apiToken: async function (body) {
    const {
    uid,
    api_key,
    secret_key
    } = body;
    const userInfo = await this.findOne({
    _id: uid
    }, {
    'compASK': 1,
    'compApi': 1,
    });
    const isHave = userInfo.compASK.filter(e => e.ak == api_key && e.sk == secret_key).length;
    if (isHave === 1) {
    let {
    _id,
    compApi
    } = userInfo;
    return {
    data: {
    token: await ctx.service.apps.jwt.sign({
    id: _id,
    group: 3,
    service: compApi,
    }),
    expiresIn: 60 * 60 * 24 * 30 * 1000
    }
    }
    } else {
    return {
    code: 422,
    message: '参数不正确'
    }
    }
    },
    // 获取ask 列表
    getASK: async function (_id) {
    try {
    const result = await this.findOne(_id);
    return {
    data: result.compASK
    }
    } catch (error) {}
    },
    // 创建ask
    createASK: async function (ctx) {
    if ((await this.getASK({
    '_id': ctx.state.user.id
    })).data.length === 20) return {
    message: '每一用户只允许创建20个ak/sk序列对!',
    code: 422
    };
    const asks = {
    _id: mongoose.Types.ObjectId(),
    info: '',
    ak: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 5)}`).digest('hex'),
    sk: crypto.createHash('md5').update(`${Math.random().toString(36).slice(2, 8)}`).digest('hex'),
    createTime: new Date()
    };
    return {
    data: (await this.findOneAndUpdate({
    '_id': ctx.state.user.id
    }, {
    $push: {
    'compASK': asks
    }
    })).compASK.pop()
    }
    },
    // 设置ask 名称
    setInfo: async function (ctx) {
    const {
    info
    } = ctx.request.body;
    const result = await this.update({
    '_id': ctx.params.id,
    'compASK._id': mongoose.Types.ObjectId(ctx.request.body.id)
    }, {
    '$set': {
    'compASK.$.info': info
    }
    });
    return result.n === 1 && {
    data: {
    _id: ctx.params.id,
    info: info
    }
    }
    },
    // 删除ak
    delASK: async function name(ctx) {
    const result = await this.update({
    '_id': ctx.state.user.id
    }, {
    "$pull": {
    'compASK': {
    '_id': mongoose.Types.ObjectId(ctx.params.id)
    }
    }
    });
    return result.n === 1 && {
    data: ctx.params.id
    };
    },
    // 锁定公司
    lockfn: async function (ctx, type) {
    return {
    data: await this.findOneAndUpdate({
    '_id': ctx.params.id
    }, {
    $set: {
    'status': 2
    }
    })
    }
    },
    // 是否已存在
    isIn: async function (params) {
    return await this.findOne({ ...params
    })
    },
    // 获取公司详细
    getComp: async function (auth) {
    return (await this.findOne({ ...(!isAdmin(auth) && {
    '_id': auth.id
    })
    }))
    },
    // 获取现金
    getCash: async function (auth) {
    return (await this.getComp(auth)).compAccount
    },
    // 获取优惠券
    getCoupon: async function (auth) {
    const coupon = (await this.getComp(auth)).compCoupon;
    return {
    coupon: coupon,
    length: coupon.length
    }
    },
    // 获取服务
    getService: async function (auth) {
    return (await this.getComp(auth)).compService
    },
    // 获取客户列表
    getCustomerList: async function (auth) {
    const List = (await this.findOne({
    '_id': auth.id
    })).compCustomer;
    const result = await this.find({
    _id: {
    $in: List
    }
    }, 'compName compEmail compPhone created');
    return result;
    },
    // 绑定邮箱
    bindMail: async function (auth) {
    const result = await this.update({
    '_id': auth.id
    }, {
    'compAuth.emailAuth': true
    }, {
    upsert: true
    });
    return result.ok === 1 && true;
    },
    // 登陆注册找回密码 pipe
    lrfAction: async function (body) {
    const {
    action,
    compPhone: SmsPhone,
    code: SmsCode
    } = body;
    delete body.action
    if (action === 'changePsd') {
    const isInUsers = await this.isIn({
    'compPhone': body.compPhone
    });
    if (!isInUsers) return {
    message: '对不起您还不是我们的客户,请先注册!'
    };
    }
    const checkCode = await ctx.model.SmsCode.check({
    SmsPhone,
    SmsCode
    });
    delete body.code
    if (checkCode !== true) return checkCode;
    return this[action](body);
    },
    // 注册
    regist: async function (body) {
    const {
    compEmail
    } = body;
    try {
    const result = await this.create(body);
    if (result._id) {
    await ctx.service.sms.mail.sendMail({
    to: compEmail,
    html: 'regist',
    });
    await ctx.model.System.Ui.User.create({
    '_comp': result._id
    });
    const datas = await ctx.model.Openstack.Identity.User.createUser(result._id);
    return {
    code: 201,
    data: {
    name: result._id,
    }
    }
    };
    } catch (error) {
    return error
    }
    },
    // 修改密码
    changePsd: async function (body) {
    const {
    compPhone,
    compPassword
    } = body;
    return await this.findOneAndUpdate({
    'compPhone': compPhone
    }, {
    'compPassword': compPassword
    })
    },
    // 绑定客户
    bindCustomer: async function (_id, auth) {
    return await this.findOneAndUpdate({
    _id
    }, {
    $push: {
    'compCustomer': auth.id
    }
    })
    },
    }
    return mongoose.model('Company', CompanySchema);
    }
    控制器
    /*************************************************************
    *
    *- Copyright (c) qiduo, 2018
    *- FileName: USERController.js 用户基本信息相关
    *- Author: 罗波 lopo1983@vip.qq.com
    *- Version: 1.0
    *- Date:2018-10-15
    *- Descripttion:openstack geecp
    *- Modules:
    *
    *- Extends
    * - 1.egg_Controller
    *----------------------------------------------------------
    *
    *- Function List :
    *
    *- StaticsList :
    * - index 获取用户列表
    * - isHave 检测用户是否存在
    * - show 获取单一用户信息
    * - create 用户注册
    *
    *- History :
    * <Author> <Date> <Desc>
    *
    **************************************************************/
    'use strict';

    const Controller = require('egg').Controller;

    class USERController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Model} MODEL 公司表
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Account.Company;
    }
    /**
    *
    * @name 获取用户列表
    *
    * @description Admin 用户可用 可使用queryParamFn 进行查询
    *
    * @example GET /user/
    *
    */
    async index() {
    const ctx = this.ctx;
    const { helper } = ctx;
    const result = await this.MODEL.getAll(helper.queryParamFn(ctx.query));
    ctx.body = result
    }
    /**
    *
    * @name 检测用户是否存在
    *
    * @param {String} compName 用户名称
    * @param {String} compEmail 用户邮箱
    * @param {String} compPhone 用户手机
    *
    * @description compName, compEmail, compPhone 三选一 或可多选
    *
    * @example GET /user/isIn/?@param = param
    *
    */
    async isHave() {
    const ctx = this.ctx;
    const { compName, compEmail, compPhone } = ctx.query;
    const result = (await this.MODEL.isIn(this.DUFn({ compName, compEmail, compPhone }))) === null;
    ctx.body = { data: `${!result}` }
    }
    /**
    *
    * @name 获取用户信息
    * @param {ObjectId} id 必传 ctx.params.id 用户id
    *
    * @example GET /user/{id}
    */
    async show() {
    const ctx = this.ctx;
    const result = await this.MODEL.getOne({ '_id': ctx.params.id });
    ctx.body = result
    }
    /**
    *
    * @name 用户注册 body = ctx.request.body
    * @param {String} action 必传 动作 regist changePsd
    * @param {String} compEmail 必传 邮箱
    * @param {String} compPhone 必传 手机号码
    * @param {String} compPassword 必传 用户密码 `${SALT}${MD5}`
    * @param {String} code 必传 手机验证码,120s次 mongodb.smscodes expiresIn_TTL_60*3
    *
    * @example POST /user/
    *
    * @description
    * - 邮箱和手机均能登陆
    * - compEmail, compPhone, compPassword, action, code 均为必选参数
    *
    */
    async create() {
    const { ctx } = this;
    const { compEmail, compPhone, compPassword, action, code } = ctx.request.body;
    const result = await this.MODEL.lrfAction({ compEmail, compPhone, compPassword, action, code });
    ctx.body = result
    }
    /**
    * @name 修改用户信息
    *
    * @param {String} action 必传 修改的方法
    * @param {action}
    * - changePsd 修改密码
    * - bindCustomer 绑定客户
    * - lrfAction 找回密码
    * -
    *
    * @example PUT /user/{ObjecId}
    */
    async update() {
    const { ctx } = this;
    const bodys = ctx.request.body;
    const { action } = bodys;
    delete bodys.action;
    const result = await this.MODEL[action](bodys)
    }
    }

    module.exports = USERController;

    二 管理员用户
    表设计
    const crypto = require('crypto');
    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const AdminSchema = new Schema({
    // 用户名
    adminName: {
    type: String,
    required: true,
    unique: [true, '用户名已存在']
    },
    // 用户密码
    adminPassword: {
    type: String,
    required: true,
    set: v => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    }
    },
    // 用户权限组
    adminGroup: {
    type: Number,
    required: true,
    default: 2
    },
    // 用户真实姓名
    adminRealName: {
    type: String
    },
    // 用户头像
    adminHeader: {
    type: String,
    default: ''
    },
    adminStaff: {
    // type: Schema.Types.ObjectId,
    // ref: 'Staff',
    },
    status: {
    type: Number,
    default: 1
    },
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    AdminSchema.statics = {
    isLogin: async function (ctx) {
    return await ctx.service.mongo.adcq.isLogin(ctx, 'Admin', 'adminPassword', async (e) => {
    let { _id, adminRealName, adminName, adminGroup, adminHeader, adminStaff } = e;
    return {
    token: await ctx.service.apps.jwt.sign({ id: _id, group: adminGroup }),
    info: { _id, adminRealName, adminName, adminHeader, adminStaff }
    }
    })
    }
    }
    return mongoose.model('Admin', AdminSchema)
    }
    OpenStack 用户
    表设计
    const crypto = require('crypto');
    module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const { ctx, helper, service } = app.createAnonymousContext();
    const OSIdentityUserSchema = new Schema({
    // The user ID.
    id: String,
    // The ID of the default project for the user.
    default_project_id: String,
    // user description
    description: String,
    // The ID of the domain.
    domain_id: String,
    // user emaill address
    email: String,
    // If the user is enabled, this value is true. If the user is disabled, this value is false.
    enabled: Boolean,
    // The links for the user resource.
    links: {},
    // user name
    name: String,
    // 密码
    password: String,
    // 角色ID
    role: String,
    // 同步状态
    sync: Boolean
    }, {
    timestamps: {
    createdAt: 'created',
    updatedAt: 'updated'
    }
    });
    OSIdentityUserSchema.statics = {
    createUser: async function(_id) {
    const setPSDFn = (v = _id) => {
    let pilipala = Math.random().toString(36).slice(2, 8);
    let bilibole = crypto.createHash('md5').update(`${v}:${pilipala}`).digest('hex');
    return `${pilipala}${bilibole}`;
    };
    const password = setPSDFn();
    try {
    /****************************创建Project*********************************/
    const PROJECT = await service.openstack.identity.projects.create({
    name: _id,
    'description': `comp_id:${_id} date:${new Date() -0 }`
    });
    const default_project_id = PROJECT.data.project.id;
    // || PROJECT.data.error.code === 409
    if (PROJECT.data.project) {
    const DATAS = await service.openstack.identity.users.create({
    'name': _id,
    password,
    default_project_id,
    'description': `comp_id:${_id} date:${new Date()-0 }`
    });
    /******************************本地创建*******************************/
    const result = await this.create({
    ...DATAS.data.user,
    password,
    default_project_id,
    sync: true
    });
    /******************************分配角色*******************************/
    if (!result.id) return;
    await service.openstack.identity.roles.update(result.default_project_id, result.id, app.config.openstack.rolesID.default);
    return result
    }
    } catch (error) {
    return error
    }
    },
    /**
    * @name 获取一个
    * @param {*} _id compid
    * @param {*} select 选择的字段(BSON name/显示的名称 -name/不显示的名称)
    */
    getOne: async function(_id, select) {
    const MODEL = this.findOne({ name: _id }, !!select && select);
    try {
    const result = await MODEL;
    return !!result ? result : await this.createUser(_id);
    } catch (error) {
    return error
    }
    },
    // 获取ObjectID
    getObjectID: async function(_id) {
    const MODEL = this.findOne({ 'name': _id }, 'default_project_id -_id')
    try {
    return await MODEL
    } catch (error) {
    return error
    }
    }
    }
    return mongoose.model('openstack_Identity_user', OSIdentityUserSchema)
    }
    service?
    role
    'use strict';
    const ServerIndex = require('../index')
    //
    class identityRolesService extends ServerIndex {
    constructor(ctx) {
    super(ctx);
    this.actions = ':5000/identity/v3/'
    };
    // 获取Region列表
    async list(parent_region_id) {
    try {
    const datas = await this.OSAJax(`${this.actions}`, { body: { parent_region_id } })
    return {
    data: {
    result: datas.regions,
    totalCount: datas.regions.length
    }
    };
    } catch (error) {
    return {
    data: error
    }
    }

    }
    // 显示regions详情
    async show(project_id, user_id) {
    let datas
    try {
    datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles`)
    } catch (error) {
    datas = error
    }
    return datas
    }
    // 创建regions
    async create(bodys) {
    }
    // 给用户赋予角色
    async update(project_id, user_id, role_id) {
    let datas;
    try {
    datas = await this.OSAJax(`${this.actions}projects/${project_id}/users/${user_id}/roles/${role_id}`, { method: 'PUT' });
    } catch (error) {
    datas = error
    }
    return { data: datas }
    }
    // 删除regions
    async destroy(id) {
    }
    }
    module.exports = identityRolesService;
    project
    'use strict';
    const ServerIndex = require('../index')
    //
    class identityProjectService extends ServerIndex {
    constructor(ctx) {
    super(ctx);
    this.actions = ':5000/identity/v3/projects'
    };
    // 获取Projects列表
    async list() {
    const datas = await this.OSAJax(`${this.actions}`);
    return {
    data: {
    'result': datas.projects,
    'totalCount': datas.projects.length
    }
    };
    }
    // 显示Projects详情
    async show(id) {
    const datas = await this.OSAJax(`${this.actions}/${id}`);
    return { data: datas };
    }
    // 创建Projects
    async create(bodys) {
    const datas = await this.OSAJax(this.actions, { body: { 'project': bodys }, method: 'POST' });
    return { data: datas }
    }
    // 修改Projects
    async update(id, bodys) {
    const datas = await this.OSAJax(`${this.actions}/${id}`, { body: { 'project': bodys }, method: 'PATCH' });
    return { data: datas }
    }
    // 删除Projects
    async destroy(id) {
    const datas = await this.OSAJax(`${this.actions}/${id}`, { method: 'DELETE' });
    return { data: datas }
    }
    }
    module.exports = identityProjectService;
    控制器
    'use strict';

    const Controller = require('egg').Controller;

    class identityUserController extends Controller {
    /**
    * @name constructor
    *
    * @param {*} ctx
    * @param {Function} DuFn 清理空字段函数
    * @param {Object} auth 用户JWT
    *
    */
    constructor(ctx) {
    super(ctx);
    this.auth = ctx.state.user;
    this.DUFn = ctx.helper.deleteUndefined;
    this.MODEL = ctx.model.Openstack.Identity.User
    this.TKMODEL = ctx.model.Openstack.Token
    };
    /**
    *
    * @name 用户列表
    *
    * @param {String} ctx.query.detail 不需要参数
    *
    * @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
    *
    * @example GET /openstack/user
    *
    */
    async index() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.list(ctx.query);
    };
    /**
    * @name 获取单一用户信息
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example GET /openstack/user/{ctx.params.id}
    *
    */
    async show() {
    const { ctx, service } = this;
    ctx.body = await service.openstack.identity.users.show(ctx.params.id);
    // const result = await this.MODEL.getOne(this.auth.id);
    // ctx.body = result;
    };
    /**
    * @name 创建用户
    *
    * @param {String} ctx.params.id 实例id
    *
    * @example
    * - POST /openstack/user/
    */
    async create() {
    const ctx = this.ctx;
    const result = await this.MODEL.createUser(this.auth.id)
    ctx.body = result;
    // const { ctx, service } = this;
    // const { default_project_id, domain_id, description, enabled = true, email, name, password } = ctx.request.body;
    // const bodys = { default_project_id, domain_id, description, enabled, email, name, password };
    // ctx.body = await service.openstack.identity.users.create(this.DUFn(bodys));
    };
    /**
    *
    * @name 测试内部用token
    *
    */
    async testToken() {
    const { ctx, service } = this;
    ctx.body = await this.TKMODEL.getToken(this.auth.id)
    };
    }

    module.exports = identityUserController;
    共用service
    'use strict';
    const Service = require('egg').Service;
    //
    class indexService extends Service {
    constructor(ctx) {
    super(ctx);
    this.OPTokenMODEL = ctx.model.Openstack.Token;
    this.OPUserMODEL = ctx.model.Openstack.Identity.User;
    this.OBJKeySort = ctx.helper.OBJKeySort;
    const {
    uri
    } = this.config.openstack;
    this.uri = `${uri}`;
    this.CurlOpt = async(method, full, token) => {
    return {
    'dataType': 'json',
    'headers': {
    ...((!full && !token) && {
    'X-Auth-Token': (await ctx.helper.TokenFn('openstack')).data
    }) || !!token && {
    'X-Auth-Token': token
    },
    'Content-Type': 'application/json',
    },
    'method': method,
    ...method !== 'DELETE' && {
    'data': {}
    },
    'timeout': 60000
    }
    }
    };
    /**
    * 基础库
    *
    * @param {Object} body 需要提交的参数
    * @param {String} method GET POST DELETE PUT PATCH
    * @param {String} params url 参数
    * @param {Boolean} full 是否显示完整参数
    * @param {String} _ucid 用户ID Optional
    */
    async OSAJax(params, {
    body = {},
    method = "GET",
    full = false,
    status = false,
    _ucid
    } = {}) {
    const ctx = this.ctx;
    const opt = await this.CurlOpt(method, full, !!_ucid ? await this.getUserToken(_ucid) : false);
    method !== 'DELETE' && Object.assign(opt.data, {...!!body ? body : ''
    });
    // console.log(opt)
    // console.log({
    // // 'getFullRES': full,
    // // 'isAdmin': !!_ucid ? `No | _ucid:${_ucid}` : 'Yes',
    // 'URI': `http://${this.uri}${!!params ? params : ''}`,
    // // 'Method': method,
    // // ...method !== 'DELETE' && {
    // // 'Body': opt.data
    // // },
    // // '_': new Date()
    // })
    try {
    const result = await ctx.curl(`${this.uri}${!!params ? params : ''}`, opt);
    return !!full && result || !!status && result.status || result.data;
    } catch (error) {
    return error
    }
    };
    // 获取普通用户token
    async getUserToken(_id) {
    const ctx = this.ctx;
    return (await ctx.model.Openstack.Token.getToken(_id)).data
    };
    // 获取普通用户projectID
    async getProject(_id) {
    const ctx = this.ctx;
    return _id !== 'admin' ? (await this.OPUserMODEL.getOne(_id, 'default_project_id'))['default_project_id'] : this.config.openstack.projectID.default
    };
    // 从支付订单创建相关实例
    /**
    *
    * @param {*} _comp 公司id
    * @param {*} model 数据库
    * @param {*} bodys 内容
    * +@param {String} _metadata 关联数据
    * @param {*} time 开通时长
    */
    async createFromOrder(_comp, model, bodys, time, payment) {
    try {
    const ctx = this.ctx;
    const MODELS = ctx.model.Openstack;
    const {
    deleteUndefined: DUFn,
    subtractMoment: TMFn
    } = ctx.helper
    let datas = {}
    if (model === 'cds') {
    const {
    availability_zone,
    snapshot_id,
    backup_id,
    imageRef,
    size,
    volume_type,
    _metadata
    } = bodys;
    const BODYS = DUFn({
    availability_zone,
    snapshot_id,
    backup_id,
    imageRef,
    size,
    volume_type,
    _metadata
    });
    datas = await MODELS.BlcokStorage.Volumes.createOne(
    _comp, {
    ...BODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment
    }
    );
    }
    if (model === 'ecs') {
    const {
    availability_zone,
    flavorRef,
    name,
    uuid,
    imageRef,
    server_password,
    key_name,
    security_groups,
    _metadata
    } = bodys;
    const SERVERBODYS = DUFn({
    availability_zone,
    flavorRef,
    name,
    uuid,
    imageRef,
    server_password,
    key_name,
    security_groups,
    _metadata
    });
    datas = await MODELS.Servers.Server.createServer(
    _comp, {
    ...SERVERBODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment,
    }
    );
    }
    if (model === 'eip') {
    const {
    description,
    _metadata
    } = bodys;
    const EIPBODYS = DUFn({
    description,
    _metadata
    });
    datas = await MODELS.Neutron.FloatingIP.createOne(
    _comp, {
    ...EIPBODYS,
    'endTime': TMFn(time, 'month', 'add'),
    payment
    })
    }
    return datas
    } catch (error) {
    console.log(error)
    }
    }
    }
    module.exports = indexService;

    egg.js+mongodb+openstack 公有云计费系统(一)

    Nodejslopo1983 发表了文章 • 0 个评论 • 1128 次浏览 • 2019-03-13 23:58 • 来自相关话题

    本代码仅供学习 参考用 请勿做其他用途
    ?本项目结构
    ?
    用户系统财务系统工单系统计费系统OpenStack (rocky)
    ?
    OpenStack 功能
    用户系统identity磁盘blcokStorage计算compute监控gnocchi网络 network
    ?
    所需依赖
    "dependencies": {
    "egg": "^2.2.1",
    "egg-scripts": "^2.5.0",
    "lodash": "^4.17.11",
    "xml2js": "^0.4.19"
    },
    "devDependencies": {
    "autod": "^3.0.1",
    "autod-egg": "^1.0.0",
    "baidu-aip-sdk": "^2.3.3",
    "bce-sdk-js": "^0.2.9",
    "decimal": "0.0.2",
    "decimal.js": "^10.0.1",
    "egg-bin": "^4.3.5",
    "egg-ci": "^1.8.0",
    "egg-cors": "^2.1.0",
    "egg-jwt": "^3.1.2",
    "egg-mock": "^3.14.0",
    "egg-mongoose": "^3.1.0",
    "egg-multipart": "^2.1.0",
    "egg-validate": "^1.1.1",
    "egg-wechat-api": "^1.2.2",
    "eslint": "^4.11.0",
    "eslint-config-egg": "^6.0.0",
    "formstream": "^1.1.0",
    "jpush-async": "^4.0.0-rc.1",
    "koa-useragent": "^1.1.0",
    "moment": "^2.22.2",
    "nodemailer": "^4.6.8",
    "request": "^2.88.0",
    "request-promise-native": "^1.0.5",
    "stream-to-array": "^2.3.0",
    "stream-wormhole": "^1.1.0",
    "webstorm-disable-index": "^1.2.0"
    },
    环境?
    node 8.11?
    mongodb4.x?
    openstack(rocky)
    ?
    注意:
    ?
    1.本教程不会上传相关代码到GitHub ;
    2.本教程需要熟悉egg.js mongoose ES6/7;
    3.熟悉Async/await
    ? 查看全部

    本代码仅供学习 参考用 请勿做其他用途


    ?本项目结构
    ?
  • 用户系统
  • 财务系统
  • 工单系统
  • 计费系统
  • OpenStack (rocky)

  • ?
    OpenStack 功能
  • 用户系统identity
  • 磁盘blcokStorage
  • 计算compute
  • 监控gnocchi
  • 网络 network

  • ?
    所需依赖
      "dependencies": {
    "egg": "^2.2.1",
    "egg-scripts": "^2.5.0",
    "lodash": "^4.17.11",
    "xml2js": "^0.4.19"
    },
    "devDependencies": {
    "autod": "^3.0.1",
    "autod-egg": "^1.0.0",
    "baidu-aip-sdk": "^2.3.3",
    "bce-sdk-js": "^0.2.9",
    "decimal": "0.0.2",
    "decimal.js": "^10.0.1",
    "egg-bin": "^4.3.5",
    "egg-ci": "^1.8.0",
    "egg-cors": "^2.1.0",
    "egg-jwt": "^3.1.2",
    "egg-mock": "^3.14.0",
    "egg-mongoose": "^3.1.0",
    "egg-multipart": "^2.1.0",
    "egg-validate": "^1.1.1",
    "egg-wechat-api": "^1.2.2",
    "eslint": "^4.11.0",
    "eslint-config-egg": "^6.0.0",
    "formstream": "^1.1.0",
    "jpush-async": "^4.0.0-rc.1",
    "koa-useragent": "^1.1.0",
    "moment": "^2.22.2",
    "nodemailer": "^4.6.8",
    "request": "^2.88.0",
    "request-promise-native": "^1.0.5",
    "stream-to-array": "^2.3.0",
    "stream-wormhole": "^1.1.0",
    "webstorm-disable-index": "^1.2.0"
    },

    环境?
    node 8.11?
    mongodb4.x?
    openstack(rocky)
    ?
    注意:
    ?
    1.本教程不会上传相关代码到GitHub ;
    2.本教程需要熟悉egg.js mongoose ES6/7;
    3.熟悉Async/await
    ?