From ca32923fd49a617dfa8f7bb795823bd0acd4353e Mon Sep 17 00:00:00 2001 From: nathangray Date: Thu, 20 Apr 2017 10:01:32 -0600 Subject: [PATCH] Calendar - better handling of recurrence when exporting & importing CSV --- .../inc/class.calendar_export_csv.inc.php | 8 +- .../inc/class.calendar_import_csv.inc.php | 20 ++++- calendar/inc/class.calendar_rrule.inc.php | 73 +++++++++++++++++++ 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/calendar/inc/class.calendar_export_csv.inc.php b/calendar/inc/class.calendar_export_csv.inc.php index 96f50dbb4d..3e353a7ec2 100644 --- a/calendar/inc/class.calendar_export_csv.inc.php +++ b/calendar/inc/class.calendar_export_csv.inc.php @@ -138,8 +138,6 @@ class calendar_export_csv implements importexport_iface_export_plugin { $export_object->set_mapping($options['mapping']); $convert_fields = calendar_egw_record::$types; - $recurrence = $this->bo->recur_types; - $record = new calendar_egw_record(); foreach ($events as $event) { @@ -154,10 +152,10 @@ class calendar_export_csv implements importexport_iface_export_plugin { if (is_array($event)) { $record->set_record($event); - if($options['mapping']['recurrence'] && is_array($recurrence)) + if($options['mapping']['recurrence']) { - $record->recurrence = $recurrence[$record->recur_type]; - if($record->recur_type != MCAL_RECUR_NONE) $record->recurrence .= ' / '. $record->recur_interval; + $rrule = calendar_rrule::event2rrule($event); + $record->recurrence = $rrule->__toString(); } // Standard stuff diff --git a/calendar/inc/class.calendar_import_csv.inc.php b/calendar/inc/class.calendar_import_csv.inc.php index b1e800a450..dcf3108ff2 100644 --- a/calendar/inc/class.calendar_import_csv.inc.php +++ b/calendar/inc/class.calendar_import_csv.inc.php @@ -181,9 +181,23 @@ class calendar_import_csv extends importexport_basic_import_csv { if($record->recurrence) { - list($record->recur_type, $record->recur_interval) = explode('/',$record->recurrence,2); - $record->recur_interval = trim($record->recur_interval); - $record->recur_type = array_search(strtolower(trim($record->recur_type)), array_map('strtolower',$this->lookups['recurrence'])); + $start = new Api\DateTime($record->start); + try + { + $rrule = calendar_rrule::from_string($record->recurrence, $start); + $record->recur_type = $rrule->type; + $record->recur_interval = $rrule->interval; + $record->recur_enddate = $rrule->enddate; + $record->recur_data = $rrule->weekdays; + $record->recur_exception = $rrule->exceptions; + } + catch (Exception $e) + { + // Try old way from export using just recur_type / interval + list($record->recur_type, $record->recur_interval) = explode('/',$record->recurrence,2); + $record->recur_interval = trim($record->recur_interval); + $record->recur_type = array_search(strtolower(trim($record->recur_type)), array_map('strtolower',$this->lookups['recurrence'])); + } unset($record->recurrence); } $record->tzid = calendar_timezones::id2tz($record->tz_id); diff --git a/calendar/inc/class.calendar_rrule.inc.php b/calendar/inc/class.calendar_rrule.inc.php index 85cd77ad83..1685ac8cbb 100644 --- a/calendar/inc/class.calendar_rrule.inc.php +++ b/calendar/inc/class.calendar_rrule.inc.php @@ -771,6 +771,79 @@ class calendar_rrule implements Iterator return new calendar_rrule($time,$event['recur_type'],$event['recur_interval'],$enddate,$event['recur_data'],$exceptions); } + /** + * Generate a rrule from a string generated by __toString(). + * @param String $rrule Recurrence rule in string format, as generated by __toString() + * @param DateTime date Optional date to work from, defaults to today + */ + public static function from_string(String $rrule, DateTime $date) + { + $time = $date ? $date : new Api\DateTime(); + $type_id = self::NONE; + $interval = 1; + $enddate = null; + $weekdays = 0; + $exceptions = array(); + + list($type, $conditions) = explode(' (', $rrule); + $conditions = explode(', ', substr($conditions, 0, -1)); + + foreach(static::$types as $id => $type_name) + { + list($str) = explode(' (',lang($type_name)); + if($str == $type) + { + $type_id = $id; + break; + } + } + + // Rejoin some extra splits for conditions with multiple values + foreach($conditions as $condition_index => $condition) + { + if(((int)$condition || strpos($condition, lang('last')) === 0) && + substr_compare( $condition, lang('day'), -strlen( lang('day') ) ) === 0) + { + $time->setDate($time->format('Y'), $time->format('m'), (int)($condition) ? (int)$condition : $time->format('t')); + unset($conditions[$condition_index]); + continue; + } + if(!strpos($condition, ':') && strpos($conditions[$condition_index-1], ':')) + { + $conditions[$condition_index-1] .= ', ' . $condition; + unset($conditions[$condition_index]); + } + } + foreach($conditions as $condition_index => $condition) + { + list($condition_name, $value) = explode(': ', $condition); + if($condition_name == lang('days repeated')) + { + foreach (self::$days as $mask => $label) + { + if (strpos($value, $label) !== FALSE || strpos($value, lang($label)) !== FALSE) + { + $weekdays += $mask; + } + } + if(stripos($condition, lang('all')) !== false) + { + $weekdays = self::ALLDAYS; + } + } + else if ($condition_name == lang('interval')) + { + $interval = (int)$value; + } + else if ($condition_name == lang('ends')) + { + list($dow, $date) = explode(', ', $value); + $enddate = new DateTime($date); + } + } + + return new calendar_rrule($time,$type_id,$interval,$enddate,$weekdays,$exceptions); + } /** * Get recurrence data (keys 'recur_*') to merge into an event *