- Fix task attendees and organizer setting and display
- Make basic iTip exchange for task assignments work - Improve wording for task assignments
This commit is contained in:
parent
445edd09b7
commit
b3c5acd66a
11 changed files with 242 additions and 161 deletions
|
@ -213,6 +213,14 @@ class libcalendaring_itip
|
||||||
$event['attendees'] = $reply_attendees;
|
$event['attendees'] = $reply_attendees;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// set RSVP=TRUE for every attendee if not set
|
||||||
|
else if ($method == 'REQUEST') {
|
||||||
|
foreach ($event['attendees'] as $i => $attendee) {
|
||||||
|
if (!isset($attendee['rsvp'])) {
|
||||||
|
$event['attendees'][$i]['rsvp']= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compose multipart message using PEAR:Mail_Mime
|
// compose multipart message using PEAR:Mail_Mime
|
||||||
$message = new Mail_mime("\r\n");
|
$message = new Mail_mime("\r\n");
|
||||||
|
@ -532,15 +540,21 @@ class libcalendaring_itip
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render event details in a table
|
* Render event/task details in a table
|
||||||
*/
|
*/
|
||||||
function itip_object_details_table($event, $title)
|
function itip_object_details_table($event, $title)
|
||||||
{
|
{
|
||||||
$table = new html_table(array('cols' => 2, 'border' => 0, 'class' => 'calendar-eventdetails'));
|
$table = new html_table(array('cols' => 2, 'border' => 0, 'class' => 'calendar-eventdetails'));
|
||||||
$table->add('ititle', $title);
|
$table->add('ititle', $title);
|
||||||
$table->add('title', Q($event['title']));
|
$table->add('title', Q($event['title']));
|
||||||
$table->add('label', $this->plugin->gettext('date'), $this->domain);
|
if ($event['start'] && $event['end']) {
|
||||||
$table->add('date', Q($this->lib->event_date_text($event)));
|
$table->add('label', $this->plugin->gettext('date'), $this->domain);
|
||||||
|
$table->add('date', Q($this->lib->event_date_text($event)));
|
||||||
|
}
|
||||||
|
else if ($event['due'] && $event['_type'] == 'task') {
|
||||||
|
$table->add('label', $this->plugin->gettext('date'), $this->domain);
|
||||||
|
$table->add('date', Q($this->lib->event_date_text($event)));
|
||||||
|
}
|
||||||
if ($event['location']) {
|
if ($event['location']) {
|
||||||
$table->add('label', $this->plugin->gettext('location'), $this->domain);
|
$table->add('label', $this->plugin->gettext('location'), $this->domain);
|
||||||
$table->add('location', Q($event['location']));
|
$table->add('location', Q($event['location']));
|
||||||
|
|
|
@ -247,11 +247,25 @@ class libcalendaring extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function event_date_text($event, $tzinfo = false)
|
public function event_date_text($event, $tzinfo = false)
|
||||||
{
|
{
|
||||||
$fromto = '';
|
$fromto = '--';
|
||||||
|
|
||||||
|
// handle task objects
|
||||||
|
if ($event['_type'] == 'task' && is_object($event['due'])) {
|
||||||
|
$date_format = $event['due']->_dateonly ? self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format'])) : null;
|
||||||
|
$fromto = $this->rc->format_date($event['due'], $date_format, false);
|
||||||
|
|
||||||
|
// add timezone information
|
||||||
|
if ($fromto && $tzinfo && ($tzname = $this->timezone->getName())) {
|
||||||
|
$fromto .= ' (' . strtr($tzname, '_', ' ') . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fromto;
|
||||||
|
}
|
||||||
|
|
||||||
// abort if no valid event dates are given
|
// abort if no valid event dates are given
|
||||||
if (!is_object($event['start']) || !is_a($event['start'], 'DateTime') || !is_object($event['end']) || !is_a($event['end'], 'DateTime'))
|
if (!is_object($event['start']) || !is_a($event['start'], 'DateTime') || !is_object($event['end']) || !is_a($event['end'], 'DateTime')) {
|
||||||
return $fromto;
|
return $fromto;
|
||||||
|
}
|
||||||
|
|
||||||
$duration = $event['start']->diff($event['end'])->format('s');
|
$duration = $event['start']->diff($event['end'])->format('s');
|
||||||
|
|
||||||
|
|
|
@ -567,7 +567,7 @@ class libvcalendar implements Iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
// make organizer part of the attendees list for compatibility reasons
|
// make organizer part of the attendees list for compatibility reasons
|
||||||
if (!empty($event['organizer']) && is_array($event['attendees'])) {
|
if (!empty($event['organizer']) && is_array($event['attendees']) && $event['_type'] == 'event') {
|
||||||
array_unshift($event['attendees'], $event['organizer']);
|
array_unshift($event['attendees'], $event['organizer']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -774,6 +774,8 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
'parent_id' => $record['parent_id'],
|
'parent_id' => $record['parent_id'],
|
||||||
'recurrence' => $record['recurrence'],
|
'recurrence' => $record['recurrence'],
|
||||||
'attendees' => $record['attendees'],
|
'attendees' => $record['attendees'],
|
||||||
|
'organizer' => $record['organizer'],
|
||||||
|
'sequence' => $record['sequence'],
|
||||||
);
|
);
|
||||||
|
|
||||||
// convert from DateTime to internal date format
|
// convert from DateTime to internal date format
|
||||||
|
@ -817,8 +819,8 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the given task record into a data structure that can be passed to kolab_storage backend for saving
|
* Convert the given task record into a data structure that can be passed to kolab_storage backend for saving
|
||||||
* (opposite of self::_to_rcube_event())
|
* (opposite of self::_to_rcube_event())
|
||||||
*/
|
*/
|
||||||
private function _from_rcube_task($task, $old = array())
|
private function _from_rcube_task($task, $old = array())
|
||||||
{
|
{
|
||||||
|
@ -826,14 +828,14 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
$object['categories'] = (array)$task['tags'];
|
$object['categories'] = (array)$task['tags'];
|
||||||
|
|
||||||
if (!empty($task['date'])) {
|
if (!empty($task['date'])) {
|
||||||
$object['due'] = new DateTime($task['date'].' '.$task['time'], $this->plugin->timezone);
|
$object['due'] = rcube_utils::anytodatetime($task['date'].' '.$task['time'], $this->plugin->timezone);
|
||||||
if (empty($task['time']))
|
if (empty($task['time']))
|
||||||
$object['due']->_dateonly = true;
|
$object['due']->_dateonly = true;
|
||||||
unset($object['date']);
|
unset($object['date']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($task['startdate'])) {
|
if (!empty($task['startdate'])) {
|
||||||
$object['start'] = new DateTime($task['startdate'].' '.$task['starttime'], $this->plugin->timezone);
|
$object['start'] = rcube_utils::anytodatetime($task['startdate'].' '.$task['starttime'], $this->plugin->timezone);
|
||||||
if (empty($task['starttime']))
|
if (empty($task['starttime']))
|
||||||
$object['start']->_dateonly = true;
|
$object['start']->_dateonly = true;
|
||||||
unset($object['startdate']);
|
unset($object['startdate']);
|
||||||
|
@ -900,12 +902,6 @@ class tasklist_kolab_driver extends tasklist_driver
|
||||||
unset($object['attachments']);
|
unset($object['attachments']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set current user as ORGANIZER
|
|
||||||
$identity = $this->rc->user->get_identity();
|
|
||||||
if (empty($object['attendees']) && $identity['email']) {
|
|
||||||
$object['attendees'] = array(array('role' => 'ORGANIZER', 'name' => $identity['name'], 'email' => $identity['email']));
|
|
||||||
}
|
|
||||||
|
|
||||||
$object['_owner'] = $identity['email'];
|
$object['_owner'] = $identity['email'];
|
||||||
|
|
||||||
unset($object['tempid'], $object['raw'], $object['list'], $object['flagged'], $object['tags']);
|
unset($object['tempid'], $object['raw'], $object['list'], $object['flagged'], $object['tags']);
|
||||||
|
|
|
@ -33,6 +33,7 @@ $labels['status-needs-action'] = 'Needs action';
|
||||||
$labels['status-in-process'] = 'In process';
|
$labels['status-in-process'] = 'In process';
|
||||||
$labels['status-completed'] = 'Completed';
|
$labels['status-completed'] = 'Completed';
|
||||||
$labels['status-cancelled'] = 'Cancelled';
|
$labels['status-cancelled'] = 'Cancelled';
|
||||||
|
$labels['assignedto'] = 'Assigned to';
|
||||||
|
|
||||||
$labels['all'] = 'All';
|
$labels['all'] = 'All';
|
||||||
$labels['flagged'] = 'Flagged';
|
$labels['flagged'] = 'Flagged';
|
||||||
|
@ -98,35 +99,35 @@ $labels['arialabeltaskselector'] = 'List mode';
|
||||||
$labels['arialabeltasklisting'] = 'Tasks listing';
|
$labels['arialabeltasklisting'] = 'Tasks listing';
|
||||||
|
|
||||||
// attendees
|
// attendees
|
||||||
$labels['attendee'] = 'Participant';
|
$labels['attendee'] = 'Assignee';
|
||||||
$labels['role'] = 'Role';
|
$labels['role'] = 'Role';
|
||||||
$labels['availability'] = 'Avail.';
|
$labels['availability'] = 'Avail.';
|
||||||
$labels['confirmstate'] = 'Status';
|
$labels['confirmstate'] = 'Status';
|
||||||
$labels['addattendee'] = 'Add participant';
|
$labels['addattendee'] = 'Add assignee';
|
||||||
$labels['roleorganizer'] = 'Organizer';
|
$labels['roleorganizer'] = 'Organizer';
|
||||||
$labels['rolerequired'] = 'Required';
|
$labels['rolerequired'] = 'Required';
|
||||||
$labels['roleoptional'] = 'Optional';
|
$labels['roleoptional'] = 'Optional';
|
||||||
$labels['rolechair'] = 'Chair';
|
$labels['rolechair'] = 'Chair';
|
||||||
$labels['rolenonparticipant'] = 'Absent';
|
$labels['rolenonparticipant'] = 'Observer';
|
||||||
$labels['sendinvitations'] = 'Send invitations';
|
$labels['sendinvitations'] = 'Send invitations';
|
||||||
$labels['sendnotifications'] = 'Notify participants about modifications';
|
$labels['sendnotifications'] = 'Notify assignees about modifications';
|
||||||
$labels['sendcancellation'] = 'Notify participants about task cancellation';
|
$labels['sendcancellation'] = 'Notify assignees about task cancellation';
|
||||||
$labels['invitationsubject'] = 'You\'ve been invited to "$title"';
|
$labels['invitationsubject'] = 'You\'ve been assigned to "$title"';
|
||||||
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with all the task details which you can import to your tasks application.";
|
$labels['invitationmailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nPlease find attached an iCalendar file with all the task details which you can import to your tasks application.";
|
||||||
$labels['invitationattendlinks'] = "In case your email client doesn't support iTip requests you can use the following link to either accept or decline this invitation:\n\$url";
|
$labels['itipupdatesubject'] = '"$title" has been updated';
|
||||||
$labels['eventupdatesubject'] = '"$title" has been updated';
|
$labels['itipupdatesubjectempty'] = 'A task that concerns you has been updated';
|
||||||
$labels['eventupdatesubjectempty'] = 'A task that concerns you has been updated';
|
$labels['itipupdatemailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nPlease find attached an iCalendar file with the updated task details which you can import to your tasks application.";
|
||||||
$labels['eventupdatemailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with the updated task details which you can import to your tasks application.";
|
$labels['itipcancelsubject'] = '"$title" has been canceled';
|
||||||
$labels['eventcancelsubject'] = '"$title" has been canceled';
|
$labels['itipcancelmailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nThe task has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated task details.";
|
||||||
$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nThe task has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated task details.";
|
$labels['saveintasklist'] = 'save in ';
|
||||||
|
|
||||||
// invitation handling (overrides labels from libcalendaring)
|
// invitation handling (overrides labels from libcalendaring)
|
||||||
$labels['itipobjectnotfound'] = 'The task referred by this message was not found in your tasks list.';
|
$labels['itipobjectnotfound'] = 'The task referred by this message was not found in your tasks list.';
|
||||||
|
|
||||||
$labels['itipmailbodyaccepted'] = "\$sender has accepted the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
$labels['itipmailbodyaccepted'] = "\$sender has accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nInvitees: \$attendees";
|
||||||
$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nInvitees: \$attendees";
|
||||||
$labels['itipmailbodydeclined'] = "\$sender has declined the assignment to the following task:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
$labels['itipmailbodydeclined'] = "\$sender has declined the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nInvitees: \$attendees";
|
||||||
$labels['itipmailbodycancel'] = "\$sender has rejected your assignment to the following task:\n\n*\$title*\n\nWhen: \$date";
|
$labels['itipmailbodycancel'] = "\$sender has rejected your assignment to the following task:\n\n*\$title*\n\nDue: \$date";
|
||||||
|
|
||||||
$labels['itipdeclineevent'] = 'Do you want to decline your assignment to this task?';
|
$labels['itipdeclineevent'] = 'Do you want to decline your assignment to this task?';
|
||||||
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?';
|
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?';
|
||||||
|
|
|
@ -855,6 +855,14 @@ a.morelink:hover {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table tbody td {
|
||||||
|
padding: 4px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-attendees-table tbody tr:last-child td {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.edit-attendees-table th.role,
|
.edit-attendees-table th.role,
|
||||||
.edit-attendees-table td.role {
|
.edit-attendees-table td.role {
|
||||||
width: 9em;
|
width: 9em;
|
||||||
|
@ -864,18 +872,19 @@ a.morelink:hover {
|
||||||
.edit-attendees-table td.availability,
|
.edit-attendees-table td.availability,
|
||||||
.edit-attendees-table th.confirmstate,
|
.edit-attendees-table th.confirmstate,
|
||||||
.edit-attendees-table td.confirmstate {
|
.edit-attendees-table td.confirmstate {
|
||||||
width: 4em;
|
width: 6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-attendees-table th.options,
|
.edit-attendees-table th.options,
|
||||||
.edit-attendees-table td.options {
|
.edit-attendees-table td.options {
|
||||||
width: 16px;
|
width: 24px;
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-attendees-table th.sendmail,
|
.edit-attendees-table th.sendmail,
|
||||||
.edit-attendees-table td.sendmail {
|
.edit-attendees-table td.sendmail {
|
||||||
width: 44px;
|
width: 48px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +964,7 @@ a.morelink:hover {
|
||||||
div.form-section {
|
div.form-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 0.2em;
|
margin-top: 0.2em;
|
||||||
margin-bottom: 0.8em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-section label {
|
.form-section label {
|
||||||
|
@ -970,6 +979,10 @@ label.block {
|
||||||
margin-bottom: 0.3em;
|
margin-bottom: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#task-description {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
#taskedit-completeness-slider {
|
#taskedit-completeness-slider {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 2em;
|
margin-left: 2em;
|
||||||
|
@ -1047,7 +1060,7 @@ label.block {
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-attendees span.organizer {
|
.task-attendees span.organizer {
|
||||||
background-position: right -80px;
|
background-position: right 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#all-task-attendees span.attendee {
|
#all-task-attendees span.attendee {
|
||||||
|
|
|
@ -156,12 +156,16 @@
|
||||||
<label><roundcube:label name="tasklist.alarms" /></label>
|
<label><roundcube:label name="tasklist.alarms" /></label>
|
||||||
<span class="task-text"></span>
|
<span class="task-text"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-section task-attendees" id="task-attendees">
|
<div id="task-attendees" class="form-section task-attendees">
|
||||||
<h5 class="label"><roundcube:label name="tasklist.tabassignments" /></h5>
|
<label><roundcube:label name="tasklist.assignedto" /></label>
|
||||||
<div class="task-text"></div>
|
<span class="task-text"></span>
|
||||||
|
</div>
|
||||||
|
<div id="task-organizer" class="form-section task-attendees">
|
||||||
|
<label><roundcube:label name="tasklist.roleorganizer" /></label>
|
||||||
|
<span class="task-text"></span>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
<div class="form-section" id="task-partstat">
|
<div id="task-partstat" class="form-section">
|
||||||
<label><roundcube:label name="tasklist.mystatus" /></label>
|
<label><roundcube:label name="tasklist.mystatus" /></label>
|
||||||
<span class="changersvp" role="button" tabindex="0" title="<roundcube:label name='tasklist.changepartstat' />">
|
<span class="changersvp" role="button" tabindex="0" title="<roundcube:label name='tasklist.changepartstat' />">
|
||||||
<span class="task-text"></span>
|
<span class="task-text"></span>
|
||||||
|
|
|
@ -81,6 +81,10 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- attendees list (assignments) -->
|
<!-- attendees list (assignments) -->
|
||||||
<div id="taskedit-panel-attendees">
|
<div id="taskedit-panel-attendees">
|
||||||
|
<div class="form-section" id="taskedit-organizer">
|
||||||
|
<label for="edit-identities-list"><roundcube:label name="tasklist.roleorganizer" /></label>
|
||||||
|
<roundcube:object name="plugin.identity_select" id="edit-identities-list" />
|
||||||
|
</div>
|
||||||
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="tasklist.arialabeleventassignments" /></h3>
|
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="tasklist.arialabeleventassignments" /></h3>
|
||||||
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="records-table edit-attendees-table" coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
|
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="records-table edit-attendees-table" coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
|
||||||
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
|
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
|
||||||
|
|
|
@ -84,7 +84,6 @@ function rcube_tasklist_ui(settings)
|
||||||
var focused_subclass;
|
var focused_subclass;
|
||||||
var task_attendees = [];
|
var task_attendees = [];
|
||||||
var attendees_list;
|
var attendees_list;
|
||||||
// var resources_list;
|
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
// general datepicker settings
|
// general datepicker settings
|
||||||
|
@ -1349,7 +1348,7 @@ function rcube_tasklist_ui(settings)
|
||||||
};
|
};
|
||||||
|
|
||||||
// check if the current user is an attendee of this task
|
// check if the current user is an attendee of this task
|
||||||
var is_attendee = function(task, role, email)
|
var is_attendee = function(task, email, role)
|
||||||
{
|
{
|
||||||
var i, attendee, emails = email ? ';' + email.toLowerCase() : settings.identity.emails;
|
var i, attendee, emails = email ? ';' + email.toLowerCase() : settings.identity.emails;
|
||||||
|
|
||||||
|
@ -1366,7 +1365,10 @@ function rcube_tasklist_ui(settings)
|
||||||
// check if the current user is the organizer
|
// check if the current user is the organizer
|
||||||
var is_organizer = function(task, email)
|
var is_organizer = function(task, email)
|
||||||
{
|
{
|
||||||
return is_attendee(task, 'ORGANIZER', email) || !task.id;
|
if (!email) email = task.organizer ? task.organizer.email : null;
|
||||||
|
if (email)
|
||||||
|
return settings.identity.emails.indexOf(';'+email) >= 0;
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// add the given list of participants
|
// add the given list of participants
|
||||||
|
@ -1421,34 +1423,10 @@ function rcube_tasklist_ui(settings)
|
||||||
if (exists)
|
if (exists)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// var list = me.selected_task && me.tasklists[me.selected_task.list] ? me.tasklists[me.selected_task.list] : me.tasklists[me.selected_list];
|
|
||||||
|
|
||||||
var dispname = Q(data.name || data.email);
|
var dispname = Q(data.name || data.email);
|
||||||
if (data.email)
|
if (data.email)
|
||||||
dispname = '<a href="mailto:' + data.email + '" title="' + Q(data.email) + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
|
dispname = '<a href="mailto:' + data.email + '" title="' + Q(data.email) + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
|
||||||
|
|
||||||
// role selection
|
|
||||||
var opts = {}, organizer = data.role == 'ORGANIZER';
|
|
||||||
if (organizer)
|
|
||||||
opts.ORGANIZER = rcmail.gettext('tasklist.roleorganizer');
|
|
||||||
opts['REQ-PARTICIPANT'] = rcmail.gettext('tasklist.rolerequired');
|
|
||||||
opts['OPT-PARTICIPANT'] = rcmail.gettext('tasklist.roleoptional');
|
|
||||||
opts['NON-PARTICIPANT'] = rcmail.gettext('tasklist.rolenonparticipant');
|
|
||||||
|
|
||||||
if (data.cutype != 'RESOURCE')
|
|
||||||
opts['CHAIR'] = rcmail.gettext('tasklist.rolechair');
|
|
||||||
|
|
||||||
if (organizer && !readonly)
|
|
||||||
dispname = rcmail.env['identities-selector'];
|
|
||||||
|
|
||||||
var select = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + ' aria-label="' + rcmail.gettext('role','tasklist') + '">';
|
|
||||||
for (var r in opts)
|
|
||||||
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
|
|
||||||
select += '</select>';
|
|
||||||
|
|
||||||
// availability
|
|
||||||
var avail = data.email ? 'loading' : 'unknown';
|
|
||||||
|
|
||||||
// delete icon
|
// delete icon
|
||||||
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
|
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
|
||||||
var dellink = '<a href="#delete" class="iconlink delete deletelink" title="' + Q(rcmail.gettext('delete')) + '">' + icon + '</a>';
|
var dellink = '<a href="#delete" class="iconlink delete deletelink" title="' + Q(rcmail.gettext('delete')) + '">' + icon + '</a>';
|
||||||
|
@ -1463,18 +1441,15 @@ function rcube_tasklist_ui(settings)
|
||||||
else if (data['delegated-from'])
|
else if (data['delegated-from'])
|
||||||
tooltip = rcmail.gettext('delegatedfrom', 'tasklist') + data['delegated-from'];
|
tooltip = rcmail.gettext('delegatedfrom', 'tasklist') + data['delegated-from'];
|
||||||
|
|
||||||
var html = '<td class="role">' + select + '</td>' +
|
var html = '<td class="name">' + dispname + '</td>' +
|
||||||
'<td class="name">' + dispname + '</td>' +
|
|
||||||
// '<td class="availability"><img src="./program/resources/blank.gif" class="availabilityicon ' + avail + '" data-email="' + data.email + '" alt="" /></td>' +
|
|
||||||
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
|
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
|
||||||
(data.cutype != 'RESOURCE' ? '<td class="sendmail">' + (organizer || readonly || !invbox ? '' : invbox) + '</td>' : '') +
|
(data.cutype != 'RESOURCE' ? '<td class="sendmail">' + (readonly || !invbox ? '' : invbox) + '</td>' : '') +
|
||||||
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
|
'<td class="options">' + (readonly ? '' : dellink) + '</td>';
|
||||||
|
|
||||||
var table = rcmail.env.tasklist_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list;
|
|
||||||
var tr = $('<tr>')
|
var tr = $('<tr>')
|
||||||
.addClass(String(data.role).toLowerCase())
|
.addClass(String(data.role).toLowerCase())
|
||||||
.html(html)
|
.html(html)
|
||||||
.appendTo(table);
|
.appendTo(attendees_list);
|
||||||
|
|
||||||
tr.find('a.deletelink').click({ id:(data.email || data.name) }, function(e) { remove_attendee(this, e.data.id); return false; });
|
tr.find('a.deletelink').click({ id:(data.email || data.name) }, function(e) { remove_attendee(this, e.data.id); return false; });
|
||||||
tr.find('a.mailtolink').click(task_attendee_click);
|
tr.find('a.mailtolink').click(task_attendee_click);
|
||||||
|
@ -1483,15 +1458,6 @@ function rcube_tasklist_ui(settings)
|
||||||
$('p.attendees-commentbox')[enabled ? 'show' : 'hide']();
|
$('p.attendees-commentbox')[enabled ? 'show' : 'hide']();
|
||||||
});
|
});
|
||||||
|
|
||||||
// select organizer identity
|
|
||||||
if (data.identity_id)
|
|
||||||
$('#edit-identities-list').val(data.identity_id);
|
|
||||||
|
|
||||||
// check free-busy status
|
|
||||||
// if (avail == 'loading') {
|
|
||||||
// check_freebusy_status(tr.find('img.availabilityicon'), data.email, me.selected_task);
|
|
||||||
// }
|
|
||||||
|
|
||||||
task_attendees.push(data);
|
task_attendees.push(data);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -1499,15 +1465,8 @@ function rcube_tasklist_ui(settings)
|
||||||
// event handler for clicks on an attendee link
|
// event handler for clicks on an attendee link
|
||||||
var task_attendee_click = function(e)
|
var task_attendee_click = function(e)
|
||||||
{
|
{
|
||||||
var cutype = $(this).attr('data-cutype'),
|
var mailto = this.href.substr(7);
|
||||||
mailto = this.href.substr(7);
|
rcmail.command('compose', mailto);
|
||||||
|
|
||||||
if (rcmail.env.tasklist_resources && cutype == 'RESOURCE') {
|
|
||||||
task_resources_dialog(mailto);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rcmail.redirect(rcmail.url('mail/compose', {_to: mailto}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -1547,7 +1506,7 @@ function rcube_tasklist_ui(settings)
|
||||||
$('#task-completeness .task-text').html(((rec.complete || 0) * 100) + '%');
|
$('#task-completeness .task-text').html(((rec.complete || 0) * 100) + '%');
|
||||||
$('#task-status')[(rec.status ? 'show' : 'hide')]().children('.task-text').html(rcmail.gettext('status-'+String(rec.status).toLowerCase(),'tasklist'));
|
$('#task-status')[(rec.status ? 'show' : 'hide')]().children('.task-text').html(rcmail.gettext('status-'+String(rec.status).toLowerCase(),'tasklist'));
|
||||||
$('#task-list .task-text').html(Q(me.tasklists[rec.list] ? me.tasklists[rec.list].name : ''));
|
$('#task-list .task-text').html(Q(me.tasklists[rec.list] ? me.tasklists[rec.list].name : ''));
|
||||||
$('#task-attendees').hide();
|
$('#task-attendees, #task-organizer').hide();
|
||||||
|
|
||||||
var itags = get_inherited_tags(rec);
|
var itags = get_inherited_tags(rec);
|
||||||
var taglist = $('#task-tags')[(rec.tags && rec.tags.length || itags.length ? 'show' : 'hide')]().children('.task-text').empty();
|
var taglist = $('#task-tags')[(rec.tags && rec.tags.length || itags.length ? 'show' : 'hide')]().children('.task-text').empty();
|
||||||
|
@ -1587,6 +1546,7 @@ function rcube_tasklist_ui(settings)
|
||||||
|
|
||||||
// list task attendees
|
// list task attendees
|
||||||
if (list.attendees && rec.attendees) {
|
if (list.attendees && rec.attendees) {
|
||||||
|
console.log(rec.attendees)
|
||||||
/*
|
/*
|
||||||
// sort resources to the end
|
// sort resources to the end
|
||||||
rec.attendees.sort(function(a,b) {
|
rec.attendees.sort(function(a,b) {
|
||||||
|
@ -1595,30 +1555,19 @@ function rcube_tasklist_ui(settings)
|
||||||
return (j - k);
|
return (j - k);
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
var j, data, dispname, tooltip, organizer = false, rsvp = false, mystatus = null, line, morelink, html = '', overflow = '';
|
var j, data, rsvp = false, mystatus = null, line, morelink, html = '', overflow = '',
|
||||||
|
organizer = is_organizer(rec);
|
||||||
|
|
||||||
for (j=0; j < rec.attendees.length; j++) {
|
for (j=0; j < rec.attendees.length; j++) {
|
||||||
data = rec.attendees[j];
|
data = rec.attendees[j];
|
||||||
dispname = Q(data.name || data.email);
|
|
||||||
tooltip = '';
|
|
||||||
|
|
||||||
if (data.email) {
|
if (data.email && settings.identity.emails.indexOf(';'+data.email) >= 0) {
|
||||||
tooltip = data.email;
|
mystatus = data.status.toLowerCase();
|
||||||
dispname = '<a href="mailto:' + data.email + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
|
if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp)
|
||||||
if (data.role == 'ORGANIZER')
|
rsvp = mystatus;
|
||||||
organizer = true;
|
|
||||||
else if (settings.identity.emails.indexOf(';'+data.email) >= 0) {
|
|
||||||
mystatus = data.status.toLowerCase();
|
|
||||||
if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp)
|
|
||||||
rsvp = mystatus;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data['delegated-to'])
|
line = task_attendee_html(data);
|
||||||
tooltip = rcmail.gettext('delegatedto', 'tasklist') + data['delegated-to'];
|
|
||||||
else if (data['delegated-from'])
|
|
||||||
tooltip = rcmail.gettext('delegatedfrom', 'tasklist') + data['delegated-from'];
|
|
||||||
|
|
||||||
line = '<span class="attendee ' + String(data.role == 'ORGANIZER' ? 'organizer' : data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + dispname + '</span> ';
|
|
||||||
|
|
||||||
if (morelink)
|
if (morelink)
|
||||||
overflow += line;
|
overflow += line;
|
||||||
|
@ -1631,7 +1580,7 @@ function rcube_tasklist_ui(settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (html && (rec.attendees.length > 1 || !organizer)) {
|
if (html) {
|
||||||
$('#task-attendees').show()
|
$('#task-attendees').show()
|
||||||
.children('.task-text')
|
.children('.task-text')
|
||||||
.html(html)
|
.html(html)
|
||||||
|
@ -1667,6 +1616,10 @@ function rcube_tasklist_ui(settings)
|
||||||
$('#task-rsvp a.reply-comment-toggle').show();
|
$('#task-rsvp a.reply-comment-toggle').show();
|
||||||
$('#task-rsvp .itip-reply-comment textarea').hide().val('');
|
$('#task-rsvp .itip-reply-comment textarea').hide().val('');
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (rec.organizer && !organizer) {
|
||||||
|
$('#task-organizer').show().children('.task-text').html(task_attendee_html(rec.organizer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// define dialog buttons
|
// define dialog buttons
|
||||||
|
@ -1697,7 +1650,7 @@ function rcube_tasklist_ui(settings)
|
||||||
closeOnEscape: true,
|
closeOnEscape: true,
|
||||||
title: rcmail.gettext('taskdetails', 'tasklist'),
|
title: rcmail.gettext('taskdetails', 'tasklist'),
|
||||||
open: function() {
|
open: function() {
|
||||||
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
$dialog.dialog('destroy').appendTo(document.body);
|
$dialog.dialog('destroy').appendTo(document.body);
|
||||||
|
@ -1711,6 +1664,24 @@ function rcube_tasklist_ui(settings)
|
||||||
me.dialog_resize($dialog.get(0), $dialog.height(), 580);
|
me.dialog_resize($dialog.get(0), $dialog.height(), 580);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// render HTML code for displaying an attendee record
|
||||||
|
function task_attendee_html(data)
|
||||||
|
{
|
||||||
|
var dispname = Q(data.name || data.email), tooltip = '';
|
||||||
|
|
||||||
|
if (data.email) {
|
||||||
|
tooltip = data.email;
|
||||||
|
dispname = '<a href="mailto:' + data.email + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data['delegated-to'])
|
||||||
|
tooltip = rcmail.gettext('delegatedto', 'tasklist') + data['delegated-to'];
|
||||||
|
else if (data['delegated-from'])
|
||||||
|
tooltip = rcmail.gettext('delegatedfrom', 'tasklist') + data['delegated-from'];
|
||||||
|
|
||||||
|
return '<span class="attendee ' + String(data.role == 'ORGANIZER' ? 'organizer' : data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + dispname + '</span> ';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the dialog to edit a task
|
* Opens the dialog to edit a task
|
||||||
*/
|
*/
|
||||||
|
@ -1786,18 +1757,17 @@ function rcube_tasklist_ui(settings)
|
||||||
|
|
||||||
task_attendees = [];
|
task_attendees = [];
|
||||||
attendees_list = $('#edit-attendees-table > tbody').html('');
|
attendees_list = $('#edit-attendees-table > tbody').html('');
|
||||||
//resources_list = $('#edit-resources-table > tbody').html('');
|
|
||||||
$('#edit-attendees-notify')[(notify.checked && allow_invitations ? 'show' : 'hide')]();
|
$('#edit-attendees-notify')[(notify.checked && allow_invitations ? 'show' : 'hide')]();
|
||||||
$('#edit-localchanges-warning')[(has_attendees(rec) && !(allow_invitations || (rec.owner && is_organizer(rec, rec.owner))) ? 'show' : 'hide')]();
|
$('#edit-localchanges-warning')[(has_attendees(rec) && !(allow_invitations || (rec.owner && is_organizer(rec, rec.owner))) ? 'show' : 'hide')]();
|
||||||
|
|
||||||
var load_attendees_tab = function()
|
// attendees (aka assignees)
|
||||||
{
|
if (list.attendees) {
|
||||||
var j, data, reply_selected = 0;
|
var j, data, reply_selected = 0;
|
||||||
if (rec.attendees) {
|
if (rec.attendees) {
|
||||||
for (j=0; j < rec.attendees.length; j++) {
|
for (j=0; j < rec.attendees.length; j++) {
|
||||||
data = rec.attendees[j];
|
data = rec.attendees[j];
|
||||||
add_attendee(data, !allow_invitations);
|
add_attendee(data, !allow_invitations);
|
||||||
if (allow_invitations && data.role != 'ORGANIZER' && !data.noreply) {
|
if (allow_invitations && !data.noreply) {
|
||||||
reply_selected++;
|
reply_selected++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1812,16 +1782,16 @@ function rcube_tasklist_ui(settings)
|
||||||
// select the correct organizer identity
|
// select the correct organizer identity
|
||||||
var identity_id = 0;
|
var identity_id = 0;
|
||||||
$.each(settings.identities, function(i,v) {
|
$.each(settings.identities, function(i,v) {
|
||||||
if (organizer && v == organizer.email) {
|
if (rec.organizer && v == rec.organizer.email) {
|
||||||
identity_id = i;
|
identity_id = i;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#edit-identities-list').val(identity_id);
|
|
||||||
$('#edit-attendees-form')[(allow_invitations?'show':'hide')]();
|
$('#edit-attendees-form')[(allow_invitations?'show':'hide')]();
|
||||||
// $('#edit-attendee-schedule')[(tasklist.freebusy?'show':'hide')]();
|
$('#edit-identities-list').val(identity_id);
|
||||||
};
|
$('#taskedit-organizer')[(organizer ? 'show' : 'hide')]();
|
||||||
|
}
|
||||||
|
|
||||||
// attachments
|
// attachments
|
||||||
rcmail.enable_command('remove-attachment', list.editable);
|
rcmail.enable_command('remove-attachment', list.editable);
|
||||||
|
@ -1904,15 +1874,9 @@ function rcube_tasklist_ui(settings)
|
||||||
if (!data.tags.length)
|
if (!data.tags.length)
|
||||||
data.tags = '';
|
data.tags = '';
|
||||||
|
|
||||||
// read attendee roles
|
|
||||||
$('select.edit-attendee-role').each(function(i, elem) {
|
|
||||||
if (data.attendees[i]) {
|
|
||||||
data.attendees[i].role = $(elem).val();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (organizer) {
|
if (organizer) {
|
||||||
data._identity = $('#edit-identities-list option:selected').val();
|
data._identity = $('#edit-identities-list option:selected').val();
|
||||||
|
delete data.organizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't submit attendees if only myself is added as organizer
|
// don't submit attendees if only myself is added as organizer
|
||||||
|
@ -1977,9 +1941,6 @@ function rcube_tasklist_ui(settings)
|
||||||
|
|
||||||
// set dialog size according to content
|
// set dialog size according to content
|
||||||
me.dialog_resize($dialog.get(0), $dialog.height(), 580);
|
me.dialog_resize($dialog.get(0), $dialog.height(), 580);
|
||||||
|
|
||||||
if (list.attendees)
|
|
||||||
window.setTimeout(load_attendees_tab, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -334,7 +334,7 @@ class tasklist extends rcube_plugin
|
||||||
$task = $action == 'delete' ? $oldrec : $this->driver->get_task($rec);
|
$task = $action == 'delete' ? $oldrec : $this->driver->get_task($rec);
|
||||||
|
|
||||||
// only notify if data really changed (TODO: do diff check on client already)
|
// only notify if data really changed (TODO: do diff check on client already)
|
||||||
if (!$oldrec || $action == 'delete' || self::task_diff($event, $old)) {
|
if (!$oldrec || $action == 'delete' || self::task_diff($task, $oldrec)) {
|
||||||
$sent = $this->notify_attendees($task, $oldrec, $action, $rec['_comment']);
|
$sent = $this->notify_attendees($task, $oldrec, $action, $rec['_comment']);
|
||||||
if ($sent > 0)
|
if ($sent > 0)
|
||||||
$this->rc->output->show_message('tasklist.itipsendsuccess', 'confirmation');
|
$this->rc->output->show_message('tasklist.itipsendsuccess', 'confirmation');
|
||||||
|
@ -366,10 +366,7 @@ class tasklist extends rcube_plugin
|
||||||
if (!$this->itip) {
|
if (!$this->itip) {
|
||||||
require_once realpath(__DIR__ . '/../libcalendaring/lib/libcalendaring_itip.php');
|
require_once realpath(__DIR__ . '/../libcalendaring/lib/libcalendaring_itip.php');
|
||||||
$this->itip = new libcalendaring_itip($this, 'tasklist');
|
$this->itip = new libcalendaring_itip($this, 'tasklist');
|
||||||
|
$this->itip->set_rsvp_actions(array('accepted','declined'));
|
||||||
// if ($this->rc->config->get('kolab_invitation_tasklists')) {
|
|
||||||
// $this->itip->set_rsvp_actions(array('accepted','tentative','declined','needs-action'));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->itip;
|
return $this->itip;
|
||||||
|
@ -520,6 +517,11 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
$rec['attachments'] = $attachments;
|
$rec['attachments'] = $attachments;
|
||||||
|
|
||||||
|
// set organizer from identity selector
|
||||||
|
if (isset($rec['_identity']) && ($identity = $this->rc->user->get_identity($rec['_identity']))) {
|
||||||
|
$rec['organizer'] = array('name' => $identity['name'], 'email' => $identity['email']);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_numeric($rec['id']) && $rec['id'] < 0)
|
if (is_numeric($rec['id']) && $rec['id'] < 0)
|
||||||
unset($rec['id']);
|
unset($rec['id']);
|
||||||
|
|
||||||
|
@ -646,7 +648,8 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// compose multipart message using PEAR:Mail_Mime
|
// compose multipart message using PEAR:Mail_Mime
|
||||||
$method = $action == 'delete' ? 'CANCEL' : 'REQUEST';
|
$method = $action == 'delete' ? 'CANCEL' : 'REQUEST';
|
||||||
$message = $itip->compose_itip_message($task, $method);
|
$object = $this->to_libcal($task);
|
||||||
|
$message = $itip->compose_itip_message($object, $method);
|
||||||
|
|
||||||
// list existing attendees from the $old task
|
// list existing attendees from the $old task
|
||||||
$old_attendees = array();
|
$old_attendees = array();
|
||||||
|
@ -671,11 +674,11 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// which template to use for mail text
|
// which template to use for mail text
|
||||||
$is_new = !in_array($attendee['email'], $old_attendees);
|
$is_new = !in_array($attendee['email'], $old_attendees);
|
||||||
$bodytext = $is_cancelled ? 'eventcancelmailbody' : ($is_new ? 'invitationmailbody' : 'eventupdatemailbody');
|
$bodytext = $is_cancelled ? 'itipcancelmailbody' : ($is_new ? 'invitationmailbody' : 'itipupdatemailbody');
|
||||||
$subject = $is_cancelled ? 'eventcancelsubject' : ($is_new ? 'invitationsubject' : ($task['title'] ? 'eventupdatesubject' : 'eventupdatesubjectempty'));
|
$subject = $is_cancelled ? 'itipcancelsubject' : ($is_new ? 'invitationsubject' : ($task['title'] ? 'itipupdatesubject' : 'itipupdatesubjectempty'));
|
||||||
|
|
||||||
// finally send the message
|
// finally send the message
|
||||||
if ($itip->send_itip_message($task, $method, $attendee, $subject, $bodytext, $message))
|
if ($itip->send_itip_message($object, $method, $attendee, $subject, $bodytext, $message))
|
||||||
$sent++;
|
$sent++;
|
||||||
else
|
else
|
||||||
$sent = -100;
|
$sent = -100;
|
||||||
|
@ -683,16 +686,16 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// send CANCEL message to removed attendees
|
// send CANCEL message to removed attendees
|
||||||
foreach ((array)$old['attendees'] as $attendee) {
|
foreach ((array)$old['attendees'] as $attendee) {
|
||||||
if ($attendee['ROLE'] == 'ORGANIZER' || !$attendee['email'] || in_array(strtolower($attendee['email']), $current)) {
|
if (!$attendee['email'] || in_array(strtolower($attendee['email']), $current)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$vevent = $old;
|
$vtodo = $this->to_libcal($old);
|
||||||
$vevent['cancelled'] = $is_cancelled;
|
$vtodo['cancelled'] = $is_cancelled;
|
||||||
$vevent['attendees'] = array($attendee);
|
$vtodo['attendees'] = array($attendee);
|
||||||
$vevent['comment'] = $comment;
|
$vtodo['comment'] = $comment;
|
||||||
|
|
||||||
if ($itip->send_itip_message($vevent, 'CANCEL', $attendee, 'eventcancelsubject', 'eventcancelmailbody'))
|
if ($itip->send_itip_message($vtodo, 'CANCEL', $attendee, 'itipcancelsubject', 'itipcancelmailbody'))
|
||||||
$sent++;
|
$sent++;
|
||||||
else
|
else
|
||||||
$sent = -100;
|
$sent = -100;
|
||||||
|
@ -1393,6 +1396,8 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// successfully parsed events?
|
// successfully parsed events?
|
||||||
if (!empty($tasks) && ($task = $tasks[$index])) {
|
if (!empty($tasks) && ($task = $tasks[$index])) {
|
||||||
|
$task = $this->from_ical($task);
|
||||||
|
|
||||||
// store the message's sender address for comparisons
|
// store the message's sender address for comparisons
|
||||||
$task['_sender'] = preg_match('/([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))/', $headers->from, $m) ? $m[1] : '';
|
$task['_sender'] = preg_match('/([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))/', $headers->from, $m) ? $m[1] : '';
|
||||||
$askt['_sender_utf'] = rcube_idn_to_utf8($task['_sender']);
|
$askt['_sender_utf'] = rcube_idn_to_utf8($task['_sender']);
|
||||||
|
@ -1496,6 +1501,7 @@ class tasklist extends rcube_plugin
|
||||||
foreach ($tasks as $task) {
|
foreach ($tasks as $task) {
|
||||||
// save to tasklist
|
// save to tasklist
|
||||||
if ($list && $list['editable'] && $task['_type'] == 'task') {
|
if ($list && $list['editable'] && $task['_type'] == 'task') {
|
||||||
|
$task = $this->from_ical($task);
|
||||||
$task['list'] = $list['id'];
|
$task['list'] = $list['id'];
|
||||||
|
|
||||||
if (!$this->driver->get_task($task['uid'])) {
|
if (!$this->driver->get_task($task['uid'])) {
|
||||||
|
@ -1555,14 +1561,11 @@ class tasklist extends rcube_plugin
|
||||||
|
|
||||||
// update my attendee status according to submitted method
|
// update my attendee status according to submitted method
|
||||||
if (!empty($status)) {
|
if (!empty($status)) {
|
||||||
$organizer = null;
|
$organizer = $task['organizer'];
|
||||||
$emails = $this->lib->get_user_emails();
|
$emails = $this->lib->get_user_emails();
|
||||||
|
|
||||||
foreach ($task['attendees'] as $i => $attendee) {
|
foreach ($task['attendees'] as $i => $attendee) {
|
||||||
if ($attendee['role'] == 'ORGANIZER') {
|
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
|
||||||
$organizer = $attendee;
|
|
||||||
}
|
|
||||||
else if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
|
|
||||||
$metadata['attendee'] = $attendee['email'];
|
$metadata['attendee'] = $attendee['email'];
|
||||||
$metadata['rsvp'] = $attendee['role'] != 'NON-PARTICIPANT';
|
$metadata['rsvp'] = $attendee['role'] != 'NON-PARTICIPANT';
|
||||||
$reply_sender = $attendee['email'];
|
$reply_sender = $attendee['email'];
|
||||||
|
@ -1714,7 +1717,7 @@ class tasklist extends rcube_plugin
|
||||||
$itip = $this->load_itip();
|
$itip = $this->load_itip();
|
||||||
$itip->set_sender_email($reply_sender);
|
$itip->set_sender_email($reply_sender);
|
||||||
|
|
||||||
if ($itip->send_itip_message($task, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
if ($itip->send_itip_message($this->to_libcal($task), 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
||||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
|
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
|
||||||
else
|
else
|
||||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||||
|
@ -1729,7 +1732,7 @@ class tasklist extends rcube_plugin
|
||||||
/**
|
/**
|
||||||
* Handler for calendar/itip-status requests
|
* Handler for calendar/itip-status requests
|
||||||
*/
|
*/
|
||||||
function task_itip_status()
|
public function task_itip_status()
|
||||||
{
|
{
|
||||||
$data = rcube_utils::get_input_value('data', rcube_utils::INPUT_POST, true);
|
$data = rcube_utils::get_input_value('data', rcube_utils::INPUT_POST, true);
|
||||||
|
|
||||||
|
@ -1768,7 +1771,7 @@ class tasklist extends rcube_plugin
|
||||||
/**
|
/**
|
||||||
* Handler for calendar/itip-remove requests
|
* Handler for calendar/itip-remove requests
|
||||||
*/
|
*/
|
||||||
function task_itip_remove()
|
public function task_itip_remove()
|
||||||
{
|
{
|
||||||
$success = false;
|
$success = false;
|
||||||
$uid = rcube_utils::get_input_value('uid', rcube_utils::INPUT_POST);
|
$uid = rcube_utils::get_input_value('uid', rcube_utils::INPUT_POST);
|
||||||
|
@ -1797,6 +1800,78 @@ class tasklist extends rcube_plugin
|
||||||
return strtoupper(md5(time() . uniqid(rand())) . '-' . substr(md5($this->rc->user->get_username()), 0, 16));
|
return strtoupper(md5(time() . uniqid(rand())) . '-' . substr(md5($this->rc->user->get_username()), 0, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map task properties for ical exprort using libcalendaring
|
||||||
|
*/
|
||||||
|
public function to_libcal($task)
|
||||||
|
{
|
||||||
|
$object = $task;
|
||||||
|
$object['categories'] = (array)$task['tags'];
|
||||||
|
|
||||||
|
// convert to datetime objects
|
||||||
|
if (!empty($task['date'])) {
|
||||||
|
$object['due'] = rcube_utils::anytodatetime($task['date'].' '.$task['time'], $this->timezone);
|
||||||
|
if (empty($task['time']))
|
||||||
|
$object['due']->_dateonly = true;
|
||||||
|
unset($object['date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($task['startdate'])) {
|
||||||
|
$object['start'] = rcube_utils::anytodatetime($task['startdate'].' '.$task['starttime'], $this->timezone);
|
||||||
|
if (empty($task['starttime']))
|
||||||
|
$object['start']->_dateonly = true;
|
||||||
|
unset($object['startdate']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$object['complete'] = $task['complete'] * 100;
|
||||||
|
if ($task['complete'] == 1.0 && empty($task['complete'])) {
|
||||||
|
$object['status'] = 'COMPLETED';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($task['flagged']) {
|
||||||
|
$object['priority'] = 1;
|
||||||
|
}
|
||||||
|
else if (!$task['priority']) {
|
||||||
|
$object['priority'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert task properties from ical parser to the internal format
|
||||||
|
*/
|
||||||
|
public function from_ical($vtodo)
|
||||||
|
{
|
||||||
|
$task = $vtodo;
|
||||||
|
|
||||||
|
$task['tags'] = array_filter((array)$vtodo['categories']);
|
||||||
|
$task['flagged'] = $vtodo['priority'] == 1;
|
||||||
|
$task['complete'] = floatval($vtodo['complete'] / 100);
|
||||||
|
|
||||||
|
// convert from DateTime to internal date format
|
||||||
|
if (is_a($vtodo['due'], 'DateTime')) {
|
||||||
|
$due = $this->lib->adjust_timezone($vtodo['due']);
|
||||||
|
$task['date'] = $due->format('Y-m-d');
|
||||||
|
if (!$vtodo['due']->_dateonly)
|
||||||
|
$task['time'] = $due->format('H:i');
|
||||||
|
}
|
||||||
|
// convert from DateTime to internal date format
|
||||||
|
if (is_a($vtodo['start'], 'DateTime')) {
|
||||||
|
$start = $this->lib->adjust_timezone($vtodo['start']);
|
||||||
|
$task['startdate'] = $start->format('Y-m-d');
|
||||||
|
if (!$vtodo['start']->_dateonly)
|
||||||
|
$task['starttime'] = $start->format('H:i');
|
||||||
|
}
|
||||||
|
if (is_a($vtodo['dtstamp'], 'DateTime')) {
|
||||||
|
$task['changed'] = $vtodo['dtstamp'];
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($task['categories'], $task['due'], $task['start'], $task['dtstamp']);
|
||||||
|
|
||||||
|
return $task;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for user_delete plugin hook
|
* Handler for user_delete plugin hook
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -56,7 +56,6 @@ class tasklist_ui
|
||||||
|
|
||||||
// copy config to client
|
// copy config to client
|
||||||
$this->rc->output->set_env('tasklist_settings', $this->load_settings());
|
$this->rc->output->set_env('tasklist_settings', $this->load_settings());
|
||||||
$this->rc->output->set_env('identities-selector', $this->identity_select(array('id' => 'edit-identities-list', 'aria-label' => $this->plugin->gettext('roleorganizer'))));
|
|
||||||
|
|
||||||
// initialize attendees autocompletion
|
// initialize attendees autocompletion
|
||||||
$this->rc->autocomplete_init();
|
$this->rc->autocomplete_init();
|
||||||
|
@ -71,7 +70,7 @@ class tasklist_ui
|
||||||
{
|
{
|
||||||
$settings = array();
|
$settings = array();
|
||||||
|
|
||||||
//$settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']);
|
$settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', 0);
|
||||||
|
|
||||||
// get user identity to create default attendee
|
// get user identity to create default attendee
|
||||||
foreach ($this->rc->user->list_identities() as $rec) {
|
foreach ($this->rc->user->list_identities() as $rec) {
|
||||||
|
@ -128,6 +127,7 @@ class tasklist_ui
|
||||||
$this->plugin->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
|
$this->plugin->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
|
||||||
$this->plugin->register_handler('plugin.attendees_list', array($this, 'attendees_list'));
|
$this->plugin->register_handler('plugin.attendees_list', array($this, 'attendees_list'));
|
||||||
$this->plugin->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
|
$this->plugin->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
|
||||||
|
$this->plugin->register_handler('plugin.identity_select', array($this, 'identity_select'));
|
||||||
$this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
|
$this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
|
||||||
|
|
||||||
$this->plugin->include_script('jquery.tagedit.js');
|
$this->plugin->include_script('jquery.tagedit.js');
|
||||||
|
@ -438,9 +438,8 @@ class tasklist_ui
|
||||||
$invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite'));
|
$invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite'));
|
||||||
$table = new html_table(array('cols' => 4 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable'));
|
$table = new html_table(array('cols' => 4 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable'));
|
||||||
|
|
||||||
$table->add_header('role', $this->plugin->gettext('role'));
|
// $table->add_header('role', $this->plugin->gettext('role'));
|
||||||
$table->add_header('name', $this->plugin->gettext($attrib['coltitle'] ?: 'attendee'));
|
$table->add_header('name', $this->plugin->gettext($attrib['coltitle'] ?: 'attendee'));
|
||||||
// $table->add_header('availability', $this->plugin->gettext('availability'));
|
|
||||||
$table->add_header('confirmstate', $this->plugin->gettext('confirmstate'));
|
$table->add_header('confirmstate', $this->plugin->gettext('confirmstate'));
|
||||||
if ($invitations) {
|
if ($invitations) {
|
||||||
$table->add_header(array('class' => 'sendmail', 'title' => $this->plugin->gettext('sendinvitations')),
|
$table->add_header(array('class' => 'sendmail', 'title' => $this->plugin->gettext('sendinvitations')),
|
||||||
|
|
Loading…
Add table
Reference in a new issue