From dbd99fac84b9517775b27876342e5c8968a5eb4c Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Wed, 18 Apr 2012 17:39:11 +0000 Subject: [PATCH] See ChangeLog Monotone-Parent: 8ff4e6d2b420caded81d7317c1170ff6ce35249e Monotone-Revision: 2b7803f8e993e96ff4490197722ef0a2a5faad70 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2012-04-18T17:39:11 --- ChangeLog | 26 ++++++++ .../English.lproj/Localizable.strings | 2 +- .../Appointments/SOGoAppointmentFolders.m | 8 +-- .../Appointments/SOGoAppointmentObject.m | 22 ++++++- SoObjects/SOGo/SOGoGCSFolder.h | 4 +- SoObjects/SOGo/SOGoGCSFolder.m | 50 +++++++++++---- SoObjects/SOGo/SOGoGroup.m | 11 +++- SoObjects/SOGo/SOGoParentFolder.m | 61 +++++++++++++++---- SoObjects/SOGo/SOGoUser.m | 4 ++ SoObjects/SOGo/SOGoUserManager.m | 17 ++++-- UI/Common/UIxAclEditor.m | 2 +- UI/Common/UIxFolderActions.m | 6 +- 12 files changed, 170 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index 23ac40e14..0a01a1d0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2012-04-18 Ludovic Marcotte + + * SoObjects/Appointments/SOGoAppointmentObject.m (-_handleResourcesConflicts: ...): + We now handle recurring appointments by fetching the freebusy information for one full + year from the date of the event. Also improved the conflict + reporting messages. + + * SoObjects/Appointments/SOGoAppointmentObject.m (-PUTAction:): + update the versit string in the request when updating the event, in + case a resource auto-accepted the event + + * SoObjects/SOGo/SOGoGCSFolder.m: renamed -subscribeUser:reallydo: to + subscribeUserOrGroup:reallydo and we now handle group subscriptions. + Refactored all callers. + + * SoObjects/SOGo/SOGoParentFolder.m (-_appendSubscribedSource:): now returns a + BOOL if the permission are still valid or not + + * SoObjects/SOGo/SOGoParentFolder.m (-appendSubscribedSources): consumes the + returned value from -_appendSubscribedSource: and cleans up SubscribedFolders + and FolderDisplayNames accordingly in the user's settings. + + * SoObjects/SOGo/SOGoUserManager.m (-_fillContactInfosForUser: ...): we now + set the isGroup attribute as we need this for quick groups + resolving. + 2012-04-18 Wolfgang Sourdeau * UI/WebServerResources/generic.js (showAuthenticationDialog): new diff --git a/SoObjects/Appointments/English.lproj/Localizable.strings b/SoObjects/Appointments/English.lproj/Localizable.strings index b2cea94aa..a963ca29a 100644 --- a/SoObjects/Appointments/English.lproj/Localizable.strings +++ b/SoObjects/Appointments/English.lproj/Localizable.strings @@ -67,4 +67,4 @@ vtodo_class2 = "(Confidential task)"; = "%{Attendee} %{SentByText}has not yet decided upon your event invitation."; /* Resources */ -"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"." = "Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"."; \ No newline at end of file +"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}."; \ No newline at end of file diff --git a/SoObjects/Appointments/SOGoAppointmentFolders.m b/SoObjects/Appointments/SOGoAppointmentFolders.m index 24ddf9879..b1ccd13dd 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolders.m +++ b/SoObjects/Appointments/SOGoAppointmentFolders.m @@ -725,8 +725,8 @@ static SoSecurityManager *sm = nil; userMax = [proxySubscribers count]; for (userCount = 0; userCount < userMax; userCount++) [currentFolder - subscribeUser: [proxySubscribers objectAtIndex: userCount] - reallyDo: YES]; + subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount] + reallyDo: YES]; } } } @@ -750,8 +750,8 @@ static SoSecurityManager *sm = nil; userMax = [proxySubscribers count]; for (userCount = 0; userCount < userMax; userCount++) [currentFolder - subscribeUser: [proxySubscribers objectAtIndex: userCount] - reallyDo: NO]; + subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount] + reallyDo: NO]; } } } diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 640ed92b4..a06c7d263 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -459,8 +459,10 @@ NSMutableArray *fbInfo; int i; + // We get the start/end date for our conflict range. If the event to be added is recurring, we + // check for at least a year to start with. start = [[theEvent startDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: 1]; - end = [[theEvent endDate] dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -1]; + end = [[theEvent endDate] dateByAddingYears: ([theEvent isRecurrent] ? 1 : 0) months: 0 days: 0 hours: 0 minutes: 0 seconds: -1]; folder = [[SOGoUser userWithLogin: currentUID] personalCalendarFolderInContext: context]; @@ -488,16 +490,23 @@ [currentAttendee setParticipationStatus: iCalPersonPartStatAccepted]; else { + iCalCalendar *calendar; NSDictionary *values; NSString *reason; + iCalEvent *event; + + calendar = [iCalCalendar parseSingleFromSource: [[fbInfo objectAtIndex: 0] objectForKey: @"c_content"]]; + event = [[calendar events] lastObject]; values = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithFormat: @"%d", [user numberOfSimultaneousBookings]], @"NumberOfSimultaneousBookings", [user cn], @"Cn", [user systemEmail], @"SystemEmail", + ([event summary] ? [event summary] : @""), @"EventTitle", + [[fbInfo objectAtIndex: 0] objectForKey: @"startDate"], @"StartDate", nil]; - reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\"."]]; + reason = [values keysWithFormat: [self labelForKey: @"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}."]]; return [NSException exceptionWithHTTPStatus:403 reason: reason]; @@ -1668,7 +1677,7 @@ else { // We might have auto-accepted resources here. If that's the - // case, let's regerate the versitstring and replace the + // case, let's regenerate the versitstring and replace the // one from the request. [rq setContent: [[[event parent] versitString] dataUsingEncoding: [rq contentEncoding]]]; } @@ -1815,6 +1824,13 @@ { if ((ex = [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent])) return ex; + else + { + // We might have auto-accepted resources here. If that's the + // case, let's regenerate the versitstring and replace the + // one from the request. + [rq setContent: [[[newEvent parent] versitString] dataUsingEncoding: [rq contentEncoding]]]; + } // A RECURRENCE-ID was removed so there has to be a change in the master event // We could also have an EXDATE added in the master component of the attendees diff --git a/SoObjects/SOGo/SOGoGCSFolder.h b/SoObjects/SOGo/SOGoGCSFolder.h index b4575b815..4bbb8f19e 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.h +++ b/SoObjects/SOGo/SOGoGCSFolder.h @@ -102,8 +102,8 @@ - (void) removeFolderSettings: (NSMutableDictionary *) moduleSettings withReference: (NSString *) reference; -- (BOOL) subscribeUser: (NSString *) subscribingUser - reallyDo: (BOOL) reallyDo; +- (BOOL) subscribeUserOrGroup: (NSString *) theIdentifier + reallyDo: (BOOL) reallyDo; - (BOOL) userIsSubscriber: (NSString *) subscribingUser; - (void) initializeQuickTablesAclsInContext: (WOContext *) localContext; diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index 9ea59715c..44a68d18a 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -840,19 +840,48 @@ static NSArray *childRecordFields = nil; return [folderSubscription containsObject: [self folderReference]]; } -- (BOOL) subscribeUser: (NSString *) subscribingUser - reallyDo: (BOOL) reallyDo +- (BOOL) subscribeUserOrGroup: (NSString *) theIdentifier + reallyDo: (BOOL) reallyDo { + NSMutableDictionary *moduleSettings; NSMutableArray *folderSubscription; NSString *subscriptionPointer; + NSMutableArray *allUsers; SOGoUserSettings *us; - NSMutableDictionary *moduleSettings; + NSDictionary *dict; SOGoUser *sogoUser; BOOL rc; + int i; - sogoUser = [SOGoUser userWithLogin: subscribingUser roles: nil]; - if (sogoUser) + dict = [[SOGoUserManager sharedUserManager] contactInfosForUserWithUIDorEmail: theIdentifier]; + + if ([[dict objectForKey: @"isGroup"] boolValue]) { + SOGoGroup *aGroup; + + aGroup = [SOGoGroup groupWithIdentifier: theIdentifier + inDomain: [[context activeUser] domain]]; + allUsers = [NSMutableArray arrayWithArray: [aGroup members]]; + + // We remove the active user from the group (if present) in order to + // not subscribe him to his own resource! + [allUsers removeObject: [context activeUser]]; + } + else + { + sogoUser = [SOGoUser userWithLogin: theIdentifier roles: nil]; + + if (sogoUser) + allUsers = [NSArray arrayWithObject: sogoUser]; + else + allUsers = [NSArray array]; + } + + rc = NO; + + for (i = 0; i < [allUsers count]; i++) + { + sogoUser = [allUsers objectAtIndex: i]; us = [sogoUser userSettings]; moduleSettings = [us objectForKey: [container nameInContainer]]; if (!(moduleSettings @@ -883,14 +912,13 @@ static NSArray *childRecordFields = nil; [self removeFolderSettings: moduleSettings withReference: subscriptionPointer]; [folderSubscription removeObject: subscriptionPointer]; - } + + } [us synchronize]; rc = YES; } - else - rc = NO; return rc; } @@ -945,8 +973,8 @@ static NSArray *childRecordFields = nil; LDAP call but more importantly, cache propagation calls that will create contention on GDNC. */ for (count = 0; count < max; count++) - [self subscribeUser: [delegatedUsers objectAtIndex: count] - reallyDo: reallyDo]; + [self subscribeUserOrGroup: [delegatedUsers objectAtIndex: count] + reallyDo: reallyDo]; } else { @@ -965,7 +993,7 @@ static NSArray *childRecordFields = nil; @"You cannot (un)subscribe to a folder that you own!"]; } else - [self subscribeUser: userLogin reallyDo: reallyDo]; + [self subscribeUserOrGroup: userLogin reallyDo: reallyDo]; } return response; diff --git a/SoObjects/SOGo/SOGoGroup.m b/SoObjects/SOGo/SOGoGroup.m index 023961c7b..031c3d8e7 100644 --- a/SoObjects/SOGo/SOGoGroup.m +++ b/SoObjects/SOGo/SOGoGroup.m @@ -23,7 +23,6 @@ /* Here are some group samples: - [ POSIX group ] dn: cn=it-staff,ou=Group,dc=zzz,dc=xxx,dc=yyy @@ -43,6 +42,16 @@ memberUid: hbt memberUid: hossein + dn: cn=inverse,ou=groups,dc=inverse,dc=ca + objectClass: groupOfUniqueNames + objectClass: top + objectClass: extensibleObject + uniqueMember: uid=flachapelle,ou=users,dc=inverse,dc=ca + uniqueMember: uid=lmarcotte,ou=users,dc=inverse,dc=ca + uniqueMember: uid=wsourdeau,ou=users,dc=inverse,dc=ca + cn: inverse + mail: inverse@inverse.ca + */ #include "SOGoGroup.h" diff --git a/SoObjects/SOGo/SOGoParentFolder.m b/SoObjects/SOGo/SOGoParentFolder.m index 58e19958b..6aa82224b 100644 --- a/SoObjects/SOGo/SOGoParentFolder.m +++ b/SoObjects/SOGo/SOGoParentFolder.m @@ -251,7 +251,7 @@ static SoSecurityManager *sm = nil; return nil; } -- (void) _appendSubscribedSource: (NSString *) sourceKey +- (BOOL) _appendSubscribedSource: (NSString *) sourceKey { SOGoGCSFolder *subscribedFolder; @@ -262,32 +262,67 @@ static SoSecurityManager *sm = nil; && ![sm validatePermission: SOGoPerm_AccessObject onObject: subscribedFolder inContext: context]) - [subscribedSubFolders setObject: subscribedFolder - forKey: [subscribedFolder nameInContainer]]; + { + [subscribedSubFolders setObject: subscribedFolder + forKey: [subscribedFolder nameInContainer]]; + return YES; + } + + return NO; } - (NSException *) appendSubscribedSources { - NSArray *subscribedReferences; - SOGoUser *ownerUser; + NSMutableDictionary *folderDisplayNames; + NSMutableArray *subscribedReferences; SOGoUserSettings *settings; NSEnumerator *allKeys; NSString *currentKey; + SOGoUser *ownerUser; NSException *error; + id o; + + BOOL dirty; error = nil; /* we ignore non-DB errors at this time... */ + dirty = NO; ownerUser = [SOGoUser userWithLogin: owner]; settings = [ownerUser userSettings]; - subscribedReferences = [[settings objectForKey: nameInContainer] - objectForKey: @"SubscribedFolders"]; - if ([subscribedReferences isKindOfClass: [NSArray class]]) - { - allKeys = [subscribedReferences objectEnumerator]; - while ((currentKey = [allKeys nextObject])) - [self _appendSubscribedSource: currentKey]; - } + subscribedReferences = [NSMutableArray arrayWithArray: [[settings objectForKey: nameInContainer] + objectForKey: @"SubscribedFolders"]]; + o = [[settings objectForKey: nameInContainer] objectForKey: @"FolderDisplayNames"]; + folderDisplayNames = nil; + + if (o) + folderDisplayNames = [NSMutableDictionary dictionaryWithDictionary: o]; + + + allKeys = [subscribedReferences objectEnumerator]; + while ((currentKey = [allKeys nextObject])) + { + if (![self _appendSubscribedSource: currentKey]) + { + // We no longer have access to this subscription, let's + // remove it from the current list. + [subscribedReferences removeObject: currentKey]; + [folderDisplayNames removeObjectForKey: currentKey]; + dirty = YES; + } + } + + // If we changed the folder subscribtion list, we must sync it + if (dirty) + { + id o; + + [[settings objectForKey: nameInContainer] setObject: subscribedReferences + forKey: @"SubscribedFolders"]; + [[settings objectForKey: nameInContainer] setObject: folderDisplayNames + forKey: @"FolderDisplayNames"]; + } + return error; } diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index fa2fe846a..2fd123e70 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -306,6 +306,10 @@ return allEmails; } +// +// We always return the last object among our list of email addresses. This value +// is always added in SOGoUserManager: -_fillContactMailRecords: +// - (NSString *) systemEmail { if (!allEmails) diff --git a/SoObjects/SOGo/SOGoUserManager.m b/SoObjects/SOGo/SOGoUserManager.m index 6540de462..1f41db01b 100644 --- a/SoObjects/SOGo/SOGoUserManager.m +++ b/SoObjects/SOGo/SOGoUserManager.m @@ -572,6 +572,9 @@ = [NSString stringWithFormat: @"%@@%@", uid, [dd mailDomain]]; else systemEmail = uid; + + // We always add the system email, which will always be returned + // by SOGoUser -systemEmail. [emails addObject: systemEmail]; [contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"]; } @@ -583,11 +586,12 @@ withUIDorEmail: (NSString *) uid inDomain: (NSString *) domain { - NSMutableArray *emails; - NSDictionary *userEntry; - NSEnumerator *sogoSources; - NSObject *currentSource; NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin; + NSObject *currentSource; + NSEnumerator *sogoSources; + NSDictionary *userEntry; + NSMutableArray *emails; + NSNumber *isGroup; NSArray *c_emails; BOOL access; @@ -635,6 +639,11 @@ if (!access) [currentUser setObject: [NSNumber numberWithBool: NO] forKey: @"MailAccess"]; + + // We check if it's a group + isGroup = [userEntry objectForKey: @"isGroup"]; + if (isGroup) + [currentUser setObject: isGroup forKey: @"isGroup"]; // We also fill the resource attributes, if any if ([userEntry objectForKey: @"isResource"]) diff --git a/UI/Common/UIxAclEditor.m b/UI/Common/UIxAclEditor.m index 27f6cfd89..a50e0ff07 100644 --- a/UI/Common/UIxAclEditor.m +++ b/UI/Common/UIxAclEditor.m @@ -138,7 +138,7 @@ - (BOOL) canSubscribeUsers { return [[self clientObject] - respondsToSelector: @selector (subscribeUser:reallyDo:)]; + respondsToSelector: @selector (subscribeUserOrGroup:reallyDo:)]; } - (BOOL) currentUserIsSubscribed diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index e8e0fe5bc..9e9ffb47a 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -91,7 +91,7 @@ } else { - [clientObject subscribeUser: login reallyDo: reallyDo]; + [clientObject subscribeUserOrGroup: login reallyDo: reallyDo]; if (isMailInvitation) { mailInvitationURL @@ -376,8 +376,8 @@ folder = [self clientObject]; max = [userIDs count]; for (count = 0; count < max; count++) - [folder subscribeUser: [userIDs objectAtIndex: count] - reallyDo: YES]; + [folder subscribeUserOrGroup: [userIDs objectAtIndex: count] + reallyDo: YES]; ex = nil; } else