Monotone-Parent: 538aedd7d01174f61f329561b71c913f2c048a26

Monotone-Revision: d4724feea77a2bfe4a1315b1572ab4ae3ea3afc9

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2010-01-19T12:28:10
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2010-01-19 12:28:10 +00:00
parent 943b044622
commit 4639bf6b99
49 changed files with 616 additions and 400 deletions

View File

@ -1,5 +1,44 @@
2010-01-19 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Common/UIxFolderActions.m (-subscribeUsersAction): new web
method that enables resource owners to subscribe other users to
their resources from the acl editor.
* UI/Common/UIxAclEditor.m (-currentUserIsSubscribed)
(-folderID): new accessors.
* Tests/utilities.py (TestACLUtility.(un)subscribe): added utility
methods.
* Tests/test-ical.py (iCalTest.testCalendarProxy2): test the
behaviour of the ical proxy mechanisms when subscriptions and
access rights are modified.
* SoObjects/SOGo/SOGoUserSettings.m (-subscribedCalendars)
(-subscribedAddressBooks): new accessors.
(-setCalendarProxyUsers:withWriteAccess:)
(-setCalendarProxySubscriptionUsers:withWriteAccess:) removed accessors.
* SoObjects/Appointments/SOGoUser+Appointments.m
(-adjustProxySubscriptionToUser:remove:forWriteAccess:) removed
methods.
(-hasSubscribedToCalendar:): new method that returns whether a
user has subscribed to a calendar resource. Might be a duplicate
of [SOGoGCSFolder userIsSubscriber:].
* SoObjects/Appointments/SOGoAppointmentFolders.m
(-adjustProxyRolesForUsers:remove:forWriteAccess:)
(-adjustProxySubscriptionsForUsers:remove:forWriteAccess:):
removed methods.
(-hasProxyCalendarsWithWriteAccess:forUserWithLogin:): new method
that returns whether the user passed as parameter should be
returned in the list of subscribers corresponding to the proper
write access.
(-proxySubscribersWithWriteAccess:) new method that returns the
list of users that have a proxy access to the current account.
(-addProxySubscribers:withWriteAccess:,-removeProxySubscribers:withWriteAccess:)
setters for the above method.
* UI/WebServerResources/ContactsUI.js (initContacts): fixed a bug
causing a null exception error on IE7 when the window is not the
main window, and is therefore missing the "uploadCancel" and

View File

@ -50,6 +50,12 @@
@class GCSFolder;
@class iCalCalendar;
typedef enum {
SOGoAppointmentProxyPermissionNone = 0,
SOGoAppointmentProxyPermissionRead = 1,
SOGoAppointmentProxyPermissionWrite = 2,
} SOGoAppointmentProxyPermission;
@interface SOGoAppointmentFolder : SOGoGCSFolder
{
NSTimeZone *timeZone;
@ -138,9 +144,6 @@
- (BOOL) showCalendarTasks;
- (void) setShowCalendarTasks: (BOOL) new;
- (BOOL) isProxied;
- (void) setIsProxied: (BOOL) isProxied;
- (NSString *) syncTag;
- (void) setSyncTag: (NSString *) newSyncTag;
@ -152,9 +155,10 @@
/* caldav proxy */
- (void) adjustProxyRolesForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write;
- (SOGoAppointmentProxyPermission)
proxyPermissionForUserWithLogin: (NSString *) login;
- (NSArray *) aclUsersWithProxyWriteAccess: (BOOL) write;
@end

View File

@ -2906,47 +2906,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return (![inactiveFolders containsObject: nameInContainer]);
}
- (BOOL) isProxied
{
NSArray *proxiedCalendars;
SOGoUser *ownerUser;
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: nil]];
proxiedCalendars = [[ownerUser userSettings] proxiedCalendars];
return [proxiedCalendars containsObject: [self realNameInContainer]];
}
- (void) setIsProxied: (BOOL) isProxied
{
NSMutableArray *proxiedCalendars;
NSArray *subscriptionUsers;
SOGoUser *ownerUser;
SOGoUserSettings *us;
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: nil]];
us = [ownerUser userSettings];
proxiedCalendars = [[us proxiedCalendars] mutableCopy];
if (isProxied)
[proxiedCalendars addObjectUniquely: [self realNameInContainer]];
else
[proxiedCalendars removeObject: [self realNameInContainer]];
[us setProxiedCalendars: proxiedCalendars];
subscriptionUsers = [us calendarProxyUsersWithWriteAccess: YES];
[self adjustProxyRolesForUsers: subscriptionUsers
remove: !isProxied
forWriteAccess: YES];
subscriptionUsers = [us calendarProxyUsersWithWriteAccess: NO];
[self adjustProxyRolesForUsers: subscriptionUsers
remove: !isProxied
forWriteAccess: NO];
[us synchronize];
[proxiedCalendars autorelease];
}
- (BOOL) importComponent: (iCalEntityObject *) event
{
SOGoAppointmentObject *object;
@ -3013,49 +2972,78 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return aclsForUser;
}
- (NSArray *) requiredProxyRolesWithWriteAccess: (BOOL) hasWriteAccess
/* caldav-proxy */
- (SOGoAppointmentProxyPermission)
proxyPermissionForUserWithLogin: (NSString *) login
{
static NSArray *writeAccessRoles = nil;
static NSArray *readAccessRoles = nil;
if (!writeAccessRoles)
SOGoAppointmentProxyPermission permission;
NSArray *roles;
static NSArray *readRoles = nil;
static NSArray *writeRoles = nil;
if (!readRoles)
{
writeAccessRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialModifier,
SOGoRole_ObjectCreator,
SOGoRole_ObjectEraser,
SOGoCalendarRole_PrivateModifier,
SOGoCalendarRole_PublicModifier,
nil];
[writeAccessRoles retain];
readRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialViewer,
SOGoCalendarRole_ConfidentialDAndTViewer,
SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PrivateDAndTViewer,
SOGoCalendarRole_PublicViewer,
SOGoCalendarRole_PublicDAndTViewer,
nil];
[readRoles retain];
}
if (!readAccessRoles)
if (!writeRoles)
{
readAccessRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialViewer,
SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PublicViewer,
nil];
[readAccessRoles retain];
writeRoles = [NSArray arrayWithObjects:
SOGoRole_ObjectCreator,
SOGoRole_ObjectEraser,
SOGoCalendarRole_ConfidentialModifier,
SOGoCalendarRole_ConfidentialResponder,
SOGoCalendarRole_PrivateModifier,
SOGoCalendarRole_PrivateResponder,
SOGoCalendarRole_PublicModifier,
SOGoCalendarRole_PublicResponder,
nil];
[writeRoles retain];
}
return (hasWriteAccess) ? writeAccessRoles : readAccessRoles;
permission = SOGoAppointmentProxyPermissionNone;
roles = [self aclsForUser: login];
if ([roles count])
{
if ([roles firstObjectCommonWithArray: readRoles])
permission = SOGoAppointmentProxyPermissionRead;
if ([roles firstObjectCommonWithArray: writeRoles])
permission = SOGoAppointmentProxyPermissionWrite;
}
return permission;
}
- (void) adjustProxyRolesForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write
- (NSArray *) aclUsersWithProxyWriteAccess: (BOOL) write
{
NSArray *roles;
NSMutableArray *users;
NSArray *aclUsers;
NSString *aclUser;
SOGoAppointmentProxyPermission permission;
int count, max;
if (remove)
[self removeAclsForUsers: proxyUsers];
else
permission = (write
? SOGoAppointmentProxyPermissionWrite
: SOGoAppointmentProxyPermissionRead);
aclUsers = [self aclUsers];
max = [aclUsers count];
users = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
roles = [self requiredProxyRolesWithWriteAccess: write];
[self setRoles: roles forUsers: proxyUsers];
aclUser = [aclUsers objectAtIndex: count];
if ([self proxyPermissionForUserWithLogin: aclUser]
== permission)
[users addObject: aclUser];
}
return users;
}
@end /* SOGoAppointmentFolder */

View File

@ -31,13 +31,15 @@
- (NSArray *) webCalendarIds;
- (void) adjustProxyRolesForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write;
- (BOOL) hasProxyCalendarsWithWriteAccess: (BOOL) write
forUserWithLogin: (NSString *) userLogin;
- (void) adjustProxySubscriptionsForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write;
- (NSArray *) proxySubscribersWithWriteAccess: (BOOL) write;
- (void) addProxySubscribers: (NSArray *) proxySubscribers
withWriteAccess: (BOOL) write;
- (void) removeProxySubscribers: (NSArray *) proxySubscribers
withWriteAccess: (BOOL) write;
@end

View File

@ -79,13 +79,14 @@
{
NSMutableArray *keys;
NSEnumerator *sortedSubFolders;
SOGoGCSFolder *currentFolder;
SOGoAppointmentFolder *currentFolder;
SOGoUser *currentUser;
NSString *login;
SOGoUser *ownerUser;
if ([[context request] isICal])
{
login = [[context activeUser] login];
currentUser = [context activeUser];
login = [currentUser login];
keys = [NSMutableArray array];
if ([owner isEqualToString: login])
{
@ -100,9 +101,12 @@
}
else
{
ownerUser = [SOGoUser userWithLogin: owner];
keys = (NSMutableArray *) [[ownerUser userSettings]
proxiedCalendars];
sortedSubFolders = [[self subFolders] objectEnumerator];
while ((currentFolder = [sortedSubFolders nextObject]))
if ([currentUser hasSubscribedToCalendar: currentFolder]
&& ([currentFolder proxyPermissionForUserWithLogin: login]
!= SOGoAppointmentProxyPermissionNone))
[keys addObject: [currentFolder nameInContainer]];
}
}
else
@ -369,50 +373,157 @@
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
}
return aclManager;
}
- (void) adjustProxyRolesForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write
- (BOOL) hasProxyCalendarsWithWriteAccess: (BOOL) write
forUserWithLogin: (NSString *) userLogin
{
NSArray *calendars;
SOGoUser *ownerUser;
SOGoAppointmentFolder *folder;
int count, max;
NSEnumerator *sortedSubFolders;
SOGoAppointmentFolder *currentFolder;
SOGoUser *currentUser;
SOGoAppointmentProxyPermission permission, curPermission, foundPermission;
BOOL rc;
ownerUser = [SOGoUser userWithLogin: owner];
calendars = [[ownerUser userSettings] proxiedCalendars];
max = [calendars count];
for (count = 0; count < max; count++)
if ([owner isEqualToString: userLogin])
rc = NO;
else
{
folder = [self lookupName: [calendars objectAtIndex: count]
inContext: context
acquire: NO];
[folder adjustProxyRolesForUsers: proxyUsers
remove: remove
forWriteAccess: write];
foundPermission = SOGoAppointmentProxyPermissionNone;
permission = (write
? SOGoAppointmentProxyPermissionWrite
: SOGoAppointmentProxyPermissionRead);
currentUser = [SOGoUser userWithLogin: userLogin];
sortedSubFolders = [[self subFolders] objectEnumerator];
while ((currentFolder = [sortedSubFolders nextObject]))
if ([currentUser hasSubscribedToCalendar: currentFolder])
{
curPermission = [currentFolder
proxyPermissionForUserWithLogin: userLogin];
if ((foundPermission == SOGoAppointmentProxyPermissionNone)
|| (foundPermission == SOGoAppointmentProxyPermissionRead
&& curPermission == SOGoAppointmentProxyPermissionWrite))
foundPermission = curPermission;
}
rc = (foundPermission == permission);
}
return rc;
}
- (NSArray *) proxySubscribersWithWriteAccess: (BOOL) write
{
SOGoAppointmentFolder *currentFolder;
SOGoUser *currentUser;
NSArray *subFolderNames, *aclUsers;
NSString *aclUser;
NSMutableArray *subscribers;
int folderCount, folderMax, userCount, userMax;
subscribers = [NSMutableArray array];
subFolderNames = [self subFolders];
folderMax = [subFolderNames count];
for (folderCount = 0; folderCount < folderMax; folderCount++)
{
currentFolder = [subFolderNames objectAtIndex: folderCount];
aclUsers = [currentFolder aclUsersWithProxyWriteAccess: write];
userMax = [aclUsers count];
for (userCount = 0; userCount < userMax; userCount++)
{
aclUser = [aclUsers objectAtIndex: userCount];
if (![subscribers containsObject: aclUser])
{
currentUser = [SOGoUser userWithLogin: aclUser];
if ([currentUser hasSubscribedToCalendar: currentFolder])
[subscribers addObject: aclUser];
}
}
}
return subscribers;
}
- (NSArray *) _requiredProxyRolesWithWriteAccess: (BOOL) hasWriteAccess
{
static NSArray *writeAccessRoles = nil;
static NSArray *readAccessRoles = nil;
if (!writeAccessRoles)
{
writeAccessRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialModifier,
SOGoRole_ObjectCreator,
SOGoRole_ObjectEraser,
SOGoCalendarRole_PrivateModifier,
SOGoCalendarRole_PublicModifier,
nil];
[writeAccessRoles retain];
}
if (!readAccessRoles)
{
readAccessRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialViewer,
SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PublicViewer,
nil];
[readAccessRoles retain];
}
return (hasWriteAccess) ? writeAccessRoles : readAccessRoles;
}
- (void) addProxySubscribers: (NSArray *) proxySubscribers
withWriteAccess: (BOOL) write
{
SOGoAppointmentFolder *currentFolder;
NSArray *subFolderNames, *proxyRoles;
NSMutableArray *subscribers;
int folderCount, folderMax, userCount, userMax;
subscribers = [NSMutableArray array];
proxyRoles = [self _requiredProxyRolesWithWriteAccess: write];
subFolderNames = [self subFolders];
folderMax = [subFolderNames count];
for (folderCount = 0; folderCount < folderMax; folderCount++)
{
currentFolder = [subFolderNames objectAtIndex: folderCount];
[currentFolder setRoles: proxyRoles
forUsers: proxySubscribers];
userMax = [proxySubscribers count];
for (userCount = 0; userCount < userMax; userCount++)
[currentFolder
subscribeUser: [proxySubscribers objectAtIndex: userCount]
reallyDo: YES];
}
}
- (void) adjustProxySubscriptionsForUsers: (NSArray *) proxyUsers
remove: (BOOL) remove
forWriteAccess: (BOOL) write
- (void) removeProxySubscribers: (NSArray *) proxySubscribers
withWriteAccess: (BOOL) write
{
int count, max;
SOGoUser *proxyUser;
SOGoAppointmentFolder *currentFolder;
NSArray *subFolderNames;
NSMutableArray *subscribers;
int folderCount, folderMax, userCount, userMax;
max = [proxyUsers count];
for (count = 0; count < max; count++)
subscribers = [NSMutableArray array];
subFolderNames = [self subFolders];
folderMax = [subFolderNames count];
for (folderCount = 0; folderCount < folderMax; folderCount++)
{
proxyUser = [SOGoUser userWithLogin: [proxyUsers objectAtIndex: count]];
if (proxyUser)
[proxyUser adjustProxySubscriptionToUser: owner
remove: remove
forWriteAccess: write];
else
[self warnWithFormat: @"(%@) user '%@' is invalid (ignored)",
NSStringFromSelector (_cmd), [proxyUser login]];
currentFolder = [subFolderNames objectAtIndex: folderCount];
[currentFolder removeAclsForUsers: proxySubscribers];
userMax = [proxySubscribers count];
for (userCount = 0; userCount < userMax; userCount++)
[currentFolder
subscribeUser: [proxySubscribers objectAtIndex: userCount]
reallyDo: NO];
}
}

View File

@ -71,21 +71,20 @@
- (NSArray *) davGroupMemberSet
{
NSMutableArray *members;
NSArray *proxyUsers, *member;
SOGoUser *ownerUser;
NSArray *proxySubscribers, *member;
NSString *appName, *proxyUser;
int count, max;
appName = [[context request] applicationName];
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]];
proxyUsers = [[ownerUser userSettings]
calendarProxyUsersWithWriteAccess: hasWriteAccess];
max = [proxyUsers count];
proxySubscribers
= [[container lookupName: @"Calendar" inContext: context acquire: NO]
proxySubscribersWithWriteAccess: hasWriteAccess];
max = [proxySubscribers count];
members = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
proxyUser = [proxyUsers objectAtIndex: count];
proxyUser = [proxySubscribers objectAtIndex: count];
member = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D",
[NSString stringWithFormat: @"/%@/dav/%@/",
appName, proxyUser],
@ -141,46 +140,35 @@
{
SOGoUser *ownerUser;
SOGoUserSettings *us;
NSMutableArray *addedUsers, *removedUsers;
NSArray *oldProxyUsers, *newProxyUsers;
NSMutableArray *addedSubscribers, *removedSubscribers;
NSArray *oldProxySubscribers, *newProxySubscribers;
NSString *login;
SOGoAppointmentFolders *folders;
login = [self ownerInContext: context];
ownerUser = [SOGoUser userWithLogin: login roles: nil];
us = [ownerUser userSettings];
oldProxyUsers = [us calendarProxyUsersWithWriteAccess: hasWriteAccess];
if (!oldProxyUsers)
oldProxyUsers = [NSMutableArray array];
newProxyUsers = [self _parseSubscribers: memberSet];
if (!newProxyUsers)
newProxyUsers = [NSMutableArray array];
[us setCalendarProxyUsers: newProxyUsers
withWriteAccess: hasWriteAccess];
folders = [container lookupName: @"Calendar"
inContext: context acquire: NO];
oldProxySubscribers
= [folders proxySubscribersWithWriteAccess: hasWriteAccess];
if (!oldProxySubscribers)
oldProxySubscribers = [NSMutableArray array];
newProxySubscribers = [self _parseSubscribers: memberSet];
if (!newProxySubscribers)
newProxySubscribers = [NSMutableArray array];
folders = [container lookupName: @"Calendar" inContext: context
acquire: NO];
addedUsers = [newProxyUsers mutableCopy];
[addedUsers removeObjectsInArray: oldProxyUsers];
[folders adjustProxyRolesForUsers: addedUsers
remove: NO
forWriteAccess: hasWriteAccess];
[folders adjustProxySubscriptionsForUsers: addedUsers
remove: NO
forWriteAccess: hasWriteAccess];
[addedUsers autorelease];
addedSubscribers = [newProxySubscribers mutableCopy];
[addedSubscribers removeObjectsInArray: oldProxySubscribers];
[addedSubscribers autorelease];
[folders addProxySubscribers: addedSubscribers
withWriteAccess: hasWriteAccess];
removedUsers = [oldProxyUsers mutableCopy];
[removedUsers removeObjectsInArray: newProxyUsers];
[folders adjustProxyRolesForUsers: removedUsers
remove: YES
forWriteAccess: hasWriteAccess];
[folders adjustProxySubscriptionsForUsers: removedUsers
remove: YES
forWriteAccess: hasWriteAccess];
[removedUsers autorelease];
[us synchronize];
removedSubscribers = [oldProxySubscribers mutableCopy];
[removedSubscribers removeObjectsInArray: newProxySubscribers];
[removedSubscribers autorelease];
[folders removeProxySubscribers: removedSubscribers
withWriteAccess: hasWriteAccess];
return nil;
}

View File

@ -25,11 +25,11 @@
#import <SOGo/SOGoUser.h>
@class SOGoAppointmentFolder;
@interface SOGoUser (SOGoCalDAVSupport)
- (void) adjustProxySubscriptionToUser: (NSString *) ownerUser
remove: (BOOL) remove
forWriteAccess: (BOOL) write;
- (BOOL) hasSubscribedToCalendar: (SOGoAppointmentFolder *) calendar;
@end

View File

@ -23,52 +23,22 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoUserSettings.h>
#import "SOGoAppointmentFolder.h"
#import "SOGoUser+Appointments.h"
@implementation SOGoUser (SOGoCalDAVSupport)
- (void) adjustProxySubscriptionToUser: (NSString *) ownerUser
remove: (BOOL) remove
forWriteAccess: (BOOL) write
#warning duplicate of [SOGoGCSFolder userIsSubscriber:]
- (BOOL) hasSubscribedToCalendar: (SOGoAppointmentFolder *) calendar
{
SOGoUserSettings *us;
NSMutableArray *subscriptions;
NSArray *subscriptions;
NSString *reference;
us = [self userSettings];
subscriptions = [[self userSettings] subscribedCalendars];
reference = [calendar folderReference];
/* first, we want to ensure the subscription does not appear in the
opposite list... */
if (!remove)
{
subscriptions
= [[us calendarProxySubscriptionUsersWithWriteAccess: !write]
mutableCopy];
[subscriptions autorelease];
if ([subscriptions containsObject: ownerUser])
{
[subscriptions removeObject: ownerUser];
[us setCalendarProxySubscriptionUsers: subscriptions
withWriteAccess: !write];
}
}
subscriptions
= [[us calendarProxySubscriptionUsersWithWriteAccess: write]
mutableCopy];
[subscriptions autorelease];
if (remove)
[subscriptions removeObject: ownerUser];
else
{
if (!subscriptions)
subscriptions = [NSMutableArray array];
[subscriptions addObjectUniquely: ownerUser];
}
[us setCalendarProxySubscriptionUsers: subscriptions
withWriteAccess: write];
[us synchronize];
return [subscriptions containsObject: reference];
}
@end

View File

@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
@ -137,25 +138,42 @@
- (NSArray *) _calendarProxiedUsersWithWriteAccess: (BOOL) write
{
NSMutableArray *proxiedUsers;
SOGoUser *ownerUser;
NSArray *subscriptions;
NSString *ownerLogin, *currentLogin;
NSMutableDictionary *proxiedUsers;
NSArray *references, *elements;
NSString *currentLogin;
NSNumber *yesNumber;
SOGoAppointmentFolders *parentFolder;
SOGoUserSettings *us;
int count, max;
ownerLogin = [self ownerInContext: nil];
ownerUser = [SOGoUser userWithLogin: ownerLogin];
subscriptions = [[ownerUser userSettings]
calendarProxySubscriptionUsersWithWriteAccess: write];
max = [subscriptions count];
proxiedUsers = [NSMutableArray arrayWithCapacity: max];
yesNumber = [NSNumber numberWithBool: YES];
us = [[SOGoUser userWithLogin: owner] userSettings];
references = [us subscribedCalendars];
max = [references count];
proxiedUsers = [NSMutableDictionary dictionaryWithCapacity: max];
for (count = 0; count < max; count++)
{
currentLogin = [subscriptions objectAtIndex: count];
[proxiedUsers addObject: currentLogin];
elements = [[references objectAtIndex: count]
componentsSeparatedByString: @":"];
if ([elements count])
{
currentLogin = [elements objectAtIndex: 0];
if (![proxiedUsers objectForKey: currentLogin])
{
parentFolder = [[container lookupName: currentLogin
inContext: context
acquire: NO]
lookupName: @"Calendar"
inContext: context acquire: NO];
if ([parentFolder hasProxyCalendarsWithWriteAccess: write
forUserWithLogin: owner])
[proxiedUsers setObject: yesNumber forKey: currentLogin];
}
}
}
return proxiedUsers;
return [proxiedUsers allKeys];
}
- (void) _addGroupMembershipToArray: (NSMutableArray *) groups

View File

@ -336,7 +336,7 @@ static SoSecurityManager *sm = nil;
return error;
}
- (NSException *) initSubFolders;
- (NSException *) initSubFolders
{
NSException *error;
@ -435,10 +435,10 @@ static SoSecurityManager *sm = nil;
error = [self initSubFolders];
if (error && isPropfind)
{
/* We exceptionnally raise the exception here because doPROPFIND:
will not care for errors in its response from
toManyRelationShipKeys, which may in turn trigger the
disappearance of user folders in the SOGo extensions. */
/* We exceptionnally raise the exception here because doPROPFIND: will
not care for errors in its response from toManyRelationShipKeys,
which may in turn trigger the disappearance of user folders in the
SOGo extensions. */
[error raise];
}

View File

@ -32,19 +32,8 @@
+ (SOGoUserSettings *) settingsForUser: (NSString *) userId;
/* the calendars that we publish to our proxy subscribers */
- (void) setProxiedCalendars: (NSArray *) proxiedCalendars;
- (NSArray *) proxiedCalendars;
/* the users that we have subscribed us as a proxy to our calendars */
- (void) setCalendarProxyUsers: (NSArray *) proxyUsers
withWriteAccess: (BOOL) writeAccess;
- (NSArray *) calendarProxyUsersWithWriteAccess: (BOOL) writeAccess;
/* the users that have subscribed us as a proxy to their calendars */
- (void) setCalendarProxySubscriptionUsers: (NSArray *) subscriptionUsers
withWriteAccess: (BOOL) writeAccess;
- (NSArray *) calendarProxySubscriptionUsersWithWriteAccess: (BOOL) writeAccess;
- (NSArray *) subscribedCalendars;
- (NSArray *) subscribedAddressBooks;
@end

View File

@ -55,65 +55,19 @@ static Class SOGoUserProfileKlass = Nil;
return ud;
}
/* the calendars that we publish to our proxy subscribers */
- (void) setProxiedCalendars: (NSArray *) proxiedCalendars
- (NSArray *) _subscribedFoldersForModule: (NSString *) module
{
[self setObject: proxiedCalendars forKey: @"ProxiedCalendars"];
return [[self dictionaryForKey: module] objectForKey: @"SubscribedFolders"];
}
- (NSArray *) proxiedCalendars
- (NSArray *) subscribedCalendars
{
NSArray *proxiedCalendars;
proxiedCalendars = [self arrayForKey: @"ProxiedCalendars"];
if (!proxiedCalendars)
proxiedCalendars = [NSArray arrayWithObject: @"personal"];
return proxiedCalendars;
return [self _subscribedFoldersForModule: @"Calendar"];
}
/* the users that we have subscribed us as a proxy to our calendars */
- (void) setCalendarProxyUsers: (NSArray *) proxyUsers
withWriteAccess: (BOOL) writeAccess
- (NSArray *) subscribedAddressBooks
{
NSString *key;
key = [NSString stringWithFormat: @"CalendarProxy%@Users",
(writeAccess ? @"Write" : @"Read")];
[self setObject: proxyUsers forKey: key];
}
- (NSArray *) calendarProxyUsersWithWriteAccess: (BOOL) writeAccess
{
NSString *key;
key = [NSString stringWithFormat: @"CalendarProxy%@Users",
(writeAccess ? @"Write" : @"Read")];
return [self arrayForKey: key];
}
/* the users that have subscribed us as a proxy to their calendars */
- (void) setCalendarProxySubscriptionUsers: (NSArray *) subscriptionUsers
withWriteAccess: (BOOL) writeAccess
{
NSString *key;
key = [NSString stringWithFormat: @"CalendarProxy%@SubscriptionUsers",
(writeAccess ? @"Write" : @"Read")];
[self setObject: subscriptionUsers forKey: key];
}
- (NSArray *) calendarProxySubscriptionUsersWithWriteAccess: (BOOL) writeAccess
{
NSString *key;
key = [NSString stringWithFormat: @"CalendarProxy%@SubscriptionUsers",
(writeAccess ? @"Write" : @"Read")];
return [self arrayForKey: key];
return [self _subscribedFoldersForModule: @"Contacts"];
}
@end

View File

@ -3,6 +3,7 @@
from config import hostname, port, username, password, subscriber_username
import unittest
import utilities
import webdavlib
class iCalTest(unittest.TestCase):
@ -121,5 +122,85 @@ class iCalTest(unittest.TestCase):
"'%s' expected to be %s proxy for %s: %s"
% (users[1], perm, users[0], proxyFor))
def _testMapping(self, client, perm, resource, rights):
dav_utility = utilities.TestCalendarACLUtility(client, resource)
dav_utility.setupRights(subscriber_username, rights)
membership = self._getMembership(subscriber_username)
self.assertEquals(['/SOGo/dav/%s/calendar-proxy-%s/'
% (username, perm)],
membership,
"'%s' must have %s access to %s's calendars:\n%s"
% (subscriber_username, perm, username, membership))
proxyFor = self._getProxyFor(subscriber_username, perm)
self.assertEquals([username], proxyFor,
"'%s' expected to be %s proxy for %s: %s"
% (subscriber_username, perm, username, proxyFor))
def testCalendarProxy2(self):
"""calendar-proxy as used from SOGo"""
client = webdavlib.WebDAVClient(hostname, port, username, password)
client.user_agent = "DAVKit/4.0.1 (730); CalendarStore/4.0.1 (973); iCal/4.0.1 (1374); Mac OS X/10.6.2 (10C540)"
personal_resource = "/SOGo/dav/%s/Calendar/personal/" % username
dav_utility = utilities.TestCalendarACLUtility(client,
personal_resource)
dav_utility.setupRights(subscriber_username, {})
dav_utility.subscribe([subscriber_username])
other_resource = ("/SOGo/dav/%s/Calendar/test-calendar-proxy2/"
% username)
delete = webdavlib.WebDAVDELETE(other_resource)
client.execute(delete)
mkcol = webdavlib.WebDAVMKCOL(other_resource)
client.execute(mkcol)
dav_utility = utilities.TestCalendarACLUtility(client,
other_resource)
dav_utility.setupRights(subscriber_username, {})
dav_utility.subscribe([subscriber_username])
## we test the rights mapping
# write: write on 'personal', none on 'test-calendar-proxy2'
self._testMapping(client, "write", personal_resource,
{ "c": True, "d": False, "pu": "v" })
self._testMapping(client, "write", personal_resource,
{ "c": False, "d": True, "pu": "v" })
self._testMapping(client, "write", personal_resource,
{ "c": False, "d": False, "pu": "m" })
self._testMapping(client, "write", personal_resource,
{ "c": False, "d": False, "pu": "r" })
# read: read on 'personal', none on 'test-calendar-proxy2'
self._testMapping(client, "read", personal_resource,
{ "c": False, "d": False, "pu": "d" })
self._testMapping(client, "read", personal_resource,
{ "c": False, "d": False, "pu": "v" })
# write: read on 'personal', write on 'test-calendar-proxy2'
self._testMapping(client, "write", other_resource,
{ "c": False, "d": False, "pu": "r" })
## we test the unsubscription
# unsubscribed from personal, subscribed to 'test-calendar-proxy2'
dav_utility = utilities.TestCalendarACLUtility(client,
personal_resource)
dav_utility.unsubscribe([subscriber_username])
membership = self._getMembership(subscriber_username)
self.assertEquals(['/SOGo/dav/%s/calendar-proxy-write/' % username],
membership,
"'%s' must have write access to %s's calendars"
% (subscriber_username, username))
# unsubscribed from personal, unsubscribed from 'test-calendar-proxy2'
dav_utility = utilities.TestCalendarACLUtility(client,
other_resource)
dav_utility.unsubscribe([subscriber_username])
membership = self._getMembership(subscriber_username)
self.assertEquals([],
membership,
"'%s' must have no access to %s's calendars"
% (subscriber_username, username))
delete = webdavlib.WebDAVDELETE(other_resource)
client.execute(delete)
if __name__ == "__main__":
unittest.main()

View File

@ -49,7 +49,7 @@ class WebdavSyncTest(unittest.TestCase):
token = int(token_node.childNodes[0].nodeValue)
self.assertTrue(token > 0)
self.assertTrue(token < int(query1.start))
self.assertTrue(token <= int(query1.start))
# we make sure that any token is invalid when the collection is empty
query2 = webdavlib.WebDAVSyncQuery(resource, "1234", [ "getetag" ])

View File

@ -33,28 +33,34 @@ class TestACLUtility(TestUtility):
TestUtility.__init__(self, client)
self.resource = resource
def subscribe(self, subscribers=None):
rights_str = "".join(["<%s/>" % x
for x in self.rightsToSOGoRights(rights) ])
def _subscriptionOperation(self, subscribers, operation):
subscribeQuery = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<subscribe"
+ "<%s" % operation
+ " xmlns=\"urn:inverse:params:xml:ns:inverse-dav\"")
if (subscribers is not None):
subscribeQuery = (subscribeQuery
+ " users=\"%s\"" % subscribers.join(","))
+ " users=\"%s\"" % ",".join(subscribers))
subscribeQuery = subscribeQuery + "/>"
post = webdavlib.HTTPPOST(self.resource, subscribeQuery)
post.content_type = "application/xml; charset=\"utf-8\""
self.client.execute(post)
self.assertEquals(post.response["status"], 204,
"subscribtion failure to set '%s' (status: %d)"
% (rights_str, post.response["status"]))
"subscribtion failure to '%s' for '%s' (status: %d)"
% (self.resource, "', '".join(subscribers),
post.response["status"]))
def subscribe(self, subscribers=None):
self._subscriptionOperation(subscribers, "subscribe")
def unsubscribe(self, subscribers=None):
self._subscriptionOperation(subscribers, "unsubscribe")
def rightsToSOGoRights(self, rights):
self.fail("subclass must implement this method")
def setupRights(self, username, rights):
rights_str = "".join(["<%s/>" % x for x in self.rightsToSOGoRights(rights) ])
rights_str = "".join(["<%s/>"
% x for x in self.rightsToSOGoRights(rights) ])
aclQuery = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<acl-query"
+ " xmlns=\"urn:inverse:params:xml:ns:inverse-dav\">"

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Divulgar a informação Livre/Ocupado";
"Default Roles" = "Papéis Padrão";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Desculpe, os direitos de usuário não podem ser modificados para este objeto.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Zveřejni informace o Volný/Zaneprázdněný";
"Default Roles" = "Výchozí role";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Omlouváme se, ale uživatelská práva pro tento objekt nemohou být nastaveny.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Beschikbaarheidsinformatie publiceren";
"Default Roles" = "Standaardmachtigingen";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "De machtigingen kunnen niet worden ingesteld voor dit object.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Publish the Free/Busy information";
"Default Roles" = "Default Roles";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Publier l'occupation du temps";
"Default Roles" = "Rôles par défaut";
"Subscribe User" = "Abonner l'utilisateur";
"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Verfügbarkeitsinformationen veröffentlichen";
"Default Roles" = "Standardrechte";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Leider können die Benutzerrechte für dieses Objekt nicht konfiguriert werden.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Foglaltsági információ nyilvánossá tétele";
"Default Roles" = "Alapértelmezett jogok";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Sajnálom, erre az objektumra nem állíthatók be felhasználói jogosultságok.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Pubblica le informazioni sullo stato (libero/impegnato)";
"Default Roles" = "Permessi predefiniti";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Non è possibile configurare i permessi per questo oggetto.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Публиковать информацию о занятом/свободном времени";
"Default Roles" = "Контроль доступа для всех";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Извините, для данного объекта невозможно настроить права доступа.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Publicar información de disponibilidad";
"Default Roles" = "Roles por defecto";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object.";

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Publisera ledig/upptagen information";
"Default Roles" = "Standardroller";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Tyvärr, användarrättigheterna kan inte konfigureras för objektet.";

View File

@ -29,11 +29,12 @@
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/SoSecurityManager.h>
#import <NGCards/iCalPerson.h>
#import <SoObjects/SOGo/SOGoUserManager.h>
#import <SoObjects/SOGo/SOGoContentObject.h>
#import <SoObjects/SOGo/SOGoPermissions.h>
#import <SoObjects/SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoContentObject.h>
#import <SOGo/SOGoGCSFolder.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoUser.h>
#import "UIxAclEditor.h"
@ -158,6 +159,16 @@
return [self _displayNameForUID: currentUser];
}
- (BOOL) currentUserIsSubscribed
{
SOGoGCSFolder *folder;
folder = [self clientObject];
return ([folder respondsToSelector: @selector (userIsSubscriber:)]
&& [folder userIsSubscriber: currentUser]);
}
- (void) setUserUIDS: (NSString *) retainedUsers
{
if ([retainedUsers length] > 0)
@ -169,6 +180,11 @@
savedUIDs = [NSArray new];
}
- (NSString *) folderID
{
return [[self clientObject] nameInContainer];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext *) context
{

View File

@ -313,23 +313,21 @@
NSException *ex;
request = [context request];
ex = nil;
if ((destinationFolderId = [request formValueForKey: @"folder"]) &&
(contactsId = [request formValuesForKey: @"uid"]))
{
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
andKeepCopy: YES];
if (ex != nil)
response = (id)ex;
}
else
response = [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'folder' and/or 'uid' parameter"];
ex = [NSException exceptionWithHTTPStatus: 400
reason: (@"missing 'folder' and/or"
@" 'uid' parameter")];
if (ex == nil)
response = [self responseWith204];
if (ex)
response = (id) ex;
else
response = [self responseWith204];
return response;
}
@ -343,25 +341,55 @@
NSException *ex;
request = [context request];
ex = nil;
if ((destinationFolderId = [request formValueForKey: @"folder"]) &&
(contactsId = [request formValuesForKey: @"uid"]))
{
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
if ((destinationFolderId = [request formValueForKey: @"folder"])
&& (contactsId = [request formValuesForKey: @"uid"]))
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
andKeepCopy: NO];
if (ex != nil)
response = (id)ex;
else
ex = [NSException exceptionWithHTTPStatus: 400
reason: (@"missing 'folder' and/or"
@"'uid' parameter")];
if (ex)
response = (id <WOActionResults>) ex;
else
response = [self responseWith204];
return response;
}
- (id <WOActionResults>) subscribeUsersAction
{
id <WOActionResults> response;
NSString *uids;
NSArray *userIDs;
SOGoGCSFolder *folder;
NSException *ex;
int count, max;
uids = [[context request] formValueForKey: @"uids"];
if ([uids length])
{
userIDs = [uids componentsSeparatedByString: @","];
folder = [self clientObject];
max = [userIDs count];
for (count = 0; count < max; count++)
[folder subscribeUser: [userIDs objectAtIndex: count]
reallyDo: YES];
ex = nil;
}
else
response = [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'folder' and/or 'uid' parameter"];
ex = [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'uids' parameter"];
if (ex == nil)
response = [self responseWith204];
return response;
if (ex)
response = (id <WOActionResults>) ex;
else
response = [self responseWith204];
return response;
}
@end

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Cyhoddwch y wybodaeth Rhydd/Brysur";
"Default Roles" = "Rolau Gwreiddiol";
"Subscribe User" = "Subscribe User";
"Sorry, the user rights can not be configured for that object." = "Sori, ni all hawliau'r defnyddiwr cael ei newid ar gyfer y gwrthrych hwn.";

View File

@ -101,6 +101,11 @@
actionClass = "UIxFolderActions";
actionName = "deactivateFolder";
};
subscribeUsers = {
protectedBy = "Change Permissions";
actionClass = "UIxFolderActions";
actionName = "subscribeUsers";
};
renameFolder = {
protectedBy = "Change Permissions";
actionClass = "UIxFolderActions";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Tarefa Confidencial)";
"Synchronize" = "Synchronize";
"Tag:" = "Marca:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Důvěrný úkol)";
"Synchronize" = "Synchronize";
"Tag:" = "Štítek:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Vertrouwelijke taak)";
"Synchronize" = "Synchronize";
"Tag:" = "Markering:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Confidential task)";
"Synchronize" = "Synchronize";
"Tag:" = "Tag:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Tâche confidentielle)";
"Synchronize" = "Synchroniser";
"Tag:" = "Label :";
"iCal Delegation" = "Délégation iCal";
"Shared when account is delegated" = "Inclure cet agenda lors de la délégation";
"Display" = "Affichage";
"Show alarms" = "Afficher les alarmes";
"Show tasks" = "Afficher les tâches";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Vertrauliche Aufgabe)";
"Synchronize" = "Synchronize";
"Tag:" = "Tag:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Bizalmas feladat)";
"Synchronize" = "Synchronize";
"Tag:" = "Cimke:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Attività confidenziale)";
"Synchronize" = "Synchronize";
"Tag:" = "Etichetta:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Confidential task)";
"Synchronize" = "Synchronize";
"Tag:" = "Tag:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Tarea confidencial)";
"Synchronize" = "Synchronize";
"Tag:" = "Redacción:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Konfidentiell uppgift)";
"Synchronize" = "Synkronisera";
"Tag:" = "Etikett:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Visa";
"Show alarms" = "Visa alarm";
"Show tasks" = "Visa uppgifter";

View File

@ -51,7 +51,4 @@
- (NSString *) calendarSyncTag;
- (void) setCalendarSyncTag: (NSString *) newTag;
- (BOOL) isProxied;
- (void) setIsProxied: (BOOL) isProxied;
@end

View File

@ -149,17 +149,6 @@
[calendar setSyncTag: newTag];
}
/* DAV: calendar-proxy protocol */
- (BOOL) isProxied
{
return [calendar isProxied];
}
- (void) setIsProxied: (BOOL) isProxied
{
[calendar setIsProxied: isProxied];
}
- (BOOL) showCalendarAlarms
{
return [calendar showCalendarAlarms];

View File

@ -512,9 +512,6 @@ vtodo_class2 = "(Tasg gyhoeddus)";
"Synchronize" = "Synchronize";
"Tag:" = "Tag:";
"iCal Delegation" = "iCal Delegation";
"Shared when account is delegated" = "Shared when account is delegated";
"Display" = "Display";
"Show alarms" = "Show alarms";
"Show tasks" = "Show tasks";

View File

@ -70,16 +70,6 @@
/></div></var:if>
</fieldset>
<var:if condition="isWebCalendar" const:negate="YES"
><fieldset>
<legend><var:string label:value="iCal Delegation"/></legend>
<div><label
><input type="checkbox" const:class="checkBox" id="isProxied"
var:checked="isProxied"
/><var:string label:value="Shared when account is delegated"
/></label></div>
</fieldset></var:if>
<fieldset>
<legend><var:string label:value="Display"/></legend>
<div><label

View File

@ -17,8 +17,7 @@
<input type="hidden" name="defaultUserID" id="defaultUserID"
var:value="defaultUserID"/>
<input type="hidden" name="action" value="saveAcls"/>
<input type="hidden" id="userUIDS" name="userUIDS"
var:value="userUIDS"/>
<input type="hidden" name="folderID" id="folderID" var:value="folderID"/>
<var:if condition="hasOwner">
<label><var:string label:value="Owner:"/>
<span class="value"><strong><var:string value="ownerName"/></strong></span></label>
@ -38,9 +37,14 @@
<ul id="userList" multiselect="yes">
<var:foreach list="usersForObject" item="currentUser"
><li var:id="currentUser">
<img rsrc:src="abcard.gif"/>
<var:string value="currentUserDisplayName"/></li>
</var:foreach>
<span class="userFullName"><img rsrc:src="abcard.gif"/>
<var:string value="currentUserDisplayName"
/></span
><label class="subscriptionArea"><input type="checkbox"
var:checked="currentUserIsSubscribed"
var:disabled="currentUserIsSubscribed"
/><var:string label:value="Subscribe User"/></label
></li></var:foreach>
</ul>
</div>
</div>

View File

@ -1891,17 +1891,20 @@ function onCalendarModify(event) {
var url = ApplicationBaseURL + calendarID + "/properties";
var windowID = sanitizeWindowName(calendarID + " properties");
var width = 310;
var height = 310;
var height = 260;
var isWebCalendar = false;
if (UserSettings['Calendar']
&& UserSettings['Calendar']['WebCalendars']) {
var webCalendars = UserSettings['Calendar']['WebCalendars'];
var realID = calendarID.substr (1, calendarID.length - 1);
if (webCalendars[realID])
if (webCalendars[realID]) {
isWebCalendar = true;
}
}
if (isWebCalendar || calendarID == "/personal")
height -= 25;
if (isWebCalendar)
height += 25;
else if (calendarID == "/personal")
height -= 25;
var properties = window.open(url, windowID,
"width="+width+",height="+height+",resizable=0");

View File

@ -57,8 +57,16 @@ UL#userList
list-style-image: none; }
UL#userList LI
{ cursor: pointer;
{ clear: both;
cursor: pointer;
text-align: right;
padding-left: 3px; }
SPAN.userFullName
{ float: left; }
DIV#userSelectorButtons A.smallToolbarButton
{ float: left; }
LABEL.subscriptionArea
{ padding-right: 5px; }

View File

@ -7,6 +7,8 @@ var AclEditor = {
userRightsWidth: null
};
var usersToSubscribe = [];
function addUser(userName, userID) {
var result = false;
if (!$(userID)) {
@ -32,19 +34,49 @@ function setEventsOnUserNode(node) {
n.observe("selectstart", listRowMouseDownHandler);
n.observe("dblclick", onOpenUserRights);
n.observe("click", onRowClick);
var cbParents = n.childNodesWithTag("label");
if (cbParents && cbParents.length) {
var cbParent = $(cbParents[0]);
var checkbox = cbParent.childNodesWithTag("input")[0];
$(checkbox).observe("change", onSubscriptionChange);
}
}
function onSubscriptionChange(event) {
var li = this.parentNode.parentNode;
var username = li.getAttribute("id");
var idx = usersToSubscribe.indexOf(username);
if (this.checked) {
if (idx < 0)
usersToSubscribe.push(username);
} else {
if (idx > -1)
usersToSubscribe.splice(idx, 1);
}
}
function nodeForUser(userName, userId) {
var node = document.createElement("li");
var node = $(document.createElement("li"));
node.setAttribute("id", userId);
node.setAttribute("class", "");
setEventsOnUserNode(node);
var span = $(document.createElement("span"));
span.addClassName("userFullName");
var image = document.createElement("img");
image.setAttribute("src", ResourcesURL + "/abcard.gif");
span.appendChild(image);
span.appendChild(document.createTextNode(" " + userName));
node.appendChild(span);
node.appendChild(image);
node.appendChild(document.createTextNode(" " + userName));
var label = $(document.createElement("label"));
label.addClassName("class", "subscriptionArea");
var cb = document.createElement("input");
cb.type = "checkbox";
label.appendChild(cb);
label.appendChild(document.createTextNode(getLabel("Subscribe User")));
node.appendChild(label);
setEventsOnUserNode(node);
return node;
}
@ -156,6 +188,24 @@ function onAclLoadHandler() {
AclEditor['userRightsHeight'] = window.opener.getUsersRightsWindowHeight();
AclEditor['userRightsWidth'] = window.opener.getUsersRightsWindowWidth();
Event.observe(window, "beforeunload", onAclCloseHandler);
}
function onAclCloseHandler(event) {
if (usersToSubscribe.length) {
var url = (URLForFolderID($("folderID").value)
+ "/subscribeUsers?uids=" + usersToSubscribe.join(","));
new Ajax.Request(url, {
asynchronous: false,
method: 'get',
onFailure: function(transport) {
log("Can't expunge current folder: " + transport.status);
}
});
}
return true;
}
document.observe("dom:loaded", onAclLoadHandler);