(feat) email alarms now have pretty formatting (fixes #805)

pull/236/head
Ludovic Marcotte 2017-04-12 08:59:29 -04:00
parent dbf5039011
commit 7d396a51f5
7 changed files with 339 additions and 13 deletions

View File

@ -22,6 +22,8 @@ vtodo_class2 = "(Confidential task)";
"location_label" = "Location";
"summary_label" = "Summary";
"comment_label" = "Comment";
"organizer_label" = "Organizer";
"attendee_label" = "Attendee";
/* Invitation */
"Event Invitation: \"%{Summary}\"" = "Event Invitation: \"%{Summary}\"";
"(sent by %{SentBy}) " = "(sent by %{SentBy}) ";

View File

@ -43,6 +43,7 @@ Appointments_OBJC_FILES = \
SOGoAptMailICalReply.m \
SOGoAptMailUpdate.m \
SOGoAptMailReceipt.m \
SOGoAptMailReminder.m \
\
SOGoEMailAlarmsManager.m \
\

View File

@ -0,0 +1,32 @@
/* SOGoAptMailReminder.h - this file is part of SOGo
*/
#ifndef SOGOAPTMAILRECEIPT_H
#define SOGOAPTMAILRECEIPT_H
#import "SOGoAptMailNotification.h"
@class NSArray;
@class NSString;
@class iCalPerson;
@interface SOGoAptMailReminder : SOGoAptMailNotification
{
NSArray *attendees;
iCalPerson *currentRecipient;
NSString *calendarName;
}
- (void) setAttendees: (NSArray *) theAttendees;
- (void) setCalendarName: (NSString *) theCalendarName;
- (NSString *) aptSummary;
- (NSString *) aptStartDate;
- (NSString *) calendarName;
- (iCalPerson *) organizer;
@end
#endif /* SOGOAPTMAILRECEIPT_H */

View File

@ -0,0 +1,162 @@
/* SOGoAptMailReminder.m - this file is part of SOGo
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSCharacterSet.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalPerson.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoDateFormatter.h>
#import <SOGo/SOGoUser.h>
#import "SOGoAptMailReminder.h"
static SOGoUserManager *um = nil;
static NSCharacterSet *wsSet = nil;
@implementation SOGoAptMailReminder
+ (void) initialize
{
if (!um)
um = [SOGoUserManager sharedUserManager];
if (!wsSet)
wsSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
}
- (id) init
{
if ((self = [super init]))
{
attendees = nil;
currentRecipient = nil;
calendarName = nil;
}
return self;
}
- (void) dealloc
{
[attendees release];
[calendarName release];
[super dealloc];
}
- (void) setupValues
{
[super setupValues];
[values setObject: [self aptStartDate]
forKey: @"StartDate"];
}
- (NSString *) getBody
{
NSString *body;
if (!values)
[self setupValues];
body = [[self generateResponse] contentAsString];
return [body stringByTrimmingCharactersInSet: wsSet];
}
- (void) setAttendees: (NSArray *) theAttendees
{
ASSIGN (attendees, theAttendees);
}
- (NSArray *) attendees
{
return attendees;
}
- (void) setCurrentRecipient: (iCalPerson *) newCurrentRecipient
{
ASSIGN (currentRecipient, newCurrentRecipient);
}
- (iCalPerson *) currentRecipient
{
return currentRecipient;
}
- (void) setCalendarName: (NSString *) theCalendarName
{
ASSIGN (calendarName, theCalendarName);
}
- (NSString *) calendarName
{
return calendarName;
}
- (NSString *) aptSummary
{
NSString *s;
if (!values)
[self setupValues];
s = [self labelForKey: @"Reminder: \"%{Summary}\" - %{StartDate}"
inContext: context];
return [values keysWithFormat: s];
}
- (NSString *) getSubject
{
return [[[self aptSummary] stringByTrimmingCharactersInSet: wsSet] asQPSubjectString: @"utf-8"];
}
- (NSString *) _formattedUserDate: (NSCalendarDate *) date
{
SOGoDateFormatter *formatter;
NSCalendarDate *tzDate;
SOGoUser *currentUser;
currentUser = [context activeUser];
tzDate = [date copy];
[tzDate setTimeZone: viewTZ];
[tzDate autorelease];
formatter = [currentUser dateFormatterInContext: context];
if ([apt isAllDay])
return [formatter formattedDate: tzDate];
else
return [NSString stringWithFormat: @"%@, %@",
[formatter formattedDate: tzDate],
[formatter formattedTime: tzDate]];
}
- (NSString *) aptStartDate
{
return [self _formattedUserDate: [apt startDate]];
}
- (NSString *) aptEndDate
{
return [self _formattedUserDate: [(iCalEvent *) apt endDate]];
}
- (iCalPerson *) organizer
{
return [apt organizer];
}
@end

View File

@ -13,4 +13,4 @@ ADDITIONAL_LIB_DIRS += \
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
-L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/ -lGDLContentStore \
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ -lNGCards \
-lEOControl -lNGStreams -lNGMime -lNGExtensions -lNGObjWeb
-lEOControl -lNGStreams -lNGMime -lNGExtensions -lNGObjWeb -lWEExtensions

View File

@ -30,6 +30,7 @@
#import <NGMail/NGMimeMessage.h>
#import <NGCards/iCalAlarm.h>
#import <NGCards/iCalEvent.h>
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSString+Utilities.h>
@ -37,9 +38,19 @@
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoProductLoader.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/NSDictionary+Utilities.m>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/SOGoUserFolder.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#import <Appointments/iCalPerson+SOGo.h>
#import <Appointments/SOGoEMailAlarmsManager.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <Appointments/SOGoAptMailReminder.h>
#import <WEExtensions/WEResourceManager.h>
#import "SOGoEAlarmsNotifier.h"
@ -81,14 +92,14 @@
- (NGMutableHashMap *) _headersForAlarm: (iCalAlarm *) alarm
withOwner: (SOGoUser *) owner
withSubject: (NSString *) subject
{
NGMutableHashMap *headers;
NSString *dateString, *subject, *fullName, *email;
NSString *dateString, *fullName, *email;
NSDictionary *identity;
headers = [NGMutableHashMap hashMap];
subject = [[alarm summary] asQPSubjectString: @"utf-8"];
[headers addObject: subject forKey: @"Subject"];
dateString = [[NSCalendarDate date] rfc822DateString];
[headers addObject: dateString forKey: @"Date"];
@ -96,11 +107,11 @@
[headers addObject: @"SOGo Alarms Notifier/1.0" forKey: @"User-Agent"];
[headers addObject: @"high" forKey: @"Importance"];
[headers addObject: @"1" forKey: @"X-Priority"];
[headers setObject: @"text/plain; charset=\"utf-8\"" forKey: @"Content-Type"];
[headers setObject: @"text/html; charset=\"utf-8\"" forKey: @"Content-Type"];
[headers setObject: @"quoted-printable" forKey: @"Content-Transfer-Encoding"];
identity = [owner primaryIdentity];
fullName = [[identity objectForKey: @"fullName"] asQPSubjectString: @"utf-8"];
fullName = [identity objectForKey: @"fullName"];
if ([fullName length])
email = [NSString stringWithFormat: @"%@ <%@>", fullName,
[identity objectForKey: @"email"]];
@ -140,20 +151,63 @@
- (void) _processAlarm: (iCalAlarm *) alarm
withOwner: (NSString *) ownerId
andContainerPath: (NSString *) containerPath
{
NGMutableHashMap *headers;
NSArray *attendees;
NSArray *attendees, *parts;
NSData *content, *qpContent;
int count, max;
SOGoMailer *mailer;
NSString *from;
NSString *from, *subject;
SOGoUser *owner;
WOContext *localContext;
WOApplication *app;
SOGoAptMailReminder *p;
NSString *pageName;
WOResourceManager *rm;
SOGoAppointmentFolders *folders;
SOGoAppointmentFolder *folder;
SOGoUserFolder *userFolder;
owner = [SOGoUser userWithLogin: ownerId];
mailer = [SOGoMailer mailerWithDomainDefaults: [owner domainDefaults]];
headers = [self _headersForAlarm: alarm withOwner: owner];
content = [[alarm comment] dataUsingEncoding: NSUTF8StringEncoding];
localContext = [WOContext context];
[localContext setActiveUser: owner];
app = [[WOApplication alloc] initWithName: @"SOGo"];
rm = [[WEResourceManager alloc] init];
[app setResourceManager:rm];
[rm release];
[app _setCurrentContext:localContext];
userFolder = [[localContext activeUser] homeFolderInContext: localContext ];
folders = [userFolder privateCalendars: @"Calendar"
inContext: localContext];
pageName = [NSString stringWithFormat: @"SOGoAptMail%@", @"Reminder"];
p = [app pageWithName: pageName inContext: localContext];
parts = [containerPath componentsSeparatedByString: @"/"];
if ([parts count] > 4)
{
folder = [folders lookupName: [parts objectAtIndex: 4]
inContext: localContext
acquire: NO];
[p setCalendarName: [folder displayName]];
}
[p setApt: [alarm parent]];
[p setAttendees: [[alarm parent] attendees]];
content = [[p getBody] dataUsingEncoding: NSUTF8StringEncoding];
subject = [p getSubject];
headers = [self _headersForAlarm: alarm withOwner: owner withSubject: subject];
qpContent = [content dataByEncodingQuotedPrintable];
from = [[owner primaryIdentity] objectForKey: @"email"];
@ -191,6 +245,8 @@
int count, max;
[[SOGoProductLoader productLoader] loadAllProducts: YES];
if ([[NSUserDefaults standardUserDefaults] stringForKey: @"h"])
{
[self usage];
@ -209,9 +265,6 @@
[staticAuthenticator retain];
}
[[SOGoProductLoader productLoader]
loadProducts: [NSArray arrayWithObject: @"Appointments.SOGo"]];
eaMgr = [NSClassFromString (@"SOGoEMailAlarmsManager")
sharedEMailAlarmsManager];
@ -225,10 +278,12 @@
second: 0]
toDate: toDate
withMetadata: metadata];
max = [alarms count];
for (count = 0; count < max; count++)
[self _processAlarm: [alarms objectAtIndex: count]
withOwner: [[metadata objectAtIndex: count] objectForKey: @"owner"]];
withOwner: [[metadata objectAtIndex: count] objectForKey: @"owner"]
andContainerPath: [[[metadata objectAtIndex: count] objectForKey: @"record"] objectForKey: @"c_path"]];
// We now update the next alarm date (if any, for recurring
// events or tasks for example). This will also delete any emai

View File

@ -0,0 +1,74 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE container>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<head>
<style type="text/css">
th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; font-size: 12px; line-height: 18px; }
</style>
</head>
<body>
<table cellpadding="2" cellspacing="2" border="0" style="width: 100%; max-width: 600px;">
<tr>
<th></th>
<td><h1 style="font-size: 18px; font-weight: normal; padding-bottom: 9px; border-bottom: 1px solid #ccc;" class="ng-hide"><var:string
value="aptSummary" const:escapeHTML="NO"/></h1></td>
</tr>
<var:if condition="calendarName.length"
><tr>
<th align="right" style="font-weight: bold;"><var:string label:value="calendar_label" const:escapeHTML="NO"/></th>
<td><var:string value="calendarName" const:escapeHTML="NO"/></td>
</tr></var:if>
<var:if condition="apt.location.length"
><tr>
<th align="right" style="font-weight: bold;"><var:string label:value="location_label" const:escapeHTML="NO"/></th>
<td><var:string value="apt.location" const:escapeHTML="NO"/></td>
</tr></var:if>
<tr>
<th align="right" style="font-weight: bold;"><var:string label:value="startDate_label" const:escapeHTML="NO"/></th>
<td><var:string value="aptStartDate" const:escapeHTML="NO"/></td>
</tr>
<tr>
<th align="right" style="font-weight: bold;"><var:string label:value="endDate_label" const:escapeHTML="NO"/></th>
<td><var:string value="aptEndDate" const:escapeHTML="NO"/></td>
</tr>
<var:if condition="apt.comment.length"
><tr>
<th align="right" style="font-weight: bold;"><var:string label:value="comment_label" const:escapeHTML="NO"/></th>
<td><var:string value="apt.comment" const:escapeHTML="NO"/></td>
</tr>
</var:if>
<var:if condition="attendees.count"
><tr></tr><tr>
<th align="right" style="font-weight: bold;"><var:string label:value="organizer_label" const:escapeHTML="NO"/></th>
<var:if condition="organizer.cn">
<td><a var:href="organizer.email"><var:string value="organizer.cn" const:escapeHTML="NO"/></a></td>
</var:if>
<var:if condition="organizer.cn" const:negate="YES">
<td><a var:href="organizer.email"><var:string value="organizer.rfc822Email" const:escapeHTML="NO"/></a></td>
</var:if>
</tr>
<tr>
<th align="right" style="font-weight: bold;"><var:string label:value="attendee_label" const:escapeHTML="NO"/></th>
<var:foreach list="attendees" item="currentRecipient">
<var:if condition="currentRecipient.cn">
<td><a var:href="currentRecipient.email"><var:string value="currentRecipient.cn" const:escapeHTML="NO"/></a></td>
</var:if>
<var:if condition="currentRecipient.cn" const:negate="YES">
<td><a var:href="currentRecipient.email"><var:string value="currentRecipient.rfc822Email" const:escapeHTML="NO"/></a></td>
</var:if>
<tr></tr><th align="right"></th>
</var:foreach>
</tr>
</var:if>
</table>
</body>
</html>