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> 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 * UI/WebServerResources/ContactsUI.js (initContacts): fixed a bug
causing a null exception error on IE7 when the window is not the causing a null exception error on IE7 when the window is not the
main window, and is therefore missing the "uploadCancel" and main window, and is therefore missing the "uploadCancel" and

View File

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

View File

@ -2906,47 +2906,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return (![inactiveFolders containsObject: nameInContainer]); 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 - (BOOL) importComponent: (iCalEntityObject *) event
{ {
SOGoAppointmentObject *object; SOGoAppointmentObject *object;
@ -3013,49 +2972,78 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
return aclsForUser; return aclsForUser;
} }
- (NSArray *) requiredProxyRolesWithWriteAccess: (BOOL) hasWriteAccess /* caldav-proxy */
- (SOGoAppointmentProxyPermission)
proxyPermissionForUserWithLogin: (NSString *) login
{ {
static NSArray *writeAccessRoles = nil; SOGoAppointmentProxyPermission permission;
static NSArray *readAccessRoles = nil; NSArray *roles;
static NSArray *readRoles = nil;
if (!writeAccessRoles) static NSArray *writeRoles = nil;
if (!readRoles)
{ {
writeAccessRoles = [NSArray arrayWithObjects: readRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialModifier, SOGoCalendarRole_ConfidentialViewer,
SOGoRole_ObjectCreator, SOGoCalendarRole_ConfidentialDAndTViewer,
SOGoRole_ObjectEraser, SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PrivateModifier, SOGoCalendarRole_PrivateDAndTViewer,
SOGoCalendarRole_PublicModifier, SOGoCalendarRole_PublicViewer,
nil]; SOGoCalendarRole_PublicDAndTViewer,
[writeAccessRoles retain]; nil];
[readRoles retain];
} }
if (!writeRoles)
if (!readAccessRoles)
{ {
readAccessRoles = [NSArray arrayWithObjects: writeRoles = [NSArray arrayWithObjects:
SOGoCalendarRole_ConfidentialViewer, SOGoRole_ObjectCreator,
SOGoCalendarRole_PrivateViewer, SOGoRole_ObjectEraser,
SOGoCalendarRole_PublicViewer, SOGoCalendarRole_ConfidentialModifier,
nil]; SOGoCalendarRole_ConfidentialResponder,
[readAccessRoles retain]; 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 - (NSArray *) aclUsersWithProxyWriteAccess: (BOOL) write
remove: (BOOL) remove
forWriteAccess: (BOOL) write
{ {
NSArray *roles; NSMutableArray *users;
NSArray *aclUsers;
NSString *aclUser;
SOGoAppointmentProxyPermission permission;
int count, max;
if (remove) permission = (write
[self removeAclsForUsers: proxyUsers]; ? SOGoAppointmentProxyPermissionWrite
else : SOGoAppointmentProxyPermissionRead);
aclUsers = [self aclUsers];
max = [aclUsers count];
users = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{ {
roles = [self requiredProxyRolesWithWriteAccess: write]; aclUser = [aclUsers objectAtIndex: count];
[self setRoles: roles forUsers: proxyUsers]; if ([self proxyPermissionForUserWithLogin: aclUser]
== permission)
[users addObject: aclUser];
} }
return users;
} }
@end /* SOGoAppointmentFolder */ @end /* SOGoAppointmentFolder */

View File

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

View File

@ -79,13 +79,14 @@
{ {
NSMutableArray *keys; NSMutableArray *keys;
NSEnumerator *sortedSubFolders; NSEnumerator *sortedSubFolders;
SOGoGCSFolder *currentFolder; SOGoAppointmentFolder *currentFolder;
SOGoUser *currentUser;
NSString *login; NSString *login;
SOGoUser *ownerUser;
if ([[context request] isICal]) if ([[context request] isICal])
{ {
login = [[context activeUser] login]; currentUser = [context activeUser];
login = [currentUser login];
keys = [NSMutableArray array]; keys = [NSMutableArray array];
if ([owner isEqualToString: login]) if ([owner isEqualToString: login])
{ {
@ -100,9 +101,12 @@
} }
else else
{ {
ownerUser = [SOGoUser userWithLogin: owner]; sortedSubFolders = [[self subFolders] objectEnumerator];
keys = (NSMutableArray *) [[ownerUser userSettings] while ((currentFolder = [sortedSubFolders nextObject]))
proxiedCalendars]; if ([currentUser hasSubscribedToCalendar: currentFolder]
&& ([currentFolder proxyPermissionForUserWithLogin: login]
!= SOGoAppointmentProxyPermissionNone))
[keys addObject: [currentFolder nameInContainer]];
} }
} }
else else
@ -369,50 +373,157 @@
withEquivalent: SoPerm_AddDocumentsImagesAndFiles withEquivalent: SoPerm_AddDocumentsImagesAndFiles
asChildOf: davElement (@"write", XMLNS_WEBDAV)]; asChildOf: davElement (@"write", XMLNS_WEBDAV)];
} }
return aclManager; return aclManager;
} }
- (void) adjustProxyRolesForUsers: (NSArray *) proxyUsers - (BOOL) hasProxyCalendarsWithWriteAccess: (BOOL) write
remove: (BOOL) remove forUserWithLogin: (NSString *) userLogin
forWriteAccess: (BOOL) write
{ {
NSArray *calendars; NSEnumerator *sortedSubFolders;
SOGoUser *ownerUser; SOGoAppointmentFolder *currentFolder;
SOGoAppointmentFolder *folder; SOGoUser *currentUser;
int count, max; SOGoAppointmentProxyPermission permission, curPermission, foundPermission;
BOOL rc;
ownerUser = [SOGoUser userWithLogin: owner]; if ([owner isEqualToString: userLogin])
calendars = [[ownerUser userSettings] proxiedCalendars]; rc = NO;
max = [calendars count]; else
for (count = 0; count < max; count++)
{ {
folder = [self lookupName: [calendars objectAtIndex: count] foundPermission = SOGoAppointmentProxyPermissionNone;
inContext: context permission = (write
acquire: NO]; ? SOGoAppointmentProxyPermissionWrite
[folder adjustProxyRolesForUsers: proxyUsers : SOGoAppointmentProxyPermissionRead);
remove: remove currentUser = [SOGoUser userWithLogin: userLogin];
forWriteAccess: write]; 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 - (void) removeProxySubscribers: (NSArray *) proxySubscribers
remove: (BOOL) remove withWriteAccess: (BOOL) write
forWriteAccess: (BOOL) write
{ {
int count, max; SOGoAppointmentFolder *currentFolder;
SOGoUser *proxyUser; NSArray *subFolderNames;
NSMutableArray *subscribers;
int folderCount, folderMax, userCount, userMax;
max = [proxyUsers count]; subscribers = [NSMutableArray array];
for (count = 0; count < max; count++)
subFolderNames = [self subFolders];
folderMax = [subFolderNames count];
for (folderCount = 0; folderCount < folderMax; folderCount++)
{ {
proxyUser = [SOGoUser userWithLogin: [proxyUsers objectAtIndex: count]]; currentFolder = [subFolderNames objectAtIndex: folderCount];
if (proxyUser) [currentFolder removeAclsForUsers: proxySubscribers];
[proxyUser adjustProxySubscriptionToUser: owner
remove: remove userMax = [proxySubscribers count];
forWriteAccess: write]; for (userCount = 0; userCount < userMax; userCount++)
else [currentFolder
[self warnWithFormat: @"(%@) user '%@' is invalid (ignored)", subscribeUser: [proxySubscribers objectAtIndex: userCount]
NSStringFromSelector (_cmd), [proxyUser login]]; reallyDo: NO];
} }
} }

View File

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

View File

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

View File

@ -23,52 +23,22 @@
#import <SOGo/NSArray+Utilities.h> #import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoUserSettings.h> #import <SOGo/SOGoUserSettings.h>
#import "SOGoAppointmentFolder.h"
#import "SOGoUser+Appointments.h" #import "SOGoUser+Appointments.h"
@implementation SOGoUser (SOGoCalDAVSupport) @implementation SOGoUser (SOGoCalDAVSupport)
- (void) adjustProxySubscriptionToUser: (NSString *) ownerUser #warning duplicate of [SOGoGCSFolder userIsSubscriber:]
remove: (BOOL) remove - (BOOL) hasSubscribedToCalendar: (SOGoAppointmentFolder *) calendar
forWriteAccess: (BOOL) write
{ {
SOGoUserSettings *us; NSArray *subscriptions;
NSMutableArray *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 return [subscriptions containsObject: reference];
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];
} }
@end @end

View File

@ -23,6 +23,7 @@
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h> #import <Foundation/NSEnumerator.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/WOContext+SoObjects.h> #import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h> #import <NGObjWeb/WOResponse.h>
@ -137,25 +138,42 @@
- (NSArray *) _calendarProxiedUsersWithWriteAccess: (BOOL) write - (NSArray *) _calendarProxiedUsersWithWriteAccess: (BOOL) write
{ {
NSMutableArray *proxiedUsers; NSMutableDictionary *proxiedUsers;
SOGoUser *ownerUser; NSArray *references, *elements;
NSArray *subscriptions; NSString *currentLogin;
NSString *ownerLogin, *currentLogin; NSNumber *yesNumber;
SOGoAppointmentFolders *parentFolder;
SOGoUserSettings *us;
int count, max; int count, max;
ownerLogin = [self ownerInContext: nil]; yesNumber = [NSNumber numberWithBool: YES];
ownerUser = [SOGoUser userWithLogin: ownerLogin];
subscriptions = [[ownerUser userSettings] us = [[SOGoUser userWithLogin: owner] userSettings];
calendarProxySubscriptionUsersWithWriteAccess: write]; references = [us subscribedCalendars];
max = [subscriptions count]; max = [references count];
proxiedUsers = [NSMutableArray arrayWithCapacity: max]; proxiedUsers = [NSMutableDictionary dictionaryWithCapacity: max];
for (count = 0; count < max; count++) for (count = 0; count < max; count++)
{ {
currentLogin = [subscriptions objectAtIndex: count]; elements = [[references objectAtIndex: count]
[proxiedUsers addObject: currentLogin]; 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 - (void) _addGroupMembershipToArray: (NSMutableArray *) groups

View File

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

View File

@ -32,19 +32,8 @@
+ (SOGoUserSettings *) settingsForUser: (NSString *) userId; + (SOGoUserSettings *) settingsForUser: (NSString *) userId;
/* the calendars that we publish to our proxy subscribers */ - (NSArray *) subscribedCalendars;
- (void) setProxiedCalendars: (NSArray *) proxiedCalendars; - (NSArray *) subscribedAddressBooks;
- (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;
@end @end

View File

@ -55,65 +55,19 @@ static Class SOGoUserProfileKlass = Nil;
return ud; return ud;
} }
/* the calendars that we publish to our proxy subscribers */ - (NSArray *) _subscribedFoldersForModule: (NSString *) module
- (void) setProxiedCalendars: (NSArray *) proxiedCalendars
{ {
[self setObject: proxiedCalendars forKey: @"ProxiedCalendars"]; return [[self dictionaryForKey: module] objectForKey: @"SubscribedFolders"];
} }
- (NSArray *) proxiedCalendars - (NSArray *) subscribedCalendars
{ {
NSArray *proxiedCalendars; return [self _subscribedFoldersForModule: @"Calendar"];
proxiedCalendars = [self arrayForKey: @"ProxiedCalendars"];
if (!proxiedCalendars)
proxiedCalendars = [NSArray arrayWithObject: @"personal"];
return proxiedCalendars;
} }
/* the users that we have subscribed us as a proxy to our calendars */ - (NSArray *) subscribedAddressBooks
- (void) setCalendarProxyUsers: (NSArray *) proxyUsers
withWriteAccess: (BOOL) writeAccess
{ {
NSString *key; return [self _subscribedFoldersForModule: @"Contacts"];
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];
} }
@end @end

View File

@ -3,6 +3,7 @@
from config import hostname, port, username, password, subscriber_username from config import hostname, port, username, password, subscriber_username
import unittest import unittest
import utilities
import webdavlib import webdavlib
class iCalTest(unittest.TestCase): class iCalTest(unittest.TestCase):
@ -121,5 +122,85 @@ class iCalTest(unittest.TestCase):
"'%s' expected to be %s proxy for %s: %s" "'%s' expected to be %s proxy for %s: %s"
% (users[1], perm, users[0], proxyFor)) % (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__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

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

View File

@ -33,28 +33,34 @@ class TestACLUtility(TestUtility):
TestUtility.__init__(self, client) TestUtility.__init__(self, client)
self.resource = resource self.resource = resource
def subscribe(self, subscribers=None): def _subscriptionOperation(self, subscribers, operation):
rights_str = "".join(["<%s/>" % x
for x in self.rightsToSOGoRights(rights) ])
subscribeQuery = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" subscribeQuery = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<subscribe" + "<%s" % operation
+ " xmlns=\"urn:inverse:params:xml:ns:inverse-dav\"") + " xmlns=\"urn:inverse:params:xml:ns:inverse-dav\"")
if (subscribers is not None): if (subscribers is not None):
subscribeQuery = (subscribeQuery subscribeQuery = (subscribeQuery
+ " users=\"%s\"" % subscribers.join(",")) + " users=\"%s\"" % ",".join(subscribers))
subscribeQuery = subscribeQuery + "/>" subscribeQuery = subscribeQuery + "/>"
post = webdavlib.HTTPPOST(self.resource, subscribeQuery) post = webdavlib.HTTPPOST(self.resource, subscribeQuery)
post.content_type = "application/xml; charset=\"utf-8\"" post.content_type = "application/xml; charset=\"utf-8\""
self.client.execute(post) self.client.execute(post)
self.assertEquals(post.response["status"], 204, self.assertEquals(post.response["status"], 204,
"subscribtion failure to set '%s' (status: %d)" "subscribtion failure to '%s' for '%s' (status: %d)"
% (rights_str, post.response["status"])) % (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): def rightsToSOGoRights(self, rights):
self.fail("subclass must implement this method") self.fail("subclass must implement this method")
def setupRights(self, username, rights): 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" aclQuery = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<acl-query" + "<acl-query"
+ " xmlns=\"urn:inverse:params:xml:ns:inverse-dav\">" + " 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"; "Publish the Free/Busy information" = "Divulgar a informação Livre/Ocupado";
"Default Roles" = "Papéis Padrão"; "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."; "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ý"; "Publish the Free/Busy information" = "Zveřejni informace o Volný/Zaneprázdněný";
"Default Roles" = "Výchozí role"; "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."; "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"; "Publish the Free/Busy information" = "Beschikbaarheidsinformatie publiceren";
"Default Roles" = "Standaardmachtigingen"; "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."; "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"; "Publish the Free/Busy information" = "Publish the Free/Busy information";
"Default Roles" = "Default Roles"; "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."; "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"; "Publish the Free/Busy information" = "Publier l'occupation du temps";
"Default Roles" = "Rôles par défaut"; "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."; "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"; "Publish the Free/Busy information" = "Verfügbarkeitsinformationen veröffentlichen";
"Default Roles" = "Standardrechte"; "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."; "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"; "Publish the Free/Busy information" = "Foglaltsági információ nyilvánossá tétele";
"Default Roles" = "Alapértelmezett jogok"; "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."; "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)"; "Publish the Free/Busy information" = "Pubblica le informazioni sullo stato (libero/impegnato)";
"Default Roles" = "Permessi predefiniti"; "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."; "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" = "Публиковать информацию о занятом/свободном времени"; "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" = "Publicar información de disponibilidad"; "Publish the Free/Busy information" = "Publicar información de disponibilidad";
"Default Roles" = "Roles por defecto"; "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."; "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"; "Publish the Free/Busy information" = "Publisera ledig/upptagen information";
"Default Roles" = "Standardroller"; "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."; "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/WORequest.h>
#import <NGObjWeb/SoSecurityManager.h> #import <NGObjWeb/SoSecurityManager.h>
#import <NGCards/iCalPerson.h> #import <NGCards/iCalPerson.h>
#import <SoObjects/SOGo/SOGoUserManager.h> #import <SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/SOGoContentObject.h> #import <SOGo/SOGoContentObject.h>
#import <SoObjects/SOGo/SOGoPermissions.h> #import <SOGo/SOGoGCSFolder.h>
#import <SoObjects/SOGo/NSArray+Utilities.h> #import <SOGo/SOGoPermissions.h>
#import <SoObjects/SOGo/SOGoUser.h> #import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoUser.h>
#import "UIxAclEditor.h" #import "UIxAclEditor.h"
@ -158,6 +159,16 @@
return [self _displayNameForUID: currentUser]; return [self _displayNameForUID: currentUser];
} }
- (BOOL) currentUserIsSubscribed
{
SOGoGCSFolder *folder;
folder = [self clientObject];
return ([folder respondsToSelector: @selector (userIsSubscriber:)]
&& [folder userIsSubscriber: currentUser]);
}
- (void) setUserUIDS: (NSString *) retainedUsers - (void) setUserUIDS: (NSString *) retainedUsers
{ {
if ([retainedUsers length] > 0) if ([retainedUsers length] > 0)
@ -169,6 +180,11 @@
savedUIDs = [NSArray new]; savedUIDs = [NSArray new];
} }
- (NSString *) folderID
{
return [[self clientObject] nameInContainer];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request - (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext *) context inContext: (WOContext *) context
{ {

View File

@ -313,23 +313,21 @@
NSException *ex; NSException *ex;
request = [context request]; request = [context request];
ex = nil;
if ((destinationFolderId = [request formValueForKey: @"folder"]) && if ((destinationFolderId = [request formValueForKey: @"folder"]) &&
(contactsId = [request formValuesForKey: @"uid"])) (contactsId = [request formValuesForKey: @"uid"]))
{ ex = [self _moveContacts: contactsId
ex = [self _moveContacts: contactsId toFolder: destinationFolderId
toFolder: destinationFolderId
andKeepCopy: YES]; andKeepCopy: YES];
if (ex != nil)
response = (id)ex;
}
else else
response = [NSException exceptionWithHTTPStatus: 400 ex = [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'folder' and/or 'uid' parameter"]; reason: (@"missing 'folder' and/or"
@" 'uid' parameter")];
if (ex == nil) if (ex)
response = [self responseWith204]; response = (id) ex;
else
response = [self responseWith204];
return response; return response;
} }
@ -343,25 +341,55 @@
NSException *ex; NSException *ex;
request = [context request]; request = [context request];
ex = nil;
if ((destinationFolderId = [request formValueForKey: @"folder"]) && if ((destinationFolderId = [request formValueForKey: @"folder"])
(contactsId = [request formValuesForKey: @"uid"])) && (contactsId = [request formValuesForKey: @"uid"]))
{ ex = [self _moveContacts: contactsId
ex = [self _moveContacts: contactsId toFolder: destinationFolderId
toFolder: destinationFolderId
andKeepCopy: NO]; andKeepCopy: NO];
if (ex != nil) else
response = (id)ex; 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 else
response = [NSException exceptionWithHTTPStatus: 400 ex = [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'folder' and/or 'uid' parameter"]; reason: @"missing 'uids' parameter"];
if (ex == nil) if (ex)
response = [self responseWith204]; response = (id <WOActionResults>) ex;
else
return response; response = [self responseWith204];
return response;
} }
@end @end

View File

@ -26,6 +26,7 @@
"Publish the Free/Busy information" = "Cyhoddwch y wybodaeth Rhydd/Brysur"; "Publish the Free/Busy information" = "Cyhoddwch y wybodaeth Rhydd/Brysur";
"Default Roles" = "Rolau Gwreiddiol"; "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."; "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"; actionClass = "UIxFolderActions";
actionName = "deactivateFolder"; actionName = "deactivateFolder";
}; };
subscribeUsers = {
protectedBy = "Change Permissions";
actionClass = "UIxFolderActions";
actionName = "subscribeUsers";
};
renameFolder = { renameFolder = {
protectedBy = "Change Permissions"; protectedBy = "Change Permissions";
actionClass = "UIxFolderActions"; actionClass = "UIxFolderActions";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -70,16 +70,6 @@
/></div></var:if> /></div></var:if>
</fieldset> </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> <fieldset>
<legend><var:string label:value="Display"/></legend> <legend><var:string label:value="Display"/></legend>
<div><label <div><label

View File

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

View File

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

View File

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

View File

@ -7,6 +7,8 @@ var AclEditor = {
userRightsWidth: null userRightsWidth: null
}; };
var usersToSubscribe = [];
function addUser(userName, userID) { function addUser(userName, userID) {
var result = false; var result = false;
if (!$(userID)) { if (!$(userID)) {
@ -32,19 +34,49 @@ function setEventsOnUserNode(node) {
n.observe("selectstart", listRowMouseDownHandler); n.observe("selectstart", listRowMouseDownHandler);
n.observe("dblclick", onOpenUserRights); n.observe("dblclick", onOpenUserRights);
n.observe("click", onRowClick); 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) { function nodeForUser(userName, userId) {
var node = document.createElement("li"); var node = $(document.createElement("li"));
node.setAttribute("id", userId); node.setAttribute("id", userId);
node.setAttribute("class", "");
setEventsOnUserNode(node);
var span = $(document.createElement("span"));
span.addClassName("userFullName");
var image = document.createElement("img"); var image = document.createElement("img");
image.setAttribute("src", ResourcesURL + "/abcard.gif"); image.setAttribute("src", ResourcesURL + "/abcard.gif");
span.appendChild(image);
span.appendChild(document.createTextNode(" " + userName));
node.appendChild(span);
node.appendChild(image); var label = $(document.createElement("label"));
node.appendChild(document.createTextNode(" " + userName)); 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; return node;
} }
@ -156,6 +188,24 @@ function onAclLoadHandler() {
AclEditor['userRightsHeight'] = window.opener.getUsersRightsWindowHeight(); AclEditor['userRightsHeight'] = window.opener.getUsersRightsWindowHeight();
AclEditor['userRightsWidth'] = window.opener.getUsersRightsWindowWidth(); 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); document.observe("dom:loaded", onAclLoadHandler);