egg.js

egg.js

eggjs 静态文件配置

Nodejslopo1983 发表了文章 • 0 个评论 • 352 次浏览 • 2019-09-04 17:20 • 来自相关话题

config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
}; 查看全部
config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
};

egg 处理提交的xml

Nodejslopo1983 发表了文章 • 0 个评论 • 213 次浏览 • 2019-09-04 17:09 • 来自相关话题

最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};
同样的方法可以处理其他的任何格式 查看全部
最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js
    config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};

同样的方法可以处理其他的任何格式


Egg 配置mongoose

Nodejslopo1983 发表了文章 • 0 个评论 • 215 次浏览 • 2019-08-31 08:55 • 来自相关话题

1.安裝npm i egg-mongoose --save2./config/plugin.jsexports.mongoose = {
enable: true,
package: 'egg-mongoose',
};3./config/config.default.js
 
單一exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};多個exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}controller/user/address (RESTful 風格)const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressControllerrouter.jsrouter.resources('user_address', '/user/address', app.jwt, controller.user.address); 查看全部
1.安裝
npm i egg-mongoose --save
2./config/plugin.js
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
3./config/config.default.js
 
單一
exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};
多個
exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};
4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}
controller/user/address (RESTful 風格)
const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressController
router.js
router.resources('user_address', '/user/address', app.jwt, controller.user.address);

egg-jwt配置

Nodejslopo1983 发表了文章 • 0 个评论 • 140 次浏览 • 2019-08-30 18:00 • 来自相关话题

1. 安裝npm i egg-jwt --save
 
2.config/config.default config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};
 
3.config/pluginexports.jwt = {
enable: true,
package: "egg-jwt"
};
 4.service/apps/jwt.jsclass jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService5.使用class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/contextmodule.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取 查看全部
1. 安裝
npm i egg-jwt --save

 
2.config/config.default
    config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};

 
3.config/plugin
exports.jwt = {
enable: true,
package: "egg-jwt"
};

 4.service/apps/jwt.js
class jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService
5.使用
class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}
6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/context
module.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};
在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取

eggjs 设置跨域

Nodejslopo1983 发表了文章 • 0 个评论 • 168 次浏览 • 2019-08-30 17:57 • 来自相关话题

1.egg-corsnpm install egg-cors --save2.config/plugin.jsexports.cors: {
enable: true,
package: 'egg-cors'
}3.config/config.default.jsconfig.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}; 查看全部
1.egg-cors
npm install  egg-cors --save
2.config/plugin.js
exports.cors: {
enable: true,
package: 'egg-cors'
}
3.config/config.default.js
config.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
};

eggjs 上传文件

Nodejslopo1983 发表了文章 • 0 个评论 • 206 次浏览 • 2019-08-30 17:52 • 来自相关话题

'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController 查看全部
'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController

egg.js+mongodb+openstack 公有云计费系统(三)OpenStack 对接 compute (一)

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

配额
控制器
'use strict';

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

class IndexController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.index;
this.serverSERVICE = ctx.service.openstack.server.servers
}
/**
* name 计算相关配额
*
* @description
*
* @example GET /openstack/blcokstorage/limits
*
* @return {Object}
* - cores VCPU数量可用 颗
* - floatingIps 自定义IP可用 个
* - instances N/A
* - RAM 内存可用量 MB
* - securityGroups 实例数量 个
* - serverGroups 实例分组数量 个
*/
async limits() {
const { ctx, service } = this;
// if (!ctx.isAdmin()) return;
const DATAS = await this.SERVICE.limits(this.auth.id, ctx.isAdmin());
ctx.body = DATAS
}
}

module.exports = IndexController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeIndexService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/'
};
// 获取服务器相关配额
async limits(_ucid, isAdmin) {
try {
const DATAS = await this.OSAJax(`${this.actions}limits`, {
...!isAdmin && { _ucid }
});
const { maxImageMeta, maxPersonality, maxPersonalitySize, maxSecurityGroupRules, maxSecurityGroups, maxServerGroupMembers, maxServerGroups, maxServerMeta, maxTotalCores, maxTotalFloatingIps, maxTotalInstances, maxTotalKeypairs, maxTotalRAMSize, totalCoresUsed, totalFloatingIpsUsed, totalInstancesUsed, totalRAMUsed, totalSecurityGroupsUsed, totalServerGroupsUsed } = (await DATAS).limits.absolute
return {
data: {
maxTotalKeypairs,
'cores': maxTotalCores - totalCoresUsed,
'RAM': maxTotalRAMSize - totalRAMUsed,
maxTotalInstances,
totalInstancesUsed,
'instances': maxTotalInstances - totalInstancesUsed,
maxServerGroups,
'serverGroups': maxServerGroups - totalServerGroupsUsed,
}
}
} catch (error) {
return error
}
}
}

module.exports = ComputeIndexService;

?keypairs
?
控制器
'use strict';

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

class OSKeypairController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.keypair;
this.MODEL = ctx.model.Openstack.Servers.Keypair
}
/**
* @name 获取用户所有密钥对
*
* @example
* - GET /openstack/compute/keypairs
*/
async index() {
const ctx = this.ctx;
// const DATAS = await this.SERVICE.index(this.auth.id, this.QPFn(ctx.query));
// ctx.body = DATAS
const RESULT = await this.MODEL.getAll(this.auth.id, this.QPFn({ ...ctx.query
}));
ctx.body = RESULT
}
/**
* @name 创建密钥对
*
* @param {String} name 密钥对名称
*
* @example
* - POST application/x-www-form-urlencoded /openstack/compute/keypairs
*/
async create() {
const ctx = this.ctx;
const {
name,
public_key,
description
} = ctx.request.body;
const BODYS = this.DUFn({
name,
public_key,
description
});
// const DATAS = await this.SERVICE.create(this.auth.id, BODYS);
// ctx.body = DATAS
const RESULT = await this.MODEL.createOne(this.auth.id, BODYS);
ctx.body = RESULT
}
/**
* @name 获取指定密钥对信息
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - GET /openstack/compute/keypairs/{ctx.params.id}
*/
async show() {
const ctx = this.ctx;
const DATAS = await this.MODEL.getOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 删除密钥对
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - DELETE /openstack/compute/keypairs/{ctx.params.id}
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.MODEL.deleteOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 绑定ECS
*
* @param {String} name 密钥对名称
* @param {String} type 'bind|unbind' 方式
* @param {String} _ECS_id 服务器id
*
*/
async setBindECS() {
const ctx = this.ctx;
const {
name,
type,
_ECS_id
} = ctx.request.body;
const BODYS = this.DUFn({
name,
type,
_ECS_id
})
const DATAS = await this.MODEL.setBindEcs(this.auth.id, BODYS);
ctx.body = DATAS
}
}

module.exports = OSKeypairController;service
'use strict';
const ServerIndex = require('../index')
class ComputeKeypairService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/os-keypairs'
};
/**
* @name 列表
* @param {*} _ucid 用户id
*/
async index(_ucid, query) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
body: { ...query.querys }
});
return {
data: {
'result': datas.keypairs,
'totalCount': datas.keypairs.length
},
}
} catch (error) {
return error
}
}
/**
* @name 获取
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async show(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, { _ucid });
return {
data: datas.keypair
}
} catch (error) {
return error
}
}
/**
* @name 创建
* @param {*} _ucid 用户id
* @param {*} body 需要提交的参数
*/
async create(_ucid, body) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
method: 'POST',
body: {
'keypair': {
...body,
}
}
});
return {
...!!datas.conflictingRequest ? { code: 422, message: `密钥对名称为:${body.name}的密钥对已存在` } : { data: datas }
}
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async destroy(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
code: datas.status,
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}

module.exports = ComputeKeypairService; 查看全部
配额
控制器
'use strict';

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

class IndexController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.index;
this.serverSERVICE = ctx.service.openstack.server.servers
}
/**
* name 计算相关配额
*
* @description
*
* @example GET /openstack/blcokstorage/limits
*
* @return {Object}
* - cores VCPU数量可用 颗
* - floatingIps 自定义IP可用 个
* - instances N/A
* - RAM 内存可用量 MB
* - securityGroups 实例数量 个
* - serverGroups 实例分组数量 个
*/
async limits() {
const { ctx, service } = this;
// if (!ctx.isAdmin()) return;
const DATAS = await this.SERVICE.limits(this.auth.id, ctx.isAdmin());
ctx.body = DATAS
}
}

module.exports = IndexController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeIndexService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/'
};
// 获取服务器相关配额
async limits(_ucid, isAdmin) {
try {
const DATAS = await this.OSAJax(`${this.actions}limits`, {
...!isAdmin && { _ucid }
});
const { maxImageMeta, maxPersonality, maxPersonalitySize, maxSecurityGroupRules, maxSecurityGroups, maxServerGroupMembers, maxServerGroups, maxServerMeta, maxTotalCores, maxTotalFloatingIps, maxTotalInstances, maxTotalKeypairs, maxTotalRAMSize, totalCoresUsed, totalFloatingIpsUsed, totalInstancesUsed, totalRAMUsed, totalSecurityGroupsUsed, totalServerGroupsUsed } = (await DATAS).limits.absolute
return {
data: {
maxTotalKeypairs,
'cores': maxTotalCores - totalCoresUsed,
'RAM': maxTotalRAMSize - totalRAMUsed,
maxTotalInstances,
totalInstancesUsed,
'instances': maxTotalInstances - totalInstancesUsed,
maxServerGroups,
'serverGroups': maxServerGroups - totalServerGroupsUsed,
}
}
} catch (error) {
return error
}
}
}

module.exports = ComputeIndexService;

?keypairs
?
控制器
'use strict';

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

class OSKeypairController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.keypair;
this.MODEL = ctx.model.Openstack.Servers.Keypair
}
/**
* @name 获取用户所有密钥对
*
* @example
* - GET /openstack/compute/keypairs
*/
async index() {
const ctx = this.ctx;
// const DATAS = await this.SERVICE.index(this.auth.id, this.QPFn(ctx.query));
// ctx.body = DATAS
const RESULT = await this.MODEL.getAll(this.auth.id, this.QPFn({ ...ctx.query
}));
ctx.body = RESULT
}
/**
* @name 创建密钥对
*
* @param {String} name 密钥对名称
*
* @example
* - POST application/x-www-form-urlencoded /openstack/compute/keypairs
*/
async create() {
const ctx = this.ctx;
const {
name,
public_key,
description
} = ctx.request.body;
const BODYS = this.DUFn({
name,
public_key,
description
});
// const DATAS = await this.SERVICE.create(this.auth.id, BODYS);
// ctx.body = DATAS
const RESULT = await this.MODEL.createOne(this.auth.id, BODYS);
ctx.body = RESULT
}
/**
* @name 获取指定密钥对信息
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - GET /openstack/compute/keypairs/{ctx.params.id}
*/
async show() {
const ctx = this.ctx;
const DATAS = await this.MODEL.getOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 删除密钥对
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - DELETE /openstack/compute/keypairs/{ctx.params.id}
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.MODEL.deleteOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 绑定ECS
*
* @param {String} name 密钥对名称
* @param {String} type 'bind|unbind' 方式
* @param {String} _ECS_id 服务器id
*
*/
async setBindECS() {
const ctx = this.ctx;
const {
name,
type,
_ECS_id
} = ctx.request.body;
const BODYS = this.DUFn({
name,
type,
_ECS_id
})
const DATAS = await this.MODEL.setBindEcs(this.auth.id, BODYS);
ctx.body = DATAS
}
}

module.exports = OSKeypairController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeKeypairService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/os-keypairs'
};
/**
* @name 列表
* @param {*} _ucid 用户id
*/
async index(_ucid, query) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
body: { ...query.querys }
});
return {
data: {
'result': datas.keypairs,
'totalCount': datas.keypairs.length
},
}
} catch (error) {
return error
}
}
/**
* @name 获取
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async show(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, { _ucid });
return {
data: datas.keypair
}
} catch (error) {
return error
}
}
/**
* @name 创建
* @param {*} _ucid 用户id
* @param {*} body 需要提交的参数
*/
async create(_ucid, body) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
method: 'POST',
body: {
'keypair': {
...body,
}
}
});
return {
...!!datas.conflictingRequest ? { code: 422, message: `密钥对名称为:${body.name}的密钥对已存在` } : { data: datas }
}
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async destroy(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
code: datas.status,
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}

module.exports = ComputeKeypairService;

egg.js+mongodb+openstack 公有云计费系统(三)OpenStack 对接 blcokStorage(2)

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

磁盘相关
控制器'use strict';

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

class OPBlcokStorageVolumeController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QMFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
this.volumeSERVICE = ctx.service.openstack.blcokStorage.volume;
};
/**
* @name 磁盘列表
*
* @param {String} detail 不需要参数
*
* ----------------------------------- 分页 -------------------------------------
*
* @param {String} limit 分页>>条数/页
* @param {String} marker markerID(上页最后条id)
*
* ----------------------------------- 排序 -------------------------------------
*
* @param {String} sort_dir a|b 排序方式 ['asc':default,'desc']
* @param {String} sort_key 排序字段 [status,name,created_at]
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume?{detail}
*
*/
async index() {
const { ctx } = this;
const RESULT = await this.volumeMODEL.getUsers(this.auth.id, this.QMFN({...ctx.query }));
ctx.body = RESULT;
};
/**
* @name 获取单一磁盘
*
* @description
*
* @example GET /openstack/blcokstorage/volume/{id}
*
*/
async show() {
const ctx = this.ctx;
// const datas = await this.volumeSERVICE.show(ctx.params.id, this.auth.id);
// ctx.body = datas;
const RESULT = await this.volumeMODEL.getOne(this.auth.id, ctx.params.id, ctx.isAdmin())
ctx.body = RESULT;
};
/**
* @name 创建磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async create() {
const { ctx } = this;
const { availability_zone, snapshot_id, backup_id, imageRef, size = 5, volume_type = "hdd" } = ctx.request.body;
const BODYS = this.DUFN({ availability_zone, snapshot_id, backup_id, imageRef, size, volume_type })
const datas = await this.volumeMODEL.createOne(this.auth.id, BODYS)
ctx.body = datas
};
/**
* @name 调整磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async update() {
const ctx = this.ctx;
const BODYS = ctx.request.body;
const { action, name } = BODYS;
delete BODYS.action;
const datas = !!action ? await this.volumeSERVICE.action(this.auth.id, this.auth.ProjectID, ctx.params.id, action, BODYS) : await this.serverSERVICE.update(ctx.params.id, this.auth.id, this.DUFn({ name }));
ctx.body = datas
};
/**
* @name 删除磁盘
*
* @description
*
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.volumeSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = DATAS
}

}

module.exports = OPBlcokStorageVolumeController;modelmodule.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
helper,
service
} = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const OSblockStorageVolumeSchema = new Schema({
// 配置
config: {},
// 公司id
_comp: {
type: Schema.Types.ObjectId,
ref: 'Company',
required: true,
index: true
},
// 支付方式
payment: {
type: String,
default: 'prepay'
},
// 到期时间
endTime: {
type: Date
},
// 后台备注描述
_description: {

},
// 源信息
_metadata: {
type: String,
index: true
},
/*---------------------------------------------------*/
"status": {
type: 'String',
default: 'creating'
},
"migration_status": {},
"user_id": {},
"attachments": ,
"availability_zone": {},
"bootable": {},
"encrypted": {},
"created_at": {},
"description": {},
"updated_at": {},
"volume_type": {},
"name": {},
"replication_status": {},
"consistencygroup_id": {},
"source_volid": {},
"imageRef": {},
"backup_id": {},
"snapshot_id": {},
"multiattach": {},
"metadata": {},
"id": {
type: String,
index: true
},
"size": {},
"os-vol-host-attr:host": {},
"os-vol-tenant-attr:tenant_id": {}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSblockStorageVolumeSchema.statics = {
getUsers: async function(_comp, queryMix) {
const serverSERVICE = ctx.service.openstack.server.servers;
const {
querys,
select,
sort,
limit,
marker
} = queryMix;
const withDetail = querys.detail === '' || querys.detail;
delete querys.detail;
let QUERTS = {};
for (const key in querys) {
QUERTS[key] = eval(`/${querys[key]}.*/i`)
}
const MODELS = (count = false) => this.find({
_comp,
...QUERTS,
...(marker && !count && {
'_id': {
"$lt": marker
}
}),
}, {
...select,
}, {
...!count && {
limit
},
'sort': {
_id: -1,
...sort
}
});
try {
const datas = await MODELS()
return {
data: {
result: datas,
limit,
marker: datas.length ? [...datas].pop()._id : '',
totalCount: await MODELS(true).count()
}
}
} catch (error) {
return error
}
},
/**
* @name 创建硬盘
* @param {*} _id
* @param {*} body
*/
createOne: async function(_id, bodys) {
try {
const {
endTime,
payment,
_metadata
} = bodys;
delete bodys._metadata;
delete bodys.endTime;
delete bodys.payment;
//
const DATAS = await service.openstack.blcokStorage.volume.create(_id, {
...bodys,
... {
"name": `volume-${Math.random().toString(36).slice(2, 8)}`
}
});
const {
id: _openstack_id
} = DATAS.data.volume;
!!DATAS.data.volume && await ctx.model.Schedule.Openstack.Volume.addOne({
_comp: _id,
_openstack_id,
type: 'volume',
active: 'creating',
_metadata
})
return !!DATAS.data.volume ? {
data: await this.create({
_comp: _id,
endTime,
payment,
_metadata,
...DATAS.data.volume
})
} : {
'code': 422,
'message': '创建失败'
};
} catch (error) {
return error
}
},
// 获取全部
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,
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return {
data: {
result: await MODELS,
totalCount: await MODELS.count()
}
};
},
// 查看单个
getOne: async function(_comp, id, isAdmin) {
const MODELS = this.findOne({...isAdmin ? {
id
} : {
_comp,
id
}
});
try {
const RESULT = await MODELS;
return {
data: RESULT
}
} catch (error) {
return error
}
},
// 绑定到磁盘
/**
* @name 绑定到磁盘
* @param {*} _comp 用户UUID
* @param {*} id 磁盘ID
* @param {*} type 'bind'|'unbind' 绑定方式
*/
bindToECS: async function({
_comp,
id,
type = "bind"
} = {}, bodys) {
const MODEL = this.findOneAndUpdate({
_comp,
id
}, {
'attachments': type === 'bind' ? [bodys] : ,
'status': type === 'bind' ? 'in-use' : 'available'
});
try {
const datas = await MODEL;
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_block_storage_volume', OSblockStorageVolumeSchema)
}service'use strict';
const ServerIndex = require('../index')
//
class VolumeService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default;
this.actions = ':8776/v3';
};
// 获取磁盘列表
async list(querys, _ucid, project_id, isAdmin) {
try {
const detail = Object.keys(querys).includes('detail');
delete querys.detail;
let SORT = {}
if (querys.sort_key) {
SORT = { 'sort': `${querys.sort_key}:${querys.sort_dir}` };
delete querys.sort_key;
delete querys.sort_dir;
}
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : project_id}/volumes${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: {
...querys,
...querys.sort_key && SORT,
...isAdmin && { 'all_tenants': true },
},
});
return {
data: {
result: datas.volumes.map(e => {
!!detail && e.attachments.length && (e.attachment = e.attachments[0].server_id)
delete e.links;
delete e.attachments;
return e
}).filter(e => e.status != 'deleting'),
totalCount: datas.volumes.length
}
};
} catch (error) {
return error
}
}
// 获取磁盘详情
async show(id, _ucid, _description) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes/${id}`, {
..._ucid !== 'admin' && { _ucid }
});
return _ucid === 'admin' ? { ...datas.volume, _description } : { data: datas.volume };
} catch (error) {
return error
}
}
// 创建磁盘
async create(_ucid, bodys, order = "false") {
const DATAS = this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes`, {
body: {
'volume': {
... {
"availability_zone": null,
"source_volid": null,
"description": null,
"multiattach": false,
"snapshot_id": null,
"backup_id": null,
"imageRef": null,
"metadata": {},
"consistencygroup_id": null
},
...bodys
}
},
method: 'POST',
_ucid
});
try {
const datas = await DATAS
return !!order ? { data: datas } : datas
} catch (error) {
return error
}

}
// 删除磁盘
async destroy(_ucid, project_id, volume_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
...datas.status === 404 && {
message: `${volume_id}不存在或已删除`
}
}
} catch (error) {

}
}
// 磁盘操作
// {'os-extend':'磁盘扩容','revert':'镜像回滚'}
async action(_ucid, project_id, volume_id, type, bodys) {
const isIn = (e) => ['os-extend', 'revert'].includes(e);
if (!isIn(type)) return { code: 422 };
const actionMAP = (e) => {
const OBJ = {};
OBJ[e] = !bodys ? null : bodys;
return OBJ;
}
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
body: actionMAP(type),
method: 'POST',
_ucid, full: true
});
return {
code: DATAS.status
}
} catch (error) {
return error
}
}
async update(_ucid, project_id, volume_id, bodys) {
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
bodys: {
...bodys
},
method: 'PUT'
});
return {
data: DATAS
}
} catch (error) {
return error
}
}
}
module.exports = VolumeService;
scheduleconst Subscription = require('egg').Subscription;

class getVolumeStatus extends Subscription {
constructor(ctx) {
super(ctx);
this.SERVICE = ctx.service.openstack.blcokStorage.volume;
this.MODELS = ctx.model.Schedule.Openstack.Volume;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
}
static get schedule() {
return {
interval: '10s',
type: 'worker',
};
}
async subscribe() {
const ctx = this.ctx;
const lists = await this.MODELS.getALL();
if (lists.length) {
const datas = await this.checkItem(lists);
}
}
async checkItem(result) {
// 调取记录
const checkFN = result.map(e => {
// 记录尝试次数
this.MODELS.retry(e._openstack_id)
return this.SERVICE.show(e._openstack_id, 'admin', e);
})
let DATAS = await Promise.all(checkFN);
// 检查ACTION
if (!!DATAS.length) {
const endOrder = DATAS.map(e => {
const { _comp, _openstack_id: id } = e._description;
delete e._description
delete e.links
if (e.status === 'available' || e.status === 'in-use') {
return this.volumeMODEL.findOneAndUpdate({ id }, { ...e });
}
})
DATAS = await Promise.all(endOrder);
};
// 清除已完成任务
if (DATAS.length) {
const clearSchedule = DATAS.map(e => {
if (!!e) {
const { id: _openstack_id } = e;
return this.MODELS.deleteOne({ '_openstack_id': _openstack_id })
}
})
DATAS = await Promise.all(clearSchedule);
}
}
}

module.exports = getVolumeStatus;
schedule model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const scheduleOSVolumeSchema = new Schema({
// 类型
type: {
type: String,
},
// 尝试次数
retry: {
type: Number,
dafault: 0
},
// 是否创建成功
status: {
type: Boolean,
default: false
},
// 操作方式 [BUILD:创建,DELETE:删除]
active: {
type: String,
},
// 数据ID
_openstack_id: {
type: String,
index: true
},
// 公司ID
_comp: {
type: String
},
// 其他配置参数
/**
* ecs:Number
*/
_description: {

},
// 其他配置元信息
_metadata: {

}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
scheduleOSVolumeSchema.statics = {
getALL: async function (limit = 50) {
const MODEL = this.find().limit(limit);
try {
return await MODEL;
} catch (error) {
return error
}
},
addOne: async function (bodys) {
const MODEL = this.create({ ...bodys });
try {
const result = await MODEL;
return { code: !!result ? 201 : 404 }
} catch (error) {
return error
}
},
// destroyOne: async function (id) {
// const MODEL = this.deleteOne(id);
// try {
// const result = await MODEL
// return result
// } catch (error) {
// return error
// }
// },
retry: async function (_openstack_id) {
const MODEL = this.findOneAndUpdate({ _openstack_id }, {
'$inc': { retry: 1 }
});
try {
await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('schedule_openstack_volume', scheduleOSVolumeSchema);
} 查看全部
磁盘相关
控制器
'use strict';

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

class OPBlcokStorageVolumeController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QMFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
this.volumeSERVICE = ctx.service.openstack.blcokStorage.volume;
};
/**
* @name 磁盘列表
*
* @param {String} detail 不需要参数
*
* ----------------------------------- 分页 -------------------------------------
*
* @param {String} limit 分页>>条数/页
* @param {String} marker markerID(上页最后条id)
*
* ----------------------------------- 排序 -------------------------------------
*
* @param {String} sort_dir a|b 排序方式 ['asc':default,'desc']
* @param {String} sort_key 排序字段 [status,name,created_at]
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume?{detail}
*
*/
async index() {
const { ctx } = this;
const RESULT = await this.volumeMODEL.getUsers(this.auth.id, this.QMFN({...ctx.query }));
ctx.body = RESULT;
};
/**
* @name 获取单一磁盘
*
* @description
*
* @example GET /openstack/blcokstorage/volume/{id}
*
*/
async show() {
const ctx = this.ctx;
// const datas = await this.volumeSERVICE.show(ctx.params.id, this.auth.id);
// ctx.body = datas;
const RESULT = await this.volumeMODEL.getOne(this.auth.id, ctx.params.id, ctx.isAdmin())
ctx.body = RESULT;
};
/**
* @name 创建磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async create() {
const { ctx } = this;
const { availability_zone, snapshot_id, backup_id, imageRef, size = 5, volume_type = "hdd" } = ctx.request.body;
const BODYS = this.DUFN({ availability_zone, snapshot_id, backup_id, imageRef, size, volume_type })
const datas = await this.volumeMODEL.createOne(this.auth.id, BODYS)
ctx.body = datas
};
/**
* @name 调整磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async update() {
const ctx = this.ctx;
const BODYS = ctx.request.body;
const { action, name } = BODYS;
delete BODYS.action;
const datas = !!action ? await this.volumeSERVICE.action(this.auth.id, this.auth.ProjectID, ctx.params.id, action, BODYS) : await this.serverSERVICE.update(ctx.params.id, this.auth.id, this.DUFn({ name }));
ctx.body = datas
};
/**
* @name 删除磁盘
*
* @description
*
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.volumeSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = DATAS
}

}

module.exports = OPBlcokStorageVolumeController;
model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
helper,
service
} = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const OSblockStorageVolumeSchema = new Schema({
// 配置
config: {},
// 公司id
_comp: {
type: Schema.Types.ObjectId,
ref: 'Company',
required: true,
index: true
},
// 支付方式
payment: {
type: String,
default: 'prepay'
},
// 到期时间
endTime: {
type: Date
},
// 后台备注描述
_description: {

},
// 源信息
_metadata: {
type: String,
index: true
},
/*---------------------------------------------------*/
"status": {
type: 'String',
default: 'creating'
},
"migration_status": {},
"user_id": {},
"attachments": ,
"availability_zone": {},
"bootable": {},
"encrypted": {},
"created_at": {},
"description": {},
"updated_at": {},
"volume_type": {},
"name": {},
"replication_status": {},
"consistencygroup_id": {},
"source_volid": {},
"imageRef": {},
"backup_id": {},
"snapshot_id": {},
"multiattach": {},
"metadata": {},
"id": {
type: String,
index: true
},
"size": {},
"os-vol-host-attr:host": {},
"os-vol-tenant-attr:tenant_id": {}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSblockStorageVolumeSchema.statics = {
getUsers: async function(_comp, queryMix) {
const serverSERVICE = ctx.service.openstack.server.servers;
const {
querys,
select,
sort,
limit,
marker
} = queryMix;
const withDetail = querys.detail === '' || querys.detail;
delete querys.detail;
let QUERTS = {};
for (const key in querys) {
QUERTS[key] = eval(`/${querys[key]}.*/i`)
}
const MODELS = (count = false) => this.find({
_comp,
...QUERTS,
...(marker && !count && {
'_id': {
"$lt": marker
}
}),
}, {
...select,
}, {
...!count && {
limit
},
'sort': {
_id: -1,
...sort
}
});
try {
const datas = await MODELS()
return {
data: {
result: datas,
limit,
marker: datas.length ? [...datas].pop()._id : '',
totalCount: await MODELS(true).count()
}
}
} catch (error) {
return error
}
},
/**
* @name 创建硬盘
* @param {*} _id
* @param {*} body
*/
createOne: async function(_id, bodys) {
try {
const {
endTime,
payment,
_metadata
} = bodys;
delete bodys._metadata;
delete bodys.endTime;
delete bodys.payment;
//
const DATAS = await service.openstack.blcokStorage.volume.create(_id, {
...bodys,
... {
"name": `volume-${Math.random().toString(36).slice(2, 8)}`
}
});
const {
id: _openstack_id
} = DATAS.data.volume;
!!DATAS.data.volume && await ctx.model.Schedule.Openstack.Volume.addOne({
_comp: _id,
_openstack_id,
type: 'volume',
active: 'creating',
_metadata
})
return !!DATAS.data.volume ? {
data: await this.create({
_comp: _id,
endTime,
payment,
_metadata,
...DATAS.data.volume
})
} : {
'code': 422,
'message': '创建失败'
};
} catch (error) {
return error
}
},
// 获取全部
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,
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return {
data: {
result: await MODELS,
totalCount: await MODELS.count()
}
};
},
// 查看单个
getOne: async function(_comp, id, isAdmin) {
const MODELS = this.findOne({...isAdmin ? {
id
} : {
_comp,
id
}
});
try {
const RESULT = await MODELS;
return {
data: RESULT
}
} catch (error) {
return error
}
},
// 绑定到磁盘
/**
* @name 绑定到磁盘
* @param {*} _comp 用户UUID
* @param {*} id 磁盘ID
* @param {*} type 'bind'|'unbind' 绑定方式
*/
bindToECS: async function({
_comp,
id,
type = "bind"
} = {}, bodys) {
const MODEL = this.findOneAndUpdate({
_comp,
id
}, {
'attachments': type === 'bind' ? [bodys] : ,
'status': type === 'bind' ? 'in-use' : 'available'
});
try {
const datas = await MODEL;
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_block_storage_volume', OSblockStorageVolumeSchema)
}
service
'use strict';
const ServerIndex = require('../index')
//
class VolumeService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default;
this.actions = ':8776/v3';
};
// 获取磁盘列表
async list(querys, _ucid, project_id, isAdmin) {
try {
const detail = Object.keys(querys).includes('detail');
delete querys.detail;
let SORT = {}
if (querys.sort_key) {
SORT = { 'sort': `${querys.sort_key}:${querys.sort_dir}` };
delete querys.sort_key;
delete querys.sort_dir;
}
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : project_id}/volumes${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: {
...querys,
...querys.sort_key && SORT,
...isAdmin && { 'all_tenants': true },
},
});
return {
data: {
result: datas.volumes.map(e => {
!!detail && e.attachments.length && (e.attachment = e.attachments[0].server_id)
delete e.links;
delete e.attachments;
return e
}).filter(e => e.status != 'deleting'),
totalCount: datas.volumes.length
}
};
} catch (error) {
return error
}
}
// 获取磁盘详情
async show(id, _ucid, _description) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes/${id}`, {
..._ucid !== 'admin' && { _ucid }
});
return _ucid === 'admin' ? { ...datas.volume, _description } : { data: datas.volume };
} catch (error) {
return error
}
}
// 创建磁盘
async create(_ucid, bodys, order = "false") {
const DATAS = this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes`, {
body: {
'volume': {
... {
"availability_zone": null,
"source_volid": null,
"description": null,
"multiattach": false,
"snapshot_id": null,
"backup_id": null,
"imageRef": null,
"metadata": {},
"consistencygroup_id": null
},
...bodys
}
},
method: 'POST',
_ucid
});
try {
const datas = await DATAS
return !!order ? { data: datas } : datas
} catch (error) {
return error
}

}
// 删除磁盘
async destroy(_ucid, project_id, volume_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
...datas.status === 404 && {
message: `${volume_id}不存在或已删除`
}
}
} catch (error) {

}
}
// 磁盘操作
// {'os-extend':'磁盘扩容','revert':'镜像回滚'}
async action(_ucid, project_id, volume_id, type, bodys) {
const isIn = (e) => ['os-extend', 'revert'].includes(e);
if (!isIn(type)) return { code: 422 };
const actionMAP = (e) => {
const OBJ = {};
OBJ[e] = !bodys ? null : bodys;
return OBJ;
}
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
body: actionMAP(type),
method: 'POST',
_ucid, full: true
});
return {
code: DATAS.status
}
} catch (error) {
return error
}
}
async update(_ucid, project_id, volume_id, bodys) {
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
bodys: {
...bodys
},
method: 'PUT'
});
return {
data: DATAS
}
} catch (error) {
return error
}
}
}
module.exports = VolumeService;

schedule
const Subscription = require('egg').Subscription;

class getVolumeStatus extends Subscription {
constructor(ctx) {
super(ctx);
this.SERVICE = ctx.service.openstack.blcokStorage.volume;
this.MODELS = ctx.model.Schedule.Openstack.Volume;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
}
static get schedule() {
return {
interval: '10s',
type: 'worker',
};
}
async subscribe() {
const ctx = this.ctx;
const lists = await this.MODELS.getALL();
if (lists.length) {
const datas = await this.checkItem(lists);
}
}
async checkItem(result) {
// 调取记录
const checkFN = result.map(e => {
// 记录尝试次数
this.MODELS.retry(e._openstack_id)
return this.SERVICE.show(e._openstack_id, 'admin', e);
})
let DATAS = await Promise.all(checkFN);
// 检查ACTION
if (!!DATAS.length) {
const endOrder = DATAS.map(e => {
const { _comp, _openstack_id: id } = e._description;
delete e._description
delete e.links
if (e.status === 'available' || e.status === 'in-use') {
return this.volumeMODEL.findOneAndUpdate({ id }, { ...e });
}
})
DATAS = await Promise.all(endOrder);
};
// 清除已完成任务
if (DATAS.length) {
const clearSchedule = DATAS.map(e => {
if (!!e) {
const { id: _openstack_id } = e;
return this.MODELS.deleteOne({ '_openstack_id': _openstack_id })
}
})
DATAS = await Promise.all(clearSchedule);
}
}
}

module.exports = getVolumeStatus;

schedule model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const scheduleOSVolumeSchema = new Schema({
// 类型
type: {
type: String,
},
// 尝试次数
retry: {
type: Number,
dafault: 0
},
// 是否创建成功
status: {
type: Boolean,
default: false
},
// 操作方式 [BUILD:创建,DELETE:删除]
active: {
type: String,
},
// 数据ID
_openstack_id: {
type: String,
index: true
},
// 公司ID
_comp: {
type: String
},
// 其他配置参数
/**
* ecs:Number
*/
_description: {

},
// 其他配置元信息
_metadata: {

}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
scheduleOSVolumeSchema.statics = {
getALL: async function (limit = 50) {
const MODEL = this.find().limit(limit);
try {
return await MODEL;
} catch (error) {
return error
}
},
addOne: async function (bodys) {
const MODEL = this.create({ ...bodys });
try {
const result = await MODEL;
return { code: !!result ? 201 : 404 }
} catch (error) {
return error
}
},
// destroyOne: async function (id) {
// const MODEL = this.deleteOne(id);
// try {
// const result = await MODEL
// return result
// } catch (error) {
// return error
// }
// },
retry: async function (_openstack_id) {
const MODEL = this.findOneAndUpdate({ _openstack_id }, {
'$inc': { retry: 1 }
});
try {
await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('schedule_openstack_volume', scheduleOSVolumeSchema);
}

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

Nodejslopo1983 发表了文章 • 0 个评论 • 231 次浏览 • 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 个评论 • 279 次浏览 • 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;

eggjs 静态文件配置

Nodejslopo1983 发表了文章 • 0 个评论 • 352 次浏览 • 2019-09-04 17:20 • 来自相关话题

config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
}; 查看全部
config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
};

egg 处理提交的xml

Nodejslopo1983 发表了文章 • 0 个评论 • 213 次浏览 • 2019-09-04 17:09 • 来自相关话题

最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};
同样的方法可以处理其他的任何格式 查看全部
最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js
    config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};

同样的方法可以处理其他的任何格式


Egg 配置mongoose

Nodejslopo1983 发表了文章 • 0 个评论 • 215 次浏览 • 2019-08-31 08:55 • 来自相关话题

1.安裝npm i egg-mongoose --save2./config/plugin.jsexports.mongoose = {
enable: true,
package: 'egg-mongoose',
};3./config/config.default.js
 
單一exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};多個exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}controller/user/address (RESTful 風格)const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressControllerrouter.jsrouter.resources('user_address', '/user/address', app.jwt, controller.user.address); 查看全部
1.安裝
npm i egg-mongoose --save
2./config/plugin.js
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
3./config/config.default.js
 
單一
exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};
多個
exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};
4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}
controller/user/address (RESTful 風格)
const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressController
router.js
router.resources('user_address', '/user/address', app.jwt, controller.user.address);

egg-jwt配置

Nodejslopo1983 发表了文章 • 0 个评论 • 140 次浏览 • 2019-08-30 18:00 • 来自相关话题

1. 安裝npm i egg-jwt --save
 
2.config/config.default config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};
 
3.config/pluginexports.jwt = {
enable: true,
package: "egg-jwt"
};
 4.service/apps/jwt.jsclass jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService5.使用class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/contextmodule.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取 查看全部
1. 安裝
npm i egg-jwt --save

 
2.config/config.default
    config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};

 
3.config/plugin
exports.jwt = {
enable: true,
package: "egg-jwt"
};

 4.service/apps/jwt.js
class jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService
5.使用
class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}
6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/context
module.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};
在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取

eggjs 设置跨域

Nodejslopo1983 发表了文章 • 0 个评论 • 168 次浏览 • 2019-08-30 17:57 • 来自相关话题

1.egg-corsnpm install egg-cors --save2.config/plugin.jsexports.cors: {
enable: true,
package: 'egg-cors'
}3.config/config.default.jsconfig.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}; 查看全部
1.egg-cors
npm install  egg-cors --save
2.config/plugin.js
exports.cors: {
enable: true,
package: 'egg-cors'
}
3.config/config.default.js
config.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
};

eggjs 上传文件

Nodejslopo1983 发表了文章 • 0 个评论 • 206 次浏览 • 2019-08-30 17:52 • 来自相关话题

'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController 查看全部
'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController

egg.js+mongodb+openstack 公有云计费系统(三)OpenStack 对接 compute (一)

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

配额
控制器
'use strict';

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

class IndexController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.index;
this.serverSERVICE = ctx.service.openstack.server.servers
}
/**
* name 计算相关配额
*
* @description
*
* @example GET /openstack/blcokstorage/limits
*
* @return {Object}
* - cores VCPU数量可用 颗
* - floatingIps 自定义IP可用 个
* - instances N/A
* - RAM 内存可用量 MB
* - securityGroups 实例数量 个
* - serverGroups 实例分组数量 个
*/
async limits() {
const { ctx, service } = this;
// if (!ctx.isAdmin()) return;
const DATAS = await this.SERVICE.limits(this.auth.id, ctx.isAdmin());
ctx.body = DATAS
}
}

module.exports = IndexController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeIndexService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/'
};
// 获取服务器相关配额
async limits(_ucid, isAdmin) {
try {
const DATAS = await this.OSAJax(`${this.actions}limits`, {
...!isAdmin && { _ucid }
});
const { maxImageMeta, maxPersonality, maxPersonalitySize, maxSecurityGroupRules, maxSecurityGroups, maxServerGroupMembers, maxServerGroups, maxServerMeta, maxTotalCores, maxTotalFloatingIps, maxTotalInstances, maxTotalKeypairs, maxTotalRAMSize, totalCoresUsed, totalFloatingIpsUsed, totalInstancesUsed, totalRAMUsed, totalSecurityGroupsUsed, totalServerGroupsUsed } = (await DATAS).limits.absolute
return {
data: {
maxTotalKeypairs,
'cores': maxTotalCores - totalCoresUsed,
'RAM': maxTotalRAMSize - totalRAMUsed,
maxTotalInstances,
totalInstancesUsed,
'instances': maxTotalInstances - totalInstancesUsed,
maxServerGroups,
'serverGroups': maxServerGroups - totalServerGroupsUsed,
}
}
} catch (error) {
return error
}
}
}

module.exports = ComputeIndexService;

?keypairs
?
控制器
'use strict';

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

class OSKeypairController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.keypair;
this.MODEL = ctx.model.Openstack.Servers.Keypair
}
/**
* @name 获取用户所有密钥对
*
* @example
* - GET /openstack/compute/keypairs
*/
async index() {
const ctx = this.ctx;
// const DATAS = await this.SERVICE.index(this.auth.id, this.QPFn(ctx.query));
// ctx.body = DATAS
const RESULT = await this.MODEL.getAll(this.auth.id, this.QPFn({ ...ctx.query
}));
ctx.body = RESULT
}
/**
* @name 创建密钥对
*
* @param {String} name 密钥对名称
*
* @example
* - POST application/x-www-form-urlencoded /openstack/compute/keypairs
*/
async create() {
const ctx = this.ctx;
const {
name,
public_key,
description
} = ctx.request.body;
const BODYS = this.DUFn({
name,
public_key,
description
});
// const DATAS = await this.SERVICE.create(this.auth.id, BODYS);
// ctx.body = DATAS
const RESULT = await this.MODEL.createOne(this.auth.id, BODYS);
ctx.body = RESULT
}
/**
* @name 获取指定密钥对信息
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - GET /openstack/compute/keypairs/{ctx.params.id}
*/
async show() {
const ctx = this.ctx;
const DATAS = await this.MODEL.getOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 删除密钥对
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - DELETE /openstack/compute/keypairs/{ctx.params.id}
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.MODEL.deleteOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 绑定ECS
*
* @param {String} name 密钥对名称
* @param {String} type 'bind|unbind' 方式
* @param {String} _ECS_id 服务器id
*
*/
async setBindECS() {
const ctx = this.ctx;
const {
name,
type,
_ECS_id
} = ctx.request.body;
const BODYS = this.DUFn({
name,
type,
_ECS_id
})
const DATAS = await this.MODEL.setBindEcs(this.auth.id, BODYS);
ctx.body = DATAS
}
}

module.exports = OSKeypairController;service
'use strict';
const ServerIndex = require('../index')
class ComputeKeypairService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/os-keypairs'
};
/**
* @name 列表
* @param {*} _ucid 用户id
*/
async index(_ucid, query) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
body: { ...query.querys }
});
return {
data: {
'result': datas.keypairs,
'totalCount': datas.keypairs.length
},
}
} catch (error) {
return error
}
}
/**
* @name 获取
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async show(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, { _ucid });
return {
data: datas.keypair
}
} catch (error) {
return error
}
}
/**
* @name 创建
* @param {*} _ucid 用户id
* @param {*} body 需要提交的参数
*/
async create(_ucid, body) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
method: 'POST',
body: {
'keypair': {
...body,
}
}
});
return {
...!!datas.conflictingRequest ? { code: 422, message: `密钥对名称为:${body.name}的密钥对已存在` } : { data: datas }
}
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async destroy(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
code: datas.status,
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}

module.exports = ComputeKeypairService; 查看全部
配额
控制器
'use strict';

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

class IndexController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.index;
this.serverSERVICE = ctx.service.openstack.server.servers
}
/**
* name 计算相关配额
*
* @description
*
* @example GET /openstack/blcokstorage/limits
*
* @return {Object}
* - cores VCPU数量可用 颗
* - floatingIps 自定义IP可用 个
* - instances N/A
* - RAM 内存可用量 MB
* - securityGroups 实例数量 个
* - serverGroups 实例分组数量 个
*/
async limits() {
const { ctx, service } = this;
// if (!ctx.isAdmin()) return;
const DATAS = await this.SERVICE.limits(this.auth.id, ctx.isAdmin());
ctx.body = DATAS
}
}

module.exports = IndexController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeIndexService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/'
};
// 获取服务器相关配额
async limits(_ucid, isAdmin) {
try {
const DATAS = await this.OSAJax(`${this.actions}limits`, {
...!isAdmin && { _ucid }
});
const { maxImageMeta, maxPersonality, maxPersonalitySize, maxSecurityGroupRules, maxSecurityGroups, maxServerGroupMembers, maxServerGroups, maxServerMeta, maxTotalCores, maxTotalFloatingIps, maxTotalInstances, maxTotalKeypairs, maxTotalRAMSize, totalCoresUsed, totalFloatingIpsUsed, totalInstancesUsed, totalRAMUsed, totalSecurityGroupsUsed, totalServerGroupsUsed } = (await DATAS).limits.absolute
return {
data: {
maxTotalKeypairs,
'cores': maxTotalCores - totalCoresUsed,
'RAM': maxTotalRAMSize - totalRAMUsed,
maxTotalInstances,
totalInstancesUsed,
'instances': maxTotalInstances - totalInstancesUsed,
maxServerGroups,
'serverGroups': maxServerGroups - totalServerGroupsUsed,
}
}
} catch (error) {
return error
}
}
}

module.exports = ComputeIndexService;

?keypairs
?
控制器
'use strict';

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

class OSKeypairController 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.QPFn = ctx.helper.queryParamFn;
this.SERVICE = ctx.service.openstack.compute.keypair;
this.MODEL = ctx.model.Openstack.Servers.Keypair
}
/**
* @name 获取用户所有密钥对
*
* @example
* - GET /openstack/compute/keypairs
*/
async index() {
const ctx = this.ctx;
// const DATAS = await this.SERVICE.index(this.auth.id, this.QPFn(ctx.query));
// ctx.body = DATAS
const RESULT = await this.MODEL.getAll(this.auth.id, this.QPFn({ ...ctx.query
}));
ctx.body = RESULT
}
/**
* @name 创建密钥对
*
* @param {String} name 密钥对名称
*
* @example
* - POST application/x-www-form-urlencoded /openstack/compute/keypairs
*/
async create() {
const ctx = this.ctx;
const {
name,
public_key,
description
} = ctx.request.body;
const BODYS = this.DUFn({
name,
public_key,
description
});
// const DATAS = await this.SERVICE.create(this.auth.id, BODYS);
// ctx.body = DATAS
const RESULT = await this.MODEL.createOne(this.auth.id, BODYS);
ctx.body = RESULT
}
/**
* @name 获取指定密钥对信息
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - GET /openstack/compute/keypairs/{ctx.params.id}
*/
async show() {
const ctx = this.ctx;
const DATAS = await this.MODEL.getOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 删除密钥对
*
* @param {String} ctx.params.id 密钥对名称
*
* @example
* - DELETE /openstack/compute/keypairs/{ctx.params.id}
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.MODEL.deleteOne(this.auth.id, ctx.params.id);
ctx.body = DATAS
}
/**
* @name 绑定ECS
*
* @param {String} name 密钥对名称
* @param {String} type 'bind|unbind' 方式
* @param {String} _ECS_id 服务器id
*
*/
async setBindECS() {
const ctx = this.ctx;
const {
name,
type,
_ECS_id
} = ctx.request.body;
const BODYS = this.DUFn({
name,
type,
_ECS_id
})
const DATAS = await this.MODEL.setBindEcs(this.auth.id, BODYS);
ctx.body = DATAS
}
}

module.exports = OSKeypairController;
service
'use strict';
const ServerIndex = require('../index')
class ComputeKeypairService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8774/v2.1/os-keypairs'
};
/**
* @name 列表
* @param {*} _ucid 用户id
*/
async index(_ucid, query) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
body: { ...query.querys }
});
return {
data: {
'result': datas.keypairs,
'totalCount': datas.keypairs.length
},
}
} catch (error) {
return error
}
}
/**
* @name 获取
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async show(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, { _ucid });
return {
data: datas.keypair
}
} catch (error) {
return error
}
}
/**
* @name 创建
* @param {*} _ucid 用户id
* @param {*} body 需要提交的参数
*/
async create(_ucid, body) {
try {
const datas = await this.OSAJax(`${this.actions}`, {
_ucid,
method: 'POST',
body: {
'keypair': {
...body,
}
}
});
return {
...!!datas.conflictingRequest ? { code: 422, message: `密钥对名称为:${body.name}的密钥对已存在` } : { data: datas }
}
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} keypair_name 密钥对名称
*/
async destroy(_ucid, keypair_name) {
try {
const datas = await this.OSAJax(`${this.actions}/${keypair_name}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
code: datas.status,
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}

module.exports = ComputeKeypairService;

egg.js+mongodb+openstack 公有云计费系统(三)OpenStack 对接 blcokStorage(2)

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

磁盘相关
控制器'use strict';

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

class OPBlcokStorageVolumeController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QMFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
this.volumeSERVICE = ctx.service.openstack.blcokStorage.volume;
};
/**
* @name 磁盘列表
*
* @param {String} detail 不需要参数
*
* ----------------------------------- 分页 -------------------------------------
*
* @param {String} limit 分页>>条数/页
* @param {String} marker markerID(上页最后条id)
*
* ----------------------------------- 排序 -------------------------------------
*
* @param {String} sort_dir a|b 排序方式 ['asc':default,'desc']
* @param {String} sort_key 排序字段 [status,name,created_at]
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume?{detail}
*
*/
async index() {
const { ctx } = this;
const RESULT = await this.volumeMODEL.getUsers(this.auth.id, this.QMFN({...ctx.query }));
ctx.body = RESULT;
};
/**
* @name 获取单一磁盘
*
* @description
*
* @example GET /openstack/blcokstorage/volume/{id}
*
*/
async show() {
const ctx = this.ctx;
// const datas = await this.volumeSERVICE.show(ctx.params.id, this.auth.id);
// ctx.body = datas;
const RESULT = await this.volumeMODEL.getOne(this.auth.id, ctx.params.id, ctx.isAdmin())
ctx.body = RESULT;
};
/**
* @name 创建磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async create() {
const { ctx } = this;
const { availability_zone, snapshot_id, backup_id, imageRef, size = 5, volume_type = "hdd" } = ctx.request.body;
const BODYS = this.DUFN({ availability_zone, snapshot_id, backup_id, imageRef, size, volume_type })
const datas = await this.volumeMODEL.createOne(this.auth.id, BODYS)
ctx.body = datas
};
/**
* @name 调整磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async update() {
const ctx = this.ctx;
const BODYS = ctx.request.body;
const { action, name } = BODYS;
delete BODYS.action;
const datas = !!action ? await this.volumeSERVICE.action(this.auth.id, this.auth.ProjectID, ctx.params.id, action, BODYS) : await this.serverSERVICE.update(ctx.params.id, this.auth.id, this.DUFn({ name }));
ctx.body = datas
};
/**
* @name 删除磁盘
*
* @description
*
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.volumeSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = DATAS
}

}

module.exports = OPBlcokStorageVolumeController;modelmodule.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
helper,
service
} = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const OSblockStorageVolumeSchema = new Schema({
// 配置
config: {},
// 公司id
_comp: {
type: Schema.Types.ObjectId,
ref: 'Company',
required: true,
index: true
},
// 支付方式
payment: {
type: String,
default: 'prepay'
},
// 到期时间
endTime: {
type: Date
},
// 后台备注描述
_description: {

},
// 源信息
_metadata: {
type: String,
index: true
},
/*---------------------------------------------------*/
"status": {
type: 'String',
default: 'creating'
},
"migration_status": {},
"user_id": {},
"attachments": ,
"availability_zone": {},
"bootable": {},
"encrypted": {},
"created_at": {},
"description": {},
"updated_at": {},
"volume_type": {},
"name": {},
"replication_status": {},
"consistencygroup_id": {},
"source_volid": {},
"imageRef": {},
"backup_id": {},
"snapshot_id": {},
"multiattach": {},
"metadata": {},
"id": {
type: String,
index: true
},
"size": {},
"os-vol-host-attr:host": {},
"os-vol-tenant-attr:tenant_id": {}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSblockStorageVolumeSchema.statics = {
getUsers: async function(_comp, queryMix) {
const serverSERVICE = ctx.service.openstack.server.servers;
const {
querys,
select,
sort,
limit,
marker
} = queryMix;
const withDetail = querys.detail === '' || querys.detail;
delete querys.detail;
let QUERTS = {};
for (const key in querys) {
QUERTS[key] = eval(`/${querys[key]}.*/i`)
}
const MODELS = (count = false) => this.find({
_comp,
...QUERTS,
...(marker && !count && {
'_id': {
"$lt": marker
}
}),
}, {
...select,
}, {
...!count && {
limit
},
'sort': {
_id: -1,
...sort
}
});
try {
const datas = await MODELS()
return {
data: {
result: datas,
limit,
marker: datas.length ? [...datas].pop()._id : '',
totalCount: await MODELS(true).count()
}
}
} catch (error) {
return error
}
},
/**
* @name 创建硬盘
* @param {*} _id
* @param {*} body
*/
createOne: async function(_id, bodys) {
try {
const {
endTime,
payment,
_metadata
} = bodys;
delete bodys._metadata;
delete bodys.endTime;
delete bodys.payment;
//
const DATAS = await service.openstack.blcokStorage.volume.create(_id, {
...bodys,
... {
"name": `volume-${Math.random().toString(36).slice(2, 8)}`
}
});
const {
id: _openstack_id
} = DATAS.data.volume;
!!DATAS.data.volume && await ctx.model.Schedule.Openstack.Volume.addOne({
_comp: _id,
_openstack_id,
type: 'volume',
active: 'creating',
_metadata
})
return !!DATAS.data.volume ? {
data: await this.create({
_comp: _id,
endTime,
payment,
_metadata,
...DATAS.data.volume
})
} : {
'code': 422,
'message': '创建失败'
};
} catch (error) {
return error
}
},
// 获取全部
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,
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return {
data: {
result: await MODELS,
totalCount: await MODELS.count()
}
};
},
// 查看单个
getOne: async function(_comp, id, isAdmin) {
const MODELS = this.findOne({...isAdmin ? {
id
} : {
_comp,
id
}
});
try {
const RESULT = await MODELS;
return {
data: RESULT
}
} catch (error) {
return error
}
},
// 绑定到磁盘
/**
* @name 绑定到磁盘
* @param {*} _comp 用户UUID
* @param {*} id 磁盘ID
* @param {*} type 'bind'|'unbind' 绑定方式
*/
bindToECS: async function({
_comp,
id,
type = "bind"
} = {}, bodys) {
const MODEL = this.findOneAndUpdate({
_comp,
id
}, {
'attachments': type === 'bind' ? [bodys] : ,
'status': type === 'bind' ? 'in-use' : 'available'
});
try {
const datas = await MODEL;
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_block_storage_volume', OSblockStorageVolumeSchema)
}service'use strict';
const ServerIndex = require('../index')
//
class VolumeService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default;
this.actions = ':8776/v3';
};
// 获取磁盘列表
async list(querys, _ucid, project_id, isAdmin) {
try {
const detail = Object.keys(querys).includes('detail');
delete querys.detail;
let SORT = {}
if (querys.sort_key) {
SORT = { 'sort': `${querys.sort_key}:${querys.sort_dir}` };
delete querys.sort_key;
delete querys.sort_dir;
}
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : project_id}/volumes${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: {
...querys,
...querys.sort_key && SORT,
...isAdmin && { 'all_tenants': true },
},
});
return {
data: {
result: datas.volumes.map(e => {
!!detail && e.attachments.length && (e.attachment = e.attachments[0].server_id)
delete e.links;
delete e.attachments;
return e
}).filter(e => e.status != 'deleting'),
totalCount: datas.volumes.length
}
};
} catch (error) {
return error
}
}
// 获取磁盘详情
async show(id, _ucid, _description) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes/${id}`, {
..._ucid !== 'admin' && { _ucid }
});
return _ucid === 'admin' ? { ...datas.volume, _description } : { data: datas.volume };
} catch (error) {
return error
}
}
// 创建磁盘
async create(_ucid, bodys, order = "false") {
const DATAS = this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes`, {
body: {
'volume': {
... {
"availability_zone": null,
"source_volid": null,
"description": null,
"multiattach": false,
"snapshot_id": null,
"backup_id": null,
"imageRef": null,
"metadata": {},
"consistencygroup_id": null
},
...bodys
}
},
method: 'POST',
_ucid
});
try {
const datas = await DATAS
return !!order ? { data: datas } : datas
} catch (error) {
return error
}

}
// 删除磁盘
async destroy(_ucid, project_id, volume_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
...datas.status === 404 && {
message: `${volume_id}不存在或已删除`
}
}
} catch (error) {

}
}
// 磁盘操作
// {'os-extend':'磁盘扩容','revert':'镜像回滚'}
async action(_ucid, project_id, volume_id, type, bodys) {
const isIn = (e) => ['os-extend', 'revert'].includes(e);
if (!isIn(type)) return { code: 422 };
const actionMAP = (e) => {
const OBJ = {};
OBJ[e] = !bodys ? null : bodys;
return OBJ;
}
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
body: actionMAP(type),
method: 'POST',
_ucid, full: true
});
return {
code: DATAS.status
}
} catch (error) {
return error
}
}
async update(_ucid, project_id, volume_id, bodys) {
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
bodys: {
...bodys
},
method: 'PUT'
});
return {
data: DATAS
}
} catch (error) {
return error
}
}
}
module.exports = VolumeService;
scheduleconst Subscription = require('egg').Subscription;

class getVolumeStatus extends Subscription {
constructor(ctx) {
super(ctx);
this.SERVICE = ctx.service.openstack.blcokStorage.volume;
this.MODELS = ctx.model.Schedule.Openstack.Volume;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
}
static get schedule() {
return {
interval: '10s',
type: 'worker',
};
}
async subscribe() {
const ctx = this.ctx;
const lists = await this.MODELS.getALL();
if (lists.length) {
const datas = await this.checkItem(lists);
}
}
async checkItem(result) {
// 调取记录
const checkFN = result.map(e => {
// 记录尝试次数
this.MODELS.retry(e._openstack_id)
return this.SERVICE.show(e._openstack_id, 'admin', e);
})
let DATAS = await Promise.all(checkFN);
// 检查ACTION
if (!!DATAS.length) {
const endOrder = DATAS.map(e => {
const { _comp, _openstack_id: id } = e._description;
delete e._description
delete e.links
if (e.status === 'available' || e.status === 'in-use') {
return this.volumeMODEL.findOneAndUpdate({ id }, { ...e });
}
})
DATAS = await Promise.all(endOrder);
};
// 清除已完成任务
if (DATAS.length) {
const clearSchedule = DATAS.map(e => {
if (!!e) {
const { id: _openstack_id } = e;
return this.MODELS.deleteOne({ '_openstack_id': _openstack_id })
}
})
DATAS = await Promise.all(clearSchedule);
}
}
}

module.exports = getVolumeStatus;
schedule model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const scheduleOSVolumeSchema = new Schema({
// 类型
type: {
type: String,
},
// 尝试次数
retry: {
type: Number,
dafault: 0
},
// 是否创建成功
status: {
type: Boolean,
default: false
},
// 操作方式 [BUILD:创建,DELETE:删除]
active: {
type: String,
},
// 数据ID
_openstack_id: {
type: String,
index: true
},
// 公司ID
_comp: {
type: String
},
// 其他配置参数
/**
* ecs:Number
*/
_description: {

},
// 其他配置元信息
_metadata: {

}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
scheduleOSVolumeSchema.statics = {
getALL: async function (limit = 50) {
const MODEL = this.find().limit(limit);
try {
return await MODEL;
} catch (error) {
return error
}
},
addOne: async function (bodys) {
const MODEL = this.create({ ...bodys });
try {
const result = await MODEL;
return { code: !!result ? 201 : 404 }
} catch (error) {
return error
}
},
// destroyOne: async function (id) {
// const MODEL = this.deleteOne(id);
// try {
// const result = await MODEL
// return result
// } catch (error) {
// return error
// }
// },
retry: async function (_openstack_id) {
const MODEL = this.findOneAndUpdate({ _openstack_id }, {
'$inc': { retry: 1 }
});
try {
await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('schedule_openstack_volume', scheduleOSVolumeSchema);
} 查看全部
磁盘相关
控制器
'use strict';

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

class OPBlcokStorageVolumeController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QMFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
this.volumeSERVICE = ctx.service.openstack.blcokStorage.volume;
};
/**
* @name 磁盘列表
*
* @param {String} detail 不需要参数
*
* ----------------------------------- 分页 -------------------------------------
*
* @param {String} limit 分页>>条数/页
* @param {String} marker markerID(上页最后条id)
*
* ----------------------------------- 排序 -------------------------------------
*
* @param {String} sort_dir a|b 排序方式 ['asc':default,'desc']
* @param {String} sort_key 排序字段 [status,name,created_at]
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume?{detail}
*
*/
async index() {
const { ctx } = this;
const RESULT = await this.volumeMODEL.getUsers(this.auth.id, this.QMFN({...ctx.query }));
ctx.body = RESULT;
};
/**
* @name 获取单一磁盘
*
* @description
*
* @example GET /openstack/blcokstorage/volume/{id}
*
*/
async show() {
const ctx = this.ctx;
// const datas = await this.volumeSERVICE.show(ctx.params.id, this.auth.id);
// ctx.body = datas;
const RESULT = await this.volumeMODEL.getOne(this.auth.id, ctx.params.id, ctx.isAdmin())
ctx.body = RESULT;
};
/**
* @name 创建磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async create() {
const { ctx } = this;
const { availability_zone, snapshot_id, backup_id, imageRef, size = 5, volume_type = "hdd" } = ctx.request.body;
const BODYS = this.DUFN({ availability_zone, snapshot_id, backup_id, imageRef, size, volume_type })
const datas = await this.volumeMODEL.createOne(this.auth.id, BODYS)
ctx.body = datas
};
/**
* @name 调整磁盘
*
* @description
*
* @example POST /openstack/blcokstorage/volume
*
* @param {String} size 大小
* @param {String} availability_zone Optional 可用区域
* @param {String} snapshot_id Optional 快照ID FN从快照创建
* @param {String} backup_id Optional 备份ID FN从备份创建
* @param {String} imageRef Optional 镜像ID FN从镜像创建
* @param {String} volume_type Optional 磁盘类型 默认HDD
*
*/
async update() {
const ctx = this.ctx;
const BODYS = ctx.request.body;
const { action, name } = BODYS;
delete BODYS.action;
const datas = !!action ? await this.volumeSERVICE.action(this.auth.id, this.auth.ProjectID, ctx.params.id, action, BODYS) : await this.serverSERVICE.update(ctx.params.id, this.auth.id, this.DUFn({ name }));
ctx.body = datas
};
/**
* @name 删除磁盘
*
* @description
*
*/
async destroy() {
const ctx = this.ctx;
const DATAS = await this.volumeSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = DATAS
}

}

module.exports = OPBlcokStorageVolumeController;
model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const {
helper,
service
} = app.createAnonymousContext();
const {
NumToStr
} = ctx.helper;
const OSblockStorageVolumeSchema = new Schema({
// 配置
config: {},
// 公司id
_comp: {
type: Schema.Types.ObjectId,
ref: 'Company',
required: true,
index: true
},
// 支付方式
payment: {
type: String,
default: 'prepay'
},
// 到期时间
endTime: {
type: Date
},
// 后台备注描述
_description: {

},
// 源信息
_metadata: {
type: String,
index: true
},
/*---------------------------------------------------*/
"status": {
type: 'String',
default: 'creating'
},
"migration_status": {},
"user_id": {},
"attachments": ,
"availability_zone": {},
"bootable": {},
"encrypted": {},
"created_at": {},
"description": {},
"updated_at": {},
"volume_type": {},
"name": {},
"replication_status": {},
"consistencygroup_id": {},
"source_volid": {},
"imageRef": {},
"backup_id": {},
"snapshot_id": {},
"multiattach": {},
"metadata": {},
"id": {
type: String,
index: true
},
"size": {},
"os-vol-host-attr:host": {},
"os-vol-tenant-attr:tenant_id": {}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSblockStorageVolumeSchema.statics = {
getUsers: async function(_comp, queryMix) {
const serverSERVICE = ctx.service.openstack.server.servers;
const {
querys,
select,
sort,
limit,
marker
} = queryMix;
const withDetail = querys.detail === '' || querys.detail;
delete querys.detail;
let QUERTS = {};
for (const key in querys) {
QUERTS[key] = eval(`/${querys[key]}.*/i`)
}
const MODELS = (count = false) => this.find({
_comp,
...QUERTS,
...(marker && !count && {
'_id': {
"$lt": marker
}
}),
}, {
...select,
}, {
...!count && {
limit
},
'sort': {
_id: -1,
...sort
}
});
try {
const datas = await MODELS()
return {
data: {
result: datas,
limit,
marker: datas.length ? [...datas].pop()._id : '',
totalCount: await MODELS(true).count()
}
}
} catch (error) {
return error
}
},
/**
* @name 创建硬盘
* @param {*} _id
* @param {*} body
*/
createOne: async function(_id, bodys) {
try {
const {
endTime,
payment,
_metadata
} = bodys;
delete bodys._metadata;
delete bodys.endTime;
delete bodys.payment;
//
const DATAS = await service.openstack.blcokStorage.volume.create(_id, {
...bodys,
... {
"name": `volume-${Math.random().toString(36).slice(2, 8)}`
}
});
const {
id: _openstack_id
} = DATAS.data.volume;
!!DATAS.data.volume && await ctx.model.Schedule.Openstack.Volume.addOne({
_comp: _id,
_openstack_id,
type: 'volume',
active: 'creating',
_metadata
})
return !!DATAS.data.volume ? {
data: await this.create({
_comp: _id,
endTime,
payment,
_metadata,
...DATAS.data.volume
})
} : {
'code': 422,
'message': '创建失败'
};
} catch (error) {
return error
}
},
// 获取全部
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,
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return {
data: {
result: await MODELS,
totalCount: await MODELS.count()
}
};
},
// 查看单个
getOne: async function(_comp, id, isAdmin) {
const MODELS = this.findOne({...isAdmin ? {
id
} : {
_comp,
id
}
});
try {
const RESULT = await MODELS;
return {
data: RESULT
}
} catch (error) {
return error
}
},
// 绑定到磁盘
/**
* @name 绑定到磁盘
* @param {*} _comp 用户UUID
* @param {*} id 磁盘ID
* @param {*} type 'bind'|'unbind' 绑定方式
*/
bindToECS: async function({
_comp,
id,
type = "bind"
} = {}, bodys) {
const MODEL = this.findOneAndUpdate({
_comp,
id
}, {
'attachments': type === 'bind' ? [bodys] : ,
'status': type === 'bind' ? 'in-use' : 'available'
});
try {
const datas = await MODEL;
} catch (error) {
return error
}
}
}
return mongoose.model('openstack_block_storage_volume', OSblockStorageVolumeSchema)
}
service
'use strict';
const ServerIndex = require('../index')
//
class VolumeService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default;
this.actions = ':8776/v3';
};
// 获取磁盘列表
async list(querys, _ucid, project_id, isAdmin) {
try {
const detail = Object.keys(querys).includes('detail');
delete querys.detail;
let SORT = {}
if (querys.sort_key) {
SORT = { 'sort': `${querys.sort_key}:${querys.sort_dir}` };
delete querys.sort_key;
delete querys.sort_dir;
}
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : project_id}/volumes${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: {
...querys,
...querys.sort_key && SORT,
...isAdmin && { 'all_tenants': true },
},
});
return {
data: {
result: datas.volumes.map(e => {
!!detail && e.attachments.length && (e.attachment = e.attachments[0].server_id)
delete e.links;
delete e.attachments;
return e
}).filter(e => e.status != 'deleting'),
totalCount: datas.volumes.length
}
};
} catch (error) {
return error
}
}
// 获取磁盘详情
async show(id, _ucid, _description) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes/${id}`, {
..._ucid !== 'admin' && { _ucid }
});
return _ucid === 'admin' ? { ...datas.volume, _description } : { data: datas.volume };
} catch (error) {
return error
}
}
// 创建磁盘
async create(_ucid, bodys, order = "false") {
const DATAS = this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/volumes`, {
body: {
'volume': {
... {
"availability_zone": null,
"source_volid": null,
"description": null,
"multiattach": false,
"snapshot_id": null,
"backup_id": null,
"imageRef": null,
"metadata": {},
"consistencygroup_id": null
},
...bodys
}
},
method: 'POST',
_ucid
});
try {
const datas = await DATAS
return !!order ? { data: datas } : datas
} catch (error) {
return error
}

}
// 删除磁盘
async destroy(_ucid, project_id, volume_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
...datas.status === 404 && {
message: `${volume_id}不存在或已删除`
}
}
} catch (error) {

}
}
// 磁盘操作
// {'os-extend':'磁盘扩容','revert':'镜像回滚'}
async action(_ucid, project_id, volume_id, type, bodys) {
const isIn = (e) => ['os-extend', 'revert'].includes(e);
if (!isIn(type)) return { code: 422 };
const actionMAP = (e) => {
const OBJ = {};
OBJ[e] = !bodys ? null : bodys;
return OBJ;
}
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
body: actionMAP(type),
method: 'POST',
_ucid, full: true
});
return {
code: DATAS.status
}
} catch (error) {
return error
}
}
async update(_ucid, project_id, volume_id, bodys) {
try {
const DATAS = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}`, {
_ucid,
bodys: {
...bodys
},
method: 'PUT'
});
return {
data: DATAS
}
} catch (error) {
return error
}
}
}
module.exports = VolumeService;

schedule
const Subscription = require('egg').Subscription;

class getVolumeStatus extends Subscription {
constructor(ctx) {
super(ctx);
this.SERVICE = ctx.service.openstack.blcokStorage.volume;
this.MODELS = ctx.model.Schedule.Openstack.Volume;
this.volumeMODEL = ctx.model.Openstack.BlcokStorage.Volumes;
}
static get schedule() {
return {
interval: '10s',
type: 'worker',
};
}
async subscribe() {
const ctx = this.ctx;
const lists = await this.MODELS.getALL();
if (lists.length) {
const datas = await this.checkItem(lists);
}
}
async checkItem(result) {
// 调取记录
const checkFN = result.map(e => {
// 记录尝试次数
this.MODELS.retry(e._openstack_id)
return this.SERVICE.show(e._openstack_id, 'admin', e);
})
let DATAS = await Promise.all(checkFN);
// 检查ACTION
if (!!DATAS.length) {
const endOrder = DATAS.map(e => {
const { _comp, _openstack_id: id } = e._description;
delete e._description
delete e.links
if (e.status === 'available' || e.status === 'in-use') {
return this.volumeMODEL.findOneAndUpdate({ id }, { ...e });
}
})
DATAS = await Promise.all(endOrder);
};
// 清除已完成任务
if (DATAS.length) {
const clearSchedule = DATAS.map(e => {
if (!!e) {
const { id: _openstack_id } = e;
return this.MODELS.deleteOne({ '_openstack_id': _openstack_id })
}
})
DATAS = await Promise.all(clearSchedule);
}
}
}

module.exports = getVolumeStatus;

schedule model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const scheduleOSVolumeSchema = new Schema({
// 类型
type: {
type: String,
},
// 尝试次数
retry: {
type: Number,
dafault: 0
},
// 是否创建成功
status: {
type: Boolean,
default: false
},
// 操作方式 [BUILD:创建,DELETE:删除]
active: {
type: String,
},
// 数据ID
_openstack_id: {
type: String,
index: true
},
// 公司ID
_comp: {
type: String
},
// 其他配置参数
/**
* ecs:Number
*/
_description: {

},
// 其他配置元信息
_metadata: {

}
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
scheduleOSVolumeSchema.statics = {
getALL: async function (limit = 50) {
const MODEL = this.find().limit(limit);
try {
return await MODEL;
} catch (error) {
return error
}
},
addOne: async function (bodys) {
const MODEL = this.create({ ...bodys });
try {
const result = await MODEL;
return { code: !!result ? 201 : 404 }
} catch (error) {
return error
}
},
// destroyOne: async function (id) {
// const MODEL = this.deleteOne(id);
// try {
// const result = await MODEL
// return result
// } catch (error) {
// return error
// }
// },
retry: async function (_openstack_id) {
const MODEL = this.findOneAndUpdate({ _openstack_id }, {
'$inc': { retry: 1 }
});
try {
await MODEL
} catch (error) {
return error
}
}
}
return mongoose.model('schedule_openstack_volume', scheduleOSVolumeSchema);
}

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

Nodejslopo1983 发表了文章 • 0 个评论 • 231 次浏览 • 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 个评论 • 279 次浏览 • 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;