mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-25 09:23:28 +01:00
Add flag in calendar import definitions (CSV & iCal) to not import conflicting events
This commit is contained in:
parent
980b967071
commit
4bb16b2bec
@ -168,7 +168,13 @@ class calendar_ical extends calendar_boupdate
|
|||||||
var $log = false;
|
var $log = false;
|
||||||
var $logfile="/tmp/log-vcal";
|
var $logfile="/tmp/log-vcal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conflict callback
|
||||||
|
* If set, conflict checking will be enabled, and the event as well as
|
||||||
|
* conflicts are passed as parameters to this callback
|
||||||
|
*/
|
||||||
|
var $conflict_callback = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -1386,7 +1392,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
// to not loose him, as EGroupware knows events without owner/ORGANIZER as participant
|
// to not loose him, as EGroupware knows events without owner/ORGANIZER as participant
|
||||||
if (isset($event_info['stored_event']['participants'][$event['owner']]) && !isset($event['participants'][$event['owner']]))
|
if (isset($event_info['stored_event']['participants'][$event['owner']]) && !isset($event['participants'][$event['owner']]))
|
||||||
{
|
{
|
||||||
$event['participant'][$event['owner']] = $event_info['stored_event']['participants'][$event['owner']];
|
$event['participants'][$event['owner']] = $event_info['stored_event']['participants'][$event['owner']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // common adjustments for new events
|
else // common adjustments for new events
|
||||||
@ -1765,6 +1771,41 @@ class calendar_ical extends calendar_boupdate
|
|||||||
return $updated_id === 0 ? 0 : $return_id;
|
return $updated_id === 0 ? 0 : $return_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override parent update function to handle conflict checking callback, if set
|
||||||
|
*
|
||||||
|
* @param array &$event event-array, on return some values might be changed due to set defaults
|
||||||
|
* @param boolean $ignore_conflicts =false just ignore conflicts or do a conflict check and return the conflicting events.
|
||||||
|
* Set to false if $this->conflict_callback is set
|
||||||
|
* @param boolean $touch_modified =true NOT USED ANYMORE (was only used in old csv-import), modified&modifier is always updated!
|
||||||
|
* @param boolean $ignore_acl =false should we ignore the acl
|
||||||
|
* @param boolean $updateTS =true update the content history of the event
|
||||||
|
* @param array &$messages=null messages about because of missing ACL removed participants or categories
|
||||||
|
* @param boolean $skip_notification =false true: send NO notifications, default false = send them
|
||||||
|
* @return mixed on success: int $cal_id > 0, on error or conflicts false.
|
||||||
|
* Conflicts are passed to $this->conflict_callback
|
||||||
|
*/
|
||||||
|
public function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false,$updateTS=true,&$messages=null, $skip_notification=false)
|
||||||
|
{
|
||||||
|
if($this->conflict_callback !== null)
|
||||||
|
{
|
||||||
|
// calendar_ical overrides search(), which breaks conflict checking
|
||||||
|
// so we make sure to use the original from parent
|
||||||
|
static $bo;
|
||||||
|
if(!$bo)
|
||||||
|
{
|
||||||
|
$bo = new calendar_boupdate();
|
||||||
|
}
|
||||||
|
$conflicts = $bo->conflicts($event);
|
||||||
|
if(is_array($conflicts) && count($conflicts) > 0)
|
||||||
|
{
|
||||||
|
call_user_func_array($this->conflict_callback, array(&$event, &$conflicts));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parent::update($event, $ignore_conflicts, $touch_modified, $ignore_acl, $updateTS, $messages, $skip_notification);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync alarms of current user: add alarms added on client and remove the ones removed
|
* Sync alarms of current user: add alarms added on client and remove the ones removed
|
||||||
*
|
*
|
||||||
|
@ -97,7 +97,7 @@ class calendar_import_csv extends importexport_basic_import_csv {
|
|||||||
{
|
{
|
||||||
$record->owner = $options['owner'];
|
$record->owner = $options['owner'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle errors in length or start/end date
|
// Handle errors in length or start/end date
|
||||||
if($record->start > $record->end)
|
if($record->start > $record->end)
|
||||||
{
|
{
|
||||||
@ -148,7 +148,8 @@ class calendar_import_csv extends importexport_basic_import_csv {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Search app via link query
|
// Search app via link query
|
||||||
$result = Link::query($resource['app'], $search, $options);
|
$link_options = array();
|
||||||
|
$result = Link::query($resource['app'], $search, $link_options);
|
||||||
|
|
||||||
if($result)
|
if($result)
|
||||||
{
|
{
|
||||||
@ -294,13 +295,39 @@ class calendar_import_csv extends importexport_basic_import_csv {
|
|||||||
}
|
}
|
||||||
if ( $this->dry_run ) {
|
if ( $this->dry_run ) {
|
||||||
//print_r($_data);
|
//print_r($_data);
|
||||||
|
// User is interested in conflict checks, do so for dry run
|
||||||
|
// Otherwise, conflicts are just ignored and imported anyway
|
||||||
|
if($this->definition->plugin_options['skip_conflicts'])
|
||||||
|
{
|
||||||
|
$conflicts = $this->bo->conflicts($_data);
|
||||||
|
if($conflicts)
|
||||||
|
{
|
||||||
|
$this->conflict_warning($record_num, $conflicts);
|
||||||
|
$this->results['skipped']++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->results[$_action]++;
|
$this->results[$_action]++;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$result = $this->bo->save( $_data, $this->is_admin);
|
$messages = null;
|
||||||
if(!$result) {
|
$result = $this->bo->update( $_data,
|
||||||
|
!$this->definition->plugin_options['skip_conflicts'],
|
||||||
|
true, $this->is_admin, true, $messages,
|
||||||
|
$this->definition->plugin_options['no_notification']
|
||||||
|
);
|
||||||
|
if(!$result)
|
||||||
|
{
|
||||||
$this->errors[$record_num] = lang('Unable to save');
|
$this->errors[$record_num] = lang('Unable to save');
|
||||||
} else {
|
}
|
||||||
|
else if (is_array($result))
|
||||||
|
{
|
||||||
|
$this->conflict_warning($record_num, $result);
|
||||||
|
$this->results['skipped']++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
$this->results[$_action]++;
|
$this->results[$_action]++;
|
||||||
// This does nothing (yet?) but update the identifier
|
// This does nothing (yet?) but update the identifier
|
||||||
$record->save($result);
|
$record->save($result);
|
||||||
@ -312,6 +339,21 @@ class calendar_import_csv extends importexport_basic_import_csv {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a warning message about conflicting events
|
||||||
|
*
|
||||||
|
* @param int $record_num Current record index
|
||||||
|
* @param Array $conflicts List of found conflicting events
|
||||||
|
*/
|
||||||
|
protected function conflict_warning($record_num, &$conflicts)
|
||||||
|
{
|
||||||
|
$this->warnings[$record_num] = lang('Conflicts') . ':';
|
||||||
|
foreach($conflicts as $conflict)
|
||||||
|
{
|
||||||
|
$this->warnings[$record_num] .= "<br />\n" . Api\DateTime::to($conflict['start']) . "\t" . $conflict['title'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns translated name of plugin
|
* returns translated name of plugin
|
||||||
|
@ -94,9 +94,9 @@ class calendar_import_ical implements importexport_iface_import_plugin {
|
|||||||
protected $errors = array();
|
protected $errors = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of actions, and how many times that action was taken
|
* List of actions, and how many times that action was taken
|
||||||
*/
|
*/
|
||||||
protected $results = array();
|
protected $results = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* imports entries according to given definition object.
|
* imports entries according to given definition object.
|
||||||
@ -136,18 +136,44 @@ class calendar_import_ical implements importexport_iface_import_plugin {
|
|||||||
{
|
{
|
||||||
$_definition->plugin_options['no_notification'] = true;
|
$_definition->plugin_options['no_notification'] = true;
|
||||||
}
|
}
|
||||||
|
// User wants conflicting events to not be imported
|
||||||
|
if($_definition->plugin_options['skip_conflicts'])
|
||||||
|
{
|
||||||
|
$calendar_ical->conflict_callback = array($this, 'conflict_warning');
|
||||||
|
}
|
||||||
if (!$calendar_ical->importVCal($_stream, -1,null,false,0,'',null,null,null,$_definition->plugin_options['no_notification']))
|
if (!$calendar_ical->importVCal($_stream, -1,null,false,0,'',null,null,null,$_definition->plugin_options['no_notification']))
|
||||||
{
|
{
|
||||||
$this->errors[] = lang('Error: importing the iCal');
|
$this->errors[] = lang('Error: importing the iCal');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->results['imported'] = $calendar_ical->events_imported;
|
$this->results['imported'] += $calendar_ical->events_imported;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $calendar_ical->events_imported;
|
return $calendar_ical->events_imported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a warning message about conflicting events
|
||||||
|
*
|
||||||
|
* @param int $record_num Current record index
|
||||||
|
* @param Array $conflicts List of found conflicting events
|
||||||
|
*/
|
||||||
|
public function conflict_warning(&$event, &$conflicts)
|
||||||
|
{
|
||||||
|
$warning = EGroupware\Api\DateTime::to($event['start']) . ' ' . $event['title'] . ' ' . lang('Conflicts') . ':';
|
||||||
|
foreach($conflicts as $conflict)
|
||||||
|
{
|
||||||
|
$warning .= "<br />\n" . EGroupware\Api\DateTime::to($conflict['start']) . "\t" . $conflict['title'];
|
||||||
|
}
|
||||||
|
$this->warnings[] = $warning;
|
||||||
|
|
||||||
|
// iCal will always count as imported, even if it wasn't
|
||||||
|
$this->results['imported'] -= 1;
|
||||||
|
|
||||||
|
$this->results['skipped']++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns translated name of plugin
|
* returns translated name of plugin
|
||||||
|
@ -15,7 +15,7 @@ use EGroupware\Api;
|
|||||||
class calendar_wizard_import_csv extends importexport_wizard_basic_import_csv
|
class calendar_wizard_import_csv extends importexport_wizard_basic_import_csv
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
*/
|
*/
|
||||||
function __construct()
|
function __construct()
|
||||||
@ -26,6 +26,9 @@ class calendar_wizard_import_csv extends importexport_wizard_basic_import_csv
|
|||||||
'wizard_step50' => lang('Manage mapping'),
|
'wizard_step50' => lang('Manage mapping'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Override conditions template to add conflict option
|
||||||
|
$this->step_templates['wizard_step55'] = 'calendar.import.conditions';
|
||||||
|
|
||||||
// Field mapping
|
// Field mapping
|
||||||
$tracking = new calendar_tracking();
|
$tracking = new calendar_tracking();
|
||||||
$this->mapping_fields = array('id' => 'Calendar ID') + $tracking->field2label;
|
$this->mapping_fields = array('id' => 'Calendar ID') + $tracking->field2label;
|
||||||
@ -67,6 +70,11 @@ class calendar_wizard_import_csv extends importexport_wizard_basic_import_csv
|
|||||||
$sel_options['string'] = array(
|
$sel_options['string'] = array(
|
||||||
'id' => 'Calendar ID'
|
'id' => 'Calendar ID'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(!$content['skip_conflicts'] && $content['plugin_options']['skip_conflicts'])
|
||||||
|
{
|
||||||
|
$content['skip_conflicts'] = $content['plugin_options']['skip_conflicts'];
|
||||||
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
84
calendar/inc/class.calendar_wizard_import_ical.inc.php
Normal file
84
calendar/inc/class.calendar_wizard_import_ical.inc.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware - Wizard for user CSV import
|
||||||
|
*
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package calendar
|
||||||
|
* @subpackage importexport
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Nathan Gray
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
|
||||||
|
class calendar_wizard_import_ical
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* List of steps. Key is the function, value is the translated title.
|
||||||
|
*/
|
||||||
|
public $steps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of eTemplates to use for each step. You can override this with your own etemplates steps.
|
||||||
|
*/
|
||||||
|
protected $step_templates = array(
|
||||||
|
'wizard_step55' => 'calendar.import.conditions'
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->steps = array(
|
||||||
|
'wizard_step55' => lang('Edit conditions'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
|
||||||
|
{
|
||||||
|
$result = parent::wizard_step50($content, $sel_options, $readonlys, $preserv);
|
||||||
|
$content['msg'] .= "\n*" ;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditions
|
||||||
|
function wizard_step55(&$content, &$sel_options, &$readonlys, &$preserv)
|
||||||
|
{
|
||||||
|
// return from step55
|
||||||
|
if ($content['step'] == 'wizard_step55')
|
||||||
|
{
|
||||||
|
switch (array_search('pressed', $content['button']))
|
||||||
|
{
|
||||||
|
case 'next':
|
||||||
|
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
|
||||||
|
case 'previous' :
|
||||||
|
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],-1);
|
||||||
|
case 'finish':
|
||||||
|
return 'wizard_finish';
|
||||||
|
default :
|
||||||
|
return $this->wizard_step55($content,$sel_options,$readonlys,$preserv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// init step30
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$content['text'] = $this->steps['wizard_step55'];
|
||||||
|
$content['step'] = 'wizard_step55';
|
||||||
|
if(!$content['skip_conflicts'] && array_key_exists('skip_conflicts', $content['plugin_options']))
|
||||||
|
{
|
||||||
|
$content['skip_conflicts'] = $content['plugin_options']['skip_conflicts'];
|
||||||
|
}
|
||||||
|
$preserv = $content;
|
||||||
|
unset ($preserv['button']);
|
||||||
|
|
||||||
|
// No real conditions, but we share a template
|
||||||
|
$content['no_conditions'] = true;
|
||||||
|
|
||||||
|
return $this->step_templates[$content['step']];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
12
calendar/templates/default/import.conditions.xet
Normal file
12
calendar/templates/default/import.conditions.xet
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE overlay PUBLIC "-//Stylite AG//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||||
|
<!-- $Id$ -->
|
||||||
|
<overlay>
|
||||||
|
<template id="calendar.import.conditions" template="" lang="" group="0" version="16.1">
|
||||||
|
<template id="importexport.wizard_basic_import_csv.conditions" disabled="@no_conditions"/>
|
||||||
|
<hbox>
|
||||||
|
<description value="Do not import conflicting events"/>
|
||||||
|
<checkbox id="skip_conflicts" />
|
||||||
|
</hbox>
|
||||||
|
</template>
|
||||||
|
</overlay>
|
Loading…
Reference in New Issue
Block a user