File: lib/role.js
"use strict";
var Errors = require("./errors");
var Query = require("./query");
var Operation = require("./operation");
var objectAssign = require('object-assign');
/**
* ロールについて扱うクラスです。
*
* ユーザや他のロール(子ロール)をまとめて権限管理を行うことができます。
* ユーザおよび子ロールの追加・削除はsave/update完了時に反映されます。
*
* ロールへのユーザもしくは子ロールの追加と削除を同時に行うことはできません。
* 追加・削除の設定を行い、保存前に他方を設定した場合、後に行った処理が上書きされます。
*
* ※注意:
* 2種類のメソッド(インスタンスメソッド Instance method とスタティックメソッド Static method)があります。
* それぞれリファレンス上の表記と利用時のメソッドが異なりますので、下記を参考にご利用ください。
*
* - リファレンス上の表記が「NCMB.Role#メソッド名」: インスタンスメソッド Instance method
* - 利用例)NCMB.Role#addUser
* ```
* var freePlanRole = new ncmb.Role("freePlan");
* freePlanRole.addUser(user);
* ```
* - リファレンス上の表記が「NCMB.RoleConstructor#メソッド名」: スタティックメソッド Static method
* - Roleの場合は、お客様に提供するスタティックメソッドはありません。
*
* @class NCMB.Role
* @extends {Operation}
* @param {string} roleName ロール名。インスタンス生成時に必須
* @param {Object} attrs インスタンス生成時に設定するプロパティ
*/
var Role = module.exports = function(ncmb){
var reserved = [
"save", "update", "delete", "className",
"addUser", "addRole", "removeUser", "removeRole",
"fetchUser", "fetchRole",
"belongUser","belongRole"];
var isReserved = function(key){
return reserved.indexOf(key) > -1;
};
var unreplaceable =[
"objectId", "createDate", "updateDate", "_id"
];
var isReplaceable = function(key){
if(unreplaceable.indexOf(key) === -1) return true;
return false;
};
function Role(roleName, attrs){
if(!roleName){
throw new Errors.NoRoleNameError("RoleName is required.");
}
if(roleName instanceof Object && roleName.roleName && typeof roleName.roleName === "string"){
attrs = roleName;
}else if(typeof roleName === "string"){
this.roleName = roleName;
}else{
throw new Errors.InvalidArgumentError("RoleName must be string.");
}
for(var attr in attrs){
if(attrs.hasOwnProperty(attr)){
if(!isReserved(attr)){
this[attr] = attrs[attr];
}
}
}
}
var className = Role.prototype.className = "/roles";
Object.keys(Query.prototype).forEach(function(attr){
if(typeof Query.prototype[attr] === "function"){
Role[attr] = function(){
var query = new Query(ncmb, className);
return query[attr].apply(query, [].slice.apply(arguments));
};
}
});
Object.keys(Operation.prototype).forEach(function(attr){
if(typeof Operation.prototype[attr] === "function"){
Role.prototype[attr] = function(){
var operation = new Operation(reserved);
return operation[attr].apply(this, [].slice.apply(arguments));
};
}
});
/**
* ロールを保存します。
*
* @method NCMB.Role#save
* @param {function} [callback] コールバック関数
* @return {Promise<this>}
*/
Role.prototype.save = function(callback){
return ncmb.request({
path: "/" + ncmb.version + this.className,
method: "POST",
data: this
}).then(function(data){
var obj = null;
try{
obj = JSON.parse(data);
}catch(err){
throw err;
}
objectAssign(this, obj);
Object.keys(this).forEach(function (key) {
if(this[key] && this[key].__op) delete this[key];
}.bind(this));
if(callback) return callback(null, this);
return this;
}.bind(this)).catch(function(err){
if(callback) return callback(err, null);
throw err;
});
};
/**
* ロールを更新します。
*
* @method NCMB.Role#update
* @param {function} [callback] コールバック関数
* @return {Promise<this>}
*/
Role.prototype.update = function(callback){
if(!this.objectId) {
return (callback || Promise.reject.bind(Promise))(new Errors.NoObjectIdError("Updated object must be saved before."));
}
var dataToUpdate = {};
Object.keys(this).forEach(function (key) {
if(!isReplaceable(key)) return;
dataToUpdate[key] = this[key];
}.bind(this));
return ncmb.request({
path: "/" + ncmb.version + this.className + "/" + this.objectId,
method: "PUT",
data: dataToUpdate
}).then(function(data){
var obj = null;
try{
obj = JSON.parse(data);
}catch(err){
throw err;
}
this.updateDate = obj.updateDate;
Object.keys(this).forEach(function (key) {
if(this[key] && this[key].__op) delete this[key];
}.bind(this));
if(callback) return callback(null, this);
return this;
}.bind(this)).catch(function(err){
if(callback) return callback(err, null);
throw err;
});
};
/**
* ロールを削除します。
*
* @method NCMB.Role#delete
* @param {function} [callback] コールバック関数
* @return {Promise<true>}
*/
Role.prototype.delete = function(callback){
if(!this.objectId){
var err = new Errors.NoObjectIdError("Deleted object must be saved before.");
return callback ? callback(err) : Promise.reject(err);
}
return ncmb.request({
path: "/" + ncmb.version + this.className + "/" + this.objectId,
method: "DEL"
}).then(function(){
if(callback) return callback(null, true);
return true;
}).catch(function(err){
if(callback) return callback(err, null);
throw err;
});
};
/**
* ロールにユーザを追加します。
*
* @method NCMB.Role#addUser
* @param {User|Array<User>} object 追加するユーザ
* @return {this}
*/
/**
* ロールに子ロールを追加します。
*
* @method NCMB.Role#addRole
* @param {Role|Array<Role>} object 追加する子ロール
* @return {this}
*/
/**
* ロールからユーザを削除します。
*
* @method NCMB.Role#removeUser
* @param {User} object 削除するユーザ
* @return {this}
*/
/**
* ロールから子ロールを削除します。
*
* @method NCMB.Role#removeRole
* @param {Role} object 削除する子ロール
* @return {this}
*/
/**
* ロールに登録されているユーザの一覧を取得します。
*
* @method NCMB.Role#fetchUser
* @param {function} [callback] コールバック関数
* @return {Promise<Array<User>>} ユーザインスタンスの配列
*/
/**
* ロールに登録されている子ロールの一覧を取得します。
*
* @method NCMB.Role#fetchRole
* @param {function} [callback] コールバック関数
* @return {Promise<Array<Role>>} 子ロールインスタンスの配列
*/
["user", "role"].forEach(function(classname){
var upper = classname[0].toUpperCase() + classname.substr(1);
var key = "belong" + upper;
["add", "remove"].forEach(function(method){
var methodName = method + upper;
Role.prototype[methodName] = function(object){
if(this[key] instanceof ncmb.Relation){
this[key][method](object);
return this;
}
this[key] = new ncmb.Relation(classname)[method](object);
return this;
};
});
var fetchName = "fetch" + upper;
Role.prototype[fetchName] = function(callback){
return ncmb[upper].relatedTo(this,key).fetchAll(callback);
};
});
ncmb.collections[className] = Role;
return Role;
};
/**
* @interface NCMB.RoleConstructor
* @extends Query<Role>
*/
/**
* @method
* @name NCMB.RoleConstructor#new
* @param {string} roleName ロール名。インスタンス生成時に必須
* @param {Object} [attrs] インスタンス生成時に設定するプロパティ
* @return {NCMB.Role}
*/