From de110b96a5579b6a43febc6f87cd56ffdc6e0ebf Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 20 Apr 2015 16:25:48 +0200 Subject: [PATCH] Display audit trail for email messages via Bonnie API (#4975) --- plugins/libkolab/js/audittrail.js | 55 ++++++++++++- plugins/libkolab/libkolab.php | 97 +++++++++++++++++++++++ plugins/libkolab/localization/en_US.inc | 32 ++++++++ plugins/libkolab/skins/larry/libkolab.css | 67 ++++++++++++++++ 4 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 plugins/libkolab/localization/en_US.inc create mode 100644 plugins/libkolab/skins/larry/libkolab.css diff --git a/plugins/libkolab/js/audittrail.js b/plugins/libkolab/js/audittrail.js index 641fa23e..b680114e 100644 --- a/plugins/libkolab/js/audittrail.js +++ b/plugins/libkolab/js/audittrail.js @@ -46,7 +46,7 @@ libkolab_audittrail.object_history_dialog = function(p) // hide and reset changelog table $dialog.find('div.notfound-message').remove(); $dialog.find('.changelog-table').show().children('tbody') - .html('' + rcmail.gettext('loading') + ''); + .html('' + rcmail.gettext('loading') + ''); // open jquery UI dialog $dialog.dialog({ @@ -163,7 +163,7 @@ libkolab_audittrail.render_changelog = function(data, object, folder) var i, change, accessible, op_append, first = data.length - 1, last = 0, is_writeable = !!folder.editable, - op_labels = { APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete' }, + op_labels = { RECEIVE: 'actionreceive', APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete', READ: 'actionread', FLAGSET: 'actionflagset', FLAGCLEAR: 'actionflagclear' }, actions = ' ' + (is_writeable ? '' : ''), tbody = $dialog.find('.changelog-table tbody').html(''); @@ -175,6 +175,9 @@ libkolab_audittrail.render_changelog = function(data, object, folder) if (change.op == 'MOVE' && change.mailbox) { op_append = ' ⇢ ' + change.mailbox; } + else if ((change.op == 'FLAGSET' || change.op == 'FLAGCLEAR') && change.flags) { + op_append = ': ' + change.flags; + } else { op_append = ''; } @@ -187,7 +190,7 @@ libkolab_audittrail.render_changelog = function(data, object, folder) .append('' + Q(i+1) + '') .append('' + Q(change.date || '') + '') .append('' + Q(change.user || 'undisclosed') + '') - .append('' + Q(rcmail.gettext(op_labels[change.op] || '', data.module) + (op_append ? ' ...' : '')) + '') + .append('' + Q(rcmail.gettext(op_labels[change.op] || '', data.module) + op_append) + '') .append('' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + '') .appendTo(tbody); } @@ -210,3 +213,49 @@ libkolab_audittrail.dialog_resize = function(id, height, width) $(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) }) .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?) }; + + +// register handlers for mail message history +window.rcmail && rcmail.addEventListener('init', function(e) { + var loading_lock; + + if (rcmail.env.task == 'mail') { + rcmail.register_command('kolab-mail-history', function() { + var dialog, uid = rcmail.get_single_uid(), rec = { uid: uid, mbox: rcmail.get_message_mailbox(uid) }; + if (!uid || !window.libkolab_audittrail) { + return false; + } + + // render dialog + $dialog = libkolab_audittrail.object_history_dialog({ + module: 'libkolab', + container: '#mailmessagehistory', + title: rcmail.gettext('objectchangelog','libkolab') + }); + + $dialog.data('rec', rec); + + // fetch changelog data + loading_lock = rcmail.set_busy(true, 'loading', loading_lock); + rcmail.http_post('plugin.message-changelog', { _uid: rec.uid, _mbox: rec.mbox }, loading_lock); + + }, rcmail.env.action == 'show'); + + rcmail.addEventListener('plugin.message_render_changelog', function(data) { + var $dialog = $('#mailmessagehistory'), + rec = $dialog.data('rec'); + + if (data === false || !data.length || !event) { + // display 'unavailable' message + $('
' + rcmail.gettext('objectchangelognotavailable','libkolab') + '
') + .insertBefore($dialog.find('.changelog-table').hide()); + return; + } + + data.module = 'libkolab'; + libkolab_audittrail.render_changelog(data, rec, {}); + }); + + rcmail.env.message_commands.push('kolab-mail-history'); + } +}); diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php index 4abb288f..1dede0d3 100644 --- a/plugins/libkolab/libkolab.php +++ b/plugins/libkolab/libkolab.php @@ -28,6 +28,7 @@ class libkolab extends rcube_plugin { static $http_requests = array(); + static $bonnie_api = false; /** * Required startup method of a Roundcube plugin @@ -52,6 +53,32 @@ class libkolab extends rcube_plugin rcube::raise_error($e, true); kolab_format::$timezone = new DateTimeZone('GMT'); } + + $this->add_texts('localization/', $rcmail->output->type == 'html' && $rcmail->task == 'mail'); + + // embed scripts and templates for email message audit trail + if ($rcmail->task == 'mail' && self::get_bonnie_api()) { + if ($rcmail->output->type == 'html') { + $this->add_hook('render_page', array($this, 'bonnie_render_page')); + + $this->include_script('js/audittrail.js'); + $this->include_stylesheet($this->local_skin_path() . '/libkolab.css'); + + // add 'Show history' item to message menu + $this->api->add_content(html::tag('li', null, + $this->api->output->button(array( + 'command' => 'kolab-mail-history', + 'label' => 'libkolab.showhistory', + 'type' => 'link', + 'classact' => 'icon history active', + 'class' => 'icon history', + 'innerclass' => 'icon history', + ))), + 'messagemenu'); + } + + $this->register_action('plugin.message-changelog', array($this, 'message_changelog')); + } } /** @@ -63,6 +90,75 @@ class libkolab extends rcube_plugin return $p; } + /** + * Getter for a singleton instance of the Bonnie API + * + * @return mixed kolab_bonnie_api instance if configured, false otherwise + */ + public static function get_bonnie_api() + { + // get configuration for the Bonnie API + if (!self::$bonnie_api && ($bonnie_config = rcube::get_instance()->config->get('kolab_bonnie_api', false))) { + self::$bonnie_api = new kolab_bonnie_api($bonnie_config); + } + + return self::$bonnie_api; + } + + /** + * Hook to append the message history dialog template to the mail view + */ + function bonnie_render_page($p) + { + if (($p['template'] === 'mail' || $p['template'] === 'message') && !$p['kolab-audittrail']) { + // append a template for the audit trail dialog + $this->api->output->add_footer( + html::div(array('id' => 'mailmessagehistory', 'class' => 'uidialog', 'aria-hidden' => 'true', 'style' => 'display:none'), + self::object_changelog_table(array('class' => 'records-table changelog-table')) + ) + ); + $this->api->output->set_env('kolab_audit_trail', true); + $p['kolab-audittrail'] = true; + } + + return $p; + } + + /** + * Handler for message audit trail changelog requests + */ + public function message_changelog() + { + if (!self::$bonnie_api) { + return false; + } + + $rcmail = rcube::get_instance(); + $msguid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST, true); + $mailbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); + + $result = $msguid && $mailbox ? self::$bonnie_api->changelog('mail', null, $mailbox, $msguid) : null; + if (is_array($result)) { + if (is_array($result['changes'])) { + $dtformat = $rcmail->config->get('date_format') . ' ' . $rcmail->config->get('time_format'); + array_walk($result['changes'], function(&$change) use ($dtformat, $rcmail) { + if ($change['date']) { + $dt = rcube_utils::anytodatetime($change['date']); + if ($dt instanceof DateTime) { + $change['date'] = $rcmail->format_date($dt, $dtformat); + } + } + }); + } + $this->api->output->command('plugin.message_render_changelog', $result['changes']); + } + else { + $this->api->output->command('plugin.message_render_changelog', false); + } + + $this->api->output->send(); + } + /** * Wrapper function to load and initalize the HTTP_Request2 Object * @@ -135,6 +231,7 @@ class libkolab extends rcube_plugin public static function object_changelog_table($attrib = array()) { $rcube = rcube::get_instance(); + $attrib += array('domain' => 'libkolab'); $table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0)); $table->add_header('diff', ''); diff --git a/plugins/libkolab/localization/en_US.inc b/plugins/libkolab/localization/en_US.inc new file mode 100644 index 00000000..c74d0040 --- /dev/null +++ b/plugins/libkolab/localization/en_US.inc @@ -0,0 +1,32 @@ +