From da6b5696a0eb312b58e23e2b99cd21f1592434ac Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Mon, 27 Aug 2012 20:35:10 +0000 Subject: [PATCH] See ChangeLog Monotone-Parent: 728de9d1f91919c2ef87a31aa2d11b9b1a3a9835 Monotone-Revision: e5e46473685093f9076981f90edbe581992247e7 Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2012-08-27T20:35:10 --- ChangeLog | 10 +- NEWS | 1 + .../English.lproj/Localizable.strings | 6 +- SoObjects/Appointments/SOGoAptMailDeletion.m | 19 +-- SoObjects/Appointments/SOGoAptMailICalReply.m | 22 ++- .../Appointments/SOGoAptMailInvitation.m | 19 +-- .../Appointments/SOGoAptMailNotification.h | 16 +- .../Appointments/SOGoAptMailNotification.m | 157 +++++++++++------- SoObjects/Appointments/SOGoAptMailUpdate.m | 74 +++++++-- .../Appointments/SOGoCalendarComponent.m | 8 +- .../Appointments/SOGoAptMailDeletion.wox | 45 ++++- .../Appointments/SOGoAptMailICalReply.wox | 31 +++- .../Appointments/SOGoAptMailInvitation.wox | 45 ++++- .../Appointments/SOGoAptMailReceipt.wox | 2 +- .../Appointments/SOGoAptMailUpdate.wox | 46 ++++- 15 files changed, 368 insertions(+), 133 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0999c912b..0899c1fe0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,19 @@ 2012-08-27 Francis Lachapelle + * SoObjects/Appointments/SOGoAptMailInvitation.m, + SoObjects/Appointments/SOGoAptMailNotification.m, + SoObjects/Appointments/SOGoAptMailDeletion.m, + SoObjects/Appointments/SOGoAptMailUpdate.m, + SoObjects/Appointments/SOGoAptMailICalReply.m, + SoObjects/Appointments/SOGoCalendarComponent.m: send HTML messages + instead of text/plain. + * UI/WebServerResources/generic.js (openMailTo): mail addresses must now be separated by semi-colons and not commas. This allow display names to contain commas. * UI/WebServerResources/SchedulerUI.js (tasksListCallback): prefix - tasks with a color box insted of changing the task's background color. + tasks with a color box instead of changing the task's background color. * UI/Scheduler/UIxCalListingActions.m (-_getStatusClassForStatusCode:andEndDateStamp::): set the diff --git a/NEWS b/NEWS index 9f4975ba6..517e996aa 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements executed, no matter if a previous condition matches) - improved tasks list display - RPM packages now treat logrotate file as a config file + - completed the transition from text/plain message templates to HTML Bug Fixes - fixed passwords that would be prefixed with '{none}' when not using a diff --git a/SoObjects/Appointments/English.lproj/Localizable.strings b/SoObjects/Appointments/English.lproj/Localizable.strings index 22106a1b9..9bce92a0a 100644 --- a/SoObjects/Appointments/English.lproj/Localizable.strings +++ b/SoObjects/Appointments/English.lproj/Localizable.strings @@ -11,9 +11,9 @@ vtodo_class2 = "(Confidential task)"; "The event \"%{Summary}\" was created" = "The event \"%{Summary}\" was created"; "The event \"%{Summary}\" was deleted" = "The event \"%{Summary}\" was deleted"; "The event \"%{Summary}\" was updated" = "The event \"%{Summary}\" was updated"; -"The following attendees(s) were notified:" = "The following attendees(s) were notified:"; -"The following attendees(s) were added:" = "The following attendees(s) were added:"; -"The following attendees(s) were removed:" = "The following attendees(s) were removed:"; +"The following attendees(s) were notified:" = "The following attendee(s) were notified:"; +"The following attendees(s) were added:" = "The following attendee(s) were added:"; +"The following attendees(s) were removed:" = "The following attendee(s) were removed:"; /* IMIP messages */ "startDate_label" = "Start:"; diff --git a/SoObjects/Appointments/SOGoAptMailDeletion.m b/SoObjects/Appointments/SOGoAptMailDeletion.m index 987a8fece..75509c59d 100644 --- a/SoObjects/Appointments/SOGoAptMailDeletion.m +++ b/SoObjects/Appointments/SOGoAptMailDeletion.m @@ -44,27 +44,14 @@ - (NSString *) getBody { - NSString *bodyFormat; + NSString *body; if (!values) [self setupValues]; - if ([values objectForKey: @"StartTime"] && [values objectForKey: @"EndTime"]) - bodyFormat = [self labelForKey: (@"%{Organizer} %{SentByText}has cancelled" - @" this event: %{Summary}.\n\n" - @"Start: %{StartDate} at %{StartTime}\n" - @"End: %{EndDate} at %{EndTime}\n" - @"Description: %{Description}") - inContext: context]; - else - bodyFormat = [self labelForKey: (@"%{Organizer} %{SentByText}has cancelled" - @" this event: %{Summary}.\n\n" - @"Start: %{StartDate}\n" - @"End: %{EndDate}\n" - @"Description: %{Description}") - inContext: context]; + body = [[self generateResponse] contentAsString]; - return [values keysWithFormat: bodyFormat]; + return [body stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end diff --git a/SoObjects/Appointments/SOGoAptMailICalReply.m b/SoObjects/Appointments/SOGoAptMailICalReply.m index 8a0f3b140..ba796632b 100644 --- a/SoObjects/Appointments/SOGoAptMailICalReply.m +++ b/SoObjects/Appointments/SOGoAptMailICalReply.m @@ -1,6 +1,6 @@ /* SOGoAptMailICalReply - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -19,6 +19,7 @@ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#import #import #import @@ -105,14 +106,11 @@ return [values keysWithFormat: subjectFormat]; } -- (NSString *) getBody +- (NSString *) bodyStartText { NSString *bodyFormat; NSString *partStat, *delegate; - if (!values) - [self setupValues]; - partStat = [[attendee partStat] lowercaseString]; if ([partStat isEqualToString: @"accepted"]) bodyFormat = @"%{Attendee} %{SentByText}has accepted your event invitation."; @@ -135,7 +133,19 @@ else bodyFormat = @"%{Attendee} %{SentByText}has not yet decided upon your event invitation."; - return [values keysWithFormat: [self labelForKey: bodyFormat inContext: context]]; + return [values keysWithFormat: bodyFormat]; +} + +- (NSString *) getBody +{ + NSString *body; + + if (!values) + [self setupValues]; + + body = [[self generateResponse] contentAsString]; + + return [body stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end diff --git a/SoObjects/Appointments/SOGoAptMailInvitation.m b/SoObjects/Appointments/SOGoAptMailInvitation.m index 09be772ce..18b285afa 100644 --- a/SoObjects/Appointments/SOGoAptMailInvitation.m +++ b/SoObjects/Appointments/SOGoAptMailInvitation.m @@ -49,27 +49,14 @@ - (NSString *) getBody { - NSString *bodyFormat; + NSString *body; if (!values) [self setupValues]; - if ([values objectForKey: @"StartTime"] && [values objectForKey: @"EndTime"]) - bodyFormat = [self labelForKey: (@"%{Organizer} %{SentByText}has invited you" - @" to %{Summary}.\n\n" - @"Start: %{StartDate} at %{StartTime}\n" - @"End: %{EndDate} at %{EndTime}\n" - @"Description: %{Description}") - inContext: context]; - else - bodyFormat = [self labelForKey: (@"%{Organizer} %{SentByText}has invited you" - @" to %{Summary}.\n\n" - @"Start: %{StartDate}\n" - @"End: %{EndDate}\n" - @"Description: %{Description}") - inContext: context]; + body = [[self generateResponse] contentAsString]; - return [values keysWithFormat: bodyFormat]; + return [body stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end diff --git a/SoObjects/Appointments/SOGoAptMailNotification.h b/SoObjects/Appointments/SOGoAptMailNotification.h index 984ca668d..407c25184 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.h +++ b/SoObjects/Appointments/SOGoAptMailNotification.h @@ -1,15 +1,15 @@ /* - Copyright (C) 2006-2010 Inverse inc. + Copyright (C) 2006-2012 Inverse inc. Copyright (C) 2000-2005 SKYRIX Software AG - This file is part of OpenGroupware.org. + This file is part of SOGo. - OGo is free software; you can redistribute it and/or modify it under + SOGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - OGo is distributed in the hope that it will be useful, but WITHOUT ANY + SOGo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. @@ -30,6 +30,7 @@ @class NSString; @class NSTimeZone; @class iCalEvent; +@class SOGoDateFormatter; /* * NOTE: We inherit from SoComponent in order to get the correct @@ -47,6 +48,7 @@ NSCalendarDate *newEndDate; NSString *organizerName; NSMutableDictionary *values; + SOGoDateFormatter *dateFormatter; } - (void) setupValues; @@ -66,6 +68,12 @@ - (NSCalendarDate *) oldEndDate; - (NSCalendarDate *) newEndDate; +- (NSString *) sentByText; +- (NSString *) formattedAptStartDate; +- (NSString *) formattedAptStartTime; +- (NSString *) formattedAptEndDate; +- (NSString *) formattedAptEndTime; + - (NSString *) getSubject; - (NSString *) getBody; diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index 70f911592..026137cc0 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -49,6 +49,7 @@ { apt = nil; values = nil; + dateFormatter = RETAIN([[context activeUser] dateFormatterInContext: context]); } return self; @@ -65,6 +66,7 @@ [newStartDate release]; [oldEndDate release]; [newEndDate release]; + [dateFormatter release]; [super dealloc]; } @@ -153,7 +155,105 @@ return organizerName; } -/* Helpers */ +- (NSString *) sentByText +{ + NSDictionary *sentByValues; + NSString *sentByText; + id value; + + sentByText = @""; + + if (organizerName) + { + value = [[apt organizer] sentBy]; + + if (value && [value length]) + { + sentByValues = [NSDictionary dictionaryWithObject: value + forKey: @"SentBy"]; + sentByText + = [sentByValues keysWithFormat: [self + labelForKey: @"(sent by %{SentBy}) " + inContext: context]]; + } + } + + return sentByText; +} + +- (NSString *) formattedAptStartDate +{ + NSString *s; + id value; + + value = [self newStartDate]; + s = @""; + + if (value) + s = [dateFormatter formattedDate: value]; + + return s; +} + + +- (NSString *) formattedAptStartTime +{ + NSString *s; + id value; + + value = [self newStartDate]; + s = @""; + + if (value && ![apt isAllDay]) + s = [dateFormatter formattedTime: value]; + + return s; +} + +- (NSString *) formattedAptEndDate +{ + NSString *s; + id value; + + value = [self newEndDate]; + s = @""; + + if (value) + s = [dateFormatter formattedDate: value]; + + return s; +} + +- (NSString *) formattedAptEndTime +{ + NSString *s; + id value; + + value = [self newEndDate]; + s = @""; + + if (value && ![apt isAllDay]) + s = [dateFormatter formattedTime: value]; + + return s; +} + +- (void) setupValues +{ + SOGoUser *user; + id value; + + user = [context activeUser]; + viewTZ = [[user userDefaults] timeZone]; + [viewTZ retain]; + + values = [NSMutableDictionary new]; + value = [self summary]; + if (!value) + value = @""; + + [values setObject: value forKey: @"Summary"]; +} /* Generate Response */ @@ -171,59 +271,4 @@ return nil; } -- (void) setupValues -{ - NSString *sentBy, *sentByText, *description; - NSCalendarDate *date; - NSDictionary *sentByValues; - SOGoUser *user; - SOGoDateFormatter *dateFormatter; - - user = [context activeUser]; - viewTZ = [[user userDefaults] timeZone]; - [viewTZ retain]; - - values = [NSMutableDictionary new]; - [values setObject: [self summary] forKey: @"Summary"]; - if (organizerName) - { - [values setObject: organizerName forKey: @"Organizer"]; - - sentBy = [[apt organizer] sentBy]; - if ([sentBy length]) - { - sentByValues = [NSDictionary dictionaryWithObject: sentBy - forKey: @"SentBy"]; - sentByText - = [sentByValues keysWithFormat: [self - labelForKey: @"(sent by %{SentBy}) " - inContext: context]]; - } - else - sentByText = @""; - [values setObject: sentByText forKey: @"SentByText"]; - } - - dateFormatter = [[context activeUser] dateFormatterInContext: context]; - - date = [self newStartDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"StartDate"]; - if (![apt isAllDay]) - [values setObject: [dateFormatter formattedTime: date] - forKey: @"StartTime"]; - - date = [self newEndDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"EndDate"]; - if (![apt isAllDay]) - [values setObject: [dateFormatter formattedTime: date] - forKey: @"EndTime"]; - - description = [[self apt] comment]; - [values setObject: (description ? description : @"") - forKey: @"Description"]; - -} - @end diff --git a/SoObjects/Appointments/SOGoAptMailUpdate.m b/SoObjects/Appointments/SOGoAptMailUpdate.m index 5b413e38b..c88854da2 100644 --- a/SoObjects/Appointments/SOGoAptMailUpdate.m +++ b/SoObjects/Appointments/SOGoAptMailUpdate.m @@ -33,10 +33,31 @@ #import "SOGoAptMailNotification.h" @interface SOGoAptMailUpdate : SOGoAptMailNotification +{ + NSMutableDictionary *changes; + NSString *currentItem; +} + @end @implementation SOGoAptMailUpdate +- (id) init +{ + self = [super init]; + + changes = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void) dealloc +{ + RELEASE(currentItem); + RELEASE(changes); + [super dealloc]; +} + - (NSString *) valueForProperty: (NSString *) property withDateFormatter: (SOGoDateFormatter *) dateFormatter { @@ -64,7 +85,10 @@ if ([valueType isEqualToString: @"date"]) { [value setTimeZone: viewTZ]; - value = [dateFormatter formattedDateAndTime: value]; + if ([apt isAllDay]) + value = [dateFormatter formattedDate: value]; + else + value = [dateFormatter formattedDateAndTime: value]; } } else @@ -75,15 +99,13 @@ - (void) _setupBodyContentWithFormatter: (SOGoDateFormatter *) dateFormatter { - NSArray *updatedProperties; - NSMutableString *bodyContent; NSString *property, *label, *value; + NSArray *updatedProperties; int count, max; updatedProperties = [[iCalEventChanges changesFromEvent: previousApt toEvent: apt] updatedProperties]; - bodyContent = [NSMutableString new]; max = [updatedProperties count]; for (count = 0; count < max; count++) { @@ -96,27 +118,40 @@ label = [self labelForKey: [NSString stringWithFormat: @"%@_label", property] inContext: context]; - [bodyContent appendFormat: @" %@ %@\n", label, value]; + [changes setObject: value forKey: label]; } } - [values setObject: bodyContent forKey: @"_bodyContent"]; - [bodyContent release]; } -- (void) _setupBodyValuesWithFormatter: (SOGoDateFormatter *) dateFormatter +- (NSArray *) allChangesList +{ + return [changes allKeys]; +} + +- (void) setCurrentItem: (NSString *) theItem +{ + ASSIGN(currentItem, theItem); +} + +- (NSString *) currentItem +{ + return currentItem; +} + +- (NSString *) valueForCurrentItem +{ + return [changes objectForKey: currentItem]; +} + +- (NSString *) bodyStartText { NSString *bodyText; bodyText = [self labelForKey: @"The following parameters have changed" @" in the \"%{Summary}\" meeting:" inContext: context]; - [values setObject: [values keysWithFormat: bodyText] - forKey: @"_bodyStart"]; - [self _setupBodyContentWithFormatter: dateFormatter]; - [values setObject: [self labelForKey: @"Please accept" - @" or decline those changes." - inContext: context] - forKey: @"_bodyEnd"]; + + return [values keysWithFormat: bodyText]; } - (void) setupValues @@ -136,7 +171,7 @@ [values setObject: [dateFormatter formattedTime: date] forKey: @"OldStartTime"]; - [self _setupBodyValuesWithFormatter: dateFormatter]; + [self _setupBodyContentWithFormatter: dateFormatter]; } - (NSString *) getSubject @@ -162,11 +197,14 @@ - (NSString *) getBody { + NSString *body; + if (!values) [self setupValues]; - return [values keysWithFormat: - @"%{_bodyStart}\n%{_bodyContent}\n%{_bodyEnd}\n"]; + body = [[self generateResponse] contentAsString]; + + return [body stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index e52aa75cc..8163cda53 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -845,8 +845,8 @@ /* text part */ headerMap = [NGMutableHashMap hashMapWithCapacity: 1]; - [headerMap setObject: @"text/plain; charset=\"UTF-8\"" - forKey: @"content-type"]; + [headerMap setObject: @"text/html; charset=utf-8" + forKey: @"content-type"]; bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap]; [bodyPart setBody: [text dataUsingEncoding: NSUTF8StringEncoding]]; @@ -927,8 +927,8 @@ /* text part */ headerMap = [NGMutableHashMap hashMapWithCapacity: 1]; - [headerMap setObject: @"text/plain; charset=utf-8" - forKey: @"content-type"]; + [headerMap setObject: @"text/html; charset=utf-8" + forKey: @"content-type"]; bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap]; bodyData = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding]; [bodyPart setBody: bodyData]; diff --git a/UI/Templates/Appointments/SOGoAptMailDeletion.wox b/UI/Templates/Appointments/SOGoAptMailDeletion.wox index 030a9112c..b19a19f2f 100644 --- a/UI/Templates/Appointments/SOGoAptMailDeletion.wox +++ b/UI/Templates/Appointments/SOGoAptMailDeletion.wox @@ -1,3 +1,44 @@ - - + + + + + + +
+

+

+ +
+
+
+
+
- +
+
+
- +
+
+
+
+
+ + diff --git a/UI/Templates/Appointments/SOGoAptMailICalReply.wox b/UI/Templates/Appointments/SOGoAptMailICalReply.wox index 030a9112c..fb8e01b75 100644 --- a/UI/Templates/Appointments/SOGoAptMailICalReply.wox +++ b/UI/Templates/Appointments/SOGoAptMailICalReply.wox @@ -1,3 +1,30 @@ - - + + + + + + +
+

+ +
+
+
+
+
+ + diff --git a/UI/Templates/Appointments/SOGoAptMailInvitation.wox b/UI/Templates/Appointments/SOGoAptMailInvitation.wox index 030a9112c..b5af75331 100644 --- a/UI/Templates/Appointments/SOGoAptMailInvitation.wox +++ b/UI/Templates/Appointments/SOGoAptMailInvitation.wox @@ -1,3 +1,44 @@ - - + + + + + + +
+

+

+ +
+
+
+
+
- +
+
+
- +
+
+
+
+
+ + diff --git a/UI/Templates/Appointments/SOGoAptMailReceipt.wox b/UI/Templates/Appointments/SOGoAptMailReceipt.wox index 957ca8fc4..c93a1dc3e 100644 --- a/UI/Templates/Appointments/SOGoAptMailReceipt.wox +++ b/UI/Templates/Appointments/SOGoAptMailReceipt.wox @@ -9,7 +9,7 @@ + + +
+ +

+

+ +
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + \ No newline at end of file