Complete iTip communication on task status changes: ask to notify the organizer on update or deletion + add icons for task-specific partstats and cancelled tasks
This commit is contained in:
parent
e46cc9499e
commit
457195102e
7 changed files with 255 additions and 65 deletions
|
@ -51,6 +51,7 @@ $labels['newtask'] = 'New Task';
|
|||
$labels['edittask'] = 'Edit Task';
|
||||
$labels['save'] = 'Save';
|
||||
$labels['cancel'] = 'Cancel';
|
||||
$labels['saveandnotify'] = 'Save and Notify';
|
||||
$labels['addsubtask'] = 'Add subtask';
|
||||
$labels['deletetask'] = 'Delete task';
|
||||
$labels['deletethisonly'] = 'Delete this task only';
|
||||
|
@ -88,6 +89,9 @@ $labels['deleteparenttasktconfirm'] = 'Do you really want to delete this task an
|
|||
$labels['deletelistconfirm'] = 'Do you really want to delete this list with all its tasks?';
|
||||
$labels['deletelistconfirmrecursive'] = 'Do you really want to delete this list with all its sub-lists and tasks?';
|
||||
$labels['aclnorights'] = 'You do not have administrator rights on this task list.';
|
||||
$labels['changetaskconfirm'] = 'Update task';
|
||||
$labels['changeconfirmnotifications'] = 'Do you want to notify the attendees about the modification?';
|
||||
$labels['partstatupdatenotification'] = 'Do you want to notify the organizer about the status change?';
|
||||
|
||||
// (hidden) titles and labels for accessibility annotations
|
||||
$labels['quickaddinput'] = 'New task date and title';
|
||||
|
@ -124,17 +128,27 @@ $labels['saveintasklist'] = 'save in ';
|
|||
// invitation handling (overrides labels from libcalendaring)
|
||||
$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\nDue: \$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\nDue: \$date\n\nInvitees: \$attendees";
|
||||
$labels['itipmailbodyaccepted'] = "\$sender has accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender has declined the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender has rejected your assignment to the following task:\n\n*\$title*\n\nDue: \$date";
|
||||
$labels['itipmailbodyin-process'] = "\$sender has set the status of the following task to in-process:\n\n*\$title*\n\nDue: \$date";
|
||||
$labels['itipmailbodycompleted'] = "\$sender has completed the following task:\n\n*\$title*\n\nDue: \$date";
|
||||
|
||||
$labels['itipdeclineevent'] = 'Do you want to decline your assignment to this task?';
|
||||
$labels['attendeeaccepted'] = 'Assignee has accepted';
|
||||
$labels['attendeetentative'] = 'Assignee has tentatively accepted';
|
||||
$labels['attendeedeclined'] = 'Assignee has declined';
|
||||
$labels['attendeedelegated'] = 'Assignee has delegated to $delegatedto';
|
||||
$labels['attendeein-process'] = 'Assignee is in-process';
|
||||
$labels['attendeecompleted'] = 'Assignee has completed';
|
||||
|
||||
$labels['itipdeclinetask'] = 'Decline your assignment to this task to the organizer';
|
||||
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?';
|
||||
$labels['itipcomment'] = 'Invitation/notification comment';
|
||||
$labels['itipcommenttitle'] = 'This comment will be attached to the invitation/notification message sent to participants';
|
||||
$labels['itipsendsuccess'] = 'Invitation sent to participants.';
|
||||
$labels['errornotifying'] = 'Failed to send notifications to task participants';
|
||||
$labels['itipcommenttitle'] = 'This comment will be attached to the invitation/notification message sent to assignees';
|
||||
$labels['itipsendsuccess'] = 'Invitation sent to assignees';
|
||||
$labels['errornotifying'] = 'Failed to send notifications to task assignees';
|
||||
$labels['removefromcalendar'] = 'Remove from my tasks';
|
||||
|
||||
$labels['andnmore'] = '$nr more...';
|
||||
$labels['delegatedto'] = 'Delegated to: ';
|
||||
|
@ -149,7 +163,7 @@ $labels['nowritetasklistfound'] = 'No tasklist found to save the task';
|
|||
$labels['importedsuccessfully'] = 'The task was successfully added to \'$list\'';
|
||||
$labels['updatedsuccessfully'] = 'The task was successfully updated in \'$list\'';
|
||||
$labels['attendeupdateesuccess'] = 'Successfully updated the participant\'s status';
|
||||
$labels['itipresponseerror'] = 'Failed to send the response to this task invitation';
|
||||
$labels['itipresponseerror'] = 'Failed to send the response to this task assignment';
|
||||
$labels['itipinvalidrequest'] = 'This invitation is no longer valid';
|
||||
$labels['sentresponseto'] = 'Successfully sent invitation response to $mailto';
|
||||
$labels['sentresponseto'] = 'Successfully sent assignment response to $mailto';
|
||||
$labels['successremoval'] = 'The task has been deleted successfully.';
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
plugins/tasklist/skins/larry/images/badge_cancelled.png
Normal file
BIN
plugins/tasklist/skins/larry/images/badge_cancelled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 620 B |
|
@ -815,6 +815,10 @@ ul.toolbarmenu li span.delete {
|
|||
color: #999;
|
||||
}
|
||||
|
||||
#taskshow.status-cancelled {
|
||||
background: url(images/badge_cancelled.png) top right no-repeat;
|
||||
}
|
||||
|
||||
#task-parent-title {
|
||||
position: relative;
|
||||
top: -0.6em;
|
||||
|
@ -1043,7 +1047,7 @@ label.block {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.task-attendees span.accepted {
|
||||
.task-attendees span.completed {
|
||||
background-position: right -20px;
|
||||
}
|
||||
|
||||
|
@ -1059,6 +1063,14 @@ label.block {
|
|||
background-position: right -180px;
|
||||
}
|
||||
|
||||
.task-attendees span.in-process {
|
||||
background-position: right -200px;
|
||||
}
|
||||
|
||||
.task-attendees span.accepted {
|
||||
background-position: right -220px;
|
||||
}
|
||||
|
||||
.task-attendees span.organizer {
|
||||
background-position: right 100px;
|
||||
}
|
||||
|
@ -1082,12 +1094,7 @@ label.block {
|
|||
width: 20em;
|
||||
}
|
||||
|
||||
.ui-dialog .task-update-confirm {
|
||||
padding: 0 0.5em 0.5em 0.5em;
|
||||
}
|
||||
|
||||
.task-dialog-message,
|
||||
.task-update-confirm .message {
|
||||
.task-dialog-message {
|
||||
margin-top: 0.5em;
|
||||
padding: 0.8em;
|
||||
border: 1px solid #ffdf0e;
|
||||
|
@ -1161,35 +1168,54 @@ div.tasklist-invitebox .rsvp-status.hint {
|
|||
}
|
||||
|
||||
#event-partstat .changersvp,
|
||||
.edit-attendees-table td.confirmstate span,
|
||||
div.tasklist-invitebox .rsvp-status.declined,
|
||||
div.tasklist-invitebox .rsvp-status.tentative,
|
||||
div.tasklist-invitebox .rsvp-status.accepted,
|
||||
div.tasklist-invitebox .rsvp-status.delegated,
|
||||
div.tasklist-invitebox .rsvp-status.needs-action {
|
||||
div.tasklist-invitebox .rsvp-status.in-process,
|
||||
div.tasklist-invitebox .rsvp-status.completed,
|
||||
div.tasklist-invitebox .rsvp-status.needs-action {
|
||||
padding: 0 0 1px 22px;
|
||||
background: url(images/attendee-status.png) 2px -20px no-repeat;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.declined,
|
||||
div.tasklist-invitebox .rsvp-status.declined {
|
||||
div.tasklist-invitebox .rsvp-status.declined,
|
||||
.edit-attendees-table td.confirmstate span.declined {
|
||||
background-position: 2px -40px;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.tentative,
|
||||
div.tasklist-invitebox .rsvp-status.tentative {
|
||||
div.tasklist-invitebox .rsvp-status.tentative,
|
||||
.edit-attendees-table td.confirmstate span.tentative {
|
||||
background-position: 2px -60px;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.delegated,
|
||||
div.tasklist-invitebox .rsvp-status.delegated {
|
||||
div.tasklist-invitebox .rsvp-status.delegated,
|
||||
.edit-attendees-table td.confirmstate span.delegated {
|
||||
background-position: 2px -180px;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.needs-action,
|
||||
div.tasklist-invitebox .rsvp-status.needs-action {
|
||||
div.tasklist-invitebox .rsvp-status.needs-action,
|
||||
.edit-attendees-table td.confirmstate span.needs-action {
|
||||
background-position: 2px 0;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.in-process,
|
||||
div.tasklist-invitebox .rsvp-status.in-process,
|
||||
.edit-attendees-table td.confirmstate span.in-process {
|
||||
background-position: 2px -200px;
|
||||
}
|
||||
|
||||
#event-partstat .changersvp.accepted,
|
||||
div.tasklist-invitebox .rsvp-status.accepted,
|
||||
.edit-attendees-table td.confirmstate span.accepted {
|
||||
background-position: 2px -220px;
|
||||
}
|
||||
|
||||
|
||||
/** Special hacks for IE7 **/
|
||||
/** They need to be in this file to also affect the task-create dialog embedded in mail view **/
|
||||
|
|
|
@ -353,9 +353,8 @@ function rcube_tasklist_ui(settings)
|
|||
if (rcmail.busy)
|
||||
return false;
|
||||
|
||||
rec.status = e.target.checked ? 'COMPLETED' : (rec.complete == 1 ? 'NEEDS-ACTION' : '');
|
||||
li.toggleClass('complete');
|
||||
save_task(rec, 'edit');
|
||||
save_task_confirm(rec, 'edit', { _status_before:rec.status + '', status:e.target.checked ? 'COMPLETED' : (rec.complete > 0 ? 'IN-PROCESS' : 'NEEDS-ACTION') });
|
||||
item.toggleClass('complete');
|
||||
return true;
|
||||
|
||||
case 'flagged':
|
||||
|
@ -363,7 +362,7 @@ function rcube_tasklist_ui(settings)
|
|||
return false;
|
||||
|
||||
rec.flagged = rec.flagged ? 0 : 1;
|
||||
li.toggleClass('flagged').find('.flagged:first').attr('aria-checked', (rec.flagged ? 'true' : 'false'));
|
||||
item.toggleClass('flagged').find('.flagged:first').attr('aria-checked', (rec.flagged ? 'true' : 'false'));
|
||||
save_task(rec, 'edit');
|
||||
break;
|
||||
|
||||
|
@ -377,8 +376,7 @@ function rcube_tasklist_ui(settings)
|
|||
input.datepicker($.extend({
|
||||
onClose: function(dateText, inst) {
|
||||
if (dateText != (rec.date || '')) {
|
||||
rec.date = dateText;
|
||||
save_task(rec, 'edit');
|
||||
save_task_confirm(rec, 'edit', { date:dateText });
|
||||
}
|
||||
input.datepicker('destroy').remove();
|
||||
link.html(dateText || rcmail.gettext('nodate','tasklist'));
|
||||
|
@ -971,6 +969,10 @@ function rcube_tasklist_ui(settings)
|
|||
*/
|
||||
function save_task(rec, action)
|
||||
{
|
||||
// show confirmation dialog when status of an assigned task has changed
|
||||
if (rec._status_before !== undefined && is_attendee(rec))
|
||||
return save_task_confirm(rec, action);
|
||||
|
||||
if (!rcmail.busy) {
|
||||
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
|
||||
rcmail.http_post('tasks/task', { action:action, t:rec, filter:filtermask });
|
||||
|
@ -981,6 +983,84 @@ function rcube_tasklist_ui(settings)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display confirm dialog when modifying/deleting a task record
|
||||
*/
|
||||
var save_task_confirm = function(rec, action, updates)
|
||||
{
|
||||
var data = $.extend({}, rec, updates || {}),
|
||||
notify = false, partstat = false, html = '';
|
||||
|
||||
// task has attendees, ask whether to notify them
|
||||
if (has_attendees(rec)) {
|
||||
if (is_organizer(rec)) {
|
||||
notify = true;
|
||||
html = rcmail.gettext('changeconfirmnotifications', 'tasklist');
|
||||
}
|
||||
// ask whether to change my partstat and notify organizer
|
||||
else if (data._status_before !== undefined && data.status && data._status_before != data.status && is_attendee(rec)) {
|
||||
partstat = true;
|
||||
html = rcmail.gettext('partstatupdatenotification', 'tasklist');
|
||||
}
|
||||
}
|
||||
|
||||
// remove to avoid endless recursion
|
||||
delete data._status_before;
|
||||
|
||||
// show dialog
|
||||
if (html) {
|
||||
var $dialog = $('<div>').html(html);
|
||||
|
||||
var buttons = [];
|
||||
buttons.push({
|
||||
text: rcmail.gettext('saveandnotify', 'tasklist'),
|
||||
click: function() {
|
||||
if (notify) data._notify = 1;
|
||||
if (partstat) data._reportpartstat = data.status == 'CANCELLED' ? 'DECLINED' : data.status;
|
||||
save_task(data, action);
|
||||
$(this).dialog('close');
|
||||
}
|
||||
});
|
||||
buttons.push({
|
||||
text: rcmail.gettext('save', 'tasklist'),
|
||||
click: function() {
|
||||
save_task(data, action);
|
||||
$(this).dialog('close');
|
||||
}
|
||||
});
|
||||
buttons.push({
|
||||
text: rcmail.gettext('cancel', 'tasklist'),
|
||||
click: function() {
|
||||
$(this).dialog('close');
|
||||
if (updates)
|
||||
render_task(rec, rec.id); // restore previous state
|
||||
}
|
||||
});
|
||||
|
||||
$dialog.dialog({
|
||||
modal: true,
|
||||
width: 460,
|
||||
closeOnEscapeType: false,
|
||||
dialogClass: 'warning no-close',
|
||||
title: rcmail.gettext('changetaskconfirm', 'tasklist'),
|
||||
buttons: buttons,
|
||||
open: function() {
|
||||
setTimeout(function(){
|
||||
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
|
||||
}, 5);
|
||||
},
|
||||
close: function(){
|
||||
$dialog.dialog('destroy').remove();
|
||||
}
|
||||
}).addClass('task-update-confirm').show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// do update
|
||||
return save_task(data, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove saving lock and free the UI for new input
|
||||
*/
|
||||
|
@ -1488,6 +1568,12 @@ function rcube_tasklist_ui(settings)
|
|||
if ($dialog.is(':ui-dialog'))
|
||||
$dialog.dialog('close');
|
||||
|
||||
// remove status-* classes
|
||||
$dialog.removeClass(function(i, oldclass) {
|
||||
var oldies = String(oldclass).split(' ');
|
||||
return $.grep(oldies, function(cls) { return cls.indexOf('status-') === 0 }).join(' ');
|
||||
});
|
||||
|
||||
if (!(rec = listdata[id]) || clear_popups({}))
|
||||
return;
|
||||
|
||||
|
@ -1528,6 +1614,10 @@ function rcube_tasklist_ui(settings)
|
|||
});
|
||||
}
|
||||
|
||||
if (rec.status) {
|
||||
$dialog.addClass('status-' + String(rec.status).toLowerCase());
|
||||
}
|
||||
|
||||
if (rec.recurrence && rec.recurrence_text) {
|
||||
$('#task-recurrence').show().children('.task-text').html(Q(rec.recurrence_text));
|
||||
}
|
||||
|
@ -1817,6 +1907,7 @@ function rcube_tasklist_ui(settings)
|
|||
var buttons = {};
|
||||
buttons[rcmail.gettext('save', 'tasklist')] = function() {
|
||||
var data = me.selected_task;
|
||||
data._status_before = me.selected_task.status + '';
|
||||
|
||||
// copy form field contents into task object to save
|
||||
$.each({ title:title, description:description, date:recdate, time:rectime, startdate:recstartdate, starttime:recstarttime, status:taskstatus, list:tasklist }, function(key,input){
|
||||
|
@ -1867,6 +1958,8 @@ function rcube_tasklist_ui(settings)
|
|||
data.complete = complete.val() / 100;
|
||||
if (isNaN(data.complete))
|
||||
data.complete = null;
|
||||
else if (data.complete == 1.0 && rec.status === '')
|
||||
data.status = 'COMPLETED';
|
||||
|
||||
if (!data.list && list.id)
|
||||
data.list = list.id;
|
||||
|
@ -1879,11 +1972,6 @@ function rcube_tasklist_ui(settings)
|
|||
delete data.organizer;
|
||||
}
|
||||
|
||||
// don't submit attendees if only myself is added as organizer
|
||||
if (data.attendees.length == 1 && data.attendees[0].role == 'ORGANIZER' && String(data.attendees[0].email).toLowerCase() == settings.identity.email) {
|
||||
data.attendees = [];
|
||||
}
|
||||
|
||||
// per-attendee notification suppression
|
||||
var need_invitation = false;
|
||||
if (allow_invitations) {
|
||||
|
@ -2050,7 +2138,34 @@ function rcube_tasklist_ui(settings)
|
|||
if (!rec || rec.readonly || rcmail.busy)
|
||||
return false;
|
||||
|
||||
var html, buttons = [];
|
||||
var html, buttons = [], $dialog = $('<div>');
|
||||
|
||||
// Subfunction to submit the delete command after confirm
|
||||
var _delete_task = function(id, mode) {
|
||||
var rec = listdata[id],
|
||||
li = $('li[rel="'+id+'"]', rcmail.gui_objects.resultlist).hide(),
|
||||
decline = $dialog.find('input.confirm-attendees-decline:checked').length,
|
||||
notify = $dialog.find('input.confirm-attendees-notify:checked').length;
|
||||
|
||||
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
|
||||
rcmail.http_post('task', { action:'delete', t:{ id:rec.id, list:rec.list, _decline:decline, _notify:notify }, mode:mode, filter:filtermask });
|
||||
|
||||
// move childs to parent/root
|
||||
if (mode != 1 && rec.children !== undefined) {
|
||||
var parent_node = rec.parent_id ? $('li[rel="'+rec.parent_id+'"] > .childtasks', rcmail.gui_objects.resultlist) : null;
|
||||
if (!parent_node || !parent_node.length)
|
||||
parent_node = rcmail.gui_objects.resultlist;
|
||||
|
||||
$.each(rec.children, function(i,cid) {
|
||||
var child = listdata[cid];
|
||||
child.parent_id = rec.parent_id;
|
||||
resort_task(child, $('li[rel="'+cid+'"]').appendTo(parent_node), true);
|
||||
});
|
||||
}
|
||||
|
||||
li.remove();
|
||||
delete listdata[id];
|
||||
}
|
||||
|
||||
if (rec.children && rec.children.length) {
|
||||
html = rcmail.gettext('deleteparenttasktconfirm','tasklist');
|
||||
|
@ -2080,6 +2195,19 @@ function rcube_tasklist_ui(settings)
|
|||
});
|
||||
}
|
||||
|
||||
if (is_attendee(rec)) {
|
||||
html += '<div class="task-dialog-message">' +
|
||||
'<label><input class="confirm-attendees-decline" type="checkbox" checked="checked" value="1" name="_decline" /> ' +
|
||||
rcmail.gettext('itipdeclinetask', 'tasklist') +
|
||||
'</label></div>';
|
||||
}
|
||||
else if (has_attendees(rec) && is_organizer(rec)) {
|
||||
html += '<div class="task-dialog-message">' +
|
||||
'<label><input class="confirm-attendees-notify" type="checkbox" checked="checked" value="1" name="_notify" /> ' +
|
||||
rcmail.gettext('sendcancellation', 'tasklist') +
|
||||
'</label></div>';
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
text: rcmail.gettext('cancel', 'tasklist'),
|
||||
click: function() {
|
||||
|
@ -2087,11 +2215,11 @@ function rcube_tasklist_ui(settings)
|
|||
}
|
||||
});
|
||||
|
||||
var $dialog = $('<div>').html(html);
|
||||
$dialog.html(html);
|
||||
$dialog.dialog({
|
||||
modal: true,
|
||||
width: 520,
|
||||
dialogClass: 'warning',
|
||||
dialogClass: 'warning no-close',
|
||||
title: rcmail.gettext('deletetask', 'tasklist'),
|
||||
buttons: buttons,
|
||||
close: function(){
|
||||
|
@ -2102,34 +2230,6 @@ function rcube_tasklist_ui(settings)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subfunction to submit the delete command after confirm
|
||||
*/
|
||||
function _delete_task(id, mode)
|
||||
{
|
||||
var rec = listdata[id],
|
||||
li = $('li[rel="'+id+'"]', rcmail.gui_objects.resultlist).hide();
|
||||
|
||||
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
|
||||
rcmail.http_post('task', { action:'delete', t:{ id:rec.id, list:rec.list }, mode:mode, filter:filtermask });
|
||||
|
||||
// move childs to parent/root
|
||||
if (mode != 1 && rec.children !== undefined) {
|
||||
var parent_node = rec.parent_id ? $('li[rel="'+rec.parent_id+'"] > .childtasks', rcmail.gui_objects.resultlist) : null;
|
||||
if (!parent_node || !parent_node.length)
|
||||
parent_node = rcmail.gui_objects.resultlist;
|
||||
|
||||
$.each(rec.children, function(i,cid) {
|
||||
var child = listdata[cid];
|
||||
child.parent_id = rec.parent_id;
|
||||
resort_task(child, $('li[rel="'+cid+'"]').appendTo(parent_node), true);
|
||||
});
|
||||
}
|
||||
|
||||
li.remove();
|
||||
delete listdata[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given task matches the current filtermask and tag selection
|
||||
*/
|
||||
|
|
|
@ -342,6 +342,24 @@ class tasklist extends rcube_plugin
|
|||
$this->rc->output->show_message('tasklist.errornotifying', 'error');
|
||||
}
|
||||
}
|
||||
else if ($success && $rec['_reportpartstat']) {
|
||||
// get the full record after update
|
||||
$task = $this->driver->get_task($rec);
|
||||
|
||||
// send iTip REPLY with the updated partstat
|
||||
if ($task['organizer'] && ($idx = $this->is_attendee($task)) !== false) {
|
||||
$sender = $task['attendees'][$idx];
|
||||
$status = strtolower($sender['status']);
|
||||
|
||||
$itip = $this->load_itip();
|
||||
$itip->set_sender_email($sender['email']);
|
||||
|
||||
if ($itip->send_itip_message($this->to_libcal($task), 'REPLY', $task['organizer'], 'itipsubject' . $status, 'itipmailbody' . $status))
|
||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $task['organizer']['name'] ?: $task['organizer']['email']))), 'confirmation');
|
||||
else
|
||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// unlock client
|
||||
$this->rc->output->command('plugin.unlock_saving');
|
||||
|
@ -367,6 +385,7 @@ class tasklist extends rcube_plugin
|
|||
require_once realpath(__DIR__ . '/../libcalendaring/lib/libcalendaring_itip.php');
|
||||
$this->itip = new libcalendaring_itip($this, 'tasklist');
|
||||
$this->itip->set_rsvp_actions(array('accepted','declined'));
|
||||
$this->itip->set_rsvp_status(array('accepted','tentative','declined','delegated','in-process','completed'));
|
||||
}
|
||||
|
||||
return $this->itip;
|
||||
|
@ -517,6 +536,20 @@ class tasklist extends rcube_plugin
|
|||
|
||||
$rec['attachments'] = $attachments;
|
||||
|
||||
// convert invalid data
|
||||
if (isset($rec['attendees']) && !is_array($rec['attendees']))
|
||||
$rec['attendees'] = array();
|
||||
|
||||
// copy the task status to my attendee partstat
|
||||
if (!empty($rec['_reportpartstat'])) {
|
||||
if (($idx = $this->is_attendee($rec)) !== false) {
|
||||
if (!($rec['_reportpartstat'] == 'NEEDS-ACTION' && $rec['attendees'][$idx]['status'] == 'ACCEPTED'))
|
||||
$rec['attendees'][$idx]['status'] = $rec['_reportpartstat'];
|
||||
else
|
||||
unset($rec['_reportpartstat']);
|
||||
}
|
||||
}
|
||||
|
||||
// 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']);
|
||||
|
@ -1044,9 +1077,25 @@ class tasklist extends rcube_plugin
|
|||
else if ($start > $weeklimit || ($rec['date'] && $duedate > $weeklimit))
|
||||
$mask |= self::FILTER_MASK_LATER;
|
||||
|
||||
// TODO: add mask for "assigned to me"
|
||||
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the current user is an attendee of the given task
|
||||
*/
|
||||
public function is_attendee($task)
|
||||
{
|
||||
$emails = $this->lib->get_user_emails();
|
||||
foreach ((array)$task['attendees'] as $i => $attendee) {
|
||||
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******* UI functions ********/
|
||||
|
||||
|
@ -1709,7 +1758,7 @@ class tasklist extends rcube_plugin
|
|||
$this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('list' => $list['name']))), 'confirmation');
|
||||
|
||||
$metadata['rsvp'] = intval($metadata['rsvp']);
|
||||
$metadata['after_action'] = $this->rc->config->get('tasklist_itip_after_action');
|
||||
$metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', 0);
|
||||
|
||||
$this->rc->output->command('plugin.itip_message_processed', $metadata);
|
||||
$error_msg = null;
|
||||
|
@ -1725,7 +1774,7 @@ class tasklist extends rcube_plugin
|
|||
$itip->set_sender_email($reply_sender);
|
||||
|
||||
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['email']))), 'confirmation');
|
||||
else
|
||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||
}
|
||||
|
@ -1813,6 +1862,7 @@ class tasklist extends rcube_plugin
|
|||
public function to_libcal($task)
|
||||
{
|
||||
$object = $task;
|
||||
$object['_type'] = 'task';
|
||||
$object['categories'] = (array)$task['tags'];
|
||||
|
||||
// convert to datetime objects
|
||||
|
|
Loading…
Add table
Reference in a new issue