Added possibility to undo last event delete action (kolab driver only)
This commit is contained in:
parent
b7564ade58
commit
83a95c9aee
7 changed files with 195 additions and 49 deletions
|
@ -109,7 +109,17 @@ class calendar extends rcube_plugin
|
|||
$this->register_action('freebusy-times', array($this, 'freebusy_times'));
|
||||
$this->register_action('randomdata', array($this, 'generate_randomdata'));
|
||||
$this->register_action('print',array($this,'print_view'));
|
||||
}
|
||||
|
||||
// remove undo information...
|
||||
if ($undo = $_SESSION['calendar_event_undo']) {
|
||||
// ...after timeout
|
||||
$undo_time = $this->rc->config->get('undo_timeout', 0);
|
||||
if ($undo['ts'] < time() - $undo_time) {
|
||||
$this->rc->session->remove('calendar_event_undo');
|
||||
// @TODO: do EXPUNGE on kolab objects?
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($this->rc->task == 'settings') {
|
||||
// add hooks for Calendar settings
|
||||
$this->add_hook('preferences_sections_list', array($this, 'preferences_sections_list'));
|
||||
|
@ -436,10 +446,10 @@ class calendar extends rcube_plugin
|
|||
*/
|
||||
function event_action()
|
||||
{
|
||||
$action = get_input_value('action', RCUBE_INPUT_POST);
|
||||
$event = get_input_value('e', RCUBE_INPUT_POST);
|
||||
$success = $reload = false;
|
||||
|
||||
$action = get_input_value('action', RCUBE_INPUT_GPC);
|
||||
$event = get_input_value('e', RCUBE_INPUT_POST);
|
||||
$success = $reload = $got_msg = false;
|
||||
|
||||
switch ($action) {
|
||||
case "new":
|
||||
// create UID for new event
|
||||
|
@ -475,31 +485,66 @@ class calendar extends rcube_plugin
|
|||
break;
|
||||
|
||||
case "remove":
|
||||
$removed = $this->driver->remove_event($event);
|
||||
$reload = true;
|
||||
// remove previous deletes
|
||||
$undo_time = $this->driver->undelete ? $this->rc->config->get('undo_timeout', 0) : 0;
|
||||
$this->rc->session->remove('calendar_event_undo');
|
||||
|
||||
$success = $this->driver->remove_event($event, $undo_time < 1);
|
||||
$reload = true;
|
||||
|
||||
if ($undo_time > 0 && $success) {
|
||||
$_SESSION['calendar_event_undo'] = array('ts' => time(), 'data' => $event);
|
||||
// display message with Undo link.
|
||||
$msg = html::span(null, $this->gettext('successremoval'))
|
||||
. ' ' . html::a(array('onclick' => sprintf("%s.http_request('event', 'action=undo', %s.display_message('', 'loading'))",
|
||||
JS_OBJECT_NAME, JS_OBJECT_NAME)), rcube_label('undo'));
|
||||
$this->rc->output->show_message($msg, 'confirmation', null, true, $undo_time);
|
||||
}
|
||||
else if ($success) {
|
||||
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
|
||||
$got_msg = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case "undo":
|
||||
// Restore deleted event
|
||||
$event = $_SESSION['calendar_event_undo']['data'];
|
||||
$reload = true;
|
||||
|
||||
if ($event)
|
||||
$success = $this->driver->restore_event($event);
|
||||
|
||||
if ($success) {
|
||||
$this->rc->session->remove('calendar_event_undo');
|
||||
$this->rc->output->show_message('calendar.successrestore', 'confirmation');
|
||||
$got_msg = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "dismiss":
|
||||
foreach (explode(',', $event['id']) as $id)
|
||||
$success |= $this->driver->dismiss_alarm($id, $event['snooze']);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// show confirmation/error message
|
||||
if (!$got_msg) {
|
||||
if ($success)
|
||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||
else
|
||||
$this->rc->output->show_message('calendar.errorsaving', 'error');
|
||||
}
|
||||
|
||||
// unlock client
|
||||
$this->rc->output->command('plugin.unlock_saving');
|
||||
|
||||
if ($success)
|
||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||
else if ($removed)
|
||||
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
|
||||
else
|
||||
$this->rc->output->show_message('calendar.errorsaving', 'error');
|
||||
|
||||
// FIXME: update a single event object on the client instead of reloading the entire source
|
||||
if ($success && $reload || ($removed && $reload))
|
||||
if ($success && $reload)
|
||||
$this->rc->output->command('plugin.reload_calendar', array('source' => $event['calendar']));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for load-requests from fullcalendar
|
||||
* This will return pure JSON formatted output
|
||||
|
|
|
@ -49,7 +49,7 @@ class caldav_driver extends calendar_driver
|
|||
// FIXME Implement. Can be done via editEvent
|
||||
}
|
||||
|
||||
public function remove_event($event) {
|
||||
public function remove_event($event, $force = true) {
|
||||
// FIXME Implement.
|
||||
}
|
||||
|
||||
|
|
|
@ -72,10 +72,11 @@
|
|||
*/
|
||||
abstract class calendar_driver
|
||||
{
|
||||
// backend features
|
||||
// features supported by backend
|
||||
public $alarms = false;
|
||||
public $attendees = false;
|
||||
public $attachments = false;
|
||||
public $undelete = false; // event undelete action
|
||||
public $categoriesimmutable = false;
|
||||
public $alarm_types = array('DISPLAY');
|
||||
|
||||
|
@ -156,11 +157,27 @@ abstract class calendar_driver
|
|||
/**
|
||||
* Remove a single event from the database
|
||||
*
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
* @param boolean Remove event irreversible (mark as deleted otherwise,
|
||||
* if supported by the backend)
|
||||
*
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
abstract function remove_event($event);
|
||||
abstract function remove_event($event, $force = true);
|
||||
|
||||
/**
|
||||
* Restores a single deleted event (if supported)
|
||||
*
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
*
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function restore_event($event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events from source.
|
||||
|
|
|
@ -513,10 +513,12 @@ class database_driver extends calendar_driver
|
|||
/**
|
||||
* Remove a single event from the database
|
||||
*
|
||||
* @param array Hash array with event properties
|
||||
* @param array Hash array with event properties
|
||||
* @param boolean Remove record irreversible (@TODO)
|
||||
*
|
||||
* @see Driver:remove_event()
|
||||
*/
|
||||
public function remove_event($event)
|
||||
public function remove_event($event, $force = true)
|
||||
{
|
||||
if (!empty($this->calendars)) {
|
||||
$event += (array)$this->get_event($event['id']);
|
||||
|
|
|
@ -294,10 +294,17 @@ class kolab_calendar
|
|||
* @see Driver:remove_event()
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function delete_event($event)
|
||||
public function delete_event($event, $force = true)
|
||||
{
|
||||
$deleted = false;
|
||||
$deleteme = $this->storage->delete($event['id']);
|
||||
$deleted = false;
|
||||
|
||||
if (!$force) {
|
||||
// Get IMAP object ID
|
||||
$imap_uid = $this->storage->_getStorageId($event['id']);
|
||||
}
|
||||
|
||||
$deleteme = $this->storage->delete($event['id'], $force);
|
||||
|
||||
if (PEAR::isError($deleteme)) {
|
||||
raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
|
@ -306,12 +313,67 @@ class kolab_calendar
|
|||
true, false);
|
||||
}
|
||||
else {
|
||||
// Save IMAP object ID in session, will be used for restore action
|
||||
if ($imap_uid)
|
||||
$_SESSION['kolab_delete_uids'][$event['id']] = $imap_uid;
|
||||
|
||||
$deleted = true;
|
||||
}
|
||||
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore deleted event record
|
||||
*
|
||||
* @see Driver:undelete_event()
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function restore_event($event)
|
||||
{
|
||||
$imap_uid = $_SESSION['kolab_delete_uids'][$event['id']];
|
||||
|
||||
if (!$imap_uid)
|
||||
return false;
|
||||
|
||||
$session = &Horde_Kolab_Session::singleton();
|
||||
$imap = &$session->getImap();
|
||||
|
||||
if (is_a($imap, 'PEAR_Error')) {
|
||||
$error = $imap;
|
||||
}
|
||||
else {
|
||||
$result = $imap->select($this->imap_folder);
|
||||
if (is_a($result, 'PEAR_Error')) {
|
||||
$error = $result;
|
||||
}
|
||||
else {
|
||||
$result = $imap->undeleteMessages($imap_uid);
|
||||
if (is_a($result, 'PEAR_Error')) {
|
||||
$error = $result;
|
||||
}
|
||||
else {
|
||||
// re-sync the cache
|
||||
$this->storage->synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error undeleting an event object(s) from the Kolab server:" . $error->getMessage()),
|
||||
true, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$rcmail = rcmail::get_instance();
|
||||
$rcmail->session->remove('kolab_delete_uids');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply fetch all records and store them in private member vars
|
||||
|
|
|
@ -27,6 +27,7 @@ class kolab_driver extends calendar_driver
|
|||
public $alarms = true;
|
||||
public $attendees = true;
|
||||
public $attachments = true;
|
||||
public $undelete = true;
|
||||
public $categoriesimmutable = true;
|
||||
|
||||
private $rc;
|
||||
|
@ -292,35 +293,37 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove a single event from the database
|
||||
* Remove a single event
|
||||
*
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
* @param boolean Remove record(s) irreversible (mark as deleted otherwise)
|
||||
*
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function remove_event($event)
|
||||
public function remove_event($event, $force = true)
|
||||
{
|
||||
$success = false;
|
||||
|
||||
|
||||
if (($storage = $this->calendars[$event['calendar']]) && ($event = $storage->get_event($event['id']))) {
|
||||
$savemode = 'all';
|
||||
$master = $event;
|
||||
|
||||
|
||||
$GLOBALS['conf']['kolab']['no_triggering'] = true;
|
||||
|
||||
|
||||
// read master if deleting a recurring event
|
||||
if ($event['recurrence'] || $event['recurrence_id']) {
|
||||
$master = $event['recurrence_id'] ? $storage->get_event($event['recurrence_id']) : $event;
|
||||
$savemode = $event['savemode'];
|
||||
}
|
||||
|
||||
|
||||
switch ($savemode) {
|
||||
case 'current':
|
||||
// add exception to master event
|
||||
$master['recurrence']['EXDATE'][] = $event['start'];
|
||||
$success = $storage->update_event($master);
|
||||
break;
|
||||
|
||||
|
||||
case 'future':
|
||||
if ($master['id'] != $event['id']) {
|
||||
// set until-date on master event
|
||||
|
@ -329,9 +332,9 @@ class kolab_driver extends calendar_driver
|
|||
$success = $storage->update_event($master);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: // 'all' is default
|
||||
$success = $storage->delete_event($master);
|
||||
$success = $storage->delete_event($master, $force);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -342,6 +345,22 @@ class kolab_driver extends calendar_driver
|
|||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a single deleted event
|
||||
*
|
||||
* @param array Hash array with event properties:
|
||||
* id: Event identifier
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function restore_event($event)
|
||||
{
|
||||
if ($storage = $this->calendars[$event['calendar']]) {
|
||||
return $storage->restore_event($event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to update an event object depending on the given savemode
|
||||
*/
|
||||
|
|
|
@ -100,15 +100,16 @@ $labels['tabattendees'] = 'Participants';
|
|||
$labels['tabattachments'] = 'Attachments';
|
||||
|
||||
// messages
|
||||
$labels['deleteventconfirm'] = "Do you really want to delete this event?";
|
||||
$labels['deletecalendarconfirm'] = "Do you really want to delete this calendar with all its events?";
|
||||
$labels['savingdata'] = "Saving data...";
|
||||
$labels['errorsaving'] = "Failed to save changes";
|
||||
$labels['operationfailed'] = "The requested operation failed";
|
||||
$labels['invalideventdates'] = "Invalid dates entered! Please check your input.";
|
||||
$labels['invalidcalendarproperties'] = "Invalid calendar properties! Please set a valid name.";
|
||||
$labels['searchnoresults'] = 'No events found in the selected calendars';
|
||||
$labels['successremoval'] = "The event was deleted successfully";
|
||||
$labels['deleteventconfirm'] = 'Do you really want to delete this event?';
|
||||
$labels['deletecalendarconfirm'] = 'Do you really want to delete this calendar with all its events?';
|
||||
$labels['savingdata'] = 'Saving data...';
|
||||
$labels['errorsaving'] = 'Failed to save changes.';
|
||||
$labels['operationfailed'] = 'The requested operation failed.';
|
||||
$labels['invalideventdates'] = 'Invalid dates entered! Please check your input.';
|
||||
$labels['invalidcalendarproperties'] = 'Invalid calendar properties! Please set a valid name.';
|
||||
$labels['searchnoresults'] = 'No events found in the selected calendars.';
|
||||
$labels['successremoval'] = 'The event has been deleted successfully.';
|
||||
$labels['successrestore'] = 'The event has been restored successfully.';
|
||||
|
||||
// recurrence form
|
||||
$labels['repeat'] = 'Repeat';
|
||||
|
|
Loading…
Add table
Reference in a new issue