From 1cd956f7085aee22daf215b97a34ddb095b544ad Mon Sep 17 00:00:00 2001 From: "Aleksander Machniak (Kolab Systems)" Date: Tue, 26 Jul 2011 13:13:04 +0200 Subject: [PATCH] Extended calendar folder management feature for kolab driver --- plugins/calendar/calendar.php | 4 +- plugins/calendar/calendar_ui.js | 10 +- plugins/calendar/drivers/calendar_driver.php | 21 +- .../calendar/drivers/kolab/kolab_driver.php | 281 +++++++++++++++--- plugins/calendar/lib/calendar_ui.php | 25 +- plugins/calendar/localization/en_US.inc | 2 + plugins/calendar/skins/default/calendar.css | 22 ++ .../default/templates/calendarform-kolab.html | 19 ++ 8 files changed, 316 insertions(+), 68 deletions(-) create mode 100644 plugins/calendar/skins/default/templates/calendarform-kolab.html diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 1c5801a1..822098ea 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -420,9 +420,9 @@ class calendar extends rcube_plugin function calendar_action() { $action = get_input_value('action', RCUBE_INPUT_GPC); - $cal = get_input_value('c', RCUBE_INPUT_POST); + $cal = get_input_value('c', RCUBE_INPUT_GPC); $success = $reload = false; - + switch ($action) { case "form-new": case "form-edit": diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index bfa2614d..64270cdd 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -1276,10 +1276,10 @@ function rcube_calendar_ui(settings) type: 'GET', dataType: 'html', url: rcmail.url('calendar'), - data: { action:(calendar.id ? 'form-edit' : 'form-new'), calendar:{ id:calendar.id } }, - success: function(data){ + data: { action:(calendar.id ? 'form-edit' : 'form-new'), c:{ id:calendar.id } }, + success: function(data) { $dialog.html(data); - form = $('#calendarform > form'); + form = $('form', $('#calendarform')); // '#calendarform > form' doesn't work here name = $('#calendar-name').prop('disabled', !calendar.editable).val(calendar.editname || calendar.name); color = $('#calendar-color').val(calendar.color).miniColors({ value: calendar.color }); name.select(); @@ -1291,7 +1291,7 @@ function rcube_calendar_ui(settings) buttons[rcmail.gettext('save', 'calendar')] = function() { // form is not loaded - if (!form) + if (!form || !form.length) return; // TODO: do some input validation @@ -1307,7 +1307,7 @@ function rcube_calendar_ui(settings) data.color = data.color.replace(/^#/, ''); if (calendar.id) data.id = calendar.id; - + rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data }); $dialog.dialog("close"); }; diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php index 2beec9cf..c9ac0c8b 100644 --- a/plugins/calendar/drivers/calendar_driver.php +++ b/plugins/calendar/drivers/calendar_driver.php @@ -288,28 +288,29 @@ abstract class calendar_driver /** * Fetch free/busy information from a person within the given range * - * @param string E-mail address of attendee + * @param string E-mail address of attendee * @param integer Requested period start date/time as unix timestamp * @param integer Requested period end date/time as unix timestamp - * @return array List of busy timeslots within the requested range + * + * @return array List of busy timeslots within the requested range */ public function get_freebusy_list($email, $start, $end) { sleep(2); return false; } - + /** - * Callback function to append additional elements to the calendar create/edit form + * Callback function to produce driver-specific calendar create/edit form * * @param string Request action 'form-edit|form-new' - * @param array Calendar properties (e.g. id) - * @param string HTML code for default edit form - * @return string HTML to be appended to form + * @param array Calendar properties (e.g. id, color) + * + * @return string HTML content of the form */ - public function calendar_form($action, $calendar, $html) + public function calendar_form($action, $calendar) { - return $html; + return null; } -} \ No newline at end of file +} diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 0430bb0d..20329332 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -140,27 +140,22 @@ class kolab_driver extends calendar_driver */ public function create_calendar($prop) { - $folder = rcube_charset_convert($prop['name'], RCMAIL_CHARSET, 'UTF7-IMAP'); + $folder = $this->folder_update($prop); - // add namespace prefix (when needed) - $this->rc->imap_init(); - $folder = $this->rc->imap->mod_mailbox($folder, 'in'); + if ($folder === false) { + return false; + } // create ID $id = rcube_kolab::folder_id($folder); - // create IMAP folder - if (rcube_kolab::folder_create($folder, 'event')) { - // save color in user prefs (temp. solution) - $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); - $prefs['kolab_calendars'][$id]['color'] = $prop['color']; + // save color in user prefs (temp. solution) + $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); + $prefs['kolab_calendars'][$id]['color'] = $prop['color']; - $this->rc->user->save_prefs($prefs); + $this->rc->user->save_prefs($prefs); - return $id; - } - - return false; + return $id; } @@ -172,34 +167,89 @@ class kolab_driver extends calendar_driver public function edit_calendar($prop) { if ($prop['id'] && ($cal = $this->calendars[$prop['id']])) { - $newfolder = rcube_charset_convert($prop['name'], RCMAIL_CHARSET, 'UTF7-IMAP'); $oldfolder = $cal->get_realname(); - // add namespace prefix (when needed) - $this->rc->imap_init(); - $newfolder = $this->rc->imap->mod_mailbox($newfolder, 'in'); + $newfolder = $this->folder_update($prop); - if (!$cal->readonly && $newfolder != $oldfolder) - $result = rcube_kolab::folder_rename($oldfolder, $newfolder); - else - $result = true; - - if ($result) { - // create ID - $id = $newfolder ? rcube_kolab::folder_id($newfolder) : $prop['id']; - // save color in user prefs (temp. solution) - $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); - unset($prefs['kolab_calendars'][$prop['id']]); - $prefs['kolab_calendars'][$id]['color'] = $prop['color']; - - $this->rc->user->save_prefs($prefs); - return true; + if ($newfolder === false) { + return false; } + + // create ID + $id = rcube_kolab::folder_id($newfolder); + + // save color in user prefs (temp. solution) + $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); + unset($prefs['kolab_calendars'][$prop['id']]); + $prefs['kolab_calendars'][$id]['color'] = $prop['color']; + + $this->rc->user->save_prefs($prefs); + return true; } return false; } + /** + * Rename or Create a new IMAP folder + * + * @param array Hash array with calendar properties + * + * @return mixed New folder name or False on failure + */ + private function folder_update($prop) + { + $folder = rcube_charset_convert($prop['name'], RCMAIL_CHARSET, 'UTF7-IMAP'); + $oldfolder = $prop['oldname']; // UTF7 + $parent = $prop['parent']; // UTF7 + $delimiter = $_SESSION['imap_delimiter']; + + // sanity checks (from steps/settings/save_folder.inc) + if (!strlen($folder)) { + return false; + } + else if (strlen($folder) > 128) { + return false; + } + else { + // these characters are problematic e.g. when used in LIST/LSUB + foreach (array($delimiter, '%', '*') as $char) { + if (strpos($folder, $delimiter) !== false) { + return false; + } + } + } + + // @TODO: $options + $options = array(); + if ($options['protected'] || $options['norename']) { + $folder = $oldfolder; + } + else if (strlen($parent)) { + $folder = $parent . $delimiter . $folder; + } + else { + // add namespace prefix (when needed) + $this->rc->imap_init(); + $folder = $this->rc->imap->mod_mailbox($folder, 'in'); + } + + // update the folder name + if (strlen($oldfolder)) { + if ($oldfolder != $folder) + $result = rcube_kolab::folder_rename($oldfolder, $folder); + else + $result = true; + } + // create new folder + else { + $result = rcube_kolab::folder_create($folder, 'event', false); + } + + return $result ? $folder : false; + } + + /** * Delete the given calendar with all its contents * @@ -768,8 +818,171 @@ class kolab_driver extends calendar_driver 'message' => "Failed triggering folder. Error was " . $trigger->getMessage()), true, false); } - + exit; } + /** + * Callback function to produce driver-specific calendar create/edit form + * + * @param string Request action 'form-edit|form-new' + * @param array Calendar properties (e.g. id, color) + * + * @return string HTML content of the form + */ + public function calendar_form($action, $calendar) + { + // Remove any scripts/css/js + $this->rc->output->reset(); + // Produce form content + $content = $this->calendar_form_content($calendar); + // Parse form template, write to output buffer + // This way other plugins (e.g. acl) will be able to add scripts/style to the content + ob_start(); + $this->rc->output->parse('calendar.calendarform-kolab', false, true); + $html = ob_get_clean(); + + return str_replace('%FORM_CONTENT%', $content, $html); + } + + /** + * Produces calendar edit/create form content + * + * @return string HTML content of the form + */ + private function calendar_form_content($calendar) + { + if ($calendar['id'] && ($cal = $this->calendars[$calendar['id']])) { + $folder = $cal->get_realname(); // UTF7 + $color = $cal->get_color(); + } + else { + $folder = ''; + $color = ''; + } + + $hidden_fields[] = array('name' => 'oldname', 'value' => $folder); + + $delim = $_SESSION['imap_delimiter']; + $form = array(); + + if (strlen($folder)) { + $path_imap = explode($delim, $folder); + $name = rcube_charset_convert(array_pop($path_imap), 'UTF7-IMAP'); + $path_imap = implode($path_imap, $delim); + + $this->rc->imap_connect(); + $options = $this->rc->imap->mailbox_info($folder); + } + else { + $path_imap = ''; + $name = ''; + } + + // General tab + $form['props'] = array( + 'name' => $this->rc->gettext('properties'), + ); + + // calendar name + $foldername = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20)); + + $form['props']['fieldsets']['location'] = array( + 'name' => $this->rc->gettext('location'), + 'content' => array( + 'name' => array( + 'label' => $this->cal->gettext('name'), + 'value' => $foldername->show($name), + ), + ), + ); + + if (!empty($options) && ($options['norename'] || $options['namespace'] != 'personal')) { + // prevent user from moving folder + $hidden_fields[] = array('name' => 'parent', 'value' => $path_imap); + } + else { + $select = rcube_kolab::folder_selector('event', array('name' => 'parent')); + + $form['props']['fieldsets']['location']['content']['path'] = array( + 'label' => $this->cal->gettext('parentcalendar'), + 'value' => $select->show($path_imap), + ); + } + + // calendar color + $color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6)); + + $form['props']['fieldsets']['settings'] = array( + 'name' => $this->rc->gettext('settings'), + 'content' => array( + 'color' => array( + 'label' => $this->cal->gettext('color'), + 'value' => $color->show($calendar['color']), + ), + ), + ); + + // Allow plugins to modify the form content (e.g. with ACL form) + $plugin = $this->rc->plugins->exec_hook('calendar_form_kolab', + array('form' => $form, 'options' => $options, 'name' => $folder)); + + $form = $plugin['form']; + $out = ''; + + if (is_array($hidden_fields)) { + foreach ($hidden_fields as $field) { + $hiddenfield = new html_hiddenfield($field); + $out .= $hiddenfield->show() . "\n"; + } + } + + // Create form output + foreach ($form as $tab) { + if (!empty($tab['fieldsets']) && is_array($tab['fieldsets'])) { + $content = ''; + foreach ($tab['fieldsets'] as $fieldset) { + $subcontent = $this->get_form_part($fieldset); + if ($subcontent) { + $content .= html::tag('fieldset', null, html::tag('legend', null, Q($fieldset['name'])) . $subcontent) ."\n"; + } + } + } + else { + $content = $this->get_form_part($tab); + } + + if ($content) { + $out .= html::tag('fieldset', null, html::tag('legend', null, Q($tab['name'])) . $content) ."\n"; + } + } + + return $out; + } + + /** + * Helper function used in calendar_form_content(). Creates a part of the form. + */ + private function get_form_part($form) + { + $content = ''; + + if (is_array($form['content']) && !empty($form['content'])) { + $table = new html_table(array('cols' => 2)); + foreach ($form['content'] as $col => $colprop) { + $colprop['id'] = '_'.$col; + $label = !empty($colprop['label']) ? $colprop['label'] : rcube_label($col); + + $table->add('title', sprintf('', $colprop['id'], Q($label))); + $table->add(null, $colprop['value']); + } + $content = $table->show(); + } + else { + $content = $form['content']; + } + + return $content; + } + } diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 07eb7b0a..9cd9e242 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -529,28 +529,19 @@ class calendar_ui } /** - * Handler for calendar form template object. - * Will get additional form fields from driver class + * Handler for calendar form template. + * The form content could be overriden by the driver */ function calendar_editform($action, $calendar = array()) { - // compose default calendar form - $input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20)); - $html = html::div('form-section', - html::label('calendar-name', $this->calendar->gettext('name')) . - $input_name->show($calendar['name'])); + $html = $this->calendar->driver->calendar_form($action, $calendar); - $input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6)); - $html .= html::div('form-section', - html::label('calendar-color', $this->calendar->gettext('color')) . - $input_color->show($calendar['color'])); - - // allow driver to extend the form - $html = $this->calendar->driver->calendar_form($action, $calendar, $html); - - return html::tag('form', array('action' => "#", 'method' => "get"), $html); + if (!$html) + $html = $this->rc->output->parse('calendar.calendarform', false, false); + + return $html; } - + /** * */ diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index 4b405ee5..20ab37df 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -1,4 +1,5 @@ + + + +
+
+ %FORM_CONTENT% +
+
+ + + +