Implemented configurable unique id's in addressbook cvs import:

- primary unique id: id (default), uid, or any custom field
- fallback: id, uid(default), two from n_family, org_name or n_given,
  or any custom field
- some bugfixes
This commit is contained in:
Ralf Becker 2009-07-09 12:27:42 +00:00
parent aa1d033532
commit dc813fd741
4 changed files with 113 additions and 37 deletions

View File

@ -42,7 +42,7 @@ if (isset($_POST['charset']))
$GLOBALS['egw_info']['flags']['app_header'] = lang('Import CSV-File into Addressbook');
$GLOBALS['egw']->common->egw_header();
$GLOBALS['egw']->contacts = new contacts();
$bocontacts = new addressbook_bo();
//$GLOBALS['egw']->template->set_unknowns('keep');
$GLOBALS['egw']->template->set_file(array('import' => 'csv_import.tpl'));
@ -64,24 +64,30 @@ $VPre = '|#'; // Value-Prefix, is expanded to \ for ereg_replace
$CPre = '|['; $CPreReg = '\|\['; // |{csv-fieldname} is expanded to the value of the csv-field
$CPos = ']'; $CPosReg = '\]'; // if used together with @ (replacement is eval-ed) value gets autom. quoted
// find in Addressbook, at least n_family AND (n_given OR org_name) have to match
/**
* Find contact with at least n_family AND (n_given OR org_name) have to match
*
* @param string $n_family
* @param string $n_given
* @param string $org_name
* @return int|boolean contact id or false if no match
*/
function addr_id($n_family,$n_given,$org_name)
{
$addrs = $GLOBALS['egw']->contacts->search(array('n_family'=>$n_family,'n_given'=>$n_given,'org_name'=>$org_name));
global $bocontacts;
$addrs = $bocontacts->search(array('n_family'=>$n_family,'n_given'=>$n_given,'org_name'=>$org_name));
if(!count($addrs))
{
$addrs = $GLOBALS['egw']->contacts->search(array('n_family'=>$n_family,'n_given'=>$n_given));
$addrs = $bocontacts->search(array('n_family'=>$n_family,'n_given'=>$n_given));
}
if(!count($addrs))
{
$addrs = $GLOBALS['egw']->contacts->search(array('n_family'=>$n_family,'org_name'=>$org_name));
$addrs = $bocontacts->search(array('n_family'=>$n_family,'org_name'=>$org_name));
}
if(count($addrs))
{
return $addrs[0]['id'];
}
return False;
}
@ -131,6 +137,8 @@ switch($_POST['action'])
case 'continue':
case 'download':
$defaults = $GLOBALS['egw_info']['user']['preferences']['addressbook']['cvs_import'];
if (!($unique_id = $GLOBALS['egw_info']['user']['preferences']['addressbook']['cvs_import_unique_id'])) $unique_id = 'id';
if (!($unique_id2 = $GLOBALS['egw_info']['user']['preferences']['addressbook']['cvs_import_unique_id2'])) $unique_id2 = 'uid';
if(!is_array($defaults))
{
$defaults = array();
@ -144,16 +152,17 @@ switch($_POST['action'])
$GLOBALS['egw']->template->set_var('lang_debug',lang('Test Import (show importable records <u>only</u> in browser)'));
$GLOBALS['egw']->template->parse('fheaderhandle','fheader');
$addr_names = $GLOBALS['egw']->contacts->contact_fields;
$addr_names = $bocontacts->contact_fields;
$addr_names['cat_id'] .= ': id or name, comma separated list';
$addr_names['private'] .= ': 0 = public, 1 = private';
$addr_names['owner'] .= ': id or account name of user or group, defaults to importing user';
$addr_names['bday'] .= ': YYYY-mm-dd';
$addr_names['uid'] = lang('Unique ID (UID)');
unset($addr_names['jpegphoto']); // cant cvs import that
foreach($GLOBALS['egw']->contacts->customfields as $name => $data)
foreach($bocontacts->customfields as $name => $data)
{
$addr_names['#'.$name] = $data['label'];
$cfs['#'.$name] = $addr_names['#'.$name] = $data['label'];
}
$addr_name_options = "<option value=\"\">none\n";
foreach($addr_names as $field => $name)
@ -182,6 +191,17 @@ switch($_POST['action'])
}
$GLOBALS['egw']->template->parse('fieldshandle','fields',True);
}
$GLOBALS['egw']->template->set_var('lang_unique_id',lang('Unique ID<br />(to update existing records)'));
$GLOBALS['egw']->template->set_var('unique_id',html::select('unique_id',$unique_id,array(
'id' => $addr_names['id'],
'uid' => $addr_names['uid'],
)+$cfs)."\n".html::select('unique_id2',$unique_id2,array(
'*none*' => lang('No fallback'),
'id' => $addr_names['id'],
'uid' => $addr_names['uid'],
'addr_id' => lang('two of: %1',$addr_names['org_name'].', '.$addr_names['n_family'].', '.$addr_names['n_given']),
)+$cfs));
$GLOBALS['egw']->template->set_var('lang_start',lang('Startrecord'));
$GLOBALS['egw']->template->set_var('start',get_var('start',array('POST'),1));
$msg = ($safe_mode = ini_get('safe_mode') == 'On') ? lang('to many might exceed your execution-time-limit'):
@ -205,7 +225,7 @@ switch($_POST['action'])
"usefull for the last pair, as they are worked from left to right.<p>".
"First example: <b>1${ASep}private${PSep}public</b><br>".
"This will translate a '1' in the CSV field to 'privat' and everything else to 'public'.<p>".
"Patterns as well as the replacement can be regular expressions (the replacement is done via ereg_replace). ".
"Patterns as well as the replacement can be regular expressions (the replacement is done via preg_replace). ".
"If, after all replacements, the value starts with an '@' the whole value is eval()'ed, so you ".
"may use all php, phpgw plus your own functions. This is quiet powerfull, but <u>circumvents all ACL</u>. ".
"Therefor this feature is only availible to Adminstrators.<p>".
@ -243,7 +263,9 @@ switch($_POST['action'])
'max' => $_POST['max'],
'debug' => $_POST['debug'],
'addr_fields' => $_POST['addr_fields'],
'trans' => $_POST['trans']
'trans' => $_POST['trans'],
'unique_id' => $_POST['unique_id'],
'unique_id2' => $_POST['unique_id2'],
));
@set_time_limit(0);
ini_set('auto_detect_line_endings',true); // to allow to import files created eg. on a mac
@ -267,10 +289,16 @@ switch($_POST['action'])
}
$GLOBALS['egw']->preferences->read_repository();
$GLOBALS['egw']->preferences->add('addressbook','cvs_import',$defaults);
$GLOBALS['egw']->preferences->add('addressbook','cvs_import_unique_id',$unique_id = $_POST['unique_id']);
$GLOBALS['egw']->preferences->add('addressbook','cvs_import_unique_id2',$unique_id2 = $_POST['unique_id2']);
$GLOBALS['egw']->preferences->save_repository(True);
$log = '<table border="1" style="border: 1px dotted black; border-collapse: collapse;">'."\n\t<tr><td>#</td>\n";
if (!in_array('id',$addr_fields)) // autocreate public access if not set by user
{
$log .= "\t\t<td><b>ID</b></td>\n";
}
if (!in_array('private',$addr_fields)) // autocreate public access if not set by user
{
$log .= "\t\t<td><b>private</b></td>\n";
@ -328,14 +356,14 @@ switch($_POST['action'])
$trans_csv = $_POST['trans'][$csv_idx];
while(list($pattern,$replace) = each($trans_csv))
{
if(ereg((string) $pattern,$val))
if(preg_match('/'.(string) $pattern.'/',$val))
{
// echo "<p>csv_idx='$csv_idx',info='$addr',trans_csv=".print_r($trans_csv).",preg_replace('/$pattern/','$replace','$val') = ";
$val = preg_replace('/'.(string) $pattern.'/',str_replace($VPre,'\\',$replace),(string) $val);
// echo "'$val'</p>";
$reg = $CPreReg.'([a-zA-Z_0-9]+)'.$CPosReg;
while(ereg($reg,$val,$vars))
while(preg_match('/'.(string) $reg.'/',$val,$vars))
{ // expand all CSV fields
$val = str_replace($CPre . $vars[1] . $CPos, $val[0] == '@' ? "'"
. addslashes($fields[array_search($vars[1], $csv_fields)])
@ -374,19 +402,51 @@ switch($_POST['action'])
// convert dates to timestamps
foreach(array('created','modified') as $date)
{
if (isset($values[$date]) && !is_numeric($date))
if (isset($values[$date]) && !is_numeric($values[$date]))
{
// convert german DD.MM.YYYY format into ISO YYYY-MM-DD format
$values[$date] = preg_replace('/([0-9]{1,2}).([0-9]{1,2}).([0-9]{4})/','\3-\2-\1',$values[$date]);
// remove fractures of seconds if present at the end of the string
if (ereg('(.*)\.[0-9]+',$values[$date],$parts)) $values[$date] = $parts[1];
if (preg_match('/(.*)\.[0-9]+/',$values[$date],$parts)) $values[$date] = $parts[1];
$values[$date] = strtotime($values[$date]);
}
}
// check unique ids
$existing = false;
if (!empty($values[$unique_id]))
{
if ($unique_id == 'id')
{
$existing = $bocontacts->read($values[$unique_id]);
}
else
{
list($existing) = $bocontacts->search(array($unique_id => $values[$unique_id]),false);
}
}
if (!$existing && (!empty($values[$unique_id2]) ||
$unique_id2 == 'addr_id' && (!empty($values['org_name'])+!empty($values['n_family'])+!empty($values['n_given'])) >= 2))
{
if ($unique_id2 == 'id' || $unique_id2 == 'addr_id' &&
($values[$unique_id2] = addr_id($values['n_family'],$values['n_given'],$values['org_name'])))
{
$existing = $bocontacts->read($values[$unique_id2]);
}
elseif ($unique_id2 != 'addr_id')
{
list($existing) = $bocontacts->search(array($unique_id2 => $values[$unique_id2]),false);
}
}
//echo "<p>unique_id=$unique_id='{$values[$unique_id]}', unique_id2=$unique_id2='{$values[$unique_id2]}' --> ".array2string($existing)."</p>\n";
if ($existing)
{
unset($values['id']); // to NOT overrite the found one
$values = array_merge($existing,$values);
}
// convert user-names to user-id's
foreach(array('owner','modifier','creator') as $user)
{
if (isset($values[$user]) && !is_numeric($user))
if (isset($values[$user]) && !is_numeric($values[$user]))
{
if (preg_match('/\[([^\]]+)\]/',$values[$user],$matches)) $values[$user] = $matches[1];
$values[$user] = $GLOBALS['egw']->accounts->name2id($values[$user],'account_lid',$user=='owner'?null:'u');
@ -396,6 +456,10 @@ switch($_POST['action'])
{
$values['owner'] = $GLOBALS['egw_info']['user']['account_id'];
}
if (!in_array('id',$addr_fields))
{
$log .= "\t\t<td>".$values['id']."</td>\n";
}
if (!in_array('private',$addr_fields))
{
$values['private'] = 0; // public access if not set by user
@ -414,7 +478,7 @@ switch($_POST['action'])
}
if(!$_POST['debug'] && !$empty) // dont import empty contacts
{
$rvalue=$GLOBALS['egw']->contacts->save($values);
$rvalue=$bocontacts->save($values);
//echo "<p>adding: ".print_r($values,true)."</p>\n";
}
// display read and interpreted results, so the user can check it

View File

@ -287,6 +287,7 @@ new contact submitted by %1 at %2 addressbook de Neuer Kontakt eingetragen von %
new window opened to edit infolog for your selection addressbook de Es wird ein neues Fenster zum erstellen des Infolog Eintrags geöffnet
next date addressbook de Nächster Termin
no categories selected addressbook de keine Kategorien ausgewählt
no fallback addressbook de Kein Ausweichlösung
no vcard addressbook de Keine VCard
number addressbook de Nummer
number of records to read (%1) addressbook de Anzahl der einzulesenden Datensätze (%1)
@ -382,7 +383,10 @@ to many might exceed your execution-time-limit addressbook de zu viel können ih
today is %1's birthday! common de Heute ist der Geburtstag von %1!
tomorrow is %1's birthday. common de Morgen ist der Geburtstag von %1.
translation addressbook de Übersetzung
two of: %1 addressbook de Zwei von: %1
type addressbook de Typ
unique id (uid) addressbook de Eindeutige ID (UID)
unique id<br />(to update existing records) addressbook de Eindeutige ID<br />(um existierende Datensätze zu aktualisieren)
update a single entry by passing the fields. addressbook de Aktualisiert einen einzelnen Eintrag durch Übergabe seiner Felder.
update fields by edited organisations? admin de Welche Felder sollen beim Bearbeiten von Organisationen aktualisiert werden?
updated addressbook de Aktualisiert

View File

@ -287,6 +287,7 @@ new contact submitted by %1 at %2 addressbook en New contact submitted by %1 at
new window opened to edit infolog for your selection addressbook en New window opened to edit Infolog for your selection
next date addressbook en Next date
no categories selected addressbook en no categories selected
no fallback addressbook en No fallback
no vcard addressbook en No VCard
number addressbook en Number
number of records to read (%1) addressbook en Number of records to read (%1)
@ -382,7 +383,10 @@ to many might exceed your execution-time-limit addressbook en to many might exce
today is %1's birthday! common en Today is %1's birthday!
tomorrow is %1's birthday. common en Tomorrow is %1's birthday.
translation addressbook en Translation
two of: %1 addressbook en two of: %1
type addressbook en Type
unique id (uid) addressbook en Unique ID (UID)
unique id<br />(to update existing records) addressbook en Unique ID<br />(to update existing records)
update a single entry by passing the fields. addressbook en Update a single entry by passing the fields.
update fields by edited organisations? admin en Update Fields by edited organisations?
updated addressbook en Updated

View File

@ -1,17 +1,17 @@
<br><center>
<FORM {enctype} action="{action_url}" method="post">
<TABLE>
<form {enctype} action="{action_url}" method="post">
<table>
<!-- BEGIN filename -->
<TR>
<TD>{lang_csvfile}</td>
<td><INPUT NAME="csvfile" SIZE=30 TYPE="file" VALUE="{csvfile}"></td>
<tr>
<td>{lang_csvfile}</td>
<td><input NAME="csvfile" SIZE=30 TYPE="file" VALUE="{csvfile}" /></td>
</tr>
<tr>
<td>{lang_fieldsep}</td>
<td><input name="fieldsep" size=1 value="{fieldsep}"></td>
<td><input name="fieldsep" size=1 value="{fieldsep}" /></td>
</tr>
<tr>
<td>{lang_charset}</td>
@ -20,8 +20,8 @@
</td>
</tr>
<tr><td>&nbsp;</td>
<td><INPUT NAME="convert" TYPE="submit" VALUE="{submit}"></TD>
</TR>
<td><input NAME="convert" TYPE="submit" VALUE="{submit}" /></TD>
</tr>
<!-- END filename -->
<!-- BEGIN fheader -->
@ -35,21 +35,25 @@
<!-- BEGIN fields -->
<tr>
<td>{csv_field}</td>
<td><SELECT name="addr_fields[{csv_idx}]">{addr_fields}</select></td>
<td><input name="trans[{csv_idx}]" size=60 value="{trans}"></td>
<td><select name="addr_fields[{csv_idx}]">{addr_fields}</select></td>
<td><input name="trans[{csv_idx}]" size=60 value="{trans}" /></td>
</tr>
<!-- END fields -->
<!-- BEGIN ffooter -->
<tr>
<td rowspan="2" valign="middle"><br>{submit}</TD>
<td colspan="2"><br>
{lang_start} <INPUT name="start" type="text" size="5" value="{start}"> &nbsp; &nbsp;
{lang_max} <INPUT name="max" type="text" size="3" value="{max}"><td>
<td>{lang_unique_id}</td>
<td colspan="2">{unique_id}</td>
</tr>
<tr>
<td colspan="3"><INPUT name="debug" type="checkbox" value="1" {debug}> {lang_debug}</td>
</TR>
<td rowspan="2" valign="middle"><br>{submit}</TD>
<td colspan="2"><br>
{lang_start} <input name="start" type="text" size="5" value="{start}" /> &nbsp; &nbsp;
{lang_max} <input name="max" type="text" size="3" value="{max}" /><td>
</tr>
<tr>
<td colspan="3"><input name="debug" type="checkbox" value="1" {debug}> {lang_debug}</td>
</tr>
<tr><td colspan="3">&nbsp;<p>
{help_on_trans}
</td></tr>
@ -61,11 +65,11 @@
{log}<p>
{anz_imported}
</td>
</TR>
</tr>
<!-- END imported -->
</TABLE>
</table>
{hiddenvars}
</form>
</CENTER>
</center>