(feat) "Materialization" of the IMIP handling template

pull/91/head
Ludovic Marcotte 2015-06-03 19:42:30 -04:00 committed by Francis Lachapelle
parent fb992db5ad
commit 8124faa6d4
13 changed files with 453 additions and 220 deletions

View File

@ -1,6 +1,6 @@
/* UIxMailPartICalActions.m - this file is part of SOGo
*
* Copyright (C) 2007-2014 Inverse inc.
* Copyright (C) 2007-2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -288,12 +288,15 @@
// BOOL receiveUpdates;
NSString *delegatedEmail, *delegatedUid;
iCalPerson *delegatedAttendee;
NSDictionary *content;
SOGoUser *user;
WORequest *request;
WOResponse *response;
request = [context request];
delegatedEmail = [request formValueForKey: @"to"];
content = [[request contentAsString] objectFromJSONString];
delegatedEmail = [content objectForKey: @"delegatedTo"];
if ([delegatedEmail length])
{
user = [context activeUser];
@ -307,13 +310,14 @@
delegatedUser = [SOGoUser userWithLogin: delegatedUid];
[delegatedAttendee setCn: [delegatedUser cn]];
}
[delegatedAttendee setRole: @"REQ-PARTICIPANT"];
[delegatedAttendee setRsvp: @"TRUE"];
[delegatedAttendee setParticipationStatus: iCalPersonPartStatNeedsAction];
[delegatedAttendee setDelegatedFrom:
[NSString stringWithFormat: @"mailto:%@", [[user allEmails] objectAtIndex: 0]]];
// receiveUpdates = [[request formValueForKey: @"receiveUpdates"] boolValue];
// receiveUpdates = [[content objectForKey: @"receiveUpdates"] boolValue];
// if (receiveUpdates)
// [delegatedAttendee setRole: @"NON-PARTICIPANT"];

View File

@ -1,22 +1,20 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
* Copyright (C) 2007-2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef UIXMAILPARTICALVIEWER_H

View File

@ -1,6 +1,5 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
Copyright (C) 2006-2013 Inverse inc.
Copyright (C) 2006-2015 Inverse inc.
This file is part of SOGo.
@ -182,6 +181,59 @@
return date;
}
/*
In v3.0, we moved the template's logic here to format
the event's start/end date-time. The previous logic was:
<dd><var:string value="startDate" />
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string value="startTime" />
</var:if>
<var:if condition="isEndDateOnSameDay">
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string label:value="to" />
<var:string value="endTime" />
</var:if>
</var:if>
<var:if condition="isEndDateOnSameDay" const:negate="YES">
<var:string label:value="to" />
<var:string value="endDate" />
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string value="endTime" />
</var:if>
</var:if>
</dd>
*/
- (NSString *) formattedDateTime
{
NSMutableString *s;
s = [NSMutableString string];
[s appendString: [self startDate]];
if (![[self inEvent] isAllDay])
[s appendFormat: @" %@", [self startTime]];
if ([self isEndDateOnSameDay] &&
![[self inEvent] isAllDay])
{
[s appendFormat: @" %@", [self labelForKey: @"to"]];
[s appendFormat: @" %@", [self endTime]];
}
else if (![self isEndDateOnSameDay])
{
[s appendFormat: @" %@", [self labelForKey: @"to"]];
[s appendFormat: @" %@", [self endDate]];
if (![[self inEvent] isAllDay])
[s appendFormat: @" %@", [self endTime]];
}
return s;
}
- (NSString *) startDate
{
return [[self dateFormatter] formattedDate: [self startCalendarDate]];
@ -388,10 +440,7 @@
cssClass = [[attendee partStatWithDefault] lowercaseString];
if ([[attendee rfc822Email] isEqualToString: [self loggedInUserEMail]])
cssClass = [cssClass stringByAppendingString: @" attendeeUser"];
return cssClass;
return [NSString stringWithFormat: @"sg-%@", cssClass];
}
/* derived fields */

View File

@ -328,6 +328,15 @@
return url;
}
- (NSString *) pathToAttachmentFromMessage
{
SOGoMailBodyPart *bodyPart;
bodyPart = [self clientPart];
return [NSString stringWithFormat: @"%@/%@", [bodyPart nameInContainer], [self _filenameForAttachment: bodyPart]];
}
- (NSString *) pathToAttachment
{
return [self _pathForAttachmentOrDownload: NO];

View File

@ -43,11 +43,6 @@
actionClass = "UIxMailPartICalActions";
actionName = "updateUserStatus";
};
/* tentative = {
protectedBy = "View";
actionClass = "UIxMailPartICalAction";
actionName = "markTentative";
}; */
addToCalendar = {
protectedBy = "View";
actionClass = "UIxMailPartICalActions";

View File

@ -14,11 +14,12 @@ th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; fon
<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;"><var:string
value="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</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="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</tr>
<tr>
<th align="right" style="font-weight: bold;"><var:string label:value="location_label" const:escapeHTML="NO"/></th>
<td><var:string value="location" const:escapeHTML="NO"/></td>

View File

@ -15,7 +15,8 @@ th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; fon
<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;"><var:string
<td><h1 style="font-size: 18px; font-weight: normal;
padding-bottom: 9px; border-bottom: 1px solid #ccc;" class="ng-hide"><var:string
value="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</tr>

View File

@ -15,7 +15,8 @@ th, td { font-family: Lucida Grande, Bitstream VeraSans, Tahoma, sans-serif; fon
<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;"><var:string
<td><h1 style="font-size: 18px; font-weight: normal;
padding-bottom: 9px; border-bottom: 1px solid #ccc;" class="ng-hide"><var:string
value="getSubject" const:escapeHTML="NO"/> <small style="font-size: 12px; color: #999;"><var:string
value="organizerName" const:escapeHTML="NO"/><var:string value="sentByText" const:escapeHTML="NO"/></small></h1></td>
</tr>

View File

@ -4,173 +4,219 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:label="OGo:label"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
class="linked_attachment_frame"
>
<!-- TODO: add iMIP actions -->
<input id="iCalendarAttachment" type="hidden"
var:value="pathToAttachment"/>
xmlns:rsrc="OGo:url">
<!-- PARSING ERROR -->
<var:if condition="couldParseCalendar" const:negate="1">
<fieldset>
<legend>Parsing Error</legend>
The SOGo/SOPE iCalendar parser could not parse the body of this MIME part.
<pre><var:string value="flatContentAsString" /></pre>
</fieldset>
</var:if>
<var:if condition="couldParseCalendar">
<div class="popupMenu" id="contactsMenu">
<ul></ul>
<div>
<md-toolbar class="md-medium-tall md-warn md-hue-3">
<div class="md-toolbar-tools">
<h2>
SOGo could not parse the body of this calendar MIME part.
</h2>
</div>
</md-toolbar>
<md-whiteframe class="md-whiteframe-z1" layout="row" layout-align="space-between center">
<pre><var:string value="flatContentAsString" /></pre>
</md-whiteframe>
</div>
<fieldset>
<legend>
<var:string label:value="Appointment"/>:
<strong><var:string value="inEvent.summary" /></strong> <!-- TODO: shorted title -->
<var:if condition="isLoggedInUserTheOrganizer">
(<var:string label:value="organized_by_you"/>)
</var:if>
<var:if condition="isLoggedInUserAnAttendee">
(<var:string label:value="you_are_an_attendee"/>)
</var:if>
</legend>
</var:if> <!-- if condition="couldParseCalendar" const:negate="1" -->
<!-- EVENT PROPERLY PARSED -->
<var:if condition="couldParseCalendar">
<md-divider class="md-padding"/>
<div sg-imip="message" var:sg-imip-path="pathToAttachmentFromMessage">
<!-- TODO - remove unused strings
<legend>
<var:string label:value="Appointment"/>:
<strong><var:string value="inEvent.summary" /></strong>
<var:if condition="isLoggedInUserTheOrganizer">
(<var:string label:value="organized_by_you"/>)
</var:if>
<var:if condition="isLoggedInUserAnAttendee">
(<var:string label:value="you_are_an_attendee"/>)
</var:if>
</legend> -->
<!-- IMIP REQUEST -->
<var:if condition="inCalendar.method.uppercaseString" const:value="REQUEST">
<!-- sent to attendees to propose or update a meeting -->
<var:if condition="isLoggedInUserAnAttendee">
<var:if condition="hasCalendarAccess">
<div class="uix_ical_toolbar" id="iCalendarToolbar">
<p>
<div>
<p>
<var:if condition="currentUserAttendee.rsvp" const:value="true">
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="ACCEPTED" const:negate="YES">
<a href="#" class="button actionButton" id="iCalendarAccept">
<span><var:string label:value="Accept" /></span></a>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DECLINED" const:negate="YES">
<a href="#" class="button actionButton" id="iCalendarDecline">
<span><var:string label:value="Decline" /></span></a>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="TENTATIVE" const:negate="YES">
<a href="#" class="button actionButton" id="iCalendarTentative">
<span><var:string label:value="Tentative" /></span></a>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DELEGATED" const:negate="YES">
<a href="#" class="button actionButton" id="editDelegate">
<span><var:string label:value="Delegate ..." /></span></a>
<span id="delegateEditor" style="display: none;">
<span class="floatLeft"><var:string label:value="Delegated to" /></span>
<input name="delegatedTo" id="delegatedTo" type="text" />
<a href="#" class="button actionButton" id="iCalendarDelegate" name="delegateOK">
<span><var:string label:value="OK" /></span></a>
</span>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DELEGATED">
<span id="delegateEditor">
<span class="floatLeft"><var:string label:value="Delegated to" />
<a var:href="currentUserAttendee.delegatedTo" name="delegatedToLink" id="delegatedToLink"><var:string value="currentUserAttendee.delegatedTo.rfc822Email" /></a></span>
<input name="delegatedTo" id="delegatedTo" type="text" var:value="currentUserAttendee.delegatedTo.rfc822Email" var:uid="currentUserAttendee.delegatedTo.rfc822Email" style="display: none;" />
<a href="#" class="button actionButton" id="iCalendarDelegate" style="display: none;">
<span><var:string label:value="OK" /></span></a>
</span>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="ACCEPTED" const:negate="YES">
<md-button type="button" ng-click="iCalendarAction('accept')">
<var:string label:value="Accept" />
</md-button>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DECLINED" const:negate="YES">
<md-button type="button" ng-click="iCalendarAction('decline')">
<var:string label:value="Decline" />
</md-button>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="TENTATIVE" const:negate="YES">
<md-button type="button" ng-click="iCalendarAction('tentative')">
<var:string label:value="Tentative" />
</md-button>
</var:if>
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DELEGATED" const:negate="YES">
<md-button type="button"
ng-click="delegateInvitation = true"
ng-hide="delegateInvitation == true">
<var:string label:value="Delegate ..." />
</md-button>
<div class="md-actions" layout="row"
layout-align="start center"
ng-show="delegateInvitation == true">
<md-autocomplete
class="md-flex"
md-search-text="searchText"
md-selected-item="delegatedTo"
md-items="user in userFilter(searchText)"
md-min-length="3"
md-no-cache="true"
md-item-text="user.$shortFormat()"
label:md-floating-label="Delegated to">
<span class="md-contact-suggestion" layout="row" layout-align="space-between center">
<span class="md-contact-name"
md-highlight-text="searchText"
md-highlight-flags="^i">{{user.cn}}</span> <span class="md-contact-email"
md-highlight-text="searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-autocomplete>
<md-button ng-click="delegateInvitation = false"><var:string label:value="Cancel"/></md-button>
<md-button class="md-primitive"
ng-click="iCalendarAction('delegate')"
ng-disabled="!delegatedTo || delegatedTo.length == 0"><var:string label:value="OK"/></md-button>
</div>
</var:if>
<!-- TODO - should we re-enable this? It never
worked in v2!
<var:if condition="currentUserAttendee.partStatWithDefault"
const:value="DELEGATED">
<span id="delegateEditor">
<span class="floatLeft"><var:string label:value="Delegated to" />
<a var:href="currentUserAttendee.delegatedTo" name="delegatedToLink" id="delegatedToLink"><var:string value="currentUserAttendee.delegatedTo.rfc822Email" /></a></span>
<input name="delegatedTo" id="delegatedTo" type="text" var:value="currentUserAttendee.delegatedTo.rfc822Email" var:uid="currentUserAttendee.delegatedTo.rfc822Email" style="display: none;" />
<a href="#" class="button actionButton" id="iCalendarDelegate" style="display: none;">
<span><var:string label:value="OK" /></span></a>
</span>
</var:if>
-->
</var:if> <!-- if condition="currentUserAttendee.rsvp" const:value="true" -->
<var:if condition="isEventStoredInCalendar" const:negate="YES">
<md-button type="button" ng-click="iCalendarAction('addToCalendar')">
<var:string label:value="Add to calendar" />
</md-button>
</var:if>
<var:if condition="isEventStoredInCalendar" const:negate="YES">
<a href="#" class="button actionButton" id="iCalendarAddToCalendar">
<span><var:string label:value="Add to calendar" /></span></a>
</p>
</div>
</var:if> <!-- if condition="hasCalendarAccess" -->
<p>
<var:string label:value="Organizer" />
<a var:href="inEvent.organizer.email"
><var:string value="organizerDisplayName" /></a>
<var:string label:value="request_info" />
</p>
</var:if> <!-- if condition="isLoggedInUserAnAttendee" -->
<var:if condition="isLoggedInUserAnAttendee" const:negate="YES">
<p>
<var:string label:value="Organizer" />
<a var:href="inEvent.organizer.email">
<var:string value="organizerDisplayName" />
</a>
<var:string label:value="request_info_no_attendee" />
</p>
</var:if>
</p>
</div>
</var:if>
<p class="clear">
<var:string label:value="Organizer" />
<a var:href="inEvent.organizer.email"
><var:string value="organizerDisplayName" /></a>
<var:string label:value="request_info" />
</p>
</var:if>
<var:if condition="isLoggedInUserAnAttendee" const:negate="YES">
<p>
<var:string label:value="Organizer" />
<a var:href="inEvent.organizer.email"
><var:string value="organizerDisplayName" /></a>
<var:string label:value="request_info_no_attendee" />
</p>
</var:if>
</var:if>
</var:if> <!-- if condition="inCalendar.method.uppercaseString"
const:value="REQUEST" -->
<!-- IMIP REPLY - sent to organizer to update the status of the
participant -->
<var:if condition="inCalendar.method.uppercaseString" const:value="REPLY">
<!-- sent to organizer to update the status of the participant -->
<var:if condition="isReplySenderAnAttendee" const:negate="1">
<p><var:string label:value="reply_info_no_attendee" /></p>
<p>
<var:string label:value="reply_info_no_attendee" />
</p>
</var:if>
<var:if condition="isReplySenderAnAttendee">
<var:if condition="canOriginalEventBeUpdated"
><dl class="dl-horizontal">
<dt><var:string label:value="Status Update" />:</dt>
<dd><i><var:string label:value="$inReplyAttendee.partStatWithDefault" /></i>,
<var:if condition="canOriginalEventBeUpdated">
<p>
<var:string label:value="Status Update" />:
<i><var:string label:value="$inReplyAttendee.partStatWithDefault" /></i>,
<var:string label:value="was" />
<i><var:string label:value="$storedReplyAttendee.partStatWithDefault" /></i>.
<br/><input id="iCalendarUpdateUserStatus" class="button"
type="button" label:value="Update status"/></dd>
</dl></var:if>
<i><var:string label:value="$storedReplyAttendee.partStatWithDefault"/></i>.
</p>
<br/>
<md-button type="button" ng-click="iCalendarAction('updateUserStatus')">
<var:string label:value="Update status" />
</md-button>
</var:if>
</var:if>
</var:if>
<!-- IMIP CANCEL - sent to attendees to notify of the attendee
being removed or the
event being deleted -->
<var:if condition="inCalendar.method.uppercaseString" const:value="CANCEL">
<!-- sent to attendees to notify of the attendee being removed or the
event being deleted -->
<dl class="dl-horizontal">
<dd><var:string label:value="cancel_info_text" />
<p><var:string label:value="cancel_info_text" /></p>
<var:if condition="isEventStoredInCalendar">
<br/><a href="#" id="iCalendarDeleteFromCalendar" class="button">
<span><var:string label:value="Delete from calendar" /></span></a>
</var:if></dd>
</dl>
<md-button type="button" ng-click="iCalendarAction('deleteFromCalendar')">
<var:string label:value="Delete from calendar" />
</md-button>
</var:if>
</var:if>
<!-- IMIP ADD - TODO -->
<var:if condition="inCalendar.method.uppercaseString" const:value="ADD">
<!-- TODO -->
<dl class="dl-horizontal">
<dd><var:string label:value="add_info_text" /></dd>
</dl>
<p><var:string label:value="add_info_text" /></p>
</var:if>
<!-- IMIP PUBLISH - none-scheduling event sent to someone for
adding to the calendar -->
<var:if condition="inCalendar.method.uppercaseString" const:value="PUBLISH">
<!-- none-scheduling event sent to someone for adding to the calendar -->
<dl class="dl-horizontal">
<dd><var:string label:value="publish_info_text" /></dd>
</dl>
<p><var:string label:value="publish_info_text" /></p>
</var:if>
<var:if condition="isLoggedInUserTheOrganizer">
<!--
Possible Status:
REPLY => check whether it matches, if not suggest change, show
comment
REFRESH => add button to resent iCal
COUNTER => show panel to decide on counter
Possible Status:
REPLY => check whether it matches, if not suggest change, show
comment
REFRESH => add button to resent iCal
COUNTER => show panel to decide on counter
-->
</var:if>
<var:if condition="isLoggedInUserTheOrganizer" const:negate="1">
<!--
Possible Status:
REQUEST => ACCEPT, TENTATIVELY, DECLINE buttons with comment field
- only show buttons for attendees
PUBLISH => just the 'add to calendar' button, rewrite organizer?
ADD / CANCEL
DECLINE-COUNTER
Possible Status:
REQUEST => ACCEPT, TENTATIVELY, DECLINE buttons with comment field
- only show buttons for attendees
PUBLISH => just the 'add to calendar' button, rewrite organizer?
ADD / CANCEL
DECLINE-COUNTER
-->
</var:if>
@ -181,57 +227,60 @@
</div>
<br />
</var:if>
<div class="linked_attachment_meta" style="background-color: white;">
<dl id="iCalAttendees" class="dl-horizontal">
<dt><var:string label:value="Time"/>:</dt>
<dd><var:string value="startDate" />
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string value="startTime" />
</var:if>
<var:if condition="isEndDateOnSameDay">
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string label:value="to" />
<var:string value="endTime" />
</var:if>
</var:if>
<var:if condition="isEndDateOnSameDay" const:negate="YES">
<var:string label:value="to" />
<var:string value="endDate" />
<var:if condition="inEvent.isAllDay" const:negate="YES">
<var:string value="endTime" />
</var:if>
</var:if>
</dd>
<dt><var:string label:value="Organizer"/>:</dt>
<dd><a var:href="authorativeEvent.organizer.email"
><var:string value="organizerDisplayName" /></a>
</dd>
<dt><var:string label:value="Attendees"/>:</dt>
<var:foreach list="authorativeEvent.participants" item="attendee">
<var:if condition="attendee.delegatedTo" const:negate="YES"><!-- don't show attendees that delegated the invitation --> <dd><span var:class="currentAttendeeClass"
><div class="status-icon"><!-- space --></div
><a var:href="attendee.email">
<var:string value="attendeeForDisplay"/></a>
(<var:string label:value="$attendee.partStatWithDefault" /><var:if condition="attendee.delegatedTo"> <var:string label:value="to" /> <var:string value="attendee.delegatedTo.rfc822Email" /></var:if><var:if condition="attendee.delegatedFrom.length">, <var:string label:value="delegated from" /> <var:string value="attendee.delegatedFrom.rfc822Email" /></var:if>)</span>
</dd></var:if>
</var:foreach>
<var:if condition="authorativeEvent.comment.isNotEmpty">
<dt><var:string label:value="Comment"/>:</dt>
<dd><var:string value="authorativeEvent.comment" const:insertBR="1" /></dd>
</var:if>
</dl>
<!-- EVENT'S METADATA (time, organizer, attendees, etc.) -->
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Organizer"/></label>
<div>
<var:string value="organizerDisplayName"/>
</div>
</div>
</fieldset>
</var:if><!-- could parse -->
<!--
<var:string value="appointment" />
<br />
<br />
<br />
-->
<!-- <pre style="display: none;"><var:string value="flatContentAsString" /></pre> -->
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Time"/></label>
<div>
<var:string value="formattedDateTime"/>
</div>
</div>
<md-list>
<header class="sg-md-subheader">
<var:string label:value="Attendees"/>
</header>
<var:foreach list="authorativeEvent.participants"
item="attendee">
<var:if condition="attendee.delegatedTo" const:negate="YES">
<md-list-item>
<div layout="row" layout-align="start center">
<div var:class="currentAttendeeClass"><!-- accepted/declided/tentative/delegated --></div>
<div class="md-list-item-text">
<p><a var:href="attendee.email"><var:string value="attendeeForDisplay"/></a></p>
<p>(<var:string label:value="$attendee.partStatWithDefault" /><var:if condition="attendee.delegatedTo"> <var:string label:value="to" /> <var:string value="attendee.delegatedTo.rfc822Email" /></var:if><var:if condition="attendee.delegatedFrom.length">, <var:string label:value="delegated from" /> <var:string value="attendee.delegatedFrom.rfc822Email" /></var:if>)</p>
</div>
</div>
</md-list-item>
</var:if>
</var:foreach>
</md-list>
<var:if condition="authorativeEvent.comment.isNotEmpty">
<div class="pseudo-input-container">
<label class="pseudo-input-label">
<var:string label:value="Comment"/>
</label>
<div>
<p>
<var:string value="authorativeEvent.comment" const:insertBR="1" />
</p>
</div>
</div>
</var:if>
</div>
</var:if><!--if condition="couldParseCalendar" -->
</div>

View File

@ -291,6 +291,25 @@
return Message.$$resource.post(this.$mailbox.$id(), 'addOrRemoveLabel', data);
};
/**
* @function $imipAction
* @memberof Message.prototype
* @desc Perform IMIP actions on the current message.
* @param {string} path - the path of the IMIP calendar part
* @param {string} action - the the IMIP action to perform
* @param {object} data - the delegation info
*/
Message.prototype.$imipAction = function(path, action, data) {
var _this = this;
Message.$$resource.post([this.id, path].join('/'), action, data).then(function(data) {
Message.$timeout(function() {
_this.$reload();
}, function() {
// TODO: show toast
});
});
};
/**
* @function $markAsFlaggedOrUnflagged
* @memberof Message.prototype

View File

@ -0,0 +1,54 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
'use strict';
/**
* sgIMIP - A directive to handle IMIP actions on emails
* @memberof SOGo.MailerUI
* @ngInject
* @example:
*/
function sgImip() {
return {
restrict: 'A',
link: link,
controller: controller
};
function link(scope, iElement, attrs, ctrl) {
ctrl.pathToAttachment = attrs.sgImipPath;
}
controller.$inject = ['$scope', 'User'];
function controller($scope, User) {
var vm = this;
$scope.delegateInvitation = false;
$scope.delegatedTo = '';
$scope.searchText = '';
$scope.userFilter = function($query) {
return User.$filter($query);
};
$scope.iCalendarAction = function(action) {
var data;
if (action == 'delegate') {
data = {receiveUpdates: false,
delegatedTo: $scope.delegatedTo.c_email};
}
$scope.message.$imipAction(vm.pathToAttachment, action, data);
};
}
}
angular
.module('SOGo.MailerUI')
.directive('sgImip', sgImip);
})();

View File

@ -85,3 +85,28 @@
margin-right: 0;
margin-left: 0;
}
.sg-accepted {
@extend .md-tile-left-accepted;
margin-right: 0;
margin-left: 0;
}
.sg-declined {
@extend .md-tile-left-declined;
margin-right: 0;
margin-left: 0;
}
.sg-delegated {
@extend .md-tile-left-delegated;
margin-right: 0;
margin-left: 0;
}
.sg-needs-action {
@extend .md-tile-left-needs-action;
margin-right: 0;
margin-left: 0;
}
.sg-tentative {
@extend .md-tile-left-tentative;
margin-right: 0;
margin-left: 0;
}

View File

@ -99,3 +99,31 @@ div.md-tile-left {
@extend .md-tile-left;
content: "\f299";
}
.md-tile-left-accepted:before {
@extend .md-tile-left;
background-color: rgba(0, 255, 0, 0.3) !important;
content: "\f299";
color: rgba(0, 0, 0, 0.5);
}
.md-tile-left-declined:before {
@extend .md-tile-left;
background-color: rgba(255, 0, 0, 0.3) !important;
content: "\f111";
color: rgba(0, 0, 0, 0.5);
}
.md-tile-left-delegated:before {
@extend .md-tile-left;
background-color: rgba(192, 192, 192, 0.3) !important;
content: "\f298";
color: rgba(0, 0, 0, 0.5);
}
.md-tile-left-needs-action:before {
@extend .md-tile-left;
background-color: rgba(255, 255, 0, 0.3) !important;
content: "?";
}
.md-tile-left-tentative:before {
@extend .md-tile-left;
background-color: rgba(255, 255, 0, 0.3) !important;
content: "\f2d8";
}