(feat) first pass of working code for ACL admin module
parent
ad40bff91f
commit
4f4b00cc54
|
@ -12,6 +12,7 @@ AdministrationUI_OBJC_FILES = \
|
|||
AdministrationUIProduct.m \
|
||||
\
|
||||
UIxAdministration.m \
|
||||
UIxAdministrationAclEditor.m \
|
||||
UIxAdministrationFilterPanel.m
|
||||
|
||||
AdministrationUI_RESOURCE_FILES += \
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* UIxAdministrationAclEditor.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2014 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef UIXACLEDITOR_H
|
||||
#define UIXACLEDITOR_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
|
||||
@interface UIxAdministrationAclEditor : UIxComponent
|
||||
{
|
||||
BOOL prepared;
|
||||
BOOL publishInFreeBusy;
|
||||
NSArray *aclUsers;
|
||||
NSArray *savedUIDs;
|
||||
NSMutableDictionary *users;
|
||||
NSString *currentUser;
|
||||
NSString *defaultUserID;
|
||||
}
|
||||
|
||||
- (NSArray *) aclsForObject;
|
||||
- (void) setCurrentUser: (NSString *) newCurrentUser;
|
||||
- (NSString *) currentUser;
|
||||
- (NSString *) currentUserClass;
|
||||
- (NSDictionary *) currentUserInfos;
|
||||
- (NSString *) currentUserDisplayName;
|
||||
- (BOOL) currentUserIsSubscribed;
|
||||
- (BOOL) isPublicAccessEnabled;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXACLEDITOR_H */
|
|
@ -0,0 +1,279 @@
|
|||
/* UIxAdministrationAclEditor.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2015 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSKeyValueCoding.h>
|
||||
|
||||
#import <NGObjWeb/SoSecurityManager.h>
|
||||
#import <NGObjWeb/SoUser.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/SOGoContentObject.h>
|
||||
#import <SOGo/SOGoGCSFolder.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
|
||||
#import "UIxAdministrationAclEditor.h"
|
||||
|
||||
@implementation UIxAdministrationAclEditor
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
aclUsers = nil;
|
||||
prepared = NO;
|
||||
publishInFreeBusy = NO;
|
||||
users = [NSMutableDictionary new];
|
||||
currentUser = nil;
|
||||
defaultUserID = nil;
|
||||
savedUIDs = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[savedUIDs release];
|
||||
[users release];
|
||||
[currentUser release];
|
||||
[defaultUserID release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *) aclsForObject
|
||||
{
|
||||
if (!aclUsers)
|
||||
aclUsers = [[self clientObject] aclUsers];
|
||||
|
||||
return aclUsers;
|
||||
}
|
||||
|
||||
- (NSString *) defaultUserID
|
||||
{
|
||||
if (!defaultUserID)
|
||||
ASSIGN (defaultUserID, [[self clientObject] defaultUserID]);
|
||||
|
||||
return defaultUserID;
|
||||
}
|
||||
|
||||
- (BOOL) canSubscribeUsers
|
||||
{
|
||||
return [[self clientObject]
|
||||
respondsToSelector: @selector (subscribeUserOrGroup:reallyDo:response:)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /so/:username/:folderPath/acls List users with rights
|
||||
* @apiVersion 1.0.0
|
||||
* @apiName GetAcls
|
||||
* @apiGroup Common
|
||||
* @apiExample {curl} Example usage:
|
||||
* curl -i http://localhost/SOGo/so/sogo1/Calendar/personal/acls
|
||||
*
|
||||
* @apiSuccess (Success 200) {Object[]} users List of users with ACL for the folder
|
||||
* @apiSuccess (Success 200) {String} users.uid User ID
|
||||
* @apiSuccess (Success 200) {String} users.userClass Either 'normal-user', 'normal-group' or 'public-access'
|
||||
* @apiSuccess (Success 200) {Number} users.isSubscribed 1 if the user is subscribed to the folder
|
||||
* @apiSuccess (Success 200) {String} [users.cn] User fullname
|
||||
* @apiSuccess (Success 200) {String} [users.c_email] User main email address
|
||||
*/
|
||||
- (id <WOActionResults>) aclsAction
|
||||
{
|
||||
NSString *currentUID, *ownerLogin, *info;
|
||||
NSDictionary *currentUserInfos;
|
||||
NSMutableDictionary *userData;
|
||||
id <WOActionResults> result;
|
||||
NSEnumerator *aclsEnum;
|
||||
|
||||
if (!prepared)
|
||||
{
|
||||
ownerLogin = [[self clientObject] ownerInContext: context];
|
||||
if (!defaultUserID)
|
||||
ASSIGN (defaultUserID, [[self clientObject] defaultUserID]);
|
||||
|
||||
aclsEnum = [[self aclsForObject] objectEnumerator];
|
||||
while ((currentUID = [aclsEnum nextObject]))
|
||||
{
|
||||
if (!([currentUID isEqualToString: ownerLogin]
|
||||
|| [currentUID isEqualToString: defaultUserID]
|
||||
|| [currentUID isEqualToString: @"anonymous"]))
|
||||
{
|
||||
// Set the current user in order to get information associated with it
|
||||
[self setCurrentUser: currentUID];
|
||||
|
||||
// Build the object associated to the current UID
|
||||
currentUserInfos = [self currentUserInfos];
|
||||
userData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
currentUser, @"uid",
|
||||
[self currentUserClass], @"userClass",
|
||||
[NSNumber numberWithBool: [self currentUserIsSubscribed]], @"isSubscribed",
|
||||
nil];
|
||||
if ((info = [currentUserInfos objectForKey: @"cn"]) && [info length])
|
||||
[userData setObject: info forKey: @"cn"];
|
||||
if ((info = [currentUserInfos objectForKey: @"c_email"]) && [info length])
|
||||
[userData setObject: info forKey: @"c_email"];
|
||||
[users setObject: userData forKey: currentUID];
|
||||
}
|
||||
}
|
||||
|
||||
// Add the 'Any authenticated' user
|
||||
if ([self canSubscribeUsers])
|
||||
{
|
||||
userData = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"<default>", @"uid",
|
||||
[self labelForKey: @"Any Authenticated User"], @"cn",
|
||||
@"public-user", @"userClass",
|
||||
nil];
|
||||
[users setObject: userData forKey: @"<default>"];
|
||||
}
|
||||
|
||||
if ([self canSubscribeUsers] && [self isPublicAccessEnabled])
|
||||
{
|
||||
// Add the 'public access' user
|
||||
userData = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"anonymous", @"uid",
|
||||
[self labelForKey: @"Public Access"], @"cn",
|
||||
@"public-user", @"userClass",
|
||||
nil];
|
||||
[users setObject: userData forKey: @"anonymous"];
|
||||
}
|
||||
|
||||
prepared = YES;
|
||||
}
|
||||
|
||||
result = [self responseWithStatus: 200
|
||||
andJSONRepresentation: [NSDictionary dictionaryWithObject: users forKey: @"users"]];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void) setCurrentUser: (NSString *) newCurrentUser
|
||||
{
|
||||
ASSIGN (currentUser, newCurrentUser);
|
||||
}
|
||||
|
||||
- (NSString *) currentUser
|
||||
{
|
||||
return ([currentUser hasPrefix: @"@"]
|
||||
? [currentUser substringFromIndex: 1]
|
||||
: currentUser);
|
||||
}
|
||||
|
||||
- (NSString *) currentUserClass
|
||||
{
|
||||
return ([currentUser hasPrefix: @"@"]
|
||||
? @"normal-group"
|
||||
: @"normal-user");
|
||||
}
|
||||
|
||||
- (NSString *) currentUserDisplayName
|
||||
{
|
||||
NSDictionary *infos;
|
||||
NSString *uid;
|
||||
SOGoUserManager *um;
|
||||
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
uid = [self currentUser];
|
||||
infos = [um contactInfosForUserWithUIDorEmail: uid inDomain: [[context activeUser] domain]];
|
||||
if (infos)
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@ <%@>",
|
||||
[infos objectForKey: @"cn"],
|
||||
[infos objectForKey: @"c_email"]];
|
||||
}
|
||||
else
|
||||
return uid;
|
||||
}
|
||||
|
||||
- (NSDictionary *) currentUserInfos
|
||||
{
|
||||
SOGoUserManager *um;
|
||||
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
|
||||
return [um contactInfosForUserWithUIDorEmail: [self currentUser]];
|
||||
}
|
||||
|
||||
- (BOOL) currentUserIsSubscribed
|
||||
{
|
||||
SOGoGCSFolder *folder;
|
||||
|
||||
folder = [self clientObject];
|
||||
|
||||
return ([folder respondsToSelector: @selector (userIsSubscriber:)]
|
||||
&& [folder userIsSubscriber: currentUser]);
|
||||
}
|
||||
|
||||
- (void) setUserUIDS: (NSString *) retainedUsers
|
||||
{
|
||||
if ([retainedUsers length] > 0)
|
||||
{
|
||||
savedUIDs = [retainedUsers componentsSeparatedByString: @","];
|
||||
[savedUIDs retain];
|
||||
}
|
||||
else
|
||||
savedUIDs = [NSArray new];
|
||||
}
|
||||
|
||||
- (NSString *) folderID
|
||||
{
|
||||
return [[self clientObject] nameInContainer];
|
||||
}
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
return ([[request method] isEqualToString: @"POST"]);
|
||||
}
|
||||
|
||||
- (id <WOActionResults>) saveAclsAction
|
||||
{
|
||||
NSEnumerator *aclsEnum;
|
||||
SOGoObject *clientObject;
|
||||
NSString *currentUID, *ownerLogin;
|
||||
|
||||
clientObject = [self clientObject];
|
||||
ownerLogin = [clientObject ownerInContext: context];
|
||||
aclsEnum = [[self aclsForObject] objectEnumerator];
|
||||
while ((currentUID = [[aclsEnum nextObject] objectForKey: @"c_uid"]))
|
||||
if ([currentUID isEqualToString: ownerLogin]
|
||||
|| [savedUIDs containsObject: currentUID])
|
||||
[users removeObjectForKey: currentUID];
|
||||
[clientObject removeAclsForUsers: [users allKeys]];
|
||||
|
||||
return [self jsCloseWithRefreshMethod: nil];
|
||||
}
|
||||
|
||||
- (BOOL) isPublicAccessEnabled
|
||||
{
|
||||
return [[SOGoSystemDefaults sharedSystemDefaults] enablePublicAccess];
|
||||
}
|
||||
|
||||
@end
|
|
@ -15,6 +15,10 @@
|
|||
protectedBy = "View";
|
||||
pageName = "UIxAdministration";
|
||||
};
|
||||
UIxAdministrationAclEditor = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxAdministrationAclEditor";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -636,7 +636,7 @@
|
|||
* @apiExample {curl} Example usage:
|
||||
* curl -i http://localhost/SOGo/so/sogo1/foldersSearch?type=contact
|
||||
*
|
||||
* @apiParam {String} type Either 'calendar' or 'contact'
|
||||
* @apiParam {String} type Either 'calendar' or 'contact'. If nothing is specifed, its both.
|
||||
*
|
||||
* @apiSuccess (Success 200) {Object[]} folders List of matching folders
|
||||
* @apiSuccess (Success 200) {String} folders.name Path of folder
|
||||
|
@ -648,27 +648,31 @@
|
|||
- (id <WOActionResults>) foldersSearchAction
|
||||
{
|
||||
NSString *folderType;
|
||||
NSArray *folders;
|
||||
NSMutableArray *folders;
|
||||
NSDictionary *message;
|
||||
id <WOActionResults> result;
|
||||
SOGoUserFolder *userFolder;
|
||||
|
||||
|
||||
folderType = [self queryParameterForKey: @"type"];
|
||||
folders = [NSMutableArray array];
|
||||
userFolder = [self clientObject];
|
||||
|
||||
if ([folderType length])
|
||||
{
|
||||
userFolder = [self clientObject];
|
||||
folders = [userFolder foldersOfType: folderType
|
||||
forUID: [userFolder ownerInContext: context]];
|
||||
result = [self _foldersResponseForResults: folders];
|
||||
[folders addObjectsFromArray: [userFolder foldersOfType: folderType
|
||||
forUID: [userFolder ownerInContext: context]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing type parameter"]
|
||||
forKey: @"error"];
|
||||
result = [self responseWithStatus: 400 andJSONRepresentation: message];
|
||||
[folders addObjectsFromArray: [userFolder foldersOfType: @"calendar"
|
||||
forUID: [userFolder ownerInContext: context]]];
|
||||
[folders addObjectsFromArray: [userFolder foldersOfType: @"contact"
|
||||
forUID: [userFolder ownerInContext: context]]];
|
||||
}
|
||||
|
||||
result = [self _foldersResponseForResults: folders];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -182,6 +182,10 @@
|
|||
actionClass = "UIxCalFolderActions";
|
||||
actionName = "import";
|
||||
};
|
||||
UIxCalUserRightsEditor = {
|
||||
protectedBy = "ReadAcls";
|
||||
pageName = "UIxCalUserRightsEditor";
|
||||
};
|
||||
userRights = {
|
||||
protectedBy = "ReadAcls";
|
||||
pageName = "UIxCalUserRightsEditor";
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:jsFiles="Common.js, Administration.js, Administration.services.js, Contacts.services.js">
|
||||
const:jsFiles="Common.js, Administration.js,
|
||||
Administration.services.js, Preferences.services.js,
|
||||
Contacts.services.js, Scheduler.services.js">
|
||||
|
||||
<main class="view layout-fill" ui-view="administration" layout="row" ng-controller="navController">
|
||||
<!-- administration -->
|
||||
|
@ -28,18 +30,7 @@
|
|||
</md-content>
|
||||
</md-sidenav>
|
||||
|
||||
<section layout="column" class="layout-fill">
|
||||
|
||||
<!-- TOP RIGHT TOOLBAR -->
|
||||
<md-toolbar layout="row" layout-align="space-between start" class="md-tall">
|
||||
<div class="md-toolbar-tools md-toolbar-tools-top" layout="row" layout-align="space-between start">
|
||||
<var:component className="UIxTopnavToolbarTemplate" />
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-content>
|
||||
<div ui-view="module"><!-- view --></div>
|
||||
</md-content>
|
||||
</section>
|
||||
<section layout="column" class="sg-app-content layout-fill" ui-view="module"><!-- admin module --></section>
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -47,11 +38,79 @@
|
|||
RIGHTS ADMINISTRATION PANEL
|
||||
-->
|
||||
<script type="text/ng-template" id="rights.html">
|
||||
<div>
|
||||
<label>TODO!</label>
|
||||
</div>
|
||||
</script>
|
||||
<!-- TOP RIGHT TOOLBAR -->
|
||||
<md-toolbar layout="row" layout-align="space-between start" class="toolbar-main">
|
||||
<div class="md-toolbar-tools md-toolbar-tools-top" layout="row" layout-align="space-between start">
|
||||
<var:component className="UIxTopnavToolbarTemplate" />
|
||||
</div>
|
||||
</md-toolbar>
|
||||
|
||||
<div layout="row" class="md-flex">
|
||||
|
||||
<div class="view-list" layout="column">
|
||||
<md-toolbar class="md-whiteframe-z1">
|
||||
<!-- sort mode (default) -->
|
||||
<div class="md-toolbar-tools sg-toolbar-secondary"
|
||||
sg-search="app.filter(searchText)">
|
||||
<md-button class="sg-icon-button" label:aria-label="Search">
|
||||
<md-icon>search</md-icon>
|
||||
</md-button>
|
||||
<md-input-container>
|
||||
<input name="folderSearch" type="search" ng-minlength="3"/>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
|
||||
<md-content id="userslist" layout="column" class="md-flex">
|
||||
<md-card ng-repeat="user in app.users"
|
||||
ng-class="{ 'sg-collapsed': user.uid !=
|
||||
app.selectedUser.uid,
|
||||
'sg-expanded': user.uid ==
|
||||
app.selectedUser.uid }">
|
||||
|
||||
<md-button ng-click="app.selectUser($index)">
|
||||
<div layout="row" layout-align="start center" class="md-flex">
|
||||
<span class="card-picture" ng-switch="user.isGroup">
|
||||
<div ng-switch-when="0">
|
||||
<sg-avatar-image class="md-avatar"
|
||||
sg-email="user.c_email"
|
||||
size="40"><!-- avatar --></sg-avatar-image>
|
||||
</div>
|
||||
<div ng-switch-when="1" class="sg-list-avatar"><!-- normal-group --></div>
|
||||
</span>
|
||||
<div class="sg-tile-content">
|
||||
<div class="sg-md-subhead"><div>{{user.cn}}</div></div>
|
||||
<div class="sg-md-body"><div>{{user.c_email}}</div></div>
|
||||
</div>
|
||||
<md-icon ng-class="{'md-rotate-180': user.uid == app.selectedUser.uid}">expand_more</md-icon>
|
||||
</div>
|
||||
</md-button>
|
||||
<md-card-content ng-show="user == app.selectedUser">
|
||||
<div ng-show="user.$$folders.length == 0">
|
||||
<md-icon>warning</md-icon>
|
||||
<var:string label:value="No resource"/>
|
||||
</div>
|
||||
<div layout="row" layout-align="start center" layout-fill="true"
|
||||
ng-repeat="folder in user.$$folders">
|
||||
<md-icon ng-class="{'icon-contacts': folder.type == 'Contact',
|
||||
'icon-event': folder.type == 'Appointment'}"><!--icon--></md-icon>
|
||||
<md-button ng-click="app.selectFolder(folder)">{{folder.displayName}}</md-button>
|
||||
</div>
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
</md-content>
|
||||
</div>
|
||||
|
||||
<div id="detailView" class="view-detail" layout="column" layout-align="start center" ui-view="acl">
|
||||
<md-toolbar class="md-whiteframe-z1 hide-sm"><!-- empty toolbar --></md-toolbar>
|
||||
<md-content class="hide-sm md-flex layout-fill md-hue-1" layout="column">
|
||||
<md-input-container layout-align="center center">
|
||||
<label class="sg-md-title"><var:string label:value="No resource selected"/></label>
|
||||
</md-input-container>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
</var:component>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.AdministrationUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.ContactsUI', 'SOGo.Authentication'])
|
||||
angular.module('SOGo.AdministrationUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.Authentication', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.SchedulerUI'])
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
|
@ -22,9 +22,6 @@
|
|||
controller: 'AdministrationController',
|
||||
controllerAs: 'app'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAdministration: stateAdministration
|
||||
}
|
||||
})
|
||||
.state('administration.rights', {
|
||||
|
@ -34,18 +31,48 @@
|
|||
templateUrl: 'rights.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('administration.rights.edit', {
|
||||
url: '/:userId/:folderId/edit',
|
||||
views: {
|
||||
acl: {
|
||||
templateUrl: 'UIxAdministrationAclEditor', // UI/Templates/Administration/UIxAdministrationAclEditor.wox
|
||||
controller: 'AdministrationAclController',
|
||||
controllerAs: 'acl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateFolder: stateFolder
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/rights');
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
stateAdministration.$inject = ['Administration'];
|
||||
function stateAdministration(Administration) {
|
||||
return Administration;
|
||||
stateFolder.$inject = ['$stateParams', 'User', 'AddressBook', 'Calendar'];
|
||||
function stateFolder($stateParams, User, AddressBook, Calendar) {
|
||||
var user = _.find(User.$users, function(user) {
|
||||
return user.uid == $stateParams.userId;
|
||||
});
|
||||
|
||||
var folder = _.find(user.$$folders, function(folder) {
|
||||
return folder.name == $stateParams.folderId;
|
||||
});
|
||||
|
||||
var o;
|
||||
|
||||
if (folder.type == "Appointment") {
|
||||
o = new Calendar({id: folder.name.split('/').pop(),
|
||||
owner: folder.owner,
|
||||
name: folder.displayName});
|
||||
} else {
|
||||
o = new AddressBook({id: folder.name.split('/').pop(),
|
||||
owner: folder.owner,
|
||||
name: folder.displayName});
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoAdministration */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AdministrationAclController.$inject = ['$state', '$mdToast', 'stateFolder', 'User'];
|
||||
function AdministrationAclController($state, $mdToast, stateFolder, User) {
|
||||
var vm = this;
|
||||
|
||||
vm.selectedUser = null;
|
||||
vm.getTemplate = getTemplate;
|
||||
vm.selectUser = selectUser;
|
||||
vm.save = save;
|
||||
|
||||
vm.userToAdd = '';
|
||||
vm.searchText = '';
|
||||
vm.userFilter = userFilter;
|
||||
vm.addUser = addUser;
|
||||
|
||||
stateFolder.$acl.$users(stateFolder.owner).then(function(data) {
|
||||
vm.users = data;
|
||||
});
|
||||
|
||||
function getTemplate() {
|
||||
if (angular.isDefined(stateFolder.$cards))
|
||||
return '../' + stateFolder.owner + '/Contacts/' + stateFolder.id + '/UIxContactsUserRightsEditor';
|
||||
|
||||
return '../' + stateFolder.owner + '/Calendar/' + stateFolder.id + '/UIxCalUserRightsEditor';
|
||||
}
|
||||
|
||||
function selectUser(user) {
|
||||
if (vm.selectedUser == user) {
|
||||
vm.selectedUser = null;
|
||||
}
|
||||
else {
|
||||
vm.selectedUser = user;
|
||||
vm.selectedUser.$rights();
|
||||
}
|
||||
}
|
||||
|
||||
function userFilter($query) {
|
||||
return User.$filter($query, stateFolder.$acl.users);
|
||||
}
|
||||
|
||||
function addUser(data) {
|
||||
if (data) {
|
||||
stateFolder.$acl.$addUser(data, stateFolder.owner).then(function() {
|
||||
vm.userToAdd = '';
|
||||
vm.searchText = '';
|
||||
}, function(error) {
|
||||
Dialog.alert(l('Warning'), error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
stateFolder.$acl.$saveUsersRights(stateFolder.owner).then(function() {
|
||||
$mdToast.show(
|
||||
$mdToast.simple()
|
||||
.content(l('ACLs saved'))
|
||||
.position('top right')
|
||||
.hideDelay(3000)
|
||||
);
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.AdministrationUI')
|
||||
.controller('AdministrationAclController', AdministrationAclController);
|
||||
|
||||
})();
|
|
@ -7,18 +7,45 @@
|
|||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AdministrationController.$inject = ['$state', '$mdDialog', '$mdToast', 'Dialog', 'User', 'stateAdministration', 'Authentication'];
|
||||
function AdministrationController($state, $mdDialog, $mdToast, Dialog, User, stateAdministration, Authentication) {
|
||||
AdministrationController.$inject = ['$state', '$mdDialog', '$mdToast', 'Dialog', 'User', 'Administration'];
|
||||
function AdministrationController($state, $mdDialog, $mdToast, Dialog, User, Administration) {
|
||||
var vm = this;
|
||||
|
||||
vm.administration = stateAdministration;
|
||||
vm.administration = Administration;
|
||||
|
||||
vm.selectedUser = null;
|
||||
vm.users = User.$users;
|
||||
|
||||
vm.go = go;
|
||||
vm.filter = filter;
|
||||
vm.selectUser = selectUser;
|
||||
vm.selectFolder = selectFolder;
|
||||
|
||||
function go(module) {
|
||||
$state.go('administration.' + module);
|
||||
}
|
||||
|
||||
function filter(searchText) {
|
||||
User.$filter(searchText).then(function() {
|
||||
});
|
||||
}
|
||||
|
||||
function selectUser(i) {
|
||||
if (vm.selectedUser == vm.users[i]) {
|
||||
vm.selectedUser = null;
|
||||
}
|
||||
else {
|
||||
// Fetch folders of specific type for selected user
|
||||
vm.users[i].$folders().then(function() {
|
||||
vm.selectedUser = vm.users[i];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function selectFolder(folder) {
|
||||
$state.go('administration.rights.edit', {userId: vm.selectedUser.uid, folderId: folder.name});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular
|
||||
|
|
|
@ -35,10 +35,11 @@
|
|||
/**
|
||||
* @function $users
|
||||
* @memberof Acl.prototype
|
||||
* @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser
|
||||
* @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.$users = function() {
|
||||
Acl.prototype.$users = function(owner) {
|
||||
var _this = this,
|
||||
deferred = Acl.$q.defer(),
|
||||
user;
|
||||
|
@ -46,14 +47,20 @@
|
|||
deferred.resolve(this.users);
|
||||
}
|
||||
else {
|
||||
return Acl.$$resource.fetch(this.folderId, 'acls').then(function(response) {
|
||||
var acls;
|
||||
if (angular.isDefined(owner))
|
||||
acls = Acl.$$resource.userResource(owner).fetch(this.folderId, 'acls');
|
||||
else
|
||||
acls = Acl.$$resource.fetch(this.folderId, 'acls');
|
||||
|
||||
return acls.then(function(response) {
|
||||
_this.users = [];
|
||||
//console.debug(JSON.stringify(users, undefined, 2));
|
||||
angular.forEach(response.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);
|
||||
user.$rights = angular.bind(user, user.$acl, _this.folderId, owner);
|
||||
_this.users.push(user);
|
||||
});
|
||||
deferred.resolve(_this.users);
|
||||
|
@ -67,9 +74,10 @@
|
|||
* @function $addUser
|
||||
* @memberof Acl.prototype
|
||||
* @param {Object} user - a User object with minimal set of attributes (uid, isGroup, cn, c_email)
|
||||
* @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser
|
||||
* @see {@link User.$filter}
|
||||
*/
|
||||
Acl.prototype.$addUser = function(user) {
|
||||
Acl.prototype.$addUser = function(user, owner) {
|
||||
var _this = this,
|
||||
deferred = Acl.$q.defer(),
|
||||
param = {uid: user.uid};
|
||||
|
@ -78,7 +86,14 @@
|
|||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
Acl.$$resource.fetch(this.folderId, 'addUserInAcls', param).then(function() {
|
||||
var acls;
|
||||
|
||||
if (angular.isDefined(owner))
|
||||
acls = Acl.$$resource.userResource(owner).fetch(this.folderId, 'addUserInAcls', param);
|
||||
else
|
||||
acls = Acl.$$resource.fetch(this.folderId, 'addUserInAcls', param);
|
||||
|
||||
acls.then(function() {
|
||||
user.wasSubscribed = false;
|
||||
user.userClass = user.isGroup ? 'group-user' : 'normal-user';
|
||||
user.$rights = angular.bind(user, user.$acl, _this.folderId);
|
||||
|
@ -123,9 +138,10 @@
|
|||
* @function $saveUsersRights
|
||||
* @memberof Acl.prototype
|
||||
* @desc Save user rights that have changed and subscribe users that have been selected.
|
||||
* @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser
|
||||
* @return a promise that resolved only if the modifications and subscriptions were successful
|
||||
*/
|
||||
Acl.prototype.$saveUsersRights = function() {
|
||||
Acl.prototype.$saveUsersRights = function(owner) {
|
||||
var _this = this,
|
||||
deferredSave = Acl.$q.defer(),
|
||||
deferredSubscribe = Acl.$q.defer(),
|
||||
|
@ -140,8 +156,14 @@
|
|||
}
|
||||
});
|
||||
if (users.length) {
|
||||
Acl.$$resource.save(this.folderId, users, param)
|
||||
.then(function() {
|
||||
var acls;
|
||||
|
||||
if (angular.isDefined(owner))
|
||||
acls = Acl.$$resource.userResource(owner).save(this.folderId, users, param);
|
||||
else
|
||||
acls = Acl.$$resource.save(this.folderId, users, param);
|
||||
|
||||
acls.then(function() {
|
||||
// Save was successful; copy rights to shadow rights
|
||||
angular.forEach(_this.users, function(user) {
|
||||
if (user.$rightsAreDirty()) {
|
||||
|
|
|
@ -128,9 +128,10 @@
|
|||
* @memberof User.prototype
|
||||
* @desc Fetch the user rights associated to a specific folder and populate the 'rights' attribute.
|
||||
* @param {string} the folder ID
|
||||
* @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser
|
||||
* @return a promise
|
||||
*/
|
||||
User.prototype.$acl = function(folderId) {
|
||||
User.prototype.$acl = function(folderId, owner) {
|
||||
var _this = this,
|
||||
deferred = User.$q.defer(),
|
||||
param = {uid: this.uid};
|
||||
|
@ -138,7 +139,14 @@
|
|||
deferred.resolve(this.rights);
|
||||
}
|
||||
else {
|
||||
User.$$resource.fetch(folderId, 'userRights', param).then(function(data) {
|
||||
var rights;
|
||||
|
||||
if (angular.isDefined(owner))
|
||||
rights = User.$$resource.userResource(owner).fetch(folderId, 'userRights', param);
|
||||
else
|
||||
rights = User.$$resource.fetch(folderId, 'userRights', param);
|
||||
|
||||
rights.then(function(data) {
|
||||
_this.rights = data;
|
||||
// Convert numbers (0|1) to boolean values
|
||||
//angular.forEach(_.keys(_this.rights), function(key) {
|
||||
|
|
Loading…
Reference in New Issue