mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-21 06:33:18 +00:00
Multiple improvements regarding ACLs
This commit is contained in:
@@ -1,51 +1,183 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function Acl(folder_id) {
|
||||
this.folder_id = folder_id;
|
||||
/**
|
||||
* @name Acl
|
||||
* @constructor
|
||||
* @param {String} folderId - the folder ID associated to the ACLs
|
||||
*/
|
||||
function Acl(folderId) {
|
||||
this.folderId = folderId;
|
||||
}
|
||||
|
||||
/* The factory we'll use to register with Angular */
|
||||
Acl.factory = ['sgSettings', 'sgResource', function(Settings, Resource) {
|
||||
/**
|
||||
* @memberof Acl
|
||||
* @desc The factory we'll use to register with Angular.
|
||||
* @return the Acl constructor
|
||||
*/
|
||||
Acl.factory = ['$q', '$timeout', 'sgSettings', 'sgResource', 'sgUser', function($q, $timeout, Settings, Resource, User) {
|
||||
angular.extend(Acl, {
|
||||
$$resource: new Resource(Settings.baseURL)
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
$$resource: new Resource(Settings.baseURL),
|
||||
$User: User
|
||||
});
|
||||
|
||||
return Acl; // return constructor
|
||||
return Acl;
|
||||
}];
|
||||
|
||||
/* Factory registration in Angular module */
|
||||
/**
|
||||
* @module SOGo.Common
|
||||
* @desc Factory registration of User in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.Common').factory('sgAcl', Acl.factory);
|
||||
|
||||
/* Instance methods
|
||||
* Public method, assigned to prototype
|
||||
/**
|
||||
* @function $users
|
||||
* @memberof Acl.prototype
|
||||
* @desc Fetch the list of users that have specific rights for the current folder.
|
||||
* @return a promise of an array of User objects
|
||||
*/
|
||||
Acl.prototype.$userRights = function(uid) {
|
||||
var param = {"uid": uid};
|
||||
return Acl.$$resource.fetch(this.folder_id, "userRights", param);
|
||||
};
|
||||
|
||||
Acl.prototype.$addUser = function(uid) {
|
||||
var param = {"uid": uid};
|
||||
return Acl.$$resource.fetch(this.folder_id, "addUserInAcls", param);
|
||||
};
|
||||
|
||||
Acl.prototype.$removeUser = function(uid) {
|
||||
var param = {"uid": uid};
|
||||
return Acl.$$resource.fetch(this.folder_id, "removeUserFromAcls", param);
|
||||
};
|
||||
|
||||
Acl.prototype.$saveUsersRights = function(dirtyObjects) {
|
||||
var param = {"action": "saveUserRights"};
|
||||
return Acl.$$resource.save(this.folder_id, dirtyObjects, param);
|
||||
};
|
||||
|
||||
Acl.prototype.$subscribeUsers = function(uids) {
|
||||
var param = {"uids": uids};
|
||||
return Acl.$$resource.fetch(this.folder_id, "subscribeUsers", param);
|
||||
};
|
||||
|
||||
Acl.prototype.$users = function() {
|
||||
return Acl.$$resource.fetch(this.folder_id, "acls");
|
||||
var _this = this,
|
||||
deferred = Acl.$q.defer(),
|
||||
user;
|
||||
if (this.users) {
|
||||
deferred.resolve(this.users);
|
||||
}
|
||||
else {
|
||||
return Acl.$$resource.fetch(this.folderId, 'acls').then(function(users) {
|
||||
_this.users = [];
|
||||
// console.debug(JSON.stringify(users, undefined, 2));
|
||||
angular.forEach(users, function(data) {
|
||||
user = new Acl.$User(data);
|
||||
user.canSubscribeUser = user.isSubscribed;
|
||||
user.wasSubscribed = user.isSubscribed;
|
||||
user.$rights = angular.bind(user, user.$acl, _this.folderId);
|
||||
_this.users.push(user);
|
||||
});
|
||||
deferred.resolve(_this.users);
|
||||
return _this.users;
|
||||
});
|
||||
}
|
||||
return deferred.promise;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* @function $addUser
|
||||
* @memberof Acl.prototype
|
||||
* @param {Object} user - a User object with minimal set of attributes (uid, isGroup, cn, c_email)
|
||||
* @see {@link User.$filter}
|
||||
*/
|
||||
Acl.prototype.$addUser = function(user) {
|
||||
var _this = this,
|
||||
deferred = Acl.$q.defer(),
|
||||
param = {uid: user.uid};
|
||||
if (!user.uid || _.indexOf(_.pluck(this.users, 'uid'), user.uid) > -1) {
|
||||
// No UID specified or user already in ACLs
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
Acl.$$resource.fetch(this.folderId, 'addUserInAcls', param).then(function() {
|
||||
user.wasSubscribed = false;
|
||||
user.userClass = user.isGroup ? 'group-user' : 'normal-user';
|
||||
user.$rights = angular.bind(user, user.$acl, _this.folderId);
|
||||
_this.users.push(user);
|
||||
deferred.resolve(_this.users);
|
||||
}, function(data, status) {
|
||||
deferred.reject(l('An error occured please try again.'));
|
||||
});
|
||||
}
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $removeUser
|
||||
* @memberof Acl.prototype
|
||||
* @desc Remove a user from the folder's ACL
|
||||
* @return a promise of the server call to remove the user from the folder's ACL
|
||||
*/
|
||||
Acl.prototype.$removeUser = function(uid) {
|
||||
var _this = this,
|
||||
param = {uid: uid};
|
||||
return Acl.$$resource.fetch(this.folderId, 'removeUserFromAcls', param).then(function() {
|
||||
var i = _.indexOf(_.pluck(_this.users, 'uid'), uid);
|
||||
if (i >= 0) {
|
||||
_this.users.splice(i, 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $resetUsersRights
|
||||
* @memberof Acl.prototype
|
||||
* @desc Restore initial rights of all users.
|
||||
*/
|
||||
Acl.prototype.$resetUsersRights = function() {
|
||||
angular.forEach(this.users, function(user) {
|
||||
user.$resetRights();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $saveUsersRights
|
||||
* @memberof Acl.prototype
|
||||
* @desc Save user rights that have changed and subscribe users that have been selected.
|
||||
* @return a promise that resolved only if the modifications and subscriptions were successful
|
||||
*/
|
||||
Acl.prototype.$saveUsersRights = function() {
|
||||
var _this = this,
|
||||
deferredSave = Acl.$q.defer(),
|
||||
deferredSubscribe = Acl.$q.defer(),
|
||||
param = {action: 'saveUserRights'},
|
||||
users = [];
|
||||
|
||||
// Save user rights
|
||||
angular.forEach(this.users, function(user) {
|
||||
if (user.$rightsAreDirty()) {
|
||||
users.push(user.$omit());
|
||||
// console.debug('save ' + JSON.stringify(user.$omit(), undefined, 2));
|
||||
}
|
||||
});
|
||||
if (users.length) {
|
||||
Acl.$$resource.save(this.folderId, users, param)
|
||||
.then(function() {
|
||||
// Save was successful; copy rights to shadow rights
|
||||
angular.forEach(_this.users, function(user) {
|
||||
if (user.$rightsAreDirty()) {
|
||||
user.$shadowRights = angular.copy(user.rights);
|
||||
}
|
||||
});
|
||||
deferredSave.resolve();
|
||||
}, deferredSave.reject);
|
||||
}
|
||||
else {
|
||||
deferredSave.resolve();
|
||||
}
|
||||
|
||||
// Subscribe users
|
||||
users = [];
|
||||
angular.forEach(this.users, function(user) {
|
||||
if (!user.wasSubscribed && user.isSubscribed) {
|
||||
users.push(user.uid);
|
||||
// console.debug('subscribe ' + user.uid);
|
||||
};
|
||||
});
|
||||
if (users.length) {
|
||||
param = {uids: users.join(',')};
|
||||
Acl.$$resource.fetch(this.folderId, 'subscribeUsers', param)
|
||||
.then(function() {
|
||||
// Subscribe was successful; reset "wasSubscribed" attribute
|
||||
angular.forEach(_this.users, function(user) {
|
||||
user.wasSubscribed = user.isSubscribed;
|
||||
});
|
||||
deferredSubscribe.resolve();
|
||||
}, deferredSubscribe.reject);
|
||||
}
|
||||
else {
|
||||
deferredSubscribe.resolve();
|
||||
}
|
||||
return Acl.$q.all([deferredSave.promise, deferredSubscribe.promise]);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/* Constructor */
|
||||
/**
|
||||
* @name Resource
|
||||
* @constructor
|
||||
* @param {Object} $http - the Angular HTTP service
|
||||
* @param {Object} $q - the Angular promise/deferred service
|
||||
* @param {String} path - the base path of the external resource
|
||||
* @param {Object} options - extra attributes to be associated to the object
|
||||
*/
|
||||
function Resource($http, $q, path, options) {
|
||||
angular.extend(this, {
|
||||
_http: $http,
|
||||
@@ -13,39 +20,40 @@
|
||||
angular.extend(this, options);
|
||||
}
|
||||
|
||||
/* The factory we'll use to register with Angular */
|
||||
/**
|
||||
* @memberof Resource
|
||||
* @desc The factory we'll use to register with Angular.
|
||||
* @return a new Resource object
|
||||
*/
|
||||
Resource.$factory = ['$http', '$q', function($http, $q) {
|
||||
return function(path, options) {
|
||||
return new Resource($http, $q, path, options);
|
||||
};
|
||||
}];
|
||||
|
||||
/* Factory registration in Angular module */
|
||||
/**
|
||||
* @module SOGo.Common
|
||||
* @desc Factory registration of Resource in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.Common').factory('sgResource', Resource.$factory);
|
||||
|
||||
/* Instance methods */
|
||||
|
||||
Resource.prototype.path = function(uid) {
|
||||
return (uid ? this._path + '/' + uid : this._path) + '/view';
|
||||
};
|
||||
|
||||
Resource.prototype.find = function(uid) {
|
||||
var deferred = this._q.defer();
|
||||
|
||||
this._http
|
||||
.get(this.path(uid))
|
||||
.success(deferred.resolve)
|
||||
.error(deferred.reject);
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Resource.prototype.filter = function(uid, params) {
|
||||
var deferred = this._q.defer();
|
||||
/**
|
||||
* @function fetch
|
||||
* @memberof Resource.prototype
|
||||
* @desc Fetch resource using a specific folder, action and/or parameters.
|
||||
* @param {string} folderId - the folder on which the action will be applied (ex: addressbook, calendar)
|
||||
* @param {string} action - the action to be used in the URL
|
||||
* @param {Object} params - Object parameters injected through the $http service
|
||||
* @return a promise
|
||||
*/
|
||||
Resource.prototype.fetch = function(folderId, action, params) {
|
||||
var deferred = this._q.defer(),
|
||||
path = [this._path, (folderId ? folderId : ''), (action ? action : '')];
|
||||
path = _.compact(path).join('/');
|
||||
|
||||
this._http({
|
||||
method: 'GET',
|
||||
url: this.path(uid),
|
||||
url: path,
|
||||
params: params
|
||||
})
|
||||
.success(deferred.resolve)
|
||||
@@ -54,9 +62,15 @@
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Resource.prototype.newguid = function(uid) {
|
||||
/**
|
||||
* @function newguid
|
||||
* @memberof Resource.prototype
|
||||
* @desc Fetch a new GUID on the specified folder ID.
|
||||
* @return a promise of the new data structure
|
||||
*/
|
||||
Resource.prototype.newguid = function(folderId) {
|
||||
var deferred = this._q.defer(),
|
||||
path = this._path + '/' + uid + '/newguid';
|
||||
path = this._path + '/' + folderId + '/newguid';
|
||||
|
||||
this._http
|
||||
.get(path)
|
||||
@@ -68,9 +82,11 @@
|
||||
|
||||
/**
|
||||
* @function create
|
||||
* @desc Create a new resource using a specific action
|
||||
* @memberof Resource.prototype
|
||||
* @desc Create a new resource using a specific action (post).
|
||||
* @param {string} action - the action to be used in the URL
|
||||
* @param {string} name - the new resource's name
|
||||
* @return a promise
|
||||
*/
|
||||
Resource.prototype.create = function(action, name) {
|
||||
var deferred = this._q.defer(),
|
||||
@@ -84,6 +100,12 @@
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function save
|
||||
* @memberof Resource.prototype
|
||||
* @desc Save a resource attributes on the server (post /save).
|
||||
* @return a promise
|
||||
*/
|
||||
Resource.prototype.save = function(id, newValue, options) {
|
||||
var deferred = this._q.defer(),
|
||||
action = (options && options.action)? options.action : 'save',
|
||||
@@ -97,6 +119,12 @@
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function remove
|
||||
* @memberof Resource.prototype
|
||||
* @desc Delete a resource (get /delete).
|
||||
* @return a promise
|
||||
*/
|
||||
Resource.prototype.remove = function(uid) {
|
||||
var deferred = this._q.defer(),
|
||||
path = this._path + '/' + uid + '/delete';
|
||||
@@ -109,26 +137,4 @@
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function fetch
|
||||
* @desc Fetch resources using a specific folder, action and/or parameters
|
||||
* @param {string} folder_id - the folder on which the action will be applied (ex: addressbook, calendar)
|
||||
* @param {string} action - the action to be used in the URL
|
||||
* @param {Object} params - Object parameters injected through the $http protocol
|
||||
*/
|
||||
Resource.prototype.fetch = function(folder_id, action, params) {
|
||||
var deferred = this._q.defer(),
|
||||
path = [this._path, (folder_id ? folder_id : ""), (action ? action : "")];
|
||||
path = _.compact(path).join("/");
|
||||
|
||||
this._http({
|
||||
method: 'GET',
|
||||
url: path,
|
||||
params: params
|
||||
})
|
||||
.success(deferred.resolve)
|
||||
.error(deferred.reject);
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,26 +1,188 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function User() {}
|
||||
/**
|
||||
* @name User
|
||||
* @constructor
|
||||
* @param {object} [userData] - some default values for the user
|
||||
*/
|
||||
function User(userData) {
|
||||
if (userData)
|
||||
angular.extend(this, userData);
|
||||
}
|
||||
|
||||
/* The factory we'll use to register with Angular */
|
||||
User.factory = ['sgSettings', 'sgResource', function(Settings, Resource) {
|
||||
/**
|
||||
* @memberof User
|
||||
* @desc The factory we'll use to register with Angular.
|
||||
* @return the User constructor
|
||||
*/
|
||||
User.factory = ['$q', 'sgSettings', 'sgResource', function($q, Settings, Resource) {
|
||||
angular.extend(User, {
|
||||
$q: $q,
|
||||
$$resource: new Resource(Settings.baseURL)
|
||||
});
|
||||
|
||||
return User; // return constructor
|
||||
return User;
|
||||
}];
|
||||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.Common').factory('User', User.factory);
|
||||
|
||||
/* Instance methods
|
||||
* Public method, assigned to prototype
|
||||
/**
|
||||
* @module SOGo.Common
|
||||
* @desc Factory registration of User in Angular module.
|
||||
*/
|
||||
User.prototype.$filter = function(search) {
|
||||
// return a collections of users for a filter
|
||||
angular.module('SOGo.Common').factory('sgUser', User.factory);
|
||||
|
||||
/**
|
||||
* @memberof User
|
||||
* @desc Search for users that match a string.
|
||||
* @param {String} search - a string used to performed the search
|
||||
* @return a promise of an array of matching User objects
|
||||
*/
|
||||
User.$filter = function(search) {
|
||||
var param = {search: search};
|
||||
return User.$$resource.fetch(null, "usersSearch", param);
|
||||
return User.$$resource.fetch(null, 'usersSearch', param).then(function(users) {
|
||||
var results = [];
|
||||
angular.forEach(users, function(data) {
|
||||
console.debug(JSON.stringify(data, undefined, 2));
|
||||
var user = new User(data);
|
||||
results.push(user);
|
||||
});
|
||||
return results;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $shortFormat
|
||||
* @memberof User.prototype
|
||||
* @return the fullname along with the email address
|
||||
*/
|
||||
User.prototype.$shortFormat = function() {
|
||||
var fullname = this.cn || this.c_email;
|
||||
if (this.c_email && fullname != this.c_email) {
|
||||
fullname += ' (' + this.c_email + ')';
|
||||
}
|
||||
return fullname;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $acl
|
||||
* @memberof User.prototype
|
||||
* @desc Fetch the user rights associated to a specific folder and populate the 'rights' attribute.
|
||||
* @param {String} the folder ID
|
||||
* @return a promise
|
||||
*/
|
||||
User.prototype.$acl = function(folderId) {
|
||||
var _this = this,
|
||||
deferred = User.$q.defer(),
|
||||
param = {uid: this.uid};
|
||||
if (this.$shadowRights) {
|
||||
deferred.resolve(this.rights);
|
||||
}
|
||||
else {
|
||||
User.$$resource.fetch(folderId, 'userRights', param).then(function(data) {
|
||||
_this.rights = data;
|
||||
// Convert numbers (0|1) to boolean values
|
||||
angular.forEach(_.keys(_this.rights), function(key) {
|
||||
_this.rights[key] = _this.rights[key] ? true : false;
|
||||
});
|
||||
// console.debug('rights ' + _this.uid + ' => ' + JSON.stringify(data, undefined, 2));
|
||||
// Keep a copy of the server's version
|
||||
_this.$shadowRights = angular.copy(data);
|
||||
deferred.resolve(data);
|
||||
return data;
|
||||
});
|
||||
}
|
||||
return deferred;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $isAnonymous
|
||||
* @memberof User.prototype
|
||||
* @return true if it's the special anonymous user
|
||||
*/
|
||||
User.prototype.$isAnonymous = function() {
|
||||
return this.uid == 'anonymous';
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $isSpecial
|
||||
* @memberof User.prototype
|
||||
* @return true if the user is not a regular system user
|
||||
*/
|
||||
User.prototype.$isSpecial = function() {
|
||||
return this.userClass && this.userClass == 'public-user';
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $confirmRights
|
||||
* @memberof User.prototype
|
||||
* @desc Check if a confirmation is required before giving some rights.
|
||||
* @return the confirmation message or false if no confirmation is required
|
||||
*/
|
||||
User.prototype.$confirmRights = function() {
|
||||
var confirmation = false;
|
||||
|
||||
if (this.$confirmation) {
|
||||
// Don't bother the user more than once
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_.some(_.values(this.rights))) {
|
||||
if (this.uid == 'anonymous') {
|
||||
confirmation = l('Potentially anyone on the Internet will be able to access your folder, even if they do not have an account on this system. Is this information suitable for the public Internet?');
|
||||
}
|
||||
else if (this.uid == '<default>') {
|
||||
confirmation = l('Any user with an account on this system will be able to access your folder. Are you certain you trust them all?');
|
||||
}
|
||||
}
|
||||
|
||||
this.$confirmation = confirmation;
|
||||
|
||||
return confirmation;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $rightsAreDirty
|
||||
* @memberof User.prototype
|
||||
* @return whether or not the rights have changed from their initial values
|
||||
*/
|
||||
User.prototype.$rightsAreDirty = function() {
|
||||
return this.rights && !_.isEqual(this.rights, this.$shadowRights);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $resetRights
|
||||
* @memberof User.prototype
|
||||
* @desc Restore initial rights or disable all rights
|
||||
* @param {Boolean} [zero] - reset all rights to zero when true
|
||||
*/
|
||||
User.prototype.$resetRights = function(zero) {
|
||||
var _this = this;
|
||||
if (zero) {
|
||||
// Disable all rights
|
||||
_.map(_.keys(this.rights), function(key) {
|
||||
_this.rights[key] = 0;
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Restore initial rights
|
||||
this.rights = angular.copy(this.$shadowRights);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $omit
|
||||
* @memberof User.prototype
|
||||
* @desc Return a sanitized object used to send to the server.
|
||||
* @return an object literal copy of the User instance
|
||||
*/
|
||||
User.prototype.$omit = function() {
|
||||
var user = {};
|
||||
angular.forEach(this, function(value, key) {
|
||||
if (key != 'constructor' && key[0] != '$') {
|
||||
user[key] = value;
|
||||
}
|
||||
});
|
||||
return user;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user