Added possibility to undo last event delete action (kolab driver only)

This commit is contained in:
Aleksander Machniak (Kolab Systems) 2011-07-18 15:28:57 +02:00
parent b7564ade58
commit 83a95c9aee
7 changed files with 195 additions and 49 deletions

View file

@ -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

View file

@ -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.
}

View file

@ -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.

View file

@ -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']);

View file

@ -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

View file

@ -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
*/

View file

@ -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';