From c1e1b16f0a26585fc2fef4c59f7dbee333528683 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 19 Nov 2007 21:07:54 +0000 Subject: [PATCH] Monotone-Parent: df2b66af0afb7884e01b50efd6f7e99acf0743fa Monotone-Revision: 1804bb2fc333899fed4fa062ac489b8006f6b8a4 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-11-19T21:07:54 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 13 + .../Appointments/SOGoAppointmentObject.m | 8 +- UI/Scheduler/UIxAppointmentEditor.m | 6 + UI/Scheduler/UIxComponentEditor.h | 11 +- UI/Scheduler/UIxComponentEditor.m | 105 ++++++-- UI/Scheduler/UIxTaskEditor.m | 10 +- .../SchedulerUI/UIxComponentEditor.wox | 9 +- UI/WebServerResources/UIxComponentEditor.css | 3 + UI/WebServerResources/UIxComponentEditor.js | 236 +++++++++--------- 9 files changed, 257 insertions(+), 144 deletions(-) diff --git a/ChangeLog b/ChangeLog index a81676055..23b0df7ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2007-11-19 Wolfgang Sourdeau + * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor + -setComponent:newComponent]): retain the component object. + ([UIxComponentEditor -organizerIdentity]): new accessor method to + handle list of possible organizers. + + * UI/Scheduler/UIxAppointmentEditor.m ([UIxAppointmentEditor + -event]): retain the returned event object. + + * SoObjects/Appointments/SOGoAppointmentObject.m + ([SOGoAppointmentObject -saveComponent:newEvent]): reset the + organizer only if there are no attendees AND the owner of the + component is not the organizer him-/herself. + * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor -toolbar]): rewrote in a way that ensures that each case is handled properly. diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 58de668a1..dac2f2547 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -230,9 +230,11 @@ { iCalEvent *oldEvent; NSArray *attendees; + SOGoUser *currentUser; [[newEvent parent] setMethod: @""]; - if ([newEvent userIsOrganizer: [context activeUser]]) + currentUser = [context activeUser]; + if ([newEvent userIsOrganizer: currentUser]) { oldEvent = [self component: NO secure: NO]; if (oldEvent) @@ -249,7 +251,9 @@ toAttendees: attendees]; } - if (![[newEvent attendees] count]) + if (![[newEvent attendees] count] + && [[self ownerInContext: context] + isEqualToString: [currentUser login]]) [[newEvent uniqueChildWithTag: @"organizer"] setValue: 0 to: @""]; } diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index be23c9363..23d899902 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -69,6 +69,12 @@ /* template values */ - (iCalEvent *) event { + if (!event) + { + event = (iCalEvent *) [[self clientObject] component: NO secure: NO]; + [event retain]; + } + return event; } diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index e9e478c6a..12ff2c7b7 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -41,6 +41,8 @@ NSString *saveURL; NSMutableArray *calendarList; + NSMutableArray *organizerList; + NSDictionary *organizerIdentity; /* individual values */ NSCalendarDate *cycleUntilDate; @@ -69,6 +71,9 @@ - (void) setSaveURL: (NSString *) newSaveURL; - (NSString *) saveURL; +- (void) setItem: (id) _item; +- (id) item; + - (NSArray *) categoryList; - (void) setCategories: (NSArray *) _categories; - (NSArray *) categories; @@ -89,16 +94,14 @@ - (NSString *) status; - (NSString *) itemStatusText; -- (void) setItem: (id) _item; -- (id) item; -- (NSString *) itemPriorityText; - - (void) setTitle: (NSString *) _value; - (NSString *) title; - (void) setLocation: (NSString *) _value; - (NSString *) location; +- (NSString *) location; + - (void) setComment: (NSString *) _value; - (NSString *) comment; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 3916100f4..28afec224 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -49,6 +49,7 @@ #import #import #import +#import #import #import #import @@ -68,6 +69,7 @@ [self setIsCycleEndNever]; componentOwner = @""; organizer = nil; + organizerIdentity = nil; attendeesNames = nil; attendeesUIDs = nil; attendeesEmails = nil; @@ -84,6 +86,7 @@ [title release]; [location release]; [organizer release]; + [organizerIdentity release]; [comment release]; [priority release]; [categories release]; @@ -95,6 +98,8 @@ [attendeesEmails release]; [calendarList release]; + [component release]; + [super dealloc]; } @@ -160,7 +165,7 @@ if (!component) { - component = newComponent; + ASSIGN (component, newComponent); co = [self clientObject]; componentOwner = [co ownerInContext: nil]; @@ -248,16 +253,75 @@ return url; } -- (BOOL) hasOrganizer -{ - return (![organizer isVoid]); -} - - (NSString *) organizerName { return [organizer mailAddress]; } +- (BOOL) canBeOrganizer +{ + NSString *owner; + SOGoCalendarComponent *co; + SOGoUser *currentUser; + BOOL hasOrganizer; + + co = [self clientObject]; + owner = [co ownerInContext: context]; + currentUser = [context activeUser]; + + hasOrganizer = ([[organizer value: 0] length] > 0); + + return ([co isNew] + || ([owner isEqualToString: [currentUser login]] + && (!hasOrganizer || [component userIsOrganizer: currentUser]))); +} + +- (BOOL) hasOrganizer +{ + return ([[organizer value: 0] length] && ![self canBeOrganizer]); +} + +- (void) setOrganizerIdentity: (NSDictionary *) newOrganizerIdentity +{ + ASSIGN (organizerIdentity, newOrganizerIdentity); +} + +- (NSDictionary *) organizerIdentity +{ + NSArray *allIdentities; + NSEnumerator *identities; + NSDictionary *currentIdentity; + NSString *orgEmail; + + orgEmail = [organizer rfc822Email]; + if (!organizerIdentity) + { + if ([orgEmail length]) + { + allIdentities = [[context activeUser] allIdentities]; + identities = [allIdentities objectEnumerator]; + while (!organizerIdentity + && ((currentIdentity = [identities nextObject]))) + if ([[currentIdentity objectForKey: @"email"] + caseInsensitiveCompare: orgEmail] + == NSOrderedSame) + ASSIGN (organizerIdentity, currentIdentity); + } + } + + return organizerIdentity; +} + +- (NSArray *) organizerList +{ + return [[context activeUser] allIdentities]; +} + +- (NSString *) itemOrganizerText +{ + return [item keysWithFormat: @"%{fullName} <%{email}>"]; +} + - (void) setAttendeesNames: (NSString *) newAttendeesNames { ASSIGN (attendeesNames, newAttendeesNames); @@ -852,19 +916,19 @@ - (void) _handleOrganizer { NSString *organizerEmail; - SOGoUser *activeUser; - NSDictionary *primaryIdentity; + NSString *owner, *login; organizerEmail = [[component organizer] email]; if ([organizerEmail length] == 0) { - if ([[component attendees] count] > 0) + owner = [[self clientObject] ownerInContext: context]; + login = [[context activeUser] login]; + if (![owner isEqualToString: login] + || [[component attendees] count] > 0) { ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]); - activeUser = [context activeUser]; - primaryIdentity = [activeUser primaryIdentity]; - [organizer setCn: [activeUser cn]]; - [organizer setEmail: [primaryIdentity objectForKey: @"email"]]; + [organizer setCn: [organizerIdentity objectForKey: @"fullName"]]; + [organizer setEmail: [organizerIdentity objectForKey: @"email"]]; [component setOrganizer: organizer]; } } @@ -908,6 +972,7 @@ #warning the following methods probably share some code... - (NSString *) _toolbarForOwner: (SOGoUser *) ownerUser + andClientObject: (SOGoCalendarComponent *) clientObject { NSString *toolbarFilename; iCalPersonPartStat participationStatus; @@ -928,7 +993,7 @@ } else { - if ([component isKindOfClass: [iCalEvent class]]) + if ([clientObject isKindOfClass: [SOGoAppointmentObject class]]) toolbarFilename = @"SOGoAppointmentObject.toolbar"; else toolbarFilename = @"SOGoTaskObject.toolbar"; @@ -938,15 +1003,13 @@ } - (NSString *) _toolbarForDelegate: (SOGoUser *) ownerUser + andClientObject: (SOGoCalendarComponent *) clientObject { - SOGoCalendarComponent *clientObject; SoSecurityManager *sm; NSString *toolbarFilename, *adminToolbar; iCalPersonPartStat participationStatus; - clientObject = [self clientObject]; - - if ([component isKindOfClass: [iCalEvent class]]) + if ([clientObject isKindOfClass: [SOGoAppointmentObject class]]) adminToolbar = @"SOGoAppointmentObject.toolbar"; else adminToolbar = @"SOGoTaskObject.toolbar"; @@ -1001,9 +1064,11 @@ roles: nil]; if ([ownerUser isEqual: [context activeUser]]) - toolbarFilename = [self _toolbarForOwner: ownerUser]; + toolbarFilename = [self _toolbarForOwner: ownerUser + andClientObject: clientObject]; else - toolbarFilename = [self _toolbarForDelegate: ownerUser]; + toolbarFilename = [self _toolbarForDelegate: ownerUser + andClientObject: clientObject]; return toolbarFilename; diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 0ec2370b9..8ea3b9edf 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -71,10 +71,12 @@ /* template values */ - (iCalToDo *) todo { - if (!todo) { - todo = (iCalToDo *) [[self clientObject] component: NO secure: NO]; - [todo retain]; - } + if (!todo) + { + todo = (iCalToDo *) [[self clientObject] component: NO secure: NO]; + [todo retain]; + } + return todo; } diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index 5a4d70428..d5c1e9761 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -57,8 +57,15 @@ + /> + diff --git a/UI/WebServerResources/UIxComponentEditor.css b/UI/WebServerResources/UIxComponentEditor.css index da6488dd1..877ef0c7b 100644 --- a/UI/WebServerResources/UIxComponentEditor.css +++ b/UI/WebServerResources/UIxComponentEditor.css @@ -1,2 +1,5 @@ #attendeesLabel { display: none; } + +#organizerListLabel +{ display: none; } diff --git a/UI/WebServerResources/UIxComponentEditor.js b/UI/WebServerResources/UIxComponentEditor.js index 45b91ae6a..4bb5f1145 100644 --- a/UI/WebServerResources/UIxComponentEditor.js +++ b/UI/WebServerResources/UIxComponentEditor.js @@ -1,160 +1,170 @@ function onPopupAttendeesWindow(event) { - if (event) - preventDefault(event); - window.open(ApplicationBaseURL + "/editAttendees", null, - "width=803,height=573"); + if (event) + preventDefault(event); + window.open(ApplicationBaseURL + "/editAttendees", null, + "width=803,height=573"); - return false; + return false; } function onSelectPrivacy(event) { - if (event.button == 0 || (isSafari() && event.button == 1)) { - var node = getTarget(event); - if (node.tagName != 'BUTTON') - node = $(node).up("button"); - popupToolbarMenu(node, "privacy-menu"); - Event.stop(event); -// preventDefault(event); - } + if (event.button == 0 || (isSafari() && event.button == 1)) { + var node = getTarget(event); + if (node.tagName != 'BUTTON') + node = $(node).up("button"); + popupToolbarMenu(node, "privacy-menu"); + Event.stop(event); + // preventDefault(event); + } } function onPopupUrlWindow(event) { - if (event) - preventDefault(event); + if (event) + preventDefault(event); - var urlInput = document.getElementById("url"); - var newUrl = window.prompt(labels["Target:"], urlInput.value); - if (newUrl != null) { - var documentHref = $("documentHref"); - var documentLabel = $("documentLabel"); - if (documentHref.childNodes.length > 0) { - documentHref.childNodes[0].nodeValue = newUrl; - if (newUrl.length > 0) - documentLabel.setStyle({ display: "block" }); - else - documentLabel.setStyle({ display: "none" }); - } - else { - documentHref.appendChild(document.createTextNode(newUrl)); - if (newUrl.length > 0) - documentLabel.setStyle({ display: "block" }); - } - urlInput.value = newUrl; - } + var urlInput = document.getElementById("url"); + var newUrl = window.prompt(labels["Target:"], urlInput.value); + if (newUrl != null) { + var documentHref = $("documentHref"); + var documentLabel = $("documentLabel"); + if (documentHref.childNodes.length > 0) { + documentHref.childNodes[0].nodeValue = newUrl; + if (newUrl.length > 0) + documentLabel.setStyle({ display: "block" }); + else + documentLabel.setStyle({ display: "none" }); + } + else { + documentHref.appendChild(document.createTextNode(newUrl)); + if (newUrl.length > 0) + documentLabel.setStyle({ display: "block" }); + } + urlInput.value = newUrl; + } - return false; + return false; } function onPopupDocumentWindow(event) { - var documentUrl = $("url"); + var documentUrl = $("url"); - preventDefault(event); - window.open(documentUrl.value, "SOGo_Document"); + preventDefault(event); + window.open(documentUrl.value, "SOGo_Document"); - return false; + return false; } function onMenuSetClassification(event) { - event.cancelBubble = true; + event.cancelBubble = true; - var classification = this.getAttribute("classification"); - if (this.parentNode.chosenNode) - this.parentNode.chosenNode.removeClassName("_chosen"); - this.addClassName("_chosen"); - this.parentNode.chosenNode = this; + var classification = this.getAttribute("classification"); + if (this.parentNode.chosenNode) + this.parentNode.chosenNode.removeClassName("_chosen"); + this.addClassName("_chosen"); + this.parentNode.chosenNode = this; -// log("classification: " + classification); - var privacyInput = document.getElementById("privacy"); - privacyInput.value = classification; + // log("classification: " + classification); + var privacyInput = document.getElementById("privacy"); + privacyInput.value = classification; } function onChangeCalendar(event) { - var calendars = $("calendarFoldersList").value.split(","); - var form = document.forms["editform"]; - var urlElems = form.getAttribute("action").split("/"); - var choice = calendars[this.value]; - urlElems[urlElems.length-3] = choice; - form.setAttribute("action", urlElems.join("/")); + var calendars = $("calendarFoldersList").value.split(","); + var form = document.forms["editform"]; + var urlElems = form.getAttribute("action").split("/"); + var choice = calendars[this.value]; + urlElems[urlElems.length-3] = choice; + form.setAttribute("action", urlElems.join("/")); } function refreshAttendees() { - var attendeesLabel = $("attendeesLabel"); - var attendeesNames = $("attendeesNames"); - var attendeesHref = $("attendeesHref"); + var attendeesLabel = $("attendeesLabel"); + var attendeesNames = $("attendeesNames"); + var attendeesHref = $("attendeesHref"); + var organizerListLabel = $("organizerListLabel"); - for (var i = 0; i < attendeesHref.childNodes.length; i++) - attendeesHref.removeChild(attendeesHref.childNodes[i]); + log ("label: "+ organizerListLabel); + for (var i = 0; i < attendeesHref.childNodes.length; i++) + attendeesHref.removeChild(attendeesHref.childNodes[i]); - if (attendeesNames.value.length > 0) { - attendeesHref.appendChild(document.createTextNode(attendeesNames.value)); - attendeesLabel.setStyle({ display: "block" }); - } - else - attendeesLabel.setStyle({ display: "none" }); + if (attendeesNames.value.length > 0) { + attendeesHref.appendChild(document.createTextNode(attendeesNames.value)); + attendeesLabel.setStyle({ display: "block" }); + if (organizerListLabel) + organizerListLabel.setStyle({ display: "block" }); + } + else { + attendeesLabel.setStyle({ display: "none" }); + if (organizerListLabel) + organizerListLabel.setStyle({ display: "none" }); + } } function initializeAttendeesHref() { - var attendeesHref = $("attendeesHref"); - var attendeesLabel = $("attendeesLabel"); - var attendeesNames = $("attendeesNames"); + var attendeesHref = $("attendeesHref"); + var attendeesLabel = $("attendeesLabel"); + var attendeesNames = $("attendeesNames"); + var organizerListLabel = $("organizerListLabel"); - Event.observe(attendeesHref, "click", onPopupAttendeesWindow, false); - if (attendeesNames.value.length > 0) { - attendeesHref.setStyle({ textDecoration: "underline", color: "#00f" }); - attendeesHref.appendChild(document.createTextNode(attendeesNames.value)); - attendeesLabel.setStyle({ display: "block" }); - } + Event.observe(attendeesHref, "click", onPopupAttendeesWindow, false); + if (attendeesNames.value.length > 0) { + if (organizerListLabel) + organizerListLabel.setStyle({ display: "block" }); + attendeesHref.setStyle({ textDecoration: "underline", color: "#00f" }); + attendeesHref.appendChild(document.createTextNode(attendeesNames.value)); + attendeesLabel.setStyle({ display: "block" }); + } } function initializeDocumentHref() { - var documentHref = $("documentHref"); - var documentLabel = $("documentLabel"); - var documentUrl = $("url"); + var documentHref = $("documentHref"); + var documentLabel = $("documentLabel"); + var documentUrl = $("url"); - Event.observe(documentHref, "click", onPopupDocumentWindow, false); - documentHref.setStyle({ textDecoration: "underline", color: "#00f" }); - if (documentUrl.value.length > 0) { - documentHref.appendChild(document.createTextNode(documentUrl.value)); - documentLabel.setStyle({ display: "block" }); - } + Event.observe(documentHref, "click", onPopupDocumentWindow, false); + documentHref.setStyle({ textDecoration: "underline", color: "#00f" }); + if (documentUrl.value.length > 0) { + documentHref.appendChild(document.createTextNode(documentUrl.value)); + documentLabel.setStyle({ display: "block" }); + } - var changeUrlButton = $("changeUrlButton"); - Event.observe(changeUrlButton, "click", onPopupUrlWindow, false); + var changeUrlButton = $("changeUrlButton"); + Event.observe(changeUrlButton, "click", onPopupUrlWindow, false); } function initializePrivacyMenu() { - var privacy = $("privacy").value.toUpperCase(); - if (privacy.length > 0) { - var privacyMenu = $("privacy-menu").childNodesWithTag("ul")[0]; - var menuEntries = $(privacyMenu).childNodesWithTag("li"); - var chosenNode; - if (privacy == "CONFIDENTIAL") - chosenNode = menuEntries[1]; - else if (privacy == "PRIVATE") - chosenNode = menuEntries[2]; - else - chosenNode = menuEntries[0]; - privacyMenu.chosenNode = chosenNode; - $(chosenNode).addClassName("_chosen"); - } + var privacy = $("privacy").value.toUpperCase(); + if (privacy.length > 0) { + var privacyMenu = $("privacy-menu").childNodesWithTag("ul")[0]; + var menuEntries = $(privacyMenu).childNodesWithTag("li"); + var chosenNode; + if (privacy == "CONFIDENTIAL") + chosenNode = menuEntries[1]; + else if (privacy == "PRIVATE") + chosenNode = menuEntries[2]; + else + chosenNode = menuEntries[0]; + privacyMenu.chosenNode = chosenNode; + $(chosenNode).addClassName("_chosen"); + } } function onComponentEditorLoad(event) { - if (!$("statusPercent")) - initializeAttendeesHref(); - initializeDocumentHref(); - initializePrivacyMenu(); - var list = $("calendarList"); - Event.observe(list, "mousedown", - onChangeCalendar.bindAsEventListener(list), - false); - list.fire("mousedown"); + if (!$("statusPercent")) + initializeAttendeesHref(); + initializeDocumentHref(); + initializePrivacyMenu(); + var list = $("calendarList"); + Event.observe(list, "mousedown", + onChangeCalendar.bindAsEventListener(list), + false); + list.fire("mousedown"); - var menuItems = $("itemPrivacyList").childNodesWithTag("li"); - for (var i = 0; i < menuItems.length; i++) - Event.observe(menuItems[i], "mousedown", - onMenuSetClassification.bindAsEventListener(menuItems[i]), - false); + var menuItems = $("itemPrivacyList").childNodesWithTag("li"); + for (var i = 0; i < menuItems.length; i++) + Event.observe(menuItems[i], "mousedown", + onMenuSetClassification.bindAsEventListener(menuItems[i]), + false); } FastInit.addOnLoad(onComponentEditorLoad);