uid and etag (optimistic locking) for addressbook

This commit is contained in:
Ralf Becker 2008-04-25 19:06:15 +00:00
parent 684d6551f2
commit 86368a1903
11 changed files with 242 additions and 159 deletions

View File

@ -8,7 +8,7 @@
* @package addressbook
* @copyright (c) 2005/6 by Cornelius Weiss <egw@von-und-zu-weiss.de> and Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
* @version $Id$
*/
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.socontacts.inc.php');
@ -34,12 +34,12 @@ class bocontacts extends socontacts
* @var int $now_su actual user (!) time
*/
var $now_su;
/**
* @var array $timestamps timestamps
*/
var $timestamps = array('modified','created');
/**
* @var array $fileas_types
*/
@ -61,7 +61,7 @@ class bocontacts extends socontacts
'n_family, n_prefix',
'n_fn',
);
/**
* @var array $org_fields fields belonging to the (virtual) organisation entry
*/
@ -95,7 +95,7 @@ class bocontacts extends socontacts
* @var double $org_common_factor minimum percentage of the contacts with identical values to construct the "common" (virtual) org-entry
*/
var $org_common_factor = 0.6;
var $contact_fields = array();
var $business_contact_fields = array();
var $home_contact_fields = array();
@ -128,17 +128,17 @@ class bocontacts extends socontacts
function bocontacts($contact_app='addressbook')
{
$this->socontacts($contact_app);
$this->tz_offset_s = 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
$this->now_su = time() + $this->tz_offset_s;
$this->prefs =& $GLOBALS['egw_info']['user']['preferences']['addressbook'];
// get the default addressbook from the users prefs
$this->default_addressbook = $GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] ?
$this->default_addressbook = $GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] ?
(int)$GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] : $this->user;
$this->default_private = substr($GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'],-1) == 'p';
$this->default_private = substr($GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'],-1) == 'p';
if ($this->default_addressbook > 0 && $this->default_addressbook != $this->user &&
($this->default_private ||
($this->default_private ||
$this->default_addressbook == (int)$GLOBALS['egw']->preferences->forced['addressbook']['add_default'] ||
$this->default_addressbook == (int)$GLOBALS['egw']->preferences->default['addressbook']['add_default']))
{
@ -251,7 +251,7 @@ class bocontacts extends socontacts
$this->org_fields = unserialize($GLOBALS['egw_info']['server']['org_fileds_to_update']);
}
}
/**
* calculate the file_as string from the contact and the file_as type
*
@ -263,13 +263,13 @@ class bocontacts extends socontacts
{
if (is_null($type)) $type = $contact['fileas_type'];
if (!$type) $type = $this->fileas_types[0];
if (strpos($type,'n_fn') !== false) $contact['n_fn'] = $this->fullname($contact);
$fileas = str_replace(array('n_prefix','n_given','n_middle','n_family','n_suffix','n_fn','org_name','org_unit','adr_one_locality'),
array($contact['n_prefix'],$contact['n_given'],$contact['n_middle'],$contact['n_family'],$contact['n_suffix'],
$contact['n_fn'],$contact['org_name'],$contact['org_unit'],$contact['adr_one_locality']),$type);
// removing empty delimiters, caused by empty contact fields
$fileas = str_replace(array(', , : ',', : ',': , ',', , ',': : '),array(': ',': ',': ',', ',': '),$fileas);
while ($fileas{0} == ':' || $fileas{0} == ',') $fileas = substr($fileas,2);
@ -289,7 +289,7 @@ class bocontacts extends socontacts
function fileas_type($contact,$file_as=null)
{
if (is_null($file_as)) $file_as = $contact['n_fileas'];
if ($file_as)
{
foreach($this->fileas_types as $type)
@ -355,7 +355,7 @@ class bocontacts extends socontacts
* it gets called everytime when data is read from the db
* This function needs to be reimplemented in the derived class
*
* @param array $data
* @param array $data
*/
function db2data($data)
{
@ -368,7 +368,7 @@ class bocontacts extends socontacts
}
}
$data['photo'] = $this->photo_src($data['id'],$data['jpegphoto']);
// set freebusy_uri for accounts
if (!$data['freebusy_uri'] && !$data['owner'] && $data['account_id'] && !is_object($GLOBALS['egw_setup']))
{
@ -378,7 +378,7 @@ class bocontacts extends socontacts
}
return $data;
}
/**
* src for photo: returns array with linkparams if jpeg exists or the $default image-name if not
* @param int $id contact_id
@ -448,7 +448,7 @@ class bocontacts extends socontacts
}
return true;
}
/**
* saves contact to db
*
@ -488,7 +488,7 @@ class bocontacts extends socontacts
// allow admins to import contacts with creator / created date set
if (!$contact['creator'] || !$this->is_admin($contact)) $contact['creator'] = $this->user;
if (!$contact['created'] || !$this->is_admin($contact)) $contact['created'] = $this->now_su;
if (!$contact['tid']) $contact['tid'] = 'n';
}
if (!$contact['owner'])
@ -529,8 +529,9 @@ class bocontacts extends socontacts
if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory))
{
$contact['id'] = $to_write['id'];
$contact['etag'] = $to_write['etag'];
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time());
if ($contact['account_id']) // invalidate the cache of the accounts class
{
$GLOBALS['egw']->accounts->cache_invalidate($contact['account_id']);
@ -545,11 +546,11 @@ class bocontacts extends socontacts
return $this->error ? false : $contact['id'];
}
/**
* reads contacts matched by key and puts all cols in the data array
*
* @param int/string $contact_id
* @param int/string $contact_id
* @return array/boolean array with contact data, null if not found or false on no view perms
*/
function read($contact_id)
@ -564,10 +565,10 @@ class bocontacts extends socontacts
}
// determine the file-as type
$data['fileas_type'] = $this->fileas_type($data);
return $data;
}
/**
* Checks if the current user has the necessary ACL rights
*
@ -581,13 +582,13 @@ class bocontacts extends socontacts
*/
function check_perms($needed,$contact,$deny_account_delete=false)
{
if ((!is_array($contact) || !isset($contact['owner'])) &&
if ((!is_array($contact) || !isset($contact['owner'])) &&
!($contact = parent::read(is_array($contact) ? $contact['id'] : $contact)))
{
return null;
}
$owner = $contact['owner'];
// allow the user to edit his own account
if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $this->user && $this->own_account_acl)
{
@ -598,10 +599,10 @@ class bocontacts extends socontacts
{
return false;
}
return ($this->grants[$owner] & $needed) &&
return ($this->grants[$owner] & $needed) &&
(!$contact['private'] || ($this->grants[$owner] & EGW_ACL_PRIVATE) || in_array($owner,$this->memberships));
}
/**
* Read (virtual) org-entry (values "common" for most contacts in the given org)
*
@ -611,7 +612,7 @@ class bocontacts extends socontacts
function read_org($org_id)
{
if (!$org_id) return false;
$org = array();
foreach(explode('|||',$org_id) as $part)
{
@ -666,7 +667,7 @@ class bocontacts extends socontacts
unset($contact);
}
}
// create a statistic about the commonness of each fields values
$fields = array();
foreach($contacts as $contact)
@ -716,7 +717,7 @@ class bocontacts extends socontacts
}
return $org;
}
/**
* Return all org-members with same content in one or more of the given fields (only org_fields are counting)
*
@ -736,7 +737,7 @@ class bocontacts extends socontacts
}
return parent::search($criteria,false,'n_family,n_given','','',false,'OR',false,array('org_name'=>$org_name));
}
/**
* Return the changed fields from two versions of a contact (not modified or modifier)
*
@ -761,7 +762,7 @@ class bocontacts extends socontacts
}
return $changed;
}
/**
* Change given fields in all members of the org with identical content in the field
*
@ -770,7 +771,7 @@ class bocontacts extends socontacts
* @param array $to changed/new version of the contact
* @param array $members=null org-members to change, default null --> function queries them itself
* @return array/boolean (changed-members,changed-fields,failed-members) or false if no org_fields changed or no (other) members matching that fields
*/
*/
function change_org($org_name,$from,$to,$members=null)
{
if (!($changed = $this->changed_fields($from,$to,true))) return false;
@ -780,7 +781,7 @@ class bocontacts extends socontacts
$members = $this->org_similar($org_name,$changed);
}
if (!$members) return false;
$changed_members = $changed_fields = $failed_members = 0;
foreach($members as $member)
{
@ -812,7 +813,7 @@ class bocontacts extends socontacts
/**
* get title for a contact identified by $contact
*
*
* Is called as hook to participate in the linking. The format is determined by the link_title preference.
*
* @param int/string/array $contact int/string id or array with contact
@ -839,7 +840,7 @@ class bocontacts extends socontacts
/**
* get title for multiple contacts identified by $ids
*
*
* Is called as hook to participate in the linking. The format is determined by the link_title preference.
*
* @param array $ids array with contact-id's
@ -901,61 +902,22 @@ class bocontacts extends socontacts
}
return $result;
}
/**
* Hook called by link-class to include calendar in the appregistry of the linkage
*
* @param array/string $location location and other parameters (not used)
* @return array with method-names
*/
function search_link($location)
{
return array(
'query' => 'addressbook.bocontacts.link_query',
'title' => 'addressbook.bocontacts.link_title',
'titles' => 'addressbook.bocontacts.link_titles',
'view' => array(
'menuaction' => 'addressbook.uicontacts.view'
),
'view_id' => 'contact_id',
'add' => array(
'menuaction' => 'addressbook.uicontacts.edit'
),
'add_app' => 'link_app',
'add_id' => 'link_id',
'add_popup' => '850x440',
);
}
/**
* Register contacts as calendar resources (items which can be sheduled by the calendar)
*
* @param array $args hook-params (not used)
* @return array
*/
function calendar_resources($args)
{
return array(
'type' => 'c',// one char type-identifiy for this resources
'info' => 'addressbook.bocontacts.calendar_info',// info method, returns array with id, type & name for a given id
);
}
/**
* returns info about contacts for calender
*
* @param int/array $ids single contact-id or array of id's
* @return array
* @return array
*/
function calendar_info($ids)
{
if (!$ids) return null;
$data = array();
foreach(!is_array($ids) ? array($ids) : $ids as $id)
{
if (!($contact = $this->read($id))) continue;
$data[] = array(
'res_id' => $id,
'email' => $contact['email'] ? $contact['email'] : $contact['email_home'],
@ -980,7 +942,7 @@ class bocontacts extends socontacts
/**
* Called by edit-account hook, when an account get edited --> not longer used
*
*
* This function is still there, to not give a fatal error, if the hook still exists.
* Can be removed after the next db-update, which also reloads the hooks. RalfBecker 2006/09/18
*
@ -992,10 +954,10 @@ class bocontacts extends socontacts
include(EGW_INCLUDE_ROOT.'/addressbook/setup/setup.inc.php');
$GLOBALS['egw']->hooks->register_hooks('addressbook',$setup_info['addressbook']['hooks']);
}
/**
* Merges some given addresses into the first one and delete the others
*
*
* If one of the other addresses is an account, everything is merged into the account.
* If two accounts are in $ids, the function fails (returns false).
*
@ -1012,7 +974,7 @@ class bocontacts extends socontacts
if (!is_null($account))
{
echo $this->error = 'Can not merge more then one account!';
return false; // we dont deal with two accounts!
return false; // we dont deal with two accounts!
}
$account = $contact;
continue;
@ -1053,7 +1015,7 @@ class bocontacts extends socontacts
if (!is_array($target['cat_id'])) $target['cat_id'] = $target['cat_id'] ? explode(',',$target['cat_id']) : array();
$target['cat_id'] = array_unique(array_merge($target['cat_id'],is_array($value)?$value:explode(',',$value)));
break;
default:
if (!$target[$name]) $target[$name] = $value;
break;
@ -1061,7 +1023,7 @@ class bocontacts extends socontacts
}
}
if (!$this->save($target)) return 0;
$success = 1;
foreach($contacts as $contact)
{
@ -1077,7 +1039,7 @@ class bocontacts extends socontacts
}
return $success;
}
/**
* Check if user has required rights for a list or list-owner
*
@ -1089,12 +1051,12 @@ class bocontacts extends socontacts
function check_list($list,$required,$owner=null)
{
if ($list && ($list_data = $this->read_list($list)))
{
{
$owner = $list_data['list_owner'];
}
return !!($this->grants[$owner] & $required);
}
/**
* Adds a distribution list
*
@ -1106,10 +1068,10 @@ class bocontacts extends socontacts
function add_list($name,$owner,$contacts=array())
{
if (!$this->check_list(null,EGW_ACL_ADD,$owner)) return false;
return parent::add_list($name,$owner,$contacts);
}
/**
* Adds one contact to a distribution list
*
@ -1120,10 +1082,10 @@ class bocontacts extends socontacts
function add2list($contact,$list)
{
if (!$this->check_list($list,EGW_ACL_EDIT)) return false;
return parent::add2list($contact,$list);
}
/**
* Removes one contact from distribution list(s)
*
@ -1134,7 +1096,7 @@ class bocontacts extends socontacts
function remove_from_list($contact,$list=null)
{
if ($list && !$this->check_list($list,EGW_ACL_EDIT)) return false;
return parent::remove_from_list($contact,$list);
}
@ -1147,10 +1109,10 @@ class bocontacts extends socontacts
function delete_list($list)
{
if (!$this->check_list($list,EGW_ACL_DELETE)) return false;
return parent::delete_list($list);
}
/**
* Read data of a distribution list
*
@ -1160,20 +1122,20 @@ class bocontacts extends socontacts
function read_list($list)
{
static $cache;
if (isset($cache[$list])) return $cache[$list];
return $cache[$list] = parent::read_list($list);
return $cache[$list] = parent::read_list($list);
}
/**
* Get the address-format of a country
*
* This is a good reference where I got nearly all information, thanks to mikaelarhelger-AT-gmail.com
* http://www.bitboost.com/ref/international-address-formats.html
*
*
* Mail me (RalfBecker-AT-outdoor-training.de) if you want your nation added or fixed.
*
*
* @param string $country
* @return string 'city_state_postcode' (eg. US) or 'postcode_city' (eg. DE)
*/
@ -1200,7 +1162,7 @@ class bocontacts extends socontacts
case 'US':
$adr_format = 'city_state_postcode';
break;
case 'AR':
case 'AT':
case 'BE':
@ -1229,7 +1191,7 @@ class bocontacts extends socontacts
case 'SE':
$adr_format = 'postcode_city';
break;
default:
$adr_format = $this->prefs['addr_format'] ? $this->prefs['addr_format'] : 'postcode_city';
}
@ -1305,7 +1267,7 @@ class bocontacts extends socontacts
{
$contact['n_fn'] = $this->fullname($contact);
}
if (!isset($contact['n_fileas']) || empty($contact['n_fileas']))
{
$contact['n_fileas'] = $this->fileas($contact);

View File

@ -464,6 +464,7 @@ class socontacts
if (!($error_nr = $this->somain->save()))
{
$contact['id'] = $this->somain->data['id'];
$contact['etag'] = $this->somain->data['etag'];
if ($this->contact_repository == 'sql-ldap')
{

View File

@ -7,7 +7,7 @@
* @package addressbook
* @copyright (c) 2006-8 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
* @version $Id$
*/
include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
@ -15,11 +15,11 @@ include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
/**
* SQL storage object of the adressbook
*/
class socontacts_sql extends so_sql
class socontacts_sql extends so_sql
{
/**
* name of customefields table
*
*
* @var string
*/
var $extra_table = 'egw_addressbook_extra';
@ -29,7 +29,7 @@ class socontacts_sql extends so_sql
var $account_repository = 'sql';
var $contact_repository = 'sql';
var $grants;
/**
* internal name of the id, gets mapped to uid
*
@ -49,7 +49,7 @@ class socontacts_sql extends so_sql
* @var string
*/
var $ab2list_table = 'egw_addressbook2list';
function socontacts_sql()
{
$this->so_sql('phpgwapi','egw_addressbook',null,'contact_',true); // true = using the global db object, no clone!
@ -67,7 +67,7 @@ class socontacts_sql extends so_sql
$this->contact_repository = $GLOBALS['egw_info']['server']['contact_repository'];
}
}
/**
* Query organisations by given parameters
*
@ -82,7 +82,7 @@ class socontacts_sql extends so_sql
* @var int $param[num_rows]
* @var string $param[sort] ASC or DESC
* @return array or arrays with keys org_name,count and evtl. adr_one_location or org_unit
*/
*/
function organisations($param)
{
$filter = is_array($param['col_filter']) ? $param['col_filter'] : array();
@ -104,7 +104,7 @@ class socontacts_sql extends so_sql
if ($param['owner'])
{
if (!$this->grants[(int) $filter['owner']]) return false; // we have no access to that addressbook
$filter['owner'] = $param['owner'];
$filter['private'] = 0;
}
@ -142,7 +142,7 @@ class socontacts_sql extends so_sql
else // by adr_one_location or org_unit
{
// org total for more then one $by
$by_expr = $by == 'org_unit_count' ? "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END)" :
$by_expr = $by == 'org_unit_count' ? "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END)" :
"COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END)";
$append = "GROUP BY org_name HAVING $by_expr > 1 ORDER BY org_name $sort";
parent::search($param['search'],array('org_name'),$append,array(
@ -165,7 +165,7 @@ class socontacts_sql extends so_sql
}
$rows = parent::search($param['search'],array('org_name'),$append,$extra,'%',false,'OR',
array($param['start'],$param['num_rows']),$filter);
if (!$rows) return false;
// query the values for *_count == 1, to display them instead
@ -177,10 +177,10 @@ class socontacts_sql extends so_sql
$filter['org_name'][$row['org_name']] = $row['org_name']; // use as key too to have every org only once
}
$org_key = $row['org_name'].($by ? '|||'.($row[$by] || $row[$by.'_count']==1 ? $row[$by] : '|||') : '');
$orgs[$org_key] = $row;
$orgs[$org_key] = $row;
}
unset($rows);
if (count($filter['org_name']))
{
foreach((array) parent::search($criteria,array('org_name','org_unit','adr_one_locality'),'GROUP BY org_name,org_unit,adr_one_locality',
@ -219,7 +219,7 @@ class socontacts_sql extends so_sql
* For a union-query you call search for each query with $start=='UNION' and one more with only $order_by and $start set to run the union-query.
*
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
* @param boolean/string/array $only_keys=true True returns only keys, False returns all cols. or
* @param boolean/string/array $only_keys=true True returns only keys, False returns all cols. or
* comma seperated list or array of columns to return
* @param string $order_by='' fieldnames + {ASC|DESC} separated by colons ',', can also contain a GROUP BY (if it contains ORDER BY)
* @param string/array $extra_cols='' string or array of strings to be added to the SELECT, eg. "count(*) as num"
@ -228,7 +228,7 @@ class socontacts_sql extends so_sql
* @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), or 'UNION' for a part of a union query
* @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, added as is after the table-name, eg. ", table2 WHERE x=y" or
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
* @return boolean/array of matching rows (the row is an array of the cols) or False
@ -250,7 +250,7 @@ class socontacts_sql extends so_sql
$filter[] = $this->_cat_filter((int)$filter['cat_id'],$not);
unset($filter['cat_id']);
}
// add filter for read ACL in sql, if user is NOT the owner of the addressbook
if (isset($this->grants) && !(isset($filter['owner']) && $filter['owner'] == $GLOBALS['egw_info']['user']['account_id']))
{
@ -258,7 +258,7 @@ class socontacts_sql extends so_sql
if (isset($filter['owner']))
{
if (!$this->grants[(int) $filter['owner']]) return false; // we have no access to that addressbook
$filter['private'] = 0;
}
else // search all addressbooks, incl. accounts
@ -400,16 +400,16 @@ class socontacts_sql extends so_sql
}
}
$rows =& parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
if ($start === false) $this->total = is_array($rows) ? count($rows) : 0; // so_sql sets total only for $start !== false!
return $rows;
}
/**
* fix cat_id filter to search in comma-separated multiple cats and return subcats
*
* @internal
*
* @internal
* @param int $cat_id
* @return string sql to filter by given cat
*/
@ -430,11 +430,11 @@ class socontacts_sql extends so_sql
}
return $cfilter;
}
/**
* fix cat_id criteria to search in comma-separated multiple cats
*
* @internal
*
* @internal
* @param int/array $cats
* @return array of sql-strings to be OR'ed or AND'ed together
*/
@ -447,7 +447,7 @@ class socontacts_sql extends so_sql
}
return $cat_filter;
}
/**
* Change the ownership of contacts owned by a given account
*
@ -472,7 +472,7 @@ class socontacts_sql extends so_sql
*
* @param array $uids user or group id's
* @return array with list_id => array(list_id,list_name,list_owner,...) pairs
*/
*/
function get_lists($uids)
{
$user = $GLOBALS['egw_info']['user']['account_id'];
@ -485,7 +485,7 @@ class socontacts_sql extends so_sql
//echo "<p>socontacts_sql::get_lists(".print_r($uids,true).")</p>\n"; _debug_array($lists);
return $lists;
}
/**
* Adds a distribution list
*
@ -497,7 +497,7 @@ class socontacts_sql extends so_sql
function add_list($name,$owner,$contacts=array())
{
if (!$name || !(int)$owner) return false;
if ($this->db->select($this->lists_table,'list_id',array(
'list_name' => $name,
'list_owner' => $owner,
@ -511,7 +511,7 @@ class socontacts_sql extends so_sql
'list_created' => time(),
'list_creator' => $GLOBALS['egw_info']['user']['account_id'],
),array(),__LINE__,__FILE__)) return false;
if ((int)($list_id = $this->db->get_last_insert_id($this->lists_table,'list_id')) && $contacts)
{
foreach($contacts as $contact)
@ -521,7 +521,7 @@ class socontacts_sql extends so_sql
}
return $list_id;
}
/**
* Adds one contact to a distribution list
*
@ -547,7 +547,7 @@ class socontacts_sql extends so_sql
'list_added_by' => $GLOBALS['egw_info']['user']['account_id'],
),array(),__LINE__,__FILE__);
}
/**
* Removes one contact from distribution list(s)
*
@ -558,7 +558,7 @@ class socontacts_sql extends so_sql
function remove_from_list($contact,$list=null)
{
if (!(int)$list && !is_null($list) || !(int)$contact) return false;
$where = array(
'contact_id' => $contact,
);
@ -566,7 +566,7 @@ class socontacts_sql extends so_sql
return $this->db->delete($this->ab2list_table,$where,__LINE__,__FILE__);
}
/**
* Deletes a distribution list (incl. it's members)
*
@ -576,13 +576,65 @@ class socontacts_sql extends so_sql
function delete_list($list)
{
if (!$this->db->delete($this->lists_table,array('list_id' => $list),__LINE__,__FILE__)) return false;
$this->db->delete($this->ab2list_table,array('list_id' => $list),__LINE__,__FILE__);
return $this->db->affected_rows();
return $this->db->affected_rows();
}
/**
* Reads a contact, reimplemented to use the uid, if a non-numeric key is given
*
* @param int|string|array $keys
* @param string|array $extra_cols
* @param string $join
* @return array|boolean
*/
function read($keys,$extra_cols='',$join='')
{
if (!is_array($keys) && !is_numeric($keys))
{
$keys = array('contact_uid' => $keys);
}
return parent::read($keys,$extra_cols,$join);
}
/**
* Saves a contact, reimplemented to check a given etag and set a uid
*
* @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param string|array $extra_where=null extra where clause, eg. to check the etag, returns 'nothing_affected' if not affected rows
* @return int 0 on success and errno != 0 else
*/
function save($keys=null)
{
if (is_array($keys) && count($keys)) $this->data_merge($keys);
if (isset($this->data['etag']))
{
$etag = $this->data['etag'];
unset($this->data['etag']);
if (!($err = parent::save(array('contact_etag=contact_etag+1'),array('contact_etag' => $etag))))
{
$this->data['etag'] = $etag+1;
}
else
{
$this->data['etag'] = $etag;
}
}
else
{
$err = parent::save();
}
if (!$err && !$this->data['uid'])
{
$this->update(array('uid' => common::generate_uid('addressbook',$this->data['id'])));
}
return $err;
}
/**
* Read data of a distribution list
*
@ -592,7 +644,7 @@ class socontacts_sql extends so_sql
function read_list($list)
{
if (!$list) return false;
return $this->db->select($this->lists_table,'*',array('list_id'=>$list),__LINE__,__FILE__)->fetch();
}
}
}

View File

@ -1278,6 +1278,16 @@ class uicontacts extends bocontacts
}
}
}
elseif($this->error === true)
{
$content['msg'] = lang('Error: the entry has been updated since you opened it for editing!').'<br />'.
lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'.
htmlspecialchars($GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'addressbook.uicontacts.edit',
'contact_id' => $content['id'],
))).'">','</a>');
break; // dont refresh the list
}
else
{
$content['msg'] = lang('Error saving the contact !!!').

View File

@ -106,6 +106,7 @@ contacts to ldap, account contact-data to sql admin de Kontakte nach LDAP, Konta
contains addressbook de beinhaltet
copied by %1, from record #%2. addressbook de Kopiert von %1, vom Datensatz Nr. %2.
copy a contact and edit the copy addressbook de Kopiert einen Kontakt und bearbeitet dann die Kopie
copy your changes to the clipboard, %1reload the entry%2 and merge them. addressbook de Kopieren Sie Ihre Änderungen in die Zwischenablage, %1laden Sie den Eintrag neu%2 und fügen diese wieder ein.
country common de Land
create new links addressbook de Neue Verknüpfung erstellen
created addressbook de Angelegt
@ -158,6 +159,7 @@ end addressbook de Ende
enter the path to the exported file here addressbook de Bitte geben Sie den Pfad für die exportierte Datei an
error deleting the contact !!! addressbook de Fehler beim Löschen des Kontakts !!!
error saving the contact !!! addressbook de Fehler beim Speichern des Kontakts !!!
error: the entry has been updated since you opened it for editing! addressbook de Fehler: der Eintrag wurde geändert, seit Sie ihn zum Bearbeiten geöffnet haben!
example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook de Beispiel: "$$IF n_prefix~Herr~Sehr geehrter~Sehr geehrte$$" - suche in dem Feld "n_prefix" nach "Herr", wenn gefunden, schreibe "Sehr geehrter", wenn nicht gefunden schreibe "Sehr geehrte"
existing links addressbook de Bestehende Verknüpfungen
export addressbook de Export
@ -362,7 +364,7 @@ updated addressbook de Aktualisiert
upload or delete the photo addressbook de Foto hochladen oder löschen
url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin de URL mit denen Telefonnummern verlinkt werden sollen (verwenden Sie %1 = anzurufende Nummer, %u = Benutzernamen, %t = Telefon des Benutzers)
use an extra category tab? addressbook de Separaten Reiter für Kategorien verwenden?
use an extra tab for private custom fields? admin de Soll ein extra Tab für private Benutzerdefinierte Felder benutzt werden?
use an extra tab for private custom fields? admin de Separaten Reiter für private benutzerdefinierte Felder verwenden?
use country list addressbook de Länderliste benutzen
use setup for a full account-migration admin de für eine komplette Benutzer Migration setup verwenden
used for links and for the own sorting of the list addressbook de wird für Verküpfungen und die eigene Sortierung der Liste benützt

View File

@ -106,6 +106,7 @@ contacts to ldap, account contact-data to sql admin en contacts to LDAP, account
contains addressbook en contains
copied by %1, from record #%2. addressbook en Copied by %1, from record #%2.
copy a contact and edit the copy addressbook en Copy a contact and edit the copy
copy your changes to the clipboard, %1reload the entry%2 and merge them. addressbook en Copy your changes to the clipboard, %1reload the entry%2 and merge them.
country common en Country
create new links addressbook en Create new links
created addressbook en Created
@ -158,6 +159,7 @@ end addressbook en End
enter the path to the exported file here addressbook en Enter the path to the exported file here
error deleting the contact !!! addressbook en Error deleting the contact !!!
error saving the contact !!! addressbook en Error saving the contact !!!
error: the entry has been updated since you opened it for editing! addressbook en Error: the entry has been updated since you opened it for editing!
example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook en Example $$IF n_prefix~Mr~Hello Mr.~Hello Ms.$$ - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms.
existing links addressbook en Existing links
export addressbook en export

File diff suppressed because one or more lines are too long

View File

@ -53,7 +53,7 @@
</rows>
</grid>
</template>
<template id="addressbook.edit.general" template="" lang="" group="0" version="1.3.005">
<template id="addressbook.edit.general" template="" lang="" group="0" version="1.5.002">
<grid height="258">
<columns>
<column/>
@ -98,7 +98,7 @@
<row>
<image src="home"/>
<description value="Organisation"/>
<textbox id="org_name" size="45" maxlength="64" onchange="setName(this);"/>
<textbox id="org_name" size="45" maxlength="128" onchange="setName(this);"/>
</row>
<row>
<description/>
@ -326,6 +326,30 @@
</rows>
</grid>
</template>
<template id="addressbook.edit.distribution_list" template="" lang="" group="0" version="1.5.001">
<grid width="100%" height="258" overflow="auto">
<columns>
<column/>
</columns>
<rows>
<row class="th">
<description value="Distribution lists"/>
</row>
<row>
<grid>
<columns>
<column/>
</columns>
<rows>
<row>
<description span="all" id="distrib_lists"/>
</row>
</rows>
</grid>
</row>
</rows>
</grid>
</template>
<template id="addressbook.edit.custom" template="" lang="" group="0" version="1.5.001">
<grid width="100%" height="258" class="row_on" spacing="0" padding="0" overflow="auto">
<columns>
@ -443,7 +467,7 @@
</rows>
</grid>
</template>
<template id="addressbook.edit" template="" lang="" group="0" version="1.5.002">
<template id="addressbook.edit" template="" lang="" group="0" version="1.5.003">
<grid>
<columns>
<column width="450"/>
@ -451,7 +475,7 @@
</columns>
<rows>
<row disabled="!@msg">
<description span="all" class="redItalic" id="msg" no_lang="1"/>
<htmlarea span="all" class="redItalic" id="msg" no_lang="1" readonly="true"/>
<description/>
</row>
<row>
@ -481,6 +505,7 @@
<tab label="Private" statustext="Home address, Birthday, ..."/>
<tab label="Details" statustext="Categories, Notes, ..."/>
<tab label="Links" statustext="Links"/>
<tab label="Distribution lists" statustext="Distribution lists, ..."/>
<tab label="Extra" statustext="Custom fields"/>
<tab label="Extra private" statustext="Private custom fields"/>
</tabs>
@ -490,6 +515,7 @@
<template id="addressbook.edit.home"/>
<template id="addressbook.edit.details"/>
<template id="addressbook.edit.links"/>
<template id="addressbook.edit.distribution_list"/>
<template id="addressbook.edit.custom"/>
<template id="addressbook.edit.custom_private"/>
</tabpanels>
@ -561,12 +587,12 @@
<row>
<image src="email.png"/>
<description value="email" options=",,,email"/>
<textbox id="email" size="28" maxlength="64"/>
<textbox id="email" size="28" maxlength="128"/>
</row>
<row>
<description/>
<description value="Private" options=",,,email_home"/>
<textbox id="email_home" size="28" maxlength="64"/>
<textbox id="email_home" size="28" maxlength="128"/>
</row>
</rows>
</grid>

View File

@ -12,7 +12,7 @@
/* Basic information about this app */
$setup_info['phpgwapi']['name'] = 'phpgwapi';
$setup_info['phpgwapi']['title'] = 'eGroupWare API';
$setup_info['phpgwapi']['version'] = '1.5.008';
$setup_info['phpgwapi']['version'] = '1.5.009';
$setup_info['phpgwapi']['versions']['current_header'] = '1.28';
$setup_info['phpgwapi']['enable'] = 3;
$setup_info['phpgwapi']['app_order'] = 1;
@ -44,9 +44,9 @@ $setup_info['phpgwapi']['tables'][] = 'egw_addressbook_extra';
$setup_info['phpgwapi']['tables'][] = 'egw_addressbook_lists';
$setup_info['phpgwapi']['tables'][] = 'egw_addressbook2list';
$setup_info['phpgwapi']['tables'][] = 'egw_sqlfs';
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
$setup_info['phpgwapi']['tables'][] = 'egw_index';
$setup_info['phpgwapi']['tables'][] = 'egw_cat2entry';
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
$setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount';
@ -64,3 +64,4 @@ $setup_info['notifywindow']['enable'] = 2;
$setup_info['notifywindow']['app_order'] = 1;
$setup_info['notifywindow']['tables'] = '';
$setup_info['notifywindow']['hooks'][] = 'home';

View File

@ -383,11 +383,13 @@ $phpgw_baseline = array(
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'),
'account_id' => array('type' => 'int','precision' => '4')
'account_id' => array('type' => 'int','precision' => '4'),
'contact_etag' => array('type' => 'int','precision' => '4','default' => '0'),
'contact_uid' => array('type' => 'varchar','precision' => '255')
),
'pk' => array('contact_id'),
'fk' => array(),
'ix' => array('contact_owner','cat_id','n_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'ix' => array('contact_owner','cat_id','n_fileas','contact_uid',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array('account_id')
),
'egw_addressbook_extra' => array(
@ -484,5 +486,5 @@ $phpgw_baseline = array(
'fk' => array(),
'ix' => array('cat_id'),
'uc' => array()
),
)
);

View File

@ -363,4 +363,29 @@ function phpgwapi_upgrade1_5_007()
}
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.008';
}
}
$test[] = '1.5.008';
function phpgwapi_upgrade1_5_008()
{
// add UID and etag columns to addressbook, required eg. for CardDAV
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','contact_etag',array(
'type' => 'int',
'precision' => '4',
'default' => '0',
));
// add UID column to addressbook, required eg. for CardDAV
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','contact_uid',array(
'type' => 'varchar',
'precision' => '255'
));
$GLOBALS['egw_setup']->db->query("SELECT config_value FROM egw_config WHERE config_app='phpgwapi' AND config_name='install_id'",__LINE__,__FILE__);
$install_id = $GLOBALS['egw_setup']->db->next_record() ? $GLOBALS['egw_setup']->db->f(0) : md5(time());
$GLOBALS['egw_setup']->db->query('UPDATE egw_addressbook SET contact_uid='.$GLOBALS['egw_setup']->db->concat("'addressbook-'",'contact_id',"'-$install_id'"),__LINE__,__FILE__);
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_addressbook',array('contact_uid'),false);
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.009';
}