diff --git a/admin/inc/class.admin_import_groups_csv.inc.php b/admin/inc/class.admin_import_groups_csv.inc.php
index e098ee0900..654f2a708a 100644
--- a/admin/inc/class.admin_import_groups_csv.inc.php
+++ b/admin/inc/class.admin_import_groups_csv.inc.php
@@ -15,27 +15,9 @@ use EGroupware\Api;
/**
* class import_csv for admin (groups)
*/
-class admin_import_groups_csv implements importexport_iface_import_plugin {
+class admin_import_groups_csv extends importexport_basic_import_csv
+{
- private static $plugin_options = array(
- 'fieldsep', // char
- 'charset', // string
- 'num_header_lines', // int number of header lines
- 'field_conversion', // array( $csv_col_num => conversion)
- 'field_mapping', // array( $csv_col_num => adb_filed)
- 'conditions', /* => array containing condition arrays:
- 'type' => exists, // exists
- 'string' => '#kundennummer',
- 'true' => array(
- 'action' => update,
- 'last' => true,
- ),
- 'false' => array(
- 'action' => insert,
- 'last' => true,
- ),*/
-
- );
/**
* actions which could be done to data entries
@@ -49,128 +31,80 @@ class admin_import_groups_csv implements importexport_iface_import_plugin {
*/
protected static $conditions = array( 'exists' );
- /**
- * @var definition
- */
- private $definition;
- /**
- * @var bool
- */
- private $dry_run = false;
+ protected function import_record(importexport_iface_egw_record &$record, &$import_csv)
+ {
+ if($this->definition->plugin_options['conditions'])
+ {
+ foreach($this->definition->plugin_options['conditions'] as $condition)
+ {
+ switch($condition['type'])
+ {
+ // exists
+ case 'exists' :
+ $accounts = array();
- /**
- * List of import warnings
- */
- protected $warnings = array();
+ // Skip the search if the field is empty
+ if($record[$condition['string']] !== '')
+ {
- /**
- * List of import errors
- */
- protected $errors = array();
-
- /**
- * List of actions, and how many times that action was taken
- */
- protected $results = array();
-
- /**
- * imports entries according to given definition object.
- * @param resource $_stream
- * @param string $_charset
- * @param definition $_definition
- */
- public function import( $_stream, importexport_definition $_definition ) {
- $import_csv = new importexport_import_csv( $_stream, array(
- 'fieldsep' => $_definition->plugin_options['fieldsep'],
- 'charset' => $_definition->plugin_options['charset'],
- ));
-
- $this->definition = $_definition;
-
- // dry run?
- $this->dry_run = isset( $_definition->plugin_options['dry_run'] ) ? $_definition->plugin_options['dry_run'] : false;
-
- // set FieldMapping.
- $import_csv->mapping = $_definition->plugin_options['field_mapping'];
-
- // set FieldConversion
- $import_csv->conversion = $_definition->plugin_options['field_conversion'];
-
- //check if file has a header lines
- if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) {
- $import_csv->skip_records($_definition->plugin_options['num_header_lines']);
- } elseif(isset($_definition->plugin_options['has_header_line']) && $_definition->plugin_options['has_header_line']) {
- // First method is preferred
- $import_csv->skip_records(1);
- }
-
- // Start counting successes
- $count = 0;
- $this->results = array();
-
- // Failures
- $this->errors = array();
-
- while ( $record = $import_csv->get_record() ) {
- $success = false;
- // don't import empty records
- if( count( array_unique( $record ) ) < 2 ) continue;
-
- importexport_import_csv::convert($record, admin_egw_group_record::$types, 'admin');
-
- if ( $_definition->plugin_options['conditions'] ) {
- foreach ( $_definition->plugin_options['conditions'] as $condition ) {
- switch ( $condition['type'] ) {
- // exists
- case 'exists' :
- $accounts = array();
-
- // Skip the search if the field is empty
- if($record[$condition['string']] !== '') {
-
- $accounts = $GLOBALS['egw']->accounts->search(array(
- 'type' => 'groups',
- 'query' => $record[$condition['string']],
- 'query_type' => $condition['string']
- ));
- }
- // Search looks in the given field, but doesn't do an exact match
- foreach ( (array)$accounts as $key => $account )
+ $accounts = $GLOBALS['egw']->accounts->search(array(
+ 'type' => 'groups',
+ 'query' => $record[$condition['string']],
+ 'query_type' => $condition['string']
+ ));
+ }
+ // Search looks in the given field, but doesn't do an exact match
+ foreach((array)$accounts as $key => $account)
+ {
+ if($account[$condition['string']] != $record[$condition['string']])
{
- if($account[$condition['string']] != $record[$condition['string']]) unset($accounts[$key]);
+ unset($accounts[$key]);
}
- if ( is_array( $accounts ) && count( $accounts ) >= 1 ) {
- $account = current($accounts);
- // apply action to all contacts matching this exists condition
- $action = $condition['true'];
- foreach ( (array)$accounts as $account ) {
- // Read full account, and copy needed info for accounts->save()
- $account = $GLOBALS['egw']->accounts->read($account['account_id']);
- $record['account_id'] = $account['account_id'];
- $record['account_firstname'] = $account['account_firstname'];
- $record['account_lastname'] = $account['account_lastname'];
- $success = $this->action( $action['action'], $record, $import_csv->get_current_position() );
- }
- } else {
- $action = $condition['false'];
- $success = ($this->action( $action['action'], $record, $import_csv->get_current_position() ));
+ }
+ if(is_array($accounts) && count($accounts) >= 1)
+ {
+ $account = current($accounts);
+ // apply action to all contacts matching this exists condition
+ $action = $condition['true'];
+ foreach((array)$accounts as $account)
+ {
+ // Read full account, and copy needed info for accounts->save()
+ $account = $GLOBALS['egw']->accounts->read($account['account_id']);
+ $record['account_id'] = $account['account_id'];
+ $record['account_firstname'] = $account['account_firstname'];
+ $record['account_lastname'] = $account['account_lastname'];
+ $success = $this->admin_action($action['action'], $record, $import_csv->get_current_position());
}
- break;
+ }
+ else
+ {
+ $action = $condition['false'];
+ $success = ($this->admin_action($action['action'], $record, $import_csv->get_current_position()));
+ }
+ break;
- // not supported action
- default :
- die('condition / action not supported!!!');
- }
- if ($action['last']) break;
+ // not supported action
+ default :
+ die('condition / action not supported!!!');
+ }
+ if($action['last'])
+ {
+ break;
}
- } else {
- // unconditional insert
- $success = $this->action( 'insert', $record, $import_csv->get_current_position() );
}
- if($success) $count++;
}
- return $count;
+ else
+ {
+ // unconditional insert
+ $success = $this->admin_action('insert', $record, $import_csv->get_current_position());
+ }
+ return $success;
+ }
+
+ protected function action($_action, importexport_iface_egw_record &$record, $record_num = 0)
+ {
+ // Not used, see admin_action()
}
/**
@@ -180,7 +114,7 @@ class admin_import_groups_csv implements importexport_iface_import_plugin {
* @param array $_data contact data for the action
* @return bool success or not
*/
- private function action ( $_action, $_data, $record_num = 0 ) {
+ private function admin_action($_action, $_data, $record_num = 0 ) {
switch ($_action) {
case 'none' :
return true;
diff --git a/admin/inc/class.admin_import_users_csv.inc.php b/admin/inc/class.admin_import_users_csv.inc.php
index 88457587e7..43d97c9ae9 100644
--- a/admin/inc/class.admin_import_users_csv.inc.php
+++ b/admin/inc/class.admin_import_users_csv.inc.php
@@ -15,28 +15,8 @@ use EGroupware\Api;
/**
* class import_csv for admin (users)
*/
-class admin_import_users_csv implements importexport_iface_import_plugin {
-
- private static $plugin_options = array(
- 'fieldsep', // char
- 'charset', // string
- 'num_header_lines', // int number of header lines
- 'field_conversion', // array( $csv_col_num => conversion)
- 'field_mapping', // array( $csv_col_num => adb_filed)
- 'conditions', /* => array containing condition arrays:
- 'type' => exists, // exists
- 'string' => '#kundennummer',
- 'true' => array(
- 'action' => update,
- 'last' => true,
- ),
- 'false' => array(
- 'action' => insert,
- 'last' => true,
- ),*/
-
- );
-
+class admin_import_users_csv extends importexport_basic_import_csv
+{
/**
* actions which could be done to data entries
*/
@@ -49,142 +29,99 @@ class admin_import_users_csv implements importexport_iface_import_plugin {
*/
protected static $conditions = array( 'exists' );
- /**
- * @var definition
- */
- private $definition;
-
- /**
- * @var bool
- */
- private $dry_run = false;
-
- /**
- * @var bool is current user admin?
- */
- private $is_admin = false;
-
- /**
- * @var int
- */
- private $user = null;
-
- /**
- * List of import warnings
- */
- protected $warnings = array();
-
- /**
- * List of import errors
- */
- protected $errors = array();
-
- /**
- * List of actions, and how many times that action was taken
- */
- protected $results = array();
-
/**
* imports entries according to given definition object.
* @param resource $_stream
* @param string $_charset
* @param definition $_definition
*/
- public function import( $_stream, importexport_definition $_definition ) {
- $import_csv = new importexport_import_csv( $_stream, array(
- 'fieldsep' => $_definition->plugin_options['fieldsep'],
- 'charset' => $_definition->plugin_options['charset'],
- ));
+ public function init(importexport_definition $definition, importexport_import_csv $import_csv = null)
+ {
+ parent::init($definition, $import_csv); // TODO: Change the autogenerated stub
- $this->definition = $_definition;
+ $this->lookups['account_status'] = array('A' => lang('Active'), '' => lang('Disabled'),
+ 'D' => lang('Disabled'));
+ }
- // user, is admin ?
- $this->is_admin = isset( $GLOBALS['egw_info']['user']['apps']['admin'] ) && $GLOBALS['egw_info']['user']['apps']['admin'];
- $this->user = $GLOBALS['egw_info']['user']['account_id'];
-
- // dry run?
- $this->dry_run = isset( $_definition->plugin_options['dry_run'] ) ? $_definition->plugin_options['dry_run'] : false;
-
- // set FieldMapping.
- $import_csv->mapping = $_definition->plugin_options['field_mapping'];
-
- // set FieldConversion
- $import_csv->conversion = $_definition->plugin_options['field_conversion'];
-
- //check if file has a header lines
- if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) {
- $import_csv->skip_records($_definition->plugin_options['num_header_lines']);
- } elseif(isset($_definition->plugin_options['has_header_line']) && $_definition->plugin_options['has_header_line']) {
- // First method is preferred
- $import_csv->skip_records(1);
+ protected function import_record(importexport_iface_egw_record &$record, &$import_csv)
+ {
+ $success = false;
+ // don't import empty records
+ if(count(array_unique($record)) < 2)
+ {
+ return $success;
}
- $admin_cmd = $_definition->plugin_options['admin_cmd'];
- // Start counting successes
- $count = 0;
- $this->results = array();
+ if(strtolower($record['account_expires']) == 'never')
+ {
+ $record['account_expires'] = -1;
+ }
- // Failures
- $this->errors = array();
-
- $lookups = array(
- 'account_status' => array('A' => lang('Active'), '' => lang('Disabled'), 'D' => lang('Disabled')),
- );
-
- while ( $record = $import_csv->get_record() ) {
- $success = false;
- // don't import empty records
- if( count( array_unique( $record ) ) < 2 ) continue;
-
- if(strtolower($record['account_expires']) == 'never') $record['account_expires'] = -1;
- importexport_import_csv::convert($record, admin_egw_user_record::$types, 'admin', $lookups);
-
- if ( $_definition->plugin_options['conditions'] ) {
- foreach ( $_definition->plugin_options['conditions'] as $condition ) {
- switch ( $condition['type'] ) {
- // exists
- case 'exists' :
- $accounts = array();
- // Skip the search if the field is empty
- if($record[$condition['string']] !== '')
+ if($this->definition->plugin_options['conditions'])
+ {
+ foreach($this->definition->plugin_options['conditions'] as $condition)
+ {
+ switch($condition['type'])
+ {
+ // exists
+ case 'exists' :
+ $accounts = array();
+ // Skip the search if the field is empty
+ if($record[$condition['string']] !== '')
+ {
+ $accounts = $GLOBALS['egw']->accounts->search(array(
+ 'type' => 'accounts',
+ 'query' => $record[$condition['string']],
+ 'query_type' => $condition['string']
+ ));
+ }
+ // Search looks in the given field, but doesn't do an exact match
+ foreach((array)$accounts as $key => $account)
+ {
+ if($account[$condition['string']] != $record[$condition['string']])
{
- $accounts = $GLOBALS['egw']->accounts->search(array(
- 'type' => 'accounts',
- 'query' => $record[$condition['string']],
- 'query_type' => $condition['string']
- ));
+ unset($accounts[$key]);
}
- // Search looks in the given field, but doesn't do an exact match
- foreach ( (array)$accounts as $key => $account )
+ }
+ if(is_array($accounts) && count($accounts) >= 1)
+ {
+ // apply action to all contacts matching this exists condition
+ $action = $condition['true'];
+ foreach((array)$accounts as $account)
{
- if($account[$condition['string']] != $record[$condition['string']]) unset($accounts[$key]);
+ $record['account_id'] = $account['account_id'];
+ $success = $this->admin_action($action['action'], $record, $import_csv->get_current_position(), $admin_cmd);
}
- if ( is_array( $accounts ) && count( $accounts ) >= 1 ) {
- // apply action to all contacts matching this exists condition
- $action = $condition['true'];
- foreach ( (array)$accounts as $account ) {
- $record['account_id'] = $account['account_id'];
- $success = $this->action( $action['action'], $record, $import_csv->get_current_position(), $admin_cmd );
- }
- } else {
- $action = $condition['false'];
- $success = ($this->action( $action['action'], $record, $import_csv->get_current_position(), $admin_cmd ));
- }
- break;
+ }
+ else
+ {
+ $action = $condition['false'];
+ $success = ($this->admin_action($action['action'], $record, $import_csv->get_current_position(), $admin_cmd));
+ }
+ break;
- // not supported action
- default :
- die('condition / action not supported!!!');
- }
- if ($action['last']) break;
+ // not supported action
+ default :
+ die('condition / action not supported!!!');
+ }
+ if($action['last'])
+ {
+ break;
}
- } else {
- // unconditional insert
- $success = $this->action( 'create', $record, $import_csv->get_current_position(), $admin_cmd );
}
- if($success) $count++;
}
- return $count;
+ else
+ {
+ // unconditional insert
+ $success = $this->admin_action('create', $record, $import_csv->get_current_position(), $admin_cmd);
+ }
+
+ return $success;
+ }
+
+ protected function action($_action, importexport_iface_egw_record &$record, $record_num = 0)
+ {
+ // Not used, see admin_action()
}
/**
@@ -194,7 +131,8 @@ class admin_import_users_csv implements importexport_iface_import_plugin {
* @param array $_data contact data for the action
* @return bool success or not
*/
- private function action ( $_action, $_data, $record_num = 0, $admin_cmd ) {
+ private function admin_action($_action, $_data, $record_num = 0, $admin_cmd)
+ {
switch ($_action) {
case 'none' :
return true;
diff --git a/calendar/inc/class.calendar_import_ical.inc.php b/calendar/inc/class.calendar_import_ical.inc.php
index 6aca01a610..65723eb582 100644
--- a/calendar/inc/class.calendar_import_ical.inc.php
+++ b/calendar/inc/class.calendar_import_ical.inc.php
@@ -99,6 +99,8 @@ class calendar_import_ical implements importexport_iface_import_plugin {
*/
protected $results = array();
+ protected $record_count = 0;
+
/**
* imports entries according to given definition object.
* @param resource $_stream
@@ -132,6 +134,15 @@ class calendar_import_ical implements importexport_iface_import_plugin {
echo lang("No preview for iCal");
return;
}
+ else
+ {
+ // Estimate event count
+ while(($line = fgets($_stream)) !== false)
+ {
+ $this->record_count += preg_match_all("/^BEGIN:VEVENT/i", $line, $matches);
+ }
+ rewind($_stream);
+ }
// switch off notifications by default
$plugin_options = $_definition->plugin_options;
if(!array_key_exists('no_notification', $_definition->plugin_options))
@@ -180,6 +191,8 @@ class calendar_import_ical implements importexport_iface_import_plugin {
$this->results['imported'] += $calendar_ical->events_imported;
}
+ importexport_import_ui::sendUpdate(100, $this->results['imported'], print_r($this->results, true));
+
return $calendar_ical->events_imported;
}
@@ -188,11 +201,16 @@ class calendar_import_ical implements importexport_iface_import_plugin {
*/
public function event_callback(&$event)
{
+ static $event_count = 0;
+
// Check & apply value overrides
foreach((array)$this->definition->plugin_options['override_values'] as $field => $settings)
{
$event[$field] = $settings['value'];
}
+ // Update UI with progress
+ $progress = $this->record_count ? (int)(100 * (++$event_count / $this->record_count)) : false;
+ importexport_import_ui::sendUpdate($progress, $this->bo->link_title($event), $this->bo->link_title($event));
return true;
}
diff --git a/importexport/inc/class.importexport_basic_import_csv.inc.php b/importexport/inc/class.importexport_basic_import_csv.inc.php
index 37d15fd83e..d92fb04e7d 100644
--- a/importexport/inc/class.importexport_basic_import_csv.inc.php
+++ b/importexport/inc/class.importexport_basic_import_csv.inc.php
@@ -148,6 +148,12 @@ abstract class importexport_basic_import_csv implements importexport_iface_impor
// set FieldConversion
$import_csv->conversion = $_definition->plugin_options['field_conversion'];
+ if(!$this->dry_run)
+ {
+ // This needs to scan the whole file, so it can take a while
+ $record_count = $import_csv->get_num_of_records();
+ }
+
//check if file has a header lines
if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) {
$import_csv->skip_records($_definition->plugin_options['num_header_lines']);
@@ -190,7 +196,19 @@ abstract class importexport_basic_import_csv implements importexport_iface_impor
{
$this->set_overrides($_definition, $egw_record);
}
- $success = $this->import_record($egw_record, $import_csv);
+ try
+ {
+ $success = $this->import_record($egw_record, $import_csv);
+ }
+ catch (Exception $e)
+ {
+ $this->errors[] = $e->getMessage();
+ $success = false;
+ if(!$this->dry_run)
+ {
+ importexport_import_ui::sendUpdate("", get_class($e), $e->getMessage());
+ }
+ }
if($success)
{
@@ -204,6 +222,13 @@ abstract class importexport_basic_import_csv implements importexport_iface_impor
set_time_limit(10);
}
+ // Send an update to client
+ if(!$this->dry_run)
+ {
+ $complete = $record_count ? (int)(100 * ($import_csv->get_current_position() / $record_count)) : false;
+ $this->sendUpdate($complete, $egw_record);
+ }
+
// Keep a few records for preview, but process the whole file
if($this->dry_run && $import_csv->get_current_position() < $GLOBALS['egw_info']['user']['preferences']['common']['maxmatchs'])
{
@@ -734,5 +759,26 @@ error_log("Searching for $custom_field = $value");
public function get_results() {
return $this->results;
}
+
+ /**
+ * Send some progress so the UI doesn't look frozen
+ *
+ * @param integer $complete 0-100 or false for indeterminate
+ * @param importexport_iface_egw_record $record
+ * @return void
+ * @throws Api\Json\Exception
+ */
+ protected function sendUpdate($complete, $record)
+ {
+ $label = "";
+ try
+ {
+ $label = $record->get_title() ?: "";
+ }
+ catch (Exception $e)
+ {
+ }
+ importexport_import_ui::sendUpdate($complete, $label, substr(array2string($record->get_record_array()), 0, 120) . '...');
+ }
} // end of iface_export_plugin
?>
diff --git a/importexport/inc/class.importexport_import_csv.inc.php b/importexport/inc/class.importexport_import_csv.inc.php
index 8c4ec19f91..8452d55743 100755
--- a/importexport/inc/class.importexport_import_csv.inc.php
+++ b/importexport/inc/class.importexport_import_csv.inc.php
@@ -175,7 +175,9 @@ class importexport_import_csv implements importexport_iface_import_record { //,
break;
case 'last' :
- while ($this->get_raw_record()) {}
+ while($this->get_raw_record() !== false)
+ {
+ }
break;
default: //somenumber
@@ -207,7 +209,7 @@ class importexport_import_csv implements importexport_iface_import_record { //,
return $this->num_of_records;
}
$current_position = $this->current_position;
- while ($this->get_raw_record()) {}
+ $this->get_raw_record('last');
$this->num_of_records = $this->current_position;
$this->get_record($current_position);
return $this->num_of_records;
diff --git a/importexport/inc/class.importexport_import_ui.inc.php b/importexport/inc/class.importexport_import_ui.inc.php
index 0a687499c8..77c2a713f7 100644
--- a/importexport/inc/class.importexport_import_ui.inc.php
+++ b/importexport/inc/class.importexport_import_ui.inc.php
@@ -137,19 +137,21 @@ use EGroupware\Api\Etemplate;
{
$this->message .= implode("
\n", $check_message) . "
\n";
}
+ // Clear first, to prevent request from being collected if the result is the same
+ $template->setElementAttribute('preview', 'value', '');
if($content['dry-run'])
{
$preview = $this->preview($plugin, $file, $definition_obj);
$template->setElementAttribute('message', 'value', $this->message);
-
- // Clear first, to prevent request from being collected if the result is the same
- $template->setElementAttribute('preview', 'value', '');
$template->setElementAttribute('preview', 'value', $preview);
return;
}
else
{
+ // Set up feedback area
+ $this->feedback($template, $content['definition'] . ': ' . $content['file']['name']);
+
// Disable push so we don't overload or spend time notifying
EGroupware\Swoolepush\Hooks::pushDisabled(true);
@@ -157,9 +159,9 @@ use EGroupware\Api\Etemplate;
$count = $plugin->import($file, $definition_obj);
EGroupware\Swoolepush\Hooks::pushDisabled(false);
-
- // Close preview
- EGroupware\Api\Json\Response::get()->call('app.importexport.closePreview');
+
+ // Don't close progress, leave it open so they can see
+ //static::sendUpdate(null);
}
}
else
@@ -180,21 +182,24 @@ use EGroupware\Api\Etemplate;
}
$total_processed = 0;
foreach($plugin->get_results() as $action => $a_count) {
- $this->message .= "
\n" . lang($action) . ": $a_count";
+ $this->message .= "\n" . lang($action) . ": $a_count";
$total_processed += $a_count;
}
if(count($plugin->get_warnings())) {
- $this->message .= "
\n".lang('Warnings').':';
+ $this->message .= "\n" . lang('Warnings') . ':';
foreach($plugin->get_warnings() as $record => $message) {
- $this->message .= "
\n$record: $message";
+ $this->message .= "\n$record: $message";
}
}
if(count($plugin->get_errors())) {
- $this->message .= "
\n".lang('Problems during import:');
+ $this->message .= "\n" . lang('Problems during import:');
foreach($plugin->get_errors() as $record => $message) {
- $this->message .= "
\n$record: $message";
+ $this->message .= "\n$record: $message";
+ }
+ if($count != $total_processed)
+ {
+ $this->message .= "\n" . lang('Some records may not have been imported');
}
- if($count != $total_processed) $this->message .= "
\n".lang('Some records may not have been imported');
}
if ($dst_file && $content['file']['tmp_name'] == $dst_file) {
// Remove file
@@ -207,6 +212,11 @@ use EGroupware\Api\Etemplate;
$this->message .= lang('Database error');
} catch (Exception $e) {
$this->message .= $e->getMessage();
+ $this->sendUpdate(false, get_class($e), $e->getMessage());
+ }
+ if($file && !$content['dry-run'] && $count)
+ {
+ static::sendUpdate(100, lang('%1 records processed', $count), $this->message);
}
}
elseif($content['cancel'])
@@ -379,6 +389,52 @@ use EGroupware\Api\Etemplate;
return '