Finish contact audit trail (#4972) with full display and restoring of old revisions
This commit is contained in:
parent
38246558b3
commit
6f948d0467
7 changed files with 169 additions and 17 deletions
|
@ -364,18 +364,49 @@ rcube_webmail.prototype.contact_history_dialog = function()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (this.contact_list && this.contact_list.data[rec.cid]) {
|
||||
$.extend(rec, this.contact_list.data[rec.cid]);
|
||||
}
|
||||
|
||||
// render dialog
|
||||
$dialog = libkolab_audittrail.object_history_dialog({
|
||||
module: 'kolab_addressbooks',
|
||||
module: 'kolab_addressbook',
|
||||
container: '#contacthistory',
|
||||
title: rcmail.gettext('objectchangelog','kolab_addressbook'),
|
||||
title: rcmail.gettext('objectchangelog','kolab_addressbook') + ' - ' + rec.name,
|
||||
|
||||
// callback function for list actions
|
||||
listfunc: function(action, rev) {
|
||||
var rec = $dialog.data('rec');
|
||||
console.log(action, rev, rec)
|
||||
//rcmail.loading_lock = rcmail.set_busy(true, 'loading', this.loading_lock);
|
||||
//rcmail.http_post('action', { _do: action, _data: { uid: rec.uid, list:rec.list, rev: rev } }, saving_lock);
|
||||
|
||||
if (action == 'show') {
|
||||
// open contact view in a dialog (iframe)
|
||||
var dialog, iframe = $('<iframe>')
|
||||
.attr('id', 'contactshowrevframe')
|
||||
.attr('width', '100%')
|
||||
.attr('height', '98%')
|
||||
.attr('frameborder', '0')
|
||||
.attr('src', rcmail.url('show', { _cid: rec.cid, _source: rec.source, _rev: rev, _framed: 1 })),
|
||||
contentframe = $('#' + rcmail.env.contentframe)
|
||||
|
||||
// open jquery UI dialog
|
||||
dialog = rcmail.show_popup_dialog(iframe, '', {}, {
|
||||
modal: false,
|
||||
resizable: true,
|
||||
closeOnEscape: true,
|
||||
title: rec.name + ' @ ' + rev,
|
||||
close: function() {
|
||||
dialog.dialog('destroy').attr('aria-hidden', 'true').remove();
|
||||
},
|
||||
minWidth: 400,
|
||||
width: contentframe.width() || 600,
|
||||
height: contentframe.height() || 400
|
||||
});
|
||||
dialog.css('padding', '0');
|
||||
}
|
||||
else {
|
||||
rcmail.kab_loading_lock = rcmail.set_busy(true, 'loading', rcmail.kab_loading_lock);
|
||||
rcmail.http_post('plugin.contact-' + action, { cid: rec.cid, source: rec.source, rev: rev }, rcmail.kab_loading_lock);
|
||||
}
|
||||
},
|
||||
|
||||
// callback function for comparing two object revisions
|
||||
|
@ -407,13 +438,10 @@ rcube_webmail.prototype.contact_render_changelog = function(data)
|
|||
}
|
||||
|
||||
source = this.env.address_sources[rec.source] || {}
|
||||
// source.editable = !source.readonly
|
||||
source.editable = !source.readonly
|
||||
|
||||
data.module = 'kolab_addressbook';
|
||||
libkolab_audittrail.render_changelog(data, rec, source);
|
||||
|
||||
// set dialog size according to content
|
||||
// dialog_resize($dialog.get(0), $dialog.height(), 600);
|
||||
};
|
||||
|
||||
// callback for rendering a diff view of two contact revisions
|
||||
|
@ -519,8 +547,24 @@ rcube_webmail.prototype.contact_show_diff = function(data)
|
|||
width: 480
|
||||
}).show();
|
||||
|
||||
// set dialog size according to content
|
||||
// dialog_resize($dialog.get(0), $dialog.height(), rcmail.gui_containers.notedetailview.width() - 40);
|
||||
// set dialog size according to content frame
|
||||
libkolab_audittrail.dialog_resize($dialog.get(0), $dialog.height(), ($('#' + rcmail.env.contentframe).width() || 440) - 40);
|
||||
};
|
||||
|
||||
|
||||
// close the contact history dialog
|
||||
rcube_webmail.prototype.close_contact_history_dialog = function(refresh)
|
||||
{
|
||||
$('#contacthistory, #contactdiff').each(function(i, elem) {
|
||||
var $dialog = $(elem);
|
||||
if ($dialog.is(':ui-dialog'))
|
||||
$dialog.dialog('close');
|
||||
});
|
||||
|
||||
// reload the contact content frame
|
||||
if (refresh && this.get_single_cid() == refresh) {
|
||||
this.load_contact(refresh, 'show', true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -541,6 +585,21 @@ function kolab_addressbook_contextmenu()
|
|||
}
|
||||
});
|
||||
}
|
||||
else if (menu.menu_name == 'contactlist' && rcmail.env.kolab_audit_trail) {
|
||||
// add "Show History" item to context menu
|
||||
menu.menu_source.push({
|
||||
label: rcmail.get_label('kolab_addressbook.showhistory'),
|
||||
command: 'contact_history_dialog',
|
||||
classes: 'history'
|
||||
});
|
||||
// enable history item if the contact source supports it
|
||||
menu.addEventListener('activate', function(p) {
|
||||
if (p.command == 'contact_history_dialog') {
|
||||
var source = rcmail.env.address_sources ? rcmail.env.address_sources[rcmail.env.source] : {};
|
||||
return !!source.audittrail;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ class kolab_addressbook extends rcube_plugin
|
|||
if ($this->rc->task == 'addressbook') {
|
||||
$this->add_texts('localization');
|
||||
$this->add_hook('contact_form', array($this, 'contact_form'));
|
||||
$this->add_hook('contact_photo', array($this, 'contact_photo'));
|
||||
$this->add_hook('template_object_directorylist', array($this, 'directorylist_html'));
|
||||
|
||||
// Plugin actions
|
||||
|
@ -73,7 +74,7 @@ class kolab_addressbook extends rcube_plugin
|
|||
|
||||
$this->register_action('plugin.contact-changelog', array($this, 'contact_changelog'));
|
||||
$this->register_action('plugin.contact-diff', array($this, 'contact_diff'));
|
||||
$this->register_action('plugin.contact-show', array($this, 'contact_show'));
|
||||
$this->register_action('plugin.contact-restore', array($this, 'contact_restore'));
|
||||
|
||||
// get configuration for the Bonnie API
|
||||
if ($bonnie_config = $this->rc->config->get('kolab_bonnie_api', false)) {
|
||||
|
@ -509,13 +510,26 @@ class kolab_addressbook extends rcube_plugin
|
|||
*/
|
||||
}
|
||||
|
||||
if ($this->bonnie_api && $this->rc->action == 'show') {
|
||||
if ($this->bonnie_api && $this->rc->action == 'show' && empty($p['record']['rev'])) {
|
||||
$this->rc->output->set_env('kolab_audit_trail', true);
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin hook for the contact photo image
|
||||
*/
|
||||
public function contact_photo($p)
|
||||
{
|
||||
// add photo data from old revision inline as data url
|
||||
if (!empty($p['record']['rev']) && !empty($p['data'])) {
|
||||
$p['url'] = 'data:image/gif;base64,' . base64_encode($p['data']);
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for contact audit trail changelog requests
|
||||
*/
|
||||
|
@ -677,21 +691,80 @@ class kolab_addressbook extends rcube_plugin
|
|||
}
|
||||
|
||||
/**
|
||||
* Handler for audit trail revision view requests
|
||||
* Handler for audit trail revision restore requests
|
||||
*/
|
||||
public function contact_show()
|
||||
public function contact_restore()
|
||||
{
|
||||
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = false;
|
||||
$contact = rcube_utils::get_input_value('cid', rcube_utils::INPUT_POST, true);
|
||||
$source = rcube_utils::get_input_value('source', rcube_utils::INPUT_POST);
|
||||
$rev = rcube_utils::get_input_value('rev', rcube_utils::INPUT_POST);
|
||||
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_contact_identity($contact, $source, $folder);
|
||||
|
||||
if ($folder && ($raw_msg = $this->bonnie_api->rawdata('contact', $uid, $rev, $mailbox))) {
|
||||
$imap = $this->rc->get_storage();
|
||||
|
||||
// insert $raw_msg as new message
|
||||
if ($imap->save_message($folder->name, $raw_msg, null, false)) {
|
||||
$success = true;
|
||||
|
||||
// delete old revision from imap and cache
|
||||
$imap->delete_message($msguid, $folder->name);
|
||||
$folder->cache->set($msguid, false);
|
||||
$this->cache = array();
|
||||
}
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'objectrestoresuccess', 'vars' => array('rev' => $rev))), 'confirmation');
|
||||
$this->rc->output->command('close_contact_history_dialog', $contact);
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('objectrestoreerror'), 'error');
|
||||
}
|
||||
|
||||
$this->rc->output->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a previous revision of the given contact record from the Bonnie API
|
||||
*/
|
||||
public function get_revision($cid, $source, $rev)
|
||||
{
|
||||
if (empty($this->bonnie_api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($uid, $mailbox, $msguid) = $this->_resolve_contact_identity($cid, $source);
|
||||
|
||||
// call Bonnie API
|
||||
$result = $this->bonnie_api->get('contact', $uid, $rev, $mailbox, $msguid);
|
||||
if (is_array($result) && $result['uid'] == $uid && !empty($result['xml'])) {
|
||||
$format = kolab_format::factory('contact');
|
||||
$format->load($result['xml']);
|
||||
$rec = $format->to_array();
|
||||
|
||||
if ($format->is_valid()) {
|
||||
$rec['rev'] = $result['rev'];
|
||||
return $rec;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to resolved the given contact identifier into uid and mailbox
|
||||
*
|
||||
* @return array (uid,mailbox,msguid) tuple
|
||||
*/
|
||||
private function _resolve_contact_identity($id, $abook)
|
||||
private function _resolve_contact_identity($id, $abook, &$folder = null)
|
||||
{
|
||||
$mailbox = $msguid = null;
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ class kolab_addressbook_ui
|
|||
|
||||
|
||||
if ($this->plugin->bonnie_api) {
|
||||
$this->rc->output->set_env('kolab_audit_trail', true);
|
||||
$this->plugin->api->include_script('libkolab/js/audittrail.js');
|
||||
|
||||
$this->rc->output->add_label(
|
||||
|
@ -121,6 +122,7 @@ class kolab_addressbook_ui
|
|||
'kolab_addressbook.actiondelete',
|
||||
'kolab_addressbook.objectdiffnotavailable',
|
||||
'kolab_addressbook.objectchangelognotavailable',
|
||||
'kolab_addressbook.revisionrestoreconfirm',
|
||||
'close'
|
||||
);
|
||||
|
||||
|
|
|
@ -554,11 +554,22 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
{
|
||||
$rec = null;
|
||||
$uid = $this->id2uid($id);
|
||||
$rev = rcube_utils::get_input_value('_rev', rcube_utils::INPUT_GPC);
|
||||
|
||||
if (strpos($uid, 'mailto:') === 0) {
|
||||
$this->_fetch_groups(true);
|
||||
$rec = $this->contacts[$id];
|
||||
$this->readonly = true; // set source to read-only
|
||||
}
|
||||
else if (!empty($rev)) {
|
||||
$rcmail = rcube::get_instance();
|
||||
$plugin = $rcmail->plugins->get_plugin('kolab_addressbook');
|
||||
if ($plugin && ($object = $plugin->get_revision($id, kolab_storage::id_encode($this->imap_folder), $rev))) {
|
||||
$rec = $this->_to_rcube_contact($object);
|
||||
$rec['rev'] = $rev;
|
||||
}
|
||||
$this->readonly = true; // set source to read-only
|
||||
}
|
||||
else if ($object = $this->storagefolder->get_object($uid)) {
|
||||
$rec = $this->_to_rcube_contact($object);
|
||||
}
|
||||
|
|
|
@ -61,9 +61,12 @@ $labels['actionmove'] = 'Moved';
|
|||
$labels['actiondelete'] = 'Deleted';
|
||||
$labels['showrevision'] = 'Show this version';
|
||||
$labels['restore'] = 'Restore this version';
|
||||
$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this contact? This will replace the current contact with the old version.';
|
||||
$labels['objectnotfound'] = 'Failed to load contact data';
|
||||
$labels['objectchangelognotavailable'] = 'Change history is not available for this contact';
|
||||
$labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions';
|
||||
$labels['objectrestoresuccess'] = 'Revision $rev successfully restored';
|
||||
$labels['objectrestoreerror'] = 'Failed to restore the old revision';
|
||||
|
||||
$messages['bookdeleteconfirm'] = 'Do you really want to delete the selected address book and all contacts in it?';
|
||||
$messages['bookdeleting'] = 'Deleting address book...';
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
@ -244,3 +244,7 @@
|
|||
content: ")";
|
||||
}
|
||||
|
||||
div.contextmenu.rcmmainmenu ul.iconized li a.history > span.icon {
|
||||
background: url(folder_icons.png) 1px -214px no-repeat;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue