moved contact-data (firstname, lastname and email) from the account-table to the contact table:

- all (sql) accounts have now allways a contact associated with them (account_id is added as new column to the contacts table)
- contacts queries are simplefied a lot now, as no more join with the accouns-table, union and case when statesments are necessary
- lot of the special handling for accounts in the contacts class is no longer needed
- new contact-repository mode "sql-ldap" which additional writes all changes to the ldap repository, to allow to use it read-only from eg. thunderbird and still have the full sql speed and features within eGW (not yet fully working!)
==> requites update of API and addressbook to work (setup!)
This commit is contained in:
Ralf Becker 2006-06-17 18:50:07 +00:00
parent 61b6d0b993
commit 9f59a77b85
14 changed files with 228 additions and 682 deletions

View File

@ -408,7 +408,7 @@ class bocontacts extends socontacts
if (!$contact['tid']) $contact['tid'] = 'n';
}
if($contact['id'] && !$this->check_perms(EGW_ACL_EDIT,$contact))
if(!$this->check_perms($isUpdate ? EGW_ACL_EDIT : EGW_ACL_ADD,$contact))
{
$this->error = 'access denied';
return false;
@ -419,8 +419,11 @@ class bocontacts extends socontacts
$contact['modifier'] = $this->user;
$contact['modified'] = $this->now_su;
// set full name and fileas from the content
$contact['n_fn'] = $this->fullname($contact);
$contact['n_fileas'] = $this->fileas($contact);
if (isset($contact['n_family']) && isset($contact['n_given']))
{
$contact['n_fn'] = $this->fullname($contact);
if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact);
}
if(!($this->error = parent::save($contact)))
{

View File

@ -91,12 +91,17 @@ class contacts_admin_prefs
'Global Categories' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.uicategories.index',
'appname' => $appname,
'global_cats'=> True)),
'Custom fields' => $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.customfields.edit',
'appname' => $appname,
'global_cats'=> True,
)),
);
// custom fields are not availible in LDAP
if ($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap')
{
$file['Custom fields'] = $GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'admin.customfields.edit',
'appname' => $appname,
));
}
if ($location == 'admin')
{
display_section($appname,$file);

View File

@ -209,7 +209,7 @@ class so_ldap
$this->personalContactsDN = 'ou=personal,ou=contacts,'. $GLOBALS['egw_info']['server']['ldap_contact_context'];
$this->sharedContactsDN = 'ou=shared,ou=contacts,'. $GLOBALS['egw_info']['server']['ldap_contact_context'];
if (is_object($GLOBALS['egw']->ldap))
if (!is_object($GLOBALS['egw']->ldap))
{
$GLOBALS['egw']->ldap =& CreateObject('phpgwapi.ldap');
}
@ -267,11 +267,6 @@ class so_ldap
*/
function read($contact_id)
{
if (substr($contact_id,0,8) == 'account:' &&
!($contact_id = $GLOBALS['egw']->accounts->id2name((int) substr($contact_id,8))))
{
return false; // account does not exist
}
$contact_id = ldap::quote($contact_id);
$rows = $this->_searchLDAP($GLOBALS['egw_info']['server']['ldap_contact_context'],
"(|(entryUUID=$contact_id)(uid=$contact_id))", $this->all_attributes, ADDRESSBOOK_ALL);
@ -287,12 +282,16 @@ class so_ldap
*/
function save($keys=null)
{
if(is_array($keys))
{
$this->data = is_array($this->data) ? array_merge($this->data,$keys) : $keys;
}
$contactUID = '';
$data =& $this->data;
$isUpdate = false;
$newObjectClasses = array();
$ldapContact = array();
$data =& $this->data;
// generate addressbook dn
if((int)$data['owner'])
@ -340,7 +339,7 @@ class so_ldap
}
if(!$contactUID)
{
$contactUID = md5($GLOBALS['egw']->common->randomstring(15));
$this->data[$this->contacts_id] = $contactUID = md5($GLOBALS['egw']->common->randomstring(15));
}
$ldapContact['uid'] = $contactUID;
@ -348,7 +347,7 @@ class so_ldap
// add for all supported objectclasses the objectclass and it's attributes
foreach($this->schema2egw as $objectclass => $mapping)
{
if(!$this->ldapServerInfo->supportsObjectClass($objectclass)) continue;
if(!$this->ldapServerInfo->supportsObjectClass($objectclass) || $objectclass == 'posixaccount') continue;
if(!in_array($objectclass, $oldObjectclasses))
{
@ -433,21 +432,19 @@ class so_ldap
$newContact['objectclass'] = array_merge($newContact['objectclass'], $ldapContact['objectClass']);
}
if(ldap_delete($this->ds, $dn))
{
if(!@ldap_add($this->ds, $newDN, $newContact))
{
//echo "<p>recreate: ldap_add($this->ds,'$newDN',".print_r($newContact,true).")</p>\n";
//print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';_debug_array($newContact);exit;
return $this->_error(__LINE__);
}
}
else
if(!ldap_delete($this->ds, $dn))
{
error_log('class.so_ldap.inc.php ('. __LINE__ .') delete of old '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
return $this->_error(__LINE__);
}
if(!@ldap_add($this->ds, $newDN, $newContact))
{
//echo "<p>recreate: ldap_add($this->ds,'$newDN',".print_r($newContact,true).")</p>\n";
//print 'class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')';_debug_array($newContact);exit;
error_log('class.so_ldap.inc.php ('. __LINE__ .') re-create contact as '. $newDN .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
error_log(print_r($newContact,true));
return $this->_error(__LINE__);
}
$dn = $newDN;
}
unset($ldapContact['objectClass']);
@ -456,6 +453,7 @@ class so_ldap
{
//echo "<p>ldap_modify($this->ds,'$dn',".print_r($ldapContact,true).")</p>\n";
error_log('class.so_ldap.inc.php ('. __LINE__ .') update of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
error_log(print_r($ldapContact,true));
return $this->_error(__LINE__);
}
}
@ -467,6 +465,7 @@ class so_ldap
{
//echo "<p>ldap_add($this->ds,'$dn',".print_r($ldapContact,true).")</p>\n";
error_log('class.so_ldap.inc.php ('. __LINE__ .') add of '. $dn .' failed errorcode: '. ldap_errno($this->ds) .' ('. ldap_error($this->ds) .')');
error_log(print_r($ldapContact,true));
return $this->_error(__LINE__);
}
}

View File

@ -13,6 +13,20 @@
/**
* General storage object of the adressbook
*
* The contact storage has 3 operation modi (contact_repository):
* - sql: contacts are stored in the SQL table egw_addressbook & egw_addressbook_extra (custom fields)
* - ldap: contacts are stored in LDAP (accounts have to be stored in LDAP too!!!).
* Custom fields are not availible in that case!
* - sql-ldap: contacts are read and searched in SQL, but saved to both SQL and LDAP.
* Other clients (Thunderbird, ...) can use LDAP readonly. The get maintained via eGroupWare only.
*
* The accounts can be stored in SQL or LDAP too (account_repository):
* If the account-repository is different from the contacts-repository, the filter all (no owner set)
* will only search the accounts and NOT the contacts! Only the filter accounts (owner=0) shows accounts.
*
* If sql-ldap is used as contact-storage (LDAP is managed from eGroupWare) the filter all, searches
* the accounts in the SQL contacts-table too. Change in made in LDAP, are not detected in that case!
*
* @package addressbook
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
@ -147,11 +161,20 @@ class socontacts
$this->user = $GLOBALS['egw_info']['user']['account_id'];
$this->memberships = $GLOBALS['egw']->accounts->memberships($this->user,true);
// contacts backend
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap')
// account backend used
if ($GLOBALS['egw_info']['server']['account_repository'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
}
elseif ($GLOBALS['egw_info']['server']['auth_type'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
}
// contacts backend (contacts in LDAP require accounts in LDAP!)
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap' && $this->account_repository == 'ldap')
{
$this->contact_repository = 'ldap';
$this->somain =& CreateObject('addressbook.so_'.$this->contact_repository);
$this->somain =& CreateObject('addressbook.so_ldap');
// static grants from ldap: all rights for the own personal addressbook and the group ones of the meberships
$this->grants = array($this->user => ~0);
@ -163,27 +186,23 @@ class socontacts
// minimum: $this->columns_to_search = array('n_family','n_given','org_name');
$this->columns_to_search = array('n_family','n_middle','n_given','org_name','org_unit','adr_one_location','adr_two_location','note');
}
else
else // sql or sql->ldap
{
$this->somain =& CreateObject('addressbook.socontacts_sql','addressbook','egw_addressbook',null,'contact_');
if ($GLOBALS['egw_info']['server']['contact_repository'] == 'sql-ldap')
{
$this->contact_repository = 'sql-ldap';
}
$this->somain =& CreateObject('addressbook.socontacts_sql');
// group grants are now grants for the group addressbook and NOT grants for all its members, therefor the param false!
$this->grants = $GLOBALS['egw']->acl->get_grants($contact_app,false);
// remove some columns, absolutly not necessary to search in sql
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),array('jpegphoto','owner','tid',
'private','id','cat_id','modified','modifier','creator','created','tz'));
$this->columns_to_search[] = $this->extra_value; // custome fields from extra_table
$this->columns_to_search = array_diff(array_values($this->somain->db_cols),array(
'jpegphoto','owner','tid','private','id','cat_id',
'modified','modifier','creator','created','tz','account_id',
));
}
// account backend
if ($GLOBALS['egw_info']['server']['account_repository'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
}
elseif ($GLOBALS['egw_info']['server']['auth_type'])
{
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
}
if ($this->account_repository == 'ldap')
if ($this->account_repository == 'ldap' && $this->contact_repository == 'sql')
{
if ($this->account_repository != $this->contact_repository)
{
@ -196,18 +215,6 @@ class socontacts
$this->account_extra_search = array('uid');
}
}
else
{
if ($this->account_repository != $this->contact_repository)
{
// contacts in ldap & accounts in sql is not tested or supported at the moment!!!
$this->so_accounts =& CreateObject('addressbook.socontacts_sql','addressbook','egw_addressbook',null,'contact_');
}
else
{
$this->account_extra_search = array('account_firstname','account_lastname','account_email','account_lid');
}
}
// add grants for accounts: admin --> everything, everyone --> read
$this->grants[0] = EGW_ACL_READ; // everyone read access
if (isset($GLOBALS['egw_info']['user']['apps']['admin'])) // admin rights can be limited by ACL!
@ -221,7 +228,7 @@ class socontacts
$this->somain->contacts_id = 'id';
$this->soextra =& CreateObject('etemplate.so_sql');
$this->soextra->so_sql('addressbook',$this->extra_table);
$this->soextra->so_sql('phpgwapi',$this->extra_table);
$custom =& CreateObject('admin.customfields',$contact_app);
$this->customfields = $custom->get_customfields();
@ -246,6 +253,12 @@ class socontacts
*/
function read_customfields($ids)
{
foreach($ids as $key => $id)
{
if (!(int)$id) unset($ids[$key]);
}
if (!$ids) return array(); // nothing to do, eg. all these contacts are in ldap
$fields = array();
foreach((array)$this->soextra->search(array($this->extra_id => $ids),false) as $data)
{
@ -283,7 +296,7 @@ class socontacts
/**
* deletes contact entry including custom fields
*
* @param mixed $contact array with key id or just the id
* @param mixed $contact array with id or just the id
* @return boolean true on success or false on failiure
*/
function delete($contact)
@ -295,7 +308,17 @@ class socontacts
{
// delete customfields, can return 0 if there are no customfields
$this->soextra->delete(array($this->extra_id => $contact));
if ($this->contact_repository == 'sql-ldap')
{
if ($contact['account_id'])
{
// LDAP uses the uid attributes for the contact-id (dn),
// which need to be the account_lid for accounts!
$contact['id'] = $GLOBALS['egw']->account->id2name($contact['account_id']);
}
ExecMethod('addressbook.so_ldap.delete',$contact);
}
return true;
}
return false;
@ -321,8 +344,22 @@ class socontacts
else
{
$this->somain->data = $this->data2db($contact);
$error_nr = $this->somain->save();
$contact['id'] = $this->somain->data['id'];
if (!($error_nr = $this->somain->save()))
{
$contact['id'] = $this->somain->data['id'];
if ($this->contact_repository == 'sql-ldap')
{
$data = $this->somain->data;
if ($contact['account_id'])
{
// LDAP uses the uid attributes for the contact-id (dn),
// which need to be the account_lid for accounts!
$data['id'] = $GLOBALS['egw']->account->id2name($contact['account_id']);
}
ExecMethod('addressbook.so_ldap.save',$data);
}
}
}
if($error_nr) return $error_nr;
@ -358,6 +395,11 @@ class socontacts
*/
function read($contact_id)
{
if (substr($contact_id,0,8) == 'account:' &&
(!($contact_id = $GLOBALS['egw']->accounts->id2name((int) substr($contact_id,8),'person_id'))))
{
return false;
}
// read main data
$backend =& $this->get_backend($contact_id);
if (!($contact = $backend->read($contact_id)))
@ -369,10 +411,13 @@ class socontacts
$this->extra_id => $contact['id'],
$this->extra_owner => $contact['owner'],
);
$customfields = $this->soextra->search($keys,false);
foreach ((array)$customfields as $field)
if ($this->customfields) // try reading customfields only if we have some
{
$contact['#'.$field[$this->extra_key]] = $field[$this->extra_value];
$customfields = $this->soextra->search($keys,false);
foreach ((array)$customfields as $field)
{
$contact['#'.$field[$this->extra_key]] = $field[$this->extra_value];
}
}
return $this->db2data($contact);
}
@ -588,9 +633,10 @@ class socontacts
* @param string $op='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
* @param mixed $start=false if != false, return only maxmatch rows begining with start, or array($start,$num)
* @param array $filter=null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
* @param string $join='' sql to do a join (only used by sql backend!), eg. " RIGHT JOIN egw_accounts USING(account_id)"
* @return array of matching rows (the row is an array of the cols) or False
*/
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null)
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='')
{
//echo "<p>socontacts::search(".print_r($criteria,true).",'$only_keys','$order_by','$extra_cols','$wildcard','$empty','$op','$start',".print_r($filter,true).",'$join')</p>\n";
@ -606,15 +652,16 @@ class socontacts
if ($backend === $this->somain)
{
$cols = $this->columns_to_search;
if (!$filter['owner']) // extra columns for search if accounts are included, eg. account_lid
{
$cols = array_merge($cols,$this->account_extra_search);
}
}
else
{
$cols = $this->account_cols_to_search;
}
// search the customfields only if some exist, but only for sql!
if (get_class($backend) == 'socontacts_sql' && $this->customfields)
{
$cols[] = $this->extra_value;
}
foreach($cols as $col)
{
$criteria[$col] = $search;
@ -779,7 +826,7 @@ class socontacts
*/
function get_fields($type='all',$contact_id=null,$owner=null)
{
$def = $this->soextra->db->get_table_definitions('addressbook','egw_addressbook');
$def = $this->soextra->db->get_table_definitions('phpgwapi','egw_addressbook');
$all_fields = array();
foreach($def['fd'] as $field => $data)

View File

@ -23,14 +23,13 @@ include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
class socontacts_sql extends so_sql
{
var $accounts_table = 'egw_accounts';
var $accounts_join = ' JOIN egw_accounts ON person_id=egw_addressbook.contact_id';
var $extra_join = ' LEFT JOIN egw_addressbook_extra ON egw_addressbook.contact_id=egw_addressbook_extra.contact_id';
var $account_repository = 'sql';
var $contact_repository = 'sql';
function socontacts_sql($app='',$table='',$db=null,$column_prefix='')
function socontacts_sql()
{
$this->so_sql($app,$table,$db,$column_prefix); // calling the constructor of the extended class
$this->so_sql('phpgwapi','egw_addressbook',null,'contact_'); // calling the constructor of the extended class
if ($GLOBALS['egw_info']['server']['account_repository'])
{
@ -40,6 +39,10 @@ class socontacts_sql extends so_sql
{
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
}
if ($GLOBALS['egw_info']['server']['contact_repository'])
{
$this->contact_repository = $GLOBALS['egw_info']['server']['contact_repository'];
}
}
/**
@ -84,6 +87,10 @@ class socontacts_sql extends so_sql
}
else // search all addressbooks, incl. accounts
{
if ($this->account_repository != 'sql' && $this->contact_repository != 'sql-ldap')
{
$filter[] = 'contact_owner != 0'; // in case there have been accounts in sql previously
}
$filter[] = "(contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id'].
" OR contact_private=0 AND contact_owner IN (".
implode(',',array_keys($this->grants))."))";
@ -223,52 +230,15 @@ class socontacts_sql extends so_sql
}
else // search all addressbooks, incl. accounts
{
if ($this->account_repository != 'sql' && $this->contact_repository != 'sql-ldap')
{
$filter[] = 'contact_owner != 0'; // in case there have been accounts in sql previously
}
$filter[] = "($this->table_name.contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id'].
" OR contact_private=0 AND $this->table_name.contact_owner IN (".
implode(',',array_keys($this->grants)).") OR $this->table_name.contact_owner IS NULL)";
}
}
if (!$owner && $this->account_repository == 'sql') // owner not set (=all) or 0 --> include accounts
{
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
$accounts2contacts = array(
'contact_id' => "CASE WHEN $this->table_name.contact_id IS NULL THEN ".$this->db->concat("'account:'",'account_id').
" ELSE $this->table_name.contact_id END AS contact_id",
'contact_owner' => "CASE WHEN $this->table_name.contact_owner IS NULL THEN 0 ELSE $this->table_name.contact_owner END AS contact_owner",
'contact_tid' => 'CASE WHEN contact_tid IS NULL THEN \'n\' ELSE contact_tid END AS contact_tid',
'n_family' => 'CASE WHEN n_family IS NULL THEN account_lastname ELSE n_family END AS n_family',
'n_given' => 'CASE WHEN n_given IS NULL THEN account_firstname ELSE n_given END AS n_given',
'n_fn' => 'CASE WHEN n_fn IS NULL THEN '.$this->db->concat('account_firstname',"' '",'account_lastname').' ELSE n_fn END AS n_fn',
'contact_email' => 'CASE WHEN contact_email IS NULL THEN account_email ELSE contact_email END AS contact_email',
);
$extra_cols = $extra_cols ? array_merge(is_array($extra_cols) ? $extra_cols : implode(',',$extra_cols),array_values($accounts2contacts)) :
array_values($accounts2contacts);
// we need to remove the above columns from the select list, as they are added again via extra_cols and
// having them double is ambigues
if (!$only_keys)
{
$only_keys = array_diff(array_keys($this->db_cols),array_keys($accounts2contacts));
}
elseif($only_keys !== true)
{
if (!is_array($only_keys)) $only_keys = explode(',',$only_keys);
foreach(array_keys($accounts2contacts) as $col)
{
if (($key = array_search($col,$only_keys)) !== false ||
($key = array_search(str_replace('contact_','',$col),$only_keys)) !== false)
{
unset($only_keys[$key]);
}
}
}
$this->_fix_filter($filter,$accounts2contacts);
// dont list groups
$filter[] = "(account_type != 'g' OR account_type IS NULL)";
if (is_array($criteria)) $this->_fix_filter($criteria,$accounts2contacts,$wildcard);
}
if ($criteria['contact_value']) // search the custom-fields
{
$join .= $this->extra_join;
@ -285,70 +255,9 @@ class socontacts_sql extends so_sql
unset($filter['owner']);
}
}
if ($this->account_repository == 'sql')
{
if (is_null($owner)) // search for accounts AND contacts of all addressbooks
{
/* only enable that after testing with postgres, I dont want to break more postgres stuff ;-)
if ($this->db->capabilities['outer_join'])
{
$join = 'OUTER'.$this->accounts_join.' '.$join;
}
else */ // simulate the outer join with a union
{
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'LEFT'.$this->accounts_join.$join,$need_full_no_count);
$filter[] = '(person_id=0 OR person_id IS NULL)'; // unfortunally both is used in eGW
parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,'UNION',$filter,
'RIGHT'.$this->accounts_join.$join,$need_full_no_count);
}
}
elseif (!$owner) // search for accounts only
{
$join = ' RIGHT'.$this->accounts_join.$join;
$filter[] = "account_type='u'"; // no groups
}
}
return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
}
/**
* Fixing column-names in the filter to use CASE expressions to include the account-data
*
* @param array &$filter column => value pairs or sql strings
* @param array $accounts2contacts mapping column-name => sql statement
* @param string $wildcard='' wildcard if one should be append before and after the value
*/
function _fix_filter(&$filter,$accounts2contacts,$wildcard='')
{
foreach($filter as $col => $value)
{
if (!is_int($col) && ($db_col = array_search($col,$this->db_cols)) !== false)
{
if (isset($accounts2contacts[$db_col]))
{
unset($filter[$col]);
$filter[] = str_replace(' AS '.$db_col,'',$accounts2contacts[$db_col]).
($value === "!''" ? "!=''" : ($wildcard ? ' LIKE ' : '=').
$this->db->quote($wildcard.$value.$wildcard,$this->table_def['fd'][$db_col]['type']));
}
elseif($value === "!''") // not empty query, will match all accounts, as their value is NULL not ''
{
unset($filter[$col]);
$filter[] = "($db_col != '' AND $db_col IS NOT NULL)";
}
}
elseif (preg_match("/^([a-z0-9_]+) *(=|!=|LIKE|NOT LIKE|=!) *'(.*)'\$/i",$value,$matches))
{
if (($db_col = array_search($matches[1],$this->db_cols)) !== false && isset($accounts2contacts[$db_col]))
{
if ($matches[2] == '=!') $matches[2] = '!=';
$filter[$col] = str_replace(' AS '.$db_col,'',$accounts2contacts[$db_col]).' '.$matches[2].' \''.$matches[3].'\'';
}
}
}
}
/**
* fix cat_id filter to search in comma-separated multiple cats and return subcats
*
@ -368,131 +277,4 @@ class socontacts_sql extends so_sql
}
return '('.implode(' OR ',$cat_filter).')';
}
/**
* reads contact data including custom fields
*
* reimplemented to read/convert accounts and return the account_id for them
*
* @param integer/string $contact_id contact_id or 'account:'.account_id
* @return array/boolean data if row could be retrived else False
*/
function read($contact_id)
{
//echo "<p>socontacts_sql::read($contact_id)</p>\n";
if (substr($contact_id,0,8) == 'account:')
{
$account_id = (int) substr($contact_id,8);
if (!$GLOBALS['egw']->accounts->exists($account_id)) return false; // account does not exist
// check if the account is already linked with a contact, if not create one with the content of the account
if (!($contact_id = $GLOBALS['egw']->accounts->id2name($account_id,'person_id')) &&
!($matching_contact_id = $this->_find_unique_contact(
$GLOBALS['egw']->accounts->id2name($account_id,'account_firstname'),
$GLOBALS['egw']->accounts->id2name($account_id,'account_lastname'))))
{
// as the account object has no function to just read a record and NOT override it's internal data,
// we have to instanciate a new object and can NOT use $GLOBALS['egw']->accounts !!!
$account =& new accounts($account_id,'u');
$account->read();
if (!$account->data['account_id']) return false; // account not found
$this->init();
$this->save(array(
'n_family' => $account->data['lastname'],
'n_given' => $account->data['firstname'],
'n_fn' => $account->data['firstname'].' '.$account->data['lastname'],
'n_fileas' => $account->data['lastname'].', '.$account->data['firstname'],
'email' => $account->data['email'],
'owner' => 0,
'tid' => 'n',
'creator' => $GLOBALS['egw_info']['user']['account_id'],
'created' => time(),
'modifier' => $GLOBALS['egw_info']['user']['account_id'],
'modified' => time(),
),$account_id);
return $this->data+array('account_id' => $account_id);
}
elseif ($matching_contact_id)
{
//echo "<p>socontacts_sql($contact_id) account_id=$account_id, matching_contact_id=$matching_contact_id</p>\n";
$contact = parent::read($matching_contact_id);
$contact['owner'] = 0;
$this->save($contact,$account_id);
return $this->data+array('account_id' => $account_id);
}
//echo "<p>socontacts_sql::read() account_id='$account_id', contact_id='$contact_id'</p>\n"; exit;
}
if (($contact = parent::read($contact_id)) && !$contact['owner']) // return account_id for accounts
{
$contact['account_id'] = $GLOBALS['egw']->accounts->name2id($contact_id,'person_id');
}
return $contact;
}
function _find_unique_contact($firstname,$lastname)
{
$contacts =& $this->search(array(
'contact_owner != 0',
'n_given' => $firstname,
'n_family' => $lastname,
'private' => 0,
));
return $contacts && count($contacts) == 1 ? $contacts[0]['id'] : false;
}
/**
* saves the content of data to the db
*
* reimplemented to write for accounts some of the data to the account too and link it with the contact
*
* @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param int $account_id if called by read account_id of account to save/link with contact (we dont overwrite the account-data in that case),
* otherwise we try getting it by accounts::name2id('person_id',$contact_id)
* @return int 0 on success and errno != 0 else
*/
function save($data=null,$account_id=0)
{
$this->data_merge($data);
// if called by read's automatic conversation --> dont change the email of the account (if set)
if (!$this->data['owner'] && $account_id &&
($email = $GLOBALS['egw']->accounts->id2name($account_id,'account_email')) && $data['email'] != $email)
{
if (!$data['email_home']) $data['email_home'] = $data['email'];
$data['email'] = $email;
}
if (!($error = parent::save()) && !$this->data['owner']) // successfully saved an account --> sync our data in the account-table
{
if (!$account_id && !($account_id = $GLOBALS['egw']->accounts->name2id($this->data['id'],'person_id')) &&
// try find a matching account for migration
!($account_id = $GLOBALS['egw']->accounts->name2id($this->data['n_given'].' '.$this->data['n_family'],'account_fullname')))
{
// ToDo create new account
}
// as the account object has no function to just read a record and NOT override it's internal data,
// we have to instanciate a new object and can NOT use $GLOBALS['egw']->accounts !!!
$account =& new accounts($account_id,'u');
$account->read_repository();
if (!$account->data['account_id']) return false; // account not found
foreach(array(
'n_family' => 'lastname',
'n_given' => 'firstname',
'email' => 'email',
'id' => 'person_id',
) as $c_name => $a_name)
{
$account->data[$a_name] = $this->data[$c_name];
}
$account->save_repository();
}
return $error;
}
}

View File

@ -39,7 +39,7 @@ class uicontacts extends bocontacts
var $private_addressbook = false;
var $org_views;
// var $config = array('call_link'=>'skype:%1?call','call_popup'=>''); // popup wxh, eg. 640x480
var $config;
function uicontacts($contact_app='addressbook')
{
@ -69,6 +69,8 @@ class uicontacts extends bocontacts
// our javascript
// to be moved in a seperate file if rewrite is over
$GLOBALS['egw_info']['flags']['java_script'] .= $this->js();
$this->config =& $GLOBALS['egw_info']['server'];
}
/**
@ -83,7 +85,6 @@ class uicontacts extends bocontacts
//echo "<p>uicontacts::index(".print_r($content,true).",'$msg')</p>\n";
if (($re_submit = is_array($content)))
{
// $msg = $content['msg'];
$do_email = $content['do_email'];
if (isset($content['nm']['rows']['delete'])) // handle a single delete like delete with the checkboxes
@ -130,8 +131,6 @@ class uicontacts extends bocontacts
{
$content['nm'] = array(
'get_rows' => 'addressbook.uicontacts.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
'header_left' => $do_email ? 'addressbook.email.left' : 'addressbook.index.left', // I template to show right of the range-value, right-aligned (optional)
// 'header_right' => 'addressbook.index.right', // I template to show right of the range-value, right-aligned (optional)
'bottom_too' => false, // I show the nextmatch-line (arrows, filters, search, ...) again after the rows
'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entrie
'start' => 0, // IO position in list
@ -156,10 +155,19 @@ class uicontacts extends bocontacts
$content['nm'] = array_merge($content['nm'],$state);
}
}
if ($do_email && !$re_submit)
if ($do_email)
{
$content['nm']['to'] = 'to';
$content['nm']['search'] = '@';
if (!$re_submit)
{
$content['nm']['to'] = 'to';
$content['nm']['search'] = '@';
}
$content['nm']['header_left'] = 'addressbook.email.left';
}
// Organisation stuff is not (yet) availible with ldap
elseif($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap')
{
$content['nm']['header_left'] = 'addressbook.index.left';
}
$sel_options = array(
'filter' => $this->get_addressbooks(EGW_ACL_READ,lang('All')),
@ -510,11 +518,12 @@ class uicontacts extends bocontacts
$rows = parent::search($query['search'],$id_only ? array('id','org_name','n_family','n_given','n_fileas') : false,
$order,'','%',false,'OR',array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']);
if (!$id_only && $this->prefs['custom_colum'] != 'never' && $rows) // do we need the custom fields
// do we need the custom fields
if (!$id_only && $this->prefs['custom_colum'] != 'never' && $rows && $this->customfields)
{
foreach((array) $rows as $n => $val)
{
if ($val) $ids[] = $val['id'];
if ($val && (int)$val['id']) $ids[] = $val['id'];
}
if ($ids) $customfields = $this->read_customfields($ids);
}
@ -614,7 +623,7 @@ class uicontacts extends bocontacts
if ($row[$name]) $homeaddress = true;
}
}
}
}
}
// disable photo column, if view contains no photo(s)
if (!$photos || $this->prefs['photo_column'] == 'never') $rows['no_photo'] = '1';
@ -1273,7 +1282,7 @@ $readonlys['button[vcard]'] = true;
{
if (!$number || !$this->config['call_link']) return false;
$link = str_replace('%1',$number,$this->config['call_link']);
$link = str_replace('%1',urlencode($number),$this->config['call_link']);
}
function js()

View File

@ -0,0 +1,28 @@
<?php
/**
* Addressbook - configuration
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package addressbook
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id: class.bocontacts.inc.php 21831 2006-06-14 16:53:14Z ralfbecker $
*/
function contact_repositories($config)
{
$repositories = array('sql' => 'SQL');
// check account-repository, contact-repository LDAP is only availible for account-repository == ldap
if ($config['account_repository'] == 'ldap' || !$config['account_repository'] && $config['auth_type'] == 'ldap')
{
$repositories['ldap'] = 'LDAP';
$repositories['sql-ldap'] = 'SQL --> LDAP ('.lang('read only').')';
}
$options = '';
foreach($repositories as $repo => $label)
{
$options .= '<option value="'.$repo.'"'.($config['contact_repository'] == $repo ? ' selected="1">' : '>').
$label."</option>\n";
}
return $options;
}

File diff suppressed because one or more lines are too long

View File

@ -14,7 +14,7 @@
/* Basic information about this app */
$setup_info['addressbook']['name'] = 'addressbook';
$setup_info['addressbook']['title'] = 'Addressbook';
$setup_info['addressbook']['version'] = '1.3.001';
$setup_info['addressbook']['version'] = '1.3.002';
$setup_info['addressbook']['app_order'] = 4;
$setup_info['addressbook']['enable'] = 1;
@ -32,21 +32,20 @@
$setup_info['addressbook']['maintainer'] = 'eGroupWare coreteam';
$setup_info['addressbook']['maintainer_email'] = 'egroupware-developers@lists.sourceforge.net';
$setup_info['addressbook']['tables'][] = 'egw_addressbook';
$setup_info['addressbook']['tables'][] = 'egw_addressbook_extra';
$setup_info['addressbook']['tables'] = array(); // addressbook tables are in phpgwapi!
/* The hooks this app includes, needed for hooks registration */
$setup_info['addressbook']['hooks']['admin'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['preferences'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['sidebox_menu'] = 'addressbook.contacts_admin_prefs.all_hooks';
$setup_info['addressbook']['hooks']['settings'] = 'addressbook.contacts_admin_prefs.settings';
$setup_info['addressbook']['hooks'][] = 'config_validate';
$setup_info['addressbook']['hooks'][] = 'home';
$setup_info['addressbook']['hooks']['editaccount'] = 'addressbook.bocontacts.editaccount';
$setup_info['addressbook']['hooks']['deleteaccount'] = 'addressbook.bocontacts.deleteaccount';
$setup_info['addressbook']['hooks'][] = 'notifywindow';
$setup_info['addressbook']['hooks']['search_link'] = 'addressbook.bocontacts.search_link';
$setup_info['addressbook']['hooks']['edit_user'] = 'addressbook.contacts_admin_prefs.edit_user';
$setup_info['addressbook']['hooks'][] = 'config';
/* Dependencies for this app to work */
$setup_info['addressbook']['depends'][] = array(
@ -58,3 +57,4 @@
'versions' => Array('1.0.0','1.0.1','1.2','1.3')
);

View File

@ -1,89 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
// $Id$
// $Source$
$phpgw_baseline = array(
'egw_addressbook' => array(
'fd' => array(
'id' => array('type' => 'auto','nullable' => False),
'lid' => array('type' => 'varchar','precision' => '32'),
'tid' => array('type' => 'char','precision' => '1'),
'owner' => array('type' => 'int','precision' => '8'),
'access' => array('type' => 'varchar','precision' => '7'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'fn' => array('type' => 'varchar','precision' => '64'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'sound' => array('type' => 'varchar','precision' => '64'),
'bday' => array('type' => 'varchar','precision' => '32'),
'note' => array('type' => 'text'),
'tz' => array('type' => 'varchar','precision' => '8'),
'geo' => array('type' => 'varchar','precision' => '32'),
'url' => array('type' => 'varchar','precision' => '128'),
'pubkey' => array('type' => 'text'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'title' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'adr_one_type' => array('type' => 'varchar','precision' => '32'),
'label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'adr_two_type' => array('type' => 'varchar','precision' => '32'),
'tel_work' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_home' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_voice' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_fax' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_msg' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_cell' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_pager' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_bbs' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_modem' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_car' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_isdn' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_video' => array('type' => 'varchar','precision' => '40','nullable' => False,'default' => '+1 (000) 000-0000'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'email' => array('type' => 'varchar','precision' => '64'),
'email_type' => array('type' => 'varchar','precision' => '32','default' => 'INTERNET'),
'email_home' => array('type' => 'varchar','precision' => '64'),
'email_home_type' => array('type' => 'varchar','precision' => '32','default' => 'INTERNET'),
'last_mod' => array('type' => 'int','precision' => '8','nullable' => False)
),
'pk' => array('id'),
'fk' => array(),
'ix' => array(array('tid','owner','access','n_family','n_given'),array('tid','cat_id','owner','access','n_family')),
'uc' => array()
),
'egw_addressbook_extra' => array(
'fd' => array(
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_owner' => array('type' => 'int','precision' => '8'),
'contact_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
'contact_value' => array('type' => 'text')
),
'pk' => array('contact_id','contact_name'),
'fk' => array(),
'ix' => array(),
'uc' => array()
),
);

View File

@ -1,93 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
$phpgw_baseline = array(
'egw_addressbook' => array(
'fd' => array(
'contact_id' => array('type' => 'auto','nullable' => False),
'contact_tid' => array('type' => 'char','precision' => '1','default' => 'n'),
'contact_owner' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_private' => array('type' => 'int','precision' => '1','default' => '0'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'n_fn' => array('type' => 'varchar','precision' => '128'),
'n_fileas' => array('type' => 'varchar','precision' => '255'),
'contact_bday' => array('type' => 'varchar','precision' => '10'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'contact_title' => array('type' => 'varchar','precision' => '64'),
'contact_role' => array('type' => 'varchar','precision' => '64'),
'contact_assistent' => array('type' => 'varchar','precision' => '64'),
'contact_room' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_street2' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'contact_label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_street2' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'tel_work' => array('type' => 'varchar','precision' => '40'),
'tel_cell' => array('type' => 'varchar','precision' => '40'),
'tel_fax' => array('type' => 'varchar','precision' => '40'),
'tel_assistent' => array('type' => 'varchar','precision' => '40'),
'tel_car' => array('type' => 'varchar','precision' => '40'),
'tel_pager' => array('type' => 'varchar','precision' => '40'),
'tel_home' => array('type' => 'varchar','precision' => '40'),
'tel_fax_home' => array('type' => 'varchar','precision' => '40'),
'tel_cell_private' => array('type' => 'varchar','precision' => '40'),
'tel_other' => array('type' => 'varchar','precision' => '40'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'contact_email' => array('type' => 'varchar','precision' => '64'),
'contact_email_home' => array('type' => 'varchar','precision' => '64'),
'contact_url' => array('type' => 'varchar','precision' => '128'),
'contact_url_home' => array('type' => 'varchar','precision' => '128'),
'contact_freebusy_uri' => array('type' => 'varchar','precision' => '128'),
'contact_calendar_uri' => array('type' => 'varchar','precision' => '128'),
'contact_note' => array('type' => 'text'),
'contact_tz' => array('type' => 'varchar','precision' => '8'),
'contact_geo' => array('type' => 'varchar','precision' => '32'),
'contact_pubkey' => array('type' => 'text'),
'contact_created' => array('type' => 'int','precision' => '8'),
'contact_creator' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'),
),
'pk' => array('contact_id'),
'fk' => array(),
'ix' => array('cat_id','contact_owner','n_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array()
),
'egw_addressbook_extra' => array(
'fd' => array(
'contact_id' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_owner' => array('type' => 'int','precision' => '8'),
'contact_name' => array('type' => 'varchar','precision' => '255','nullable' => False),
'contact_value' => array('type' => 'text')
),
'pk' => array('contact_id','contact_name'),
'fk' => array(),
'ix' => array(),
'uc' => array()
)
);

View File

@ -1,168 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.eGroupWare.org *
* Created by eTemplates DB-Tools written by ralfbecker@outdoor-training.de *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
$test[] = '1.0.0';
function addressbook_upgrade1_0_0()
{
$GLOBALS['egw_setup']->oProc->RenameTable('phpgw_addressbook','egw_addressbook');
$GLOBALS['egw_setup']->oProc->RenameTable('phpgw_addressbook_extra','egw_addressbook_extra');
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.2';
}
$test[] = '1.2';
function addressbook_upgrade1_2()
{
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_addressbook',array(
'fd' => array(
'contact_id' => array('type' => 'auto','nullable' => False),
'contact_tid' => array('type' => 'char','precision' => '1','default' => 'n'),
'contact_owner' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_private' => array('type' => 'int','precision' => '1','default' => '0'),
'cat_id' => array('type' => 'varchar','precision' => '32'),
'n_family' => array('type' => 'varchar','precision' => '64'),
'n_given' => array('type' => 'varchar','precision' => '64'),
'n_middle' => array('type' => 'varchar','precision' => '64'),
'n_prefix' => array('type' => 'varchar','precision' => '64'),
'n_suffix' => array('type' => 'varchar','precision' => '64'),
'n_fn' => array('type' => 'varchar','precision' => '128'),
'n_fileas' => array('type' => 'varchar','precision' => '255'),
'contact_bday' => array('type' => 'varchar','precision' => '10'),
'org_name' => array('type' => 'varchar','precision' => '64'),
'org_unit' => array('type' => 'varchar','precision' => '64'),
'contact_title' => array('type' => 'varchar','precision' => '64'),
'contact_role' => array('type' => 'varchar','precision' => '64'),
'contact_assistent' => array('type' => 'varchar','precision' => '64'),
'contact_room' => array('type' => 'varchar','precision' => '64'),
'adr_one_street' => array('type' => 'varchar','precision' => '64'),
'adr_one_street2' => array('type' => 'varchar','precision' => '64'),
'adr_one_locality' => array('type' => 'varchar','precision' => '64'),
'adr_one_region' => array('type' => 'varchar','precision' => '64'),
'adr_one_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_one_countryname' => array('type' => 'varchar','precision' => '64'),
'contact_label' => array('type' => 'text'),
'adr_two_street' => array('type' => 'varchar','precision' => '64'),
'adr_two_street2' => array('type' => 'varchar','precision' => '64'),
'adr_two_locality' => array('type' => 'varchar','precision' => '64'),
'adr_two_region' => array('type' => 'varchar','precision' => '64'),
'adr_two_postalcode' => array('type' => 'varchar','precision' => '64'),
'adr_two_countryname' => array('type' => 'varchar','precision' => '64'),
'tel_work' => array('type' => 'varchar','precision' => '40'),
'tel_cell' => array('type' => 'varchar','precision' => '40'),
'tel_fax' => array('type' => 'varchar','precision' => '40'),
'tel_assistent' => array('type' => 'varchar','precision' => '40'),
'tel_car' => array('type' => 'varchar','precision' => '40'),
'tel_pager' => array('type' => 'varchar','precision' => '40'),
'tel_home' => array('type' => 'varchar','precision' => '40'),
'tel_fax_home' => array('type' => 'varchar','precision' => '40'),
'tel_cell_private' => array('type' => 'varchar','precision' => '40'),
'tel_other' => array('type' => 'varchar','precision' => '40'),
'tel_prefer' => array('type' => 'varchar','precision' => '32'),
'contact_email' => array('type' => 'varchar','precision' => '64'),
'contact_email_home' => array('type' => 'varchar','precision' => '64'),
'contact_url' => array('type' => 'varchar','precision' => '128'),
'contact_url_home' => array('type' => 'varchar','precision' => '128'),
'contact_freebusy_uri' => array('type' => 'varchar','precision' => '128'),
'contact_calendar_uri' => array('type' => 'varchar','precision' => '128'),
'contact_note' => array('type' => 'text'),
'contact_tz' => array('type' => 'varchar','precision' => '8'),
'contact_geo' => array('type' => 'varchar','precision' => '32'),
'contact_pubkey' => array('type' => 'text'),
'contact_created' => array('type' => 'int','precision' => '8'),
'contact_creator' => array('type' => 'int','precision' => '4','nullable' => False),
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'),
),
'pk' => array('contact_id'),
'fk' => array(),
'ix' => array('cat_id','contact_owner','n_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array()
),array(
// new colum prefix
'contact_id' => 'id',
'contact_tid' => 'tid',
'contact_owner' => 'owner',
'contact_private' => "CASE access WHEN 'private' THEN 1 ELSE 0 END",
'n_fn' => 'fn',
'contact_title' => 'title',
'contact_bday' => 'bday',
'contact_note' => 'note',
'contact_tz' => 'tz',
'contact_geo' => 'geo',
'contact_url' => 'url',
'contact_pubkey' => 'pubkey',
'contact_label' => 'label',
'contact_email' => 'email',
'contact_email_home' => 'email_home',
'contact_modified' => 'last_mod',
// remove stupid old default values, rename phone-numbers, tel_bbs and tel_video are droped
'tel_work' => "CASE tel_work WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_work END",
'tel_cell' => "CASE tel_cell WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_cell END",
'tel_fax' => "CASE tel_fax WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_fax END",
'tel_assistent' => "CASE tel_msg WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_msg END",
'tel_car' => "CASE tel_car WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_car END",
'tel_pager' => "CASE tel_pager WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_pager END",
'tel_home' => "CASE tel_home WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_home END",
'tel_fax_home' => "CASE tel_modem WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_modem END",
'tel_cell_private' => "CASE tel_isdn WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_isdn END",
'tel_other' => "CASE tel_voice WHEN '+1 (000) 000-0000' THEN NULL ELSE tel_voice END",
'tel_prefer' => "CASE tel_prefer WHEN 'tel_voice' THEN 'tel_other' WHEN 'tel_msg' THEN 'tel_assistent' WHEN 'tel_modem' THEN 'tel_fax_home' WHEN 'tel_isdn' THEN 'tel_cell_private' WHEN 'ophone' THEN 'tel_other' ELSE tel_prefer END",
// set creator from owner
'contact_creator' => 'owner',
// set contact_fileas from org_name, n_family and n_given
'n_fileas' => "CASE WHEN org_name='' THEN (".
($name_sql = "CASE WHEN n_given='' THEN n_family ELSE ".$GLOBALS['egw_setup']->db->concat('n_family',"', '",'n_given').' END').
") ELSE (CASE WHEN n_family='' THEN org_name ELSE ".$GLOBALS['egw_setup']->db->concat('org_name',"': '",$name_sql).' END) END',
));
// migrate values saved in custom fields to the new table
$db2 = clone($GLOBALS['egw_setup']->db);
$GLOBALS['egw_setup']->db->select('egw_addressbook_extra','contact_id,contact_name,contact_value',
"contact_name IN ('ophone','address2','address3','freebusy_url') AND contact_value != '' AND NOT contact_value IS NULL"
,__LINE__,__FILE__,false,'','addressbook');
$old2new = array(
'ophone' => 'tel_other',
'address2' => 'adr_one_street2',
'address3' => 'adr_two_street2',
'freebusy_url' => 'contact_freebusy_uri',
);
while (($row = $GLOBALS['egw_setup']->db->row(true)))
{
$db2->update('egw_addressbook',array($old2new[$row['contact_name']] => $row['contact_value']),array(
'contact_id' => $row['contact_id'],
'('.$old2new[$row['contact_name']].'IS NULL OR '.$old2new[$row['contact_name']]."='')",
),__LINE__,__FILE__,'addressbook');
}
// delete the not longer used custom fields plus rubish from old bugs
$GLOBALS['egw_setup']->db->delete('egw_addressbook_extra',"contact_name IN ('ophone','address2','address3','freebusy_url','cat_id','tid','lid','id','ab_id','access','owner','rights')".
" OR contact_value='' OR contact_value IS NULL".
($db2->capabilities['subqueries'] ? " OR contact_id NOT IN (SELECT contact_id FROM egw_addressbook)" : ''),
__LINE__,__FILE__,'addressbook');
// change the m/d/Y birthday format to Y-m-d
$GLOBALS['egw_setup']->db->select('egw_addressbook','contact_id,contact_bday',"contact_bday != ''",
__LINE__,__FILE__,false,'','addressbook');
while (($row = $GLOBALS['egw_setup']->db->row(true)))
{
list($m,$d,$y) = explode('/',$row['contact_bday']);
$db2->update('egw_addressbook',array(
'contact_bday' => sprintf('%04d-%02d-%02d',$y,$m,$d)
),array(
'contact_id' => $row['contact_id'],
),__LINE__,__FILE__,'addressbook');
}
return $GLOBALS['setup_info']['addressbook']['currentver'] = '1.3.001';
}

View File

@ -11,28 +11,51 @@
<!-- END header -->
<!-- BEGIN body -->
<tr class="th">
<td colspan="2">&nbsp;<b>{lang_Addressbook}/{lang_Contact_Settings}</b></td>
<td colspan="2">&nbsp;<b>{lang_Telephony_integration}</b></td>
</tr>
<tr class="row_on">
<td>&nbsp;{lang_URL_to_link_telephone_numbers_to_(use_%1_for_the_number)}:</td>
<td><input name="newsettings[call_link]" value="{value_call_link}" size="40"></td>
</tr>
<tr class="row_off">
<td>{lang_Select_where_you_want_to_store_/_retrieve_contacts}.</td>
<td>&nbsp;{lang_Size_of_popup_(WxH,_eg.400x300,_if_a_popup_should_be_used)}:</td>
<td><input name="newsettings[call_popup]" value="{value_call_popup}" size="10"></td>
</tr>
<tr class="th">
<td colspan="2">&nbsp;<b>{lang_Contact_repository}</b></td>
</tr>
<tr class="row_on">
<td>&nbsp;{lang_Select_where_you_want_to_store_/_retrieve_contacts}:</td>
<td>
<select name="newsettings[contact_repository]">
<option value="sql" {selected_contact_repository_sql}>SQL</option>
<option value="ldap" {selected_contact_repository_ldap}>LDAP</option>
{hook_contact_repositories}
</select>
</td>
</tr>
<tr class="row_off">
<td colspan="2">&nbsp;{lang_You_can_only_use_LDAP_as_contact_repository_if_the_accounts_are_stored_in_LDAP_too!}</td>
</tr>
<tr class="row_on">
<td>{lang_LDAP_host_for_contacts}:</td>
<td>&nbsp;{lang_Account_repository}:</td>
<td>
<b><script>document.write('{value_account_reposiory}' == 'ldap' || '{value_account_reposiory}' == '' && '{value_auth_type}' == 'ldap' ? 'LDAP' : 'SQL');</script></b>
({lang_Can_be_changed_via_Setup_>>_Configuration})
</td>
</tr>
<tr class="th">
<td colspan="2">&nbsp;<b>{lang_LDAP_settings_for_contacts}</b></td>
</tr>
<tr class="row_on">
<td>&nbsp;{lang_LDAP_host_for_contacts}:</td>
<td><input name="newsettings[ldap_contact_host]" value="{value_ldap_contact_host}"></td>
</tr>
<tr class="row_off">
<td>{lang_LDAP_context_for_contacts}:</td>
<td>&nbsp;{lang_LDAP_context_for_contacts}:</td>
<td><input name="newsettings[ldap_contact_context]" value="{value_ldap_contact_context}" size="40"></td>
</tr>
<tr class="th">
<td colspan="2">
{lang_Additional_information_about_using_LDAP_as_contact_repository}:
&nbsp;{lang_Additional_information_about_using_LDAP_as_contact_repository}:
<a href="addressbook/doc/README" target="_blank">README</a>
</td>
</tr>

View File

@ -113,10 +113,10 @@
<description id="${row}[adr_two_street2]" no_lang="1"/>
</vbox>
<vbox orient=",0,0">
<description no_lang="1" id="${row}[tel_work]" class="telNumbers" options=",$row_cont[tel_work_link],,,,$row_cont[call_popup]"/>
<description id="${row}[tel_cell]" no_lang="1" class="telNumbers" options=",$row_cont[tel_cell_link],,,,$row_cont[call_popup]"/>
<description id="${row}[tel_home]" no_lang="1" class="telNumbers" options=",$row_cont[tel_home_link],,,,$row_cont[call_popup]"/>
<description id="${row}[tel_prefered]" no_lang="1" options=",$row_cont[tel_prefered_link],,,,$row_cont[call_popup]"/>
<description no_lang="1" id="${row}[tel_work]" class="telNumbers" options=",$row_cont[tel_work_link],,,calling,$cont[call_popup]"/>
<description id="${row}[tel_cell]" no_lang="1" class="telNumbers" options=",$row_cont[tel_cell_link],,,calling,$cont[call_popup]"/>
<description id="${row}[tel_home]" no_lang="1" class="telNumbers" options=",$row_cont[tel_home_link],,,calling,$cont[call_popup]"/>
<description id="${row}[tel_prefered]" no_lang="1" options=",$row_cont[tel_prefered_link],,,calling,$cont[call_popup]"/>
</vbox>
<vbox orient=",0,0">
<description options=",,1" class="fixedHeight" no_lang="1" id="${row}[url]"/>