* Improvements to import - file checking, more warnings, destination addressbook checking

This commit is contained in:
Nathan Gray 2012-09-25 14:49:27 +00:00
parent 41470de3b4
commit 3386edced3
10 changed files with 287 additions and 61 deletions

View File

@ -166,7 +166,9 @@ class addressbook_import_contacts_csv implements importexport_iface_import_plugi
// don't import empty contacts
if( count( array_unique( $record ) ) < 2 ) continue;
importexport_import_csv::convert($record, addressbook_egw_record::$types, 'addressbook', $_lookups, $_definition->plugin_options['convert']);
$warning = importexport_import_csv::convert($record, addressbook_egw_record::$types, 'addressbook', $_lookups, $_definition->plugin_options['convert']);
if($warning) $this->warnings[$import_csv->get_current_position()] = $warning;
// Set owner, unless it's supposed to come from CSV file
if($_definition->plugin_options['owner_from_csv']) {
if($record['owner'] && !is_numeric($record['owner'])) {
@ -187,6 +189,23 @@ class addressbook_import_contacts_csv implements importexport_iface_import_plugi
$record['owner'] = $contact_owner;
}
// Check that owner (addressbook) is allowed
if(!in_array($record['owner'], $this->bocontacts->get_addressbooks()))
{
$this->errors[$import_csv->get_current_position()] = lang("Unable to import into %1, using %2",
common::grab_owner_name($record['owner']),
common::grab_owner_name($this->user)
);
$record['owner'] = $this->user;
}
// Do not allow owner == 0 (accounts) without an account_id
// It causes the contact to be filed as an account, and can't delete
if(!$record['owner'] && !$record['account_id'])
{
$record['owner'] = $this->user;
}
// Also handle categories in their own field
$more_categories = array();
foreach($_definition->plugin_options['field_mapping'] as $number => $field_name) {
@ -318,6 +337,7 @@ class addressbook_import_contacts_csv implements importexport_iface_import_plugi
// org_name is a trigger to update n_fileas
$_data['org_name'] = '';
}
if ( $this->dry_run ) {
//print_r($_data);
$this->results[$_action]++;
@ -332,7 +352,7 @@ class addressbook_import_contacts_csv implements importexport_iface_import_plugi
return $result;
}
default:
throw new egw_exception('Unsupported action');
throw new egw_exception('Unsupported action: '. $_action);
}
}

View File

@ -69,14 +69,14 @@ class importexport_admin_prefs_sidebox_hooks
if ($GLOBALS['egw_info']['user']['apps']['admin'] && $location != 'preferences')
{
$file = Array(
'Site Configuration' => egw::link('/index.php','menuaction=importexport.importexport_definitions_ui.site_config'),
'Import definitions' => egw::link('/index.php','menuaction=importexport.importexport_definitions_ui.import_definition'),
'Site Configuration' => egw::link('/index.php','menuaction=importexport.importexport_definitions_ui.site_config','admin'),
'Import definitions' => egw::link('/index.php','menuaction=importexport.importexport_definitions_ui.import_definition','admin'),
'Define imports|exports' => egw::link('/index.php',array(
'menuaction' => 'importexport.importexport_definitions_ui.index',
),$location),
),'admin'),
'Schedule' => egw::link('/index.php', array(
'menuaction' => 'importexport.importexport_schedule_ui.index'
)),
),'admin'),
);
if ($location == 'admin')
{

View File

@ -47,7 +47,7 @@ class importexport_definitions_bo {
$this_membership = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'], true);
$this_membership[] = $GLOBALS['egw_info']['user']['account_id'];
$sql .= ' (';
$read = array('all');
$read = array();
foreach($this_membership as $id)
{
$read[] = 'allowed_users '.

View File

@ -425,11 +425,37 @@ class importexport_definitions_ui
return $bodefinitions->get_rows($query, $rows, $readonlys);
}
/**
* Edit a definition
*
* To jump to a certain step, pass the previous step in the URL step=wizard_stepXX
* The wizard will validate that step, then display the _next_ step..
*/
function edit()
{
if(!$_definition = $_GET['definition'])
{
//close window
$content = array(
'edit' => true,
'application' => $_GET['application'],
'plugin' => $_GET['plugin']
);
// Jump to a step
if($_GET['step'])
{
$content['edit'] = false;
// Wizard will process previous step, then advance
$content['step'] = $this->get_step($_GET['step'],-1);
$content['button']['next'] = 'pressed';
$this->wizard($content);
}
else
{
// Initial form
$this->wizard($content);
}
return;
}
if(is_numeric($_GET['definition']))
{
@ -442,6 +468,14 @@ class importexport_definitions_ui
$bodefinitions = new importexport_definitions_bo();
$definition = $bodefinitions->read($definition);
$definition['edit'] = true;
// Jump to a step
if($_GET['step'])
{
$definition['edit'] = false;
// Wizard will process previous step, then advance
$definition['step'] = $_GET['step'];;
$definition['button'] = array('next' => 'pressed');
}
$this->wizard($definition);
}
@ -495,10 +529,6 @@ class importexport_definitions_ui
$button = array_keys($content['button']);
$content['button'] = array($button[0] => 'pressed');
}
// Override next button on step 21, to do a regular submit for the file upload
if($content['step'] == 'wizard_step21') {
$this->etpl->set_cell_attribute('button[next]', 'onclick', '');
}
// post process submitted step
if($content['step']) {
@ -520,6 +550,12 @@ class importexport_definitions_ui
// pre precess next step
$sel_options = $readonlys = $preserv = array();
// Override next button on step 30, to do a regular submit for the file upload
if($next_step == 'wizard_step30')
{
$this->etpl->set_cell_attribute('button[next]', 'onclick', '');
}
// Disable finish button if required fields are missing
if(!$content['name'] || !$content['type'] || !$content['plugin']) {
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][finish]');");
@ -569,8 +605,8 @@ class importexport_definitions_ui
if ($content['closewindow'])
{
$this->response->addScript("opener.location.reload();");
$this->response->addScript("window.close();");
$this->response->addScript("opener.location = '" . egw::link('/index.php', array('menuaction' => 'importexport.importexport_definitions_ui.index')) . "';");
// If Browser can't close window we display a "close" buuton and
// need to disable normal buttons
$this->response->addAssign('exec[button][previous]','style.display', 'none');

View File

@ -230,7 +230,8 @@ class importexport_import_csv implements importexport_iface_import_record { //,
protected function do_fieldmapping( ) {
$record = $this->record;
$this->record = array();
foreach ($this->mapping as $cvs_idx => $new_idx) {
foreach ($this->mapping as $cvs_idx => $new_idx)
{
if( $new_idx == '' ) continue;
$this->record[$new_idx] = $record[$cvs_idx];
}

View File

@ -50,69 +50,122 @@
// Set this so plugin doesn't do any data changes
$definition_obj->plugin_options = (array)$definition_obj->plugin_options + array('dry_run' => true);
}
$options =& $definition_obj->plugin_options;
if($content['delimiter']) {
$options =& $definition_obj->plugin_options;
$options['fieldsep'] =
$content['delimiter'] == 'other' ? $content['other_delimiter'] : $content['delimiter'];
$definition_obj->plugin_options = $options;
}
$plugin = new $definition_obj->plugin;
// Check file encoding matches import
$sample = file_get_contents($content['file']['tmp_name'],false, null, 0, 1024);
$required = $options['charset'] == 'user' || !$options['charset'] ? $GLOBALS['egw_info']['user']['preferences']['common']['csv_charset'] : $options['charset'];
$encoding = mb_detect_encoding($sample,$required,true);
if($encoding && strtoupper($required) != strtoupper($encoding))
{
$this->message = lang("Encoding mismatch. Expected %1 file, you uploaded %2.<br />\n",
$required,
$encoding
);
}
$file = fopen($content['file']['tmp_name'], 'r');
$count = 0;
// Some of the translation, conversion, etc look here
$GLOBALS['egw_info']['flags']['currentapp'] = $appname;
// Destination if we need to hold the file
$cachefile = new egw_cache_files(array());
$dst_file = $cachefile->filename(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id']), true),true);
if($content['dry-run'])
if($file)
{
echo $this->preview($file, $definition_obj);
$cachefile = new egw_cache_files(array());
$dst_file = $cachefile->filename(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id']), true),true);
// Keep file
if($dst_file)
{
if(copy($content['file']['tmp_name'],$dst_file)) {
if($content['file']['name'] && copy($content['file']['tmp_name'],$dst_file)) {
$preserve['file']['tmp_name'] = $dst_file;
}
}
} elseif ($dst_file && $content['file']['tmp_name'] == $dst_file) {
// Remove file
$cachefile->delete(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id'])));
}
$count = $plugin->import($file, $definition_obj);
$this->message = lang('%1 records processed', $count);
// Check on matching columns
$check_message = array();
if(!self::check_file($file, $definition_obj, $check_message, $dst_file))
{
// Set this so plugin doesn't do any data changes
$content['dry-run'] = true;
$this->message .= '<b>' . lang('Import aborted').":</b><br />\n";
$definition_obj->plugin_options = (array)$definition_obj->plugin_options + array('dry_run' => true);
}
$this->message .= implode($check_message, "<br />\n") . "<br />\n";
if($content['dry-run'])
{
echo $this->preview($file, $definition_obj);
}
$count = $plugin->import($file, $definition_obj);
}
else
{
$this->message .= lang('please select file to import'."<br />\n");
}
if($content['dry-run'])
{
$this->message .= '<b>' . lang('test only').":</b><br />\n";
}
$this->message .= lang('%1 records processed', $count);
// Refresh opening window
if(!$content['dry-run']) $GLOBALS['egw']->js->set_onload("window.opener.egw_refresh('{$this->message}','$appname');");
$total_processed = 0;
foreach($plugin->get_results() as $action => $a_count) {
$this->message .= "\n" . lang($action) . ": $a_count";
$this->message .= "<br />\n" . lang($action) . ": $a_count";
$total_processed += $a_count;
}
if(count($plugin->get_warnings())) {
$this->message .= "\n".lang('Warnings').':';
$this->message .= "<br />\n".lang('Warnings').':';
foreach($plugin->get_warnings() as $record => $message) {
$this->message .= "\n$record: $message";
}
}
if(count($plugin->get_errors())) {
$this->message .= "\n".lang('Problems during import:');
$this->message .= "<br />\n".lang('Problems during import:');
foreach($plugin->get_errors() as $record => $message) {
$this->message .= "\n$record: $message";
$this->message .= "<br />\n$record: $message";
}
if($count != $total_processed) $this->message .= "\n".lang('Some records may not have been imported');
if($count != $total_processed) $this->message .= "<br />\n".lang('Some records may not have been imported');
}
if ($dst_file && $content['file']['tmp_name'] == $dst_file) {
// Remove file
$cachefile->delete(egw_cache::keys(egw_cache::INSTANCE, 'importexport',
'import_'.md5($content['file']['name'].$GLOBALS['egw_info']['user']['account_id'])));
unset($dst_file);
}
} catch (Exception $e) {
$this->message = $e->getMessage();
$this->message .= $e->getMessage();
}
} elseif($content['cancel']) {
}
elseif($content['cancel'])
{
$GLOBALS['egw']->js->set_onload('window.close();');
}
elseif ($GLOBALS['egw_info']['user']['apps']['admin'])
{
$this->message .= lang('You may want to <a href="%1" target="_new">backup</a> first.',
egw::link('/index.php',
array('menuaction' => 'admin.admin_db_backup.index')
)
);
}
if(!array_key_exists('dry-run',$content))
{
$data['dry-run'] = true;
}
$data['appname'] = $preserve['appname'] = $appname ? $appname : ($definition_obj ? $definition_obj->application : '');
$data['definition'] = $definition;
@ -217,7 +270,98 @@
// Rewind
rewind($_stream);
return html::table($rows);
return '<h2>' . lang('Preview') . '</h2>' . html::table($rows);
}
/**
* Simple check to see if the file at least matches the definition
*
* Checks that column headers match
*/
public static function check_file(&$file, &$definition, &$message = array(), $dst_file = false)
{
$options =& $definition->plugin_options;
$data = fgetcsv($file, 8000, $options['fieldsep']);
rewind($file);
$data = translation::convert($data,$options['charset']);
$ok = true;
if(max(array_keys($data)) != max(array_keys($options['csv_fields'])))
{
$message[] = lang("Column mismatch. Expected %1 columns, your file has %2.",
max(array_keys($options['csv_fields'])),
max(array_keys($data))
);
$ok = false;
}
foreach($data as $index => $header)
{
if($index < count($options['csv_fields']) && !$options['field_mapping'][$index])
{
// Skipped column in definition
continue;
}
elseif($index < count($options['csv_fields']) && $options['csv_fields'][$index] != $header)
{
// Problem
$message[] = lang("Column mismatch: %1 should be %2, not %3",
$index,$options['csv_fields'][$index], $header);
// But can still continue
// $ok = false;
}
}
if(!$ok)
{
// Add links for new / edit definition
$config = config::read('importexport');
if($GLOBALS['egw_info']['user']['apps']['admin'] || $config['users_create_definitions'])
{
$actions = '';
// New definition
$add_link = egw::link('/index.php',array(
'menuaction' => 'importexport.importexport_definitions_ui.edit',
'application' => $definition->application,
'plugin' => $definition->plugin,
// Jump to name step
'step' => 'wizard_step21'
));
$add_link = "
javascript:this.window.location = '" . egw::link('/index.php', array(
'menuaction' => 'importexport.importexport_import_ui.import_dialog',
// Don't set appname, or user won't be able to select & see their new definition
//'appname' => $definition->application,
)) . "';
egw_openWindowCentered2('$add_link','_blank',500,500,'yes');
";
$actions[] = lang('Create a <a href="%1">new definition</a> for this file', $add_link);
// Edit selected definition, if allowed
if($definition->owner == $GLOBALS['egw_info']['user']['account_id'] ||
!$definition->owner && $GLOBALS['egw_info']['user']['apps']['admin'])
{
$edit_link = array(
'menuaction' => 'importexport.importexport_definitions_ui.edit',
'definition' => $definition->name,
// Jump to file step
'step' => 'wizard_step21'
);
if($dst_file)
{
// Still have uploaded file, jump there
$GLOBALS['egw']->session->appsession('csvfile','',$dst_file);
$edit_link['step'] = 'wizard_step30';
}
$edit_link = egw::link('/index.php',$edit_link);
$edit_link = "javascript:egw_openWindowCentered2('$edit_link','_blank',500,500,'yes')";
$actions[] = lang('Edit definition <a href="%1">%2</a> to match your file',
$edit_link, $definition->name );
}
$actions[] = lang('Edit your file to match the definition: ')
. implode(array_intersect_key($options['csv_fields'],$options['field_mapping']),', ');
$message[] = "\n<li>".implode($actions,"\n<li>");
}
}
return $ok;
}
}
?>

View File

@ -1,12 +1,12 @@
<?php
/**
* eGroupWare - A basic implementation of a wizard to go with the basic CSV plugin.
*
*
* To add or remove steps, change $this->steps appropriately. The key is the function, the value is the title.
* Don't go past 80, as that's where the wizard picks it back up again to finish it off.
*
*
* For the mapping to work properly, you will have to fill $mapping_fields with the target fields for your application.
*
*
* NB: Your wizard class must be in <appname>/inc/class.appname_wizard_<plugin_name>.inc.php
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -15,7 +15,7 @@
* @author Nathan Gray
*/
class importexport_wizard_basic_import_csv
class importexport_wizard_basic_import_csv
{
const TEMPLATE_MARKER = '-eTemplate-';
@ -81,7 +81,7 @@ class importexport_wizard_basic_import_csv
if($content['file']['tmp_name']) {
$csvfile = tempnam($GLOBALS['egw_info']['server']['temp_dir'],$content['plugin']."_");
move_uploaded_file($content['file']['tmp_name'], $csvfile);
$GLOBALS['egw']->session->appsession('csvfile','',$csvfile);
$GLOBALS['egw']->session->appsession('csvfile',$content['application'],$csvfile);
}
unset($content['file']);
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
@ -124,20 +124,22 @@ class importexport_wizard_basic_import_csv
{
case 'next':
// Process sample file for fields
if (($handle = fopen($GLOBALS['egw']->session->appsession('csvfile'), "rb")) !== FALSE) {
if (($handle = fopen($GLOBALS['egw']->session->appsession('csvfile',$content['application']), "rb")) !== FALSE) {
$data = fgetcsv($handle, 8000, $content['fieldsep']);
fclose($handle);
unlink($GLOBALS['egw']->session->appsession('csvfile'));
// Remove & forget file
unlink($GLOBALS['egw']->session->appsession('csvfile',$content['application']));
egw_cache::setSession($content['application'], 'csvfile', '');
$content['csv_fields'] = translation::convert($data,$content['charset']);
// Reset field mapping for new file
$content['field_mapping'] = array();
// Try to match automatically
$english = array();
foreach($content['csv_fields'] as $index => $field) {
if($content['field_mapping'][$index]) continue;
if(is_array($content['plugin_options']['field_mapping']) && $content['plugin_options']['field_mapping'][$index]) {
# Copy already set, but allow new file to update
$content['field_mapping'][$index] = $content['plugin_options']['field_mapping'][$index];
}
$best_match = '';
$best_match_value = 0;
foreach($this->mapping_fields as $key => $field_name) {
@ -162,7 +164,7 @@ class importexport_wizard_basic_import_csv
// Check for similar but slightly different
$match = 0;
if(similar_text(strtolower($field), strtolower($field_name), $match) &&
if(similar_text(strtolower($field), strtolower($field_name), $match) &&
$match > 85 &&
$match > $best_match_value
) {
@ -208,12 +210,22 @@ class importexport_wizard_basic_import_csv
if(!$content['num_header_lines'] && $content['plugin_options']['num_header_lines']) {
$content['num_header_lines'] = $content['plugin_options']['num_header_lines'];
}
else
{
// Default to 1 line
$content['num_header_lines'] = 1;
}
if(!$content['update_cats'] && $content['plugin_options']['update_cats']) {
$content['update_cats'] = $content['plugin_options']['update_cats'];
}
if(!array_key_exists('convert', $content) && array_key_exists('convert', $content['plugin_options'])) {
$content['convert'] = $content['plugin_options']['convert'];
}
else
{
// Default to human
$content['convert'] = 1;
}
$sel_options['charset'] = $GLOBALS['egw']->translation->get_installed_charsets()+
array(
@ -249,10 +261,10 @@ class importexport_wizard_basic_import_csv
}
/**
* Process the sample file, get the fields out of it, then allow them to be mapped onto
* Process the sample file, get the fields out of it, then allow them to be mapped onto
* the fields the destination understands. Also, set any translations to be done to the field.
*
* You can use the eTemplate
*
* You can use the eTemplate
*/
function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
{
@ -330,13 +342,14 @@ class importexport_wizard_basic_import_csv
$content[++$i]['index'] = $i - 1;
if(strstr($field,'no_csv_')) $j++;
}
while ($j <= 3)
while ($j <= 3)
{
$content['csv_fields'][] = 'no_csv_'.$j;
$content['field_mapping'][] = $content['field_conversion'][] = '';
$j++;
}
$sel_options['field_mapping'] = array('--NONE--' => lang('none')) + $this->mapping_fields;
$GLOBALS['egw']->js->set_onload('$j("option[value=\'--NONE--\']:selected").closest("tr").animate({backgroundColor: "#ffff99"}, 1000);');
unset ($preserv['button']);
return $this->step_templates[$content['step']];
}
@ -354,10 +367,20 @@ class importexport_wizard_basic_import_csv
{
// Clear conditions that don't do anything
foreach($content['conditions'] as $key => $condition) {
foreach($content['conditions'] as $key => &$condition) {
if(($condition['true']['action'] == 'none' || !$condition['true']['action']) && !$condition['true']['stop']
&& ($condition['false']['action'] == 'none' || !$condition['false']['action']) && !$condition['false']['stop']) {
unset($content['conditions'][$key]);
continue;
}
// Check for true without false, or false without true - set to 'none'
elseif($condition['true']['action'] == '' && $condition['false']['action'] != '' ||
$condition['true']['action'] != '' && $condition['false']['action'] == '' ||
!$condition['true'] || !$condition['false']
)
{
$condition[$condition['true']['action'] == '' ? 'true' : 'false']['action'] = "none";
}
}
@ -390,13 +413,13 @@ class importexport_wizard_basic_import_csv
$sel_options['type'] = $this->conditions;
$sel_options['action'] = $this->actions;
// Make 3 empty conditions
$j = 1;
foreach ($content['conditions'] as $condition)
// Make at least 1 (empty) conditions
$j = count($content['conditions']);
while ($j < 1)
{
if(!$condition['string']) $j++;
}
while ($j <= 3)
while ($j <= 3)
{
$content['conditions'][] = array('string' => '');
$j++;

View File

@ -24,6 +24,7 @@ choose a plugin importexport en Choose a plugin
choose an application importexport en Choose an application
choose fields to export importexport en Choose fields to export
choose seperator and charset importexport en Choose separator and charset
column mismatch. expected %1 columns, your file has %2. importexport en Column mismatch. Expected %1 columns, your file has %2.
condition importexport en Condition
copied importexport en Copied.
csv field importexport en CSV field

View File

@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application importexport
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2012-06-20 11:32
* generated by soetemplate::dump4setup() 2012-09-25 08:47
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package importexport
@ -93,7 +93,7 @@ $templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','temp
$templ_data[] = array('name' => 'importexport.import_definition','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:92:"Import definitions (Attension: Existing definitions with equal names will be overwritten!!!)";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:4:"file";s:4:"name";s:11:"import_file";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"update";s:5:"label";s:26:"Update default-definitions";}}}}s:4:"rows";i:3;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1306253183',);
$templ_data[] = array('name' => 'importexport.import_dialog','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:8:{i:0;a:1:{s:2:"h1";s:10:",!@message";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:11:"all,message";s:4:"name";s:7:"message";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:11:"Application";}s:1:"B";a:3:{s:4:"type";s:6:"select";s:4:"name";s:7:"appname";s:8:"onchange";s:87:"xajax_doXMLHTTP(\'importexport.importexport_import_ui.ajax_get_definitions\',this.value);";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Import definition";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:10:"definition";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:9:"Delimiter";}s:1:"B";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";s:7:"no_lang";s:1:"1";i:1;a:4:{s:4:"type";s:6:"select";s:7:"no_lang";s:1:"1";s:4:"name";s:9:"delimiter";s:8:"onchange";s:163:"var _this = jQuery(this); var text = _this.parent().parent().find(\'input\'); if(_this.val() ==\'other\') {text.val(\'\');text.show(); text.focus();} else {text.hide();}";}i:2;a:4:{s:4:"type";s:4:"text";s:4:"name";s:15:"other_delimiter";s:4:"size";s:3:"2,1";s:4:"span";s:5:",hide";}}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:28:"Please select file to import";}s:1:"B";a:2:{s:4:"type";s:4:"file";s:4:"name";s:4:"file";}}i:6;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:7;a:2:{s:1:"A";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";s:4:"span";s:3:"all";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"cancel";s:5:"label";s:6:"Cancel";}i:3;a:4:{s:4:"type";s:8:"checkbox";s:4:"name";s:7:"dry-run";s:5:"label";s:9:"Test only";s:5:"align";s:5:"right";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:7;s:4:"cols";i:2;}}','size' => '','style' => '.hide input {
$templ_data[] = array('name' => 'importexport.import_dialog','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:8:{i:0;a:1:{s:2:"h1";s:10:",!@message";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"span";s:11:"all,message";s:4:"name";s:7:"message";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:11:"Application";}s:1:"B";a:3:{s:4:"type";s:6:"select";s:4:"name";s:7:"appname";s:8:"onchange";s:87:"xajax_doXMLHTTP(\'importexport.importexport_import_ui.ajax_get_definitions\',this.value);";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Import definition";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:10:"definition";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:9:"Delimiter";}s:1:"B";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";s:7:"no_lang";s:1:"1";i:1;a:4:{s:4:"type";s:6:"select";s:7:"no_lang";s:1:"1";s:4:"name";s:9:"delimiter";s:8:"onchange";s:163:"var _this = jQuery(this); var text = _this.parent().parent().find(\'input\'); if(_this.val() ==\'other\') {text.val(\'\');text.show(); text.focus();} else {text.hide();}";}i:2;a:4:{s:4:"type";s:4:"text";s:4:"name";s:15:"other_delimiter";s:4:"size";s:3:"2,1";s:4:"span";s:5:",hide";}}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:28:"Please select file to import";}s:1:"B";a:2:{s:4:"type";s:4:"file";s:4:"name";s:4:"file";}}i:6;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:7;a:2:{s:1:"A";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";s:4:"span";s:3:"all";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"cancel";s:5:"label";s:6:"Cancel";}i:3;a:4:{s:4:"type";s:8:"checkbox";s:4:"name";s:7:"dry-run";s:5:"label";s:9:"Test only";s:5:"align";s:5:"right";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:7;s:4:"cols";i:2;}}','size' => '','style' => '.hide input {
display: none;
}','modified' => '1320333891',);

View File

@ -174,7 +174,8 @@ class timesheet_import_csv implements importexport_iface_import_plugin {
// don't import empty records
if( count( array_unique( $record ) ) < 2 ) continue;
importexport_import_csv::convert($record, timesheet_egw_record::$types, 'timesheet', $lookups);
$result = importexport_import_csv::convert($record, timesheet_egw_record::$types, 'timesheet', $lookups);
if($result) $this->warnings[$import_csv->get_current_position()] = $result;
// Automatically handle text categories without explicit translation
foreach(array('ts_status','cat_id') as $field) {