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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.contact_list && this.contact_list.data[rec.cid]) {
|
||||||
|
$.extend(rec, this.contact_list.data[rec.cid]);
|
||||||
|
}
|
||||||
|
|
||||||
// render dialog
|
// render dialog
|
||||||
$dialog = libkolab_audittrail.object_history_dialog({
|
$dialog = libkolab_audittrail.object_history_dialog({
|
||||||
module: 'kolab_addressbooks',
|
module: 'kolab_addressbook',
|
||||||
container: '#contacthistory',
|
container: '#contacthistory',
|
||||||
title: rcmail.gettext('objectchangelog','kolab_addressbook'),
|
title: rcmail.gettext('objectchangelog','kolab_addressbook') + ' - ' + rec.name,
|
||||||
|
|
||||||
// callback function for list actions
|
// callback function for list actions
|
||||||
listfunc: function(action, rev) {
|
listfunc: function(action, rev) {
|
||||||
var rec = $dialog.data('rec');
|
var rec = $dialog.data('rec');
|
||||||
console.log(action, rev, rec)
|
|
||||||
//rcmail.loading_lock = rcmail.set_busy(true, 'loading', this.loading_lock);
|
if (action == 'show') {
|
||||||
//rcmail.http_post('action', { _do: action, _data: { uid: rec.uid, list:rec.list, rev: rev } }, saving_lock);
|
// 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
|
// 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 = this.env.address_sources[rec.source] || {}
|
||||||
// source.editable = !source.readonly
|
source.editable = !source.readonly
|
||||||
|
|
||||||
data.module = 'kolab_addressbook';
|
data.module = 'kolab_addressbook';
|
||||||
libkolab_audittrail.render_changelog(data, rec, source);
|
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
|
// callback for rendering a diff view of two contact revisions
|
||||||
|
@ -519,8 +547,24 @@ rcube_webmail.prototype.contact_show_diff = function(data)
|
||||||
width: 480
|
width: 480
|
||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
// set dialog size according to content
|
// set dialog size according to content frame
|
||||||
// dialog_resize($dialog.get(0), $dialog.height(), rcmail.gui_containers.notedetailview.width() - 40);
|
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') {
|
if ($this->rc->task == 'addressbook') {
|
||||||
$this->add_texts('localization');
|
$this->add_texts('localization');
|
||||||
$this->add_hook('contact_form', array($this, 'contact_form'));
|
$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'));
|
$this->add_hook('template_object_directorylist', array($this, 'directorylist_html'));
|
||||||
|
|
||||||
// Plugin actions
|
// 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-changelog', array($this, 'contact_changelog'));
|
||||||
$this->register_action('plugin.contact-diff', array($this, 'contact_diff'));
|
$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
|
// get configuration for the Bonnie API
|
||||||
if ($bonnie_config = $this->rc->config->get('kolab_bonnie_api', false)) {
|
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);
|
$this->rc->output->set_env('kolab_audit_trail', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $p;
|
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
|
* 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();
|
$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
|
* Helper method to resolved the given contact identifier into uid and mailbox
|
||||||
*
|
*
|
||||||
* @return array (uid,mailbox,msguid) tuple
|
* @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;
|
$mailbox = $msguid = null;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ class kolab_addressbook_ui
|
||||||
|
|
||||||
|
|
||||||
if ($this->plugin->bonnie_api) {
|
if ($this->plugin->bonnie_api) {
|
||||||
|
$this->rc->output->set_env('kolab_audit_trail', true);
|
||||||
$this->plugin->api->include_script('libkolab/js/audittrail.js');
|
$this->plugin->api->include_script('libkolab/js/audittrail.js');
|
||||||
|
|
||||||
$this->rc->output->add_label(
|
$this->rc->output->add_label(
|
||||||
|
@ -121,6 +122,7 @@ class kolab_addressbook_ui
|
||||||
'kolab_addressbook.actiondelete',
|
'kolab_addressbook.actiondelete',
|
||||||
'kolab_addressbook.objectdiffnotavailable',
|
'kolab_addressbook.objectdiffnotavailable',
|
||||||
'kolab_addressbook.objectchangelognotavailable',
|
'kolab_addressbook.objectchangelognotavailable',
|
||||||
|
'kolab_addressbook.revisionrestoreconfirm',
|
||||||
'close'
|
'close'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -554,11 +554,22 @@ class rcube_kolab_contacts extends rcube_addressbook
|
||||||
{
|
{
|
||||||
$rec = null;
|
$rec = null;
|
||||||
$uid = $this->id2uid($id);
|
$uid = $this->id2uid($id);
|
||||||
|
$rev = rcube_utils::get_input_value('_rev', rcube_utils::INPUT_GPC);
|
||||||
|
|
||||||
if (strpos($uid, 'mailto:') === 0) {
|
if (strpos($uid, 'mailto:') === 0) {
|
||||||
$this->_fetch_groups(true);
|
$this->_fetch_groups(true);
|
||||||
$rec = $this->contacts[$id];
|
$rec = $this->contacts[$id];
|
||||||
$this->readonly = true; // set source to read-only
|
$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)) {
|
else if ($object = $this->storagefolder->get_object($uid)) {
|
||||||
$rec = $this->_to_rcube_contact($object);
|
$rec = $this->_to_rcube_contact($object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,9 +61,12 @@ $labels['actionmove'] = 'Moved';
|
||||||
$labels['actiondelete'] = 'Deleted';
|
$labels['actiondelete'] = 'Deleted';
|
||||||
$labels['showrevision'] = 'Show this version';
|
$labels['showrevision'] = 'Show this version';
|
||||||
$labels['restore'] = 'Restore 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['objectnotfound'] = 'Failed to load contact data';
|
||||||
$labels['objectchangelognotavailable'] = 'Change history is not available for this contact';
|
$labels['objectchangelognotavailable'] = 'Change history is not available for this contact';
|
||||||
$labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions';
|
$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['bookdeleteconfirm'] = 'Do you really want to delete the selected address book and all contacts in it?';
|
||||||
$messages['bookdeleting'] = 'Deleting address book...';
|
$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: ")";
|
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