Update of /cvsroot/egroupware/addressbook/inc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5279/inc Modified Files: class.bocontacts.inc.php class.contacts_admin_prefs.inc.php class.socontacts.inc.php class.socontacts_sql.inc.php class.uicontacts.inc.php Log Message: addressbook can now group contacts by organisations (sql only atm.) and change organisational fields for all organisation members Index: class.bocontacts.inc.php =================================================================== RCS file: /cvsroot/egroupware/addressbook/inc/class.bocontacts.inc.php,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** class.bocontacts.inc.php 26 Apr 2006 21:23:09 -0000 1.13 --- class.bocontacts.inc.php 30 Apr 2006 09:34:22 -0000 1.14 *************** *** 64,67 **** --- 64,93 ---- ); + /** + * @var array $org_fields fields belonging to the (virtual) organisation entry + */ + var $org_fields = array( + 'org_name', + 'org_unit', + 'adr_one_street', + 'adr_one_street2', + 'adr_one_locality', + 'adr_one_region', + 'adr_one_postalcode', + 'adr_one_countryname', + 'label', + 'tel_work', + 'tel_fax', + 'tel_assistent', + 'assistent', + 'email', + 'url', + 'tz', + ); + /** + * @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(); *************** *** 442,445 **** --- 468,611 ---- (!$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) + * + * @param string $org_id org_name:oooooo|||org_unit:uuuuuuuuu|||adr_one_locality:lllllll (org_unit and adr_one_locality are optional) + * @return array/boolean array with common org fields or false if org not found + */ + function read_org($org_id) + { + if (!$org_id) return false; + + $org = array(); + foreach(explode('|||',$org_id) as $part) + { + list($name,$value) = explode(':',$part); + $org[$name] = $value; + } + $contacts = parent::search('',$this->org_fields,'','','',false,'AND',false,$org); + + if (!$contacts) return false; + + // create a statistic about the commonness of each fields values + $fields = array(); + foreach($contacts as $contact) + { + foreach($contact as $name => $value) + { + $fields[$name][$value]++; + } + } + foreach($fields as $name => $values) + { + if (!in_array($name,$this->org_fields)) continue; + + arsort($values,SORT_NUMERIC); + + list($value,$num) = each($values); + //echo "<p>$name: '$value' $num/".count($contacts)."=".($num / (double) count($contacts))." >= $this->org_common_factor = ".($num / (double) count($contacts) >= $this->org_common_factor ? 'true' : 'false')."</p>\n"; + if ($value && $num / (double) count($contacts) >= $this->org_common_factor) + { + $org[$name] = $value; + } + } + echo $org_id; _debug_array($org); + + return $org; + } + + /** + * Return all org-members with same content in one or more of the given fields (only org_fields are counting) + * + * @param string $org_name + * @param array $fields field-name => value pairs + * @return array with contacts + */ + function org_similar($org_name,$fields) + { + $criteria = array(); + foreach($this->org_fields as $name) + { + if (isset($fields[$name])) + { + $criteria[$name] = $fields[$name]; + } + } + 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) + * + * @param array $from original/old version of the contact + * @param array $to changed/new version of the contact + * @param boolean $onld_org_fields=true check and return only org_fields, default true + * @return array with field-name => value from $from + */ + function changed_fields($from,$to,$only_org_fields=true) + { + $changed = array(); + foreach($only_org_fields ? $this->org_fields : array_keys($this->contact_fields) as $name) + { + if (!isset($from[$name]) || in_array($name,array('modified','modifier'))) // never count these + { + continue; + } + if ((string) $from[$name] != (string) $to[$name]) + { + $changed[$name] = $from[$name]; + } + } + return $changed; + } + + /** + * Change given fields in all members of the org with identical content in the field + * + * @param string $org_name + * @param array $from original/old version of the contact + * @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; + + if (is_null($members) || !is_array($members)) + { + $members = $this->org_similar($org_name,$changed); + } + if (!$members) return false; + + $changed_members = $changed_fields = $failed_members = 0; + foreach($members as $member) + { + $fields = 0; + foreach($changed as $name => $value) + { + if ((string)$value == (string)$member[$name]) + { + $member[$name] = $to[$name]; + //echo "<p>$member[n_family], $member[n_given]: $name='{$to[$name]}'</p>\n"; + ++$fields; + } + } + if ($fields) + { + if (!$this->check_perms(EGW_ACL_EDIT,$member) || !$this->save($member)) + { + ++$failed_members; + } + else + { + ++$changed_members; + $changed_fields += $fields; + } + } + } + return array($changed_members,$changed_fields,$failed_members); + } /** Index: class.contacts_admin_prefs.inc.php =================================================================== RCS file: /cvsroot/egroupware/addressbook/inc/class.contacts_admin_prefs.inc.php,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** class.contacts_admin_prefs.inc.php 26 Apr 2006 21:23:09 -0000 1.2 --- class.contacts_admin_prefs.inc.php 30 Apr 2006 09:34:22 -0000 1.3 *************** *** 57,61 **** // 'Advanced search'=>$GLOBALS['egw']->link('/index.php','menuaction=addressbook.uicontacts.search'), // 'import contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.import'), ! // 'export contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.export') 'CSV-Import' => $GLOBALS['egw']->link('/addressbook/csv_import.php') ); --- 57,61 ---- // 'Advanced search'=>$GLOBALS['egw']->link('/index.php','menuaction=addressbook.uicontacts.search'), // 'import contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.import'), ! // 'export contacts' => $GLOBALS['egw']->link('/index.php','menuaction=addressbook.uiXport.export'), 'CSV-Import' => $GLOBALS['egw']->link('/addressbook/csv_import.php') ); Index: class.socontacts.inc.php =================================================================== RCS file: /cvsroot/egroupware/addressbook/inc/class.socontacts.inc.php,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** class.socontacts.inc.php 26 Apr 2006 12:23:10 -0000 1.18 --- class.socontacts.inc.php 30 Apr 2006 09:34:23 -0000 1.19 *************** *** 94,97 **** --- 94,106 ---- var $total; + /** + * @var object $somain sql (socontacts_sql) or ldap (so_ldap) backend class + */ + var $somain; + /** + * @var so_sql-object $soextra custom fields backend + */ + var $soextra; + function socontacts($contact_app='addressbook') { *************** *** 148,155 **** $custom =& CreateObject('admin.customfields',$contact_app); $this->customfields = $custom->get_customfields(); - // if ($this->customfields && !is_array($this->customfields)) $this->customfields = unserialize($this->customfields); - // if (!$this->customfields) $this->customfields = array(); $this->content_types = $custom->get_content_types(); - // if ($this->content_types && !is_array($this->content_types)) $this->content_types = unserialize($this->content_types); if (!$this->content_types) { --- 157,161 ---- *************** *** 553,556 **** --- 559,621 ---- return $rows; } + + /** + * Query organisations by given parameters + * + * @var array $param + * @var string $param[org_view] 'org_name', 'org_name,adr_one_location', 'org_name,org_unit' how to group + * @var int $param[owner] addressbook to search + * @var string $param[search] search pattern for org_name + * @var string $param[searchletter] letter the org_name need to start with + * @var int $param[start] + * @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) + { + if (!method_exists($this->somain,'organisations')) return false; + + if ($param['search'] && !is_array($param['search'])) + { + $search = $param['search']; + $param['search'] = array(); + foreach($this->columns_to_search as $col) + { + if ($col != 'contact_value') $param['search'][$col] = $search; // we dont search the customfields + } + } + if (is_array($param['search']) && count($param['search'])) + { + $param['search'] = $this->data2db($param['search']); + } + $rows = $this->somain->organisations($param); + //echo "<p>socontacts::organisations(".print_r($param,true).")<br />".$this->somain->db->Query_ID->sql."</p>\n"; + + if (!$rows) return array(); + + list(,$by) = explode(',',$param['org_view']); + if (!$by) $by = 'adr_one_locality'; + + foreach($rows as $n => $row) + { + $rows[$n]['id'] = 'org_name:'.$row['org_name']; + foreach(array( + 'org_unit' => lang('departments'), + 'adr_one_locality' => lang('locations'), + ) as $by => $by_label) + { + if ($row[$by.'_count'] > 1) + { + $rows[$n][$by] = $row[$by.'_count'].' '.$by_label; + } + else + { + $rows[$n]['id'] .= '|||'.$by.':'.$row[$by]; + } + } + } + return $rows; + } /** Index: class.socontacts_sql.inc.php =================================================================== RCS file: /cvsroot/egroupware/addressbook/inc/class.socontacts_sql.inc.php,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** class.socontacts_sql.inc.php 26 Apr 2006 12:11:12 -0000 1.5 --- class.socontacts_sql.inc.php 30 Apr 2006 09:34:23 -0000 1.6 *************** *** 31,34 **** --- 31,163 ---- /** + * Query organisations by given parameters + * + * @var array $param + * @var string $param[org_view] 'org_name', 'org_name,adr_one_location', 'org_name,org_unit' how to group + * @var int $param[owner] addressbook to search + * @var string $param[search] search pattern for org_name + * @var string $param[searchletter] letter the org_name need to start with + * @var array $param[col_filter] filter + * @var string $param[search] or'ed search pattern + * @var int $param[start] + * @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(); + + // add filter for read ACL in sql, if user is NOT the owner of the addressbook + if ($param['owner'] && $param['owner'] == $GLOBALS['egw_info']['user']['account_id']) + { + $filter['owner'] = $param['owner']; + } + else + { + // we have no private grants in addressbook at the moment, they have then to be added here too + 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; + } + else // search all addressbooks, incl. accounts + { + $filter[] = "(contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id']. + " OR contact_private=0 AND contact_owner IN (". + implode(',',array_keys($this->grants))."))"; + } + } + if ($param['searchletter']) + { + $filter[] = 'org_name LIKE '.$this->db->quote($param['searchletter'].'%'); + } + else + { + $filter[] = "org_name != ''";// AND org_name IS NOT NULL"; + } + $sort = $param['sort'] == 'DESC' ? 'DESC' : 'ASC'; + + list(,$by) = explode(',',$param['org_view']); + if (!$by) + { + $extra = array( + 'COUNT(org_name) AS org_count', + "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END) AS org_unit_count", + "COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count", + ); + $append = "GROUP BY org_name ORDER BY org_name $sort"; + } + else // by adr_one_location or org_unit + { + // org total for more then one $by + $append = "GROUP BY org_name HAVING {$by}_count > 1 ORDER BY org_name $sort"; + parent::search($param['search'],array('org_name'),$append,array( + "NULL AS $by", + 'COUNT(org_name) AS org_count', + "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END) AS org_unit_count", + "COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count", + ),'%',false,'OR','UNION',$filter); + // org by location + $append = "GROUP BY org_name,$by ORDER BY org_name $sort,$by $sort"; + parent::search($param['search'],array('org_name'),$append,array( + "CASE WHEN $by IS NULL THEN '' ELSE $by END AS $by", + 'COUNT(org_name) AS org_count', + "COUNT(DISTINCT CASE WHEN org_unit IS NULL THEN '' ELSE org_unit END) AS org_unit_count", + "COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count", + ),'%',false,'OR','UNION',$filter); + $append = "ORDER BY org_name $sort,CASE WHEN $by IS NULL THEN 1 ELSE 2 END,$by $sort"; + } + $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 + $filter['org_name'] = $orgs = array(); + foreach($rows as $n => $row) + { + if ($row['org_unit_count'] == 1 || $row['adr_one_locality_count'] == 1) + { + $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; + } + 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', + '','%',false,'AND',false,$filter) as $row) + { + $org_key = $row['org_name'].($by ? '|||'.$row[$by] : ''); + if ($orgs[$org_key]['org_unit_count'] == 1) + { + $orgs[$org_key]['org_unit'] = $row['org_unit']; + } + if ($orgs[$org_key]['adr_one_locality_count'] == 1) + { + $orgs[$org_key]['adr_one_locality'] = $row['adr_one_locality']; + } + if ($by && isset($orgs[$org_key = $row['org_name'].'||||||'])) + { + if ($orgs[$org_key]['org_unit_count'] == 1) + { + $orgs[$org_key]['org_unit'] = $row['org_unit']; + } + if ($orgs[$org_key]['adr_one_locality_count'] == 1) + { + $orgs[$org_key]['adr_one_locality'] = $row['adr_one_locality']; + } + } + } + } + return array_values($orgs); + } + + /** * searches db for rows matching searchcriteria * Index: class.uicontacts.inc.php =================================================================== RCS file: /cvsroot/egroupware/addressbook/inc/class.uicontacts.inc.php,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -d -r1.24 -r1.25 *** class.uicontacts.inc.php 26 Apr 2006 21:23:09 -0000 1.24 --- class.uicontacts.inc.php 30 Apr 2006 09:34:23 -0000 1.25 *************** *** 39,42 **** --- 39,43 ---- */ var $private_addressbook = false; + var $org_views; function uicontacts($contact_app='addressbook') *************** *** 58,61 **** --- 59,68 ---- $this->prefs =& $GLOBALS['egw_info']['user']['preferences']['addressbook']; $this->private_addressbook = $this->contacts_repository == 'sql' && $this->prefs['private_addressbook']; + + $this->org_views = array( + 'org_name' => lang('Organisations'), + 'org_name,adr_one_locality' => lang('Organisations by location'), + 'org_name,org_unit' => lang('Organisations by departments'), + ); // our javascript *************** *** 72,75 **** --- 79,83 ---- function index($content=null,$msg=null) { + //echo "<p>uicontacts::index(".print_r($content,true).",'$msg')</p>\n"; if (is_array($content)) { *************** *** 100,103 **** --- 108,119 ---- } } + if ($content['nm']['rows']['view']) // show all contacts of an organisation + { + list($org_view) = each($content['nm']['rows']['view']); + } + else + { + $org_view = $content['nm']['org_view']; + } } $content = array( *************** *** 109,113 **** $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_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 --- 125,130 ---- $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' => '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 *************** *** 139,148 **** 'delete' => lang('Delete'), 'csv' => lang('Export as CSV'), ! 'vcard' => lang('Export as VCard'), )+$this->get_addressbooks(EGW_ACL_ADD); ! foreach($this->content_types as $tid => $data) { ! $sel_options['col_filter[tid]'][$tid] = $data['name']; } $this->tmpl->read('addressbook.index'); return $this->tmpl->exec('addressbook.uicontacts.index',$content,$sel_options,$readonlys,$preserv); --- 156,193 ---- 'delete' => lang('Delete'), 'csv' => lang('Export as CSV'), ! // ToDo: 'vcard' => lang('Export as VCard'), ! // ToDo: 'copy' => lang('Copy a contact and edit the copy'), )+$this->get_addressbooks(EGW_ACL_ADD); ! ! // dont show tid-selection if we have only one content_type ! if (count($this->content_types) <= 1) { ! $preserv['tid'] = 'n'; ! } ! else ! { ! $content['nm']['header_right'] = 'addressbook.index.right'; ! foreach($this->content_types as $tid => $data) ! { ! $sel_options['col_filter[tid]'][$tid] = $data['name']; ! } ! } ! ! // get the availible org-views plus the label of the contacts view of one org ! $sel_options['org_view'] = $this->org_views; ! if (isset($org_view)) $content['nm']['org_view'] = $org_view; ! if (!isset($sel_options['org_view'][(string) $content['nm']['org_view']])) ! { ! $org_name = array(); ! foreach(explode('|||',$content['nm']['org_view']) as $part) ! { ! list(,$name) = explode(':',$part,2); ! if ($name) $org_name[] = $name; ! } ! $org_name = implode(': ',$org_name); ! $sel_options['org_view'][(string) $content['nm']['org_view']] = $org_name; } + $content['nm']['org_view_label'] = $sel_options['org_view'][(string) $content['nm']['org_view']]; + $this->tmpl->read('addressbook.index'); return $this->tmpl->exec('addressbook.uicontacts.index',$content,$sel_options,$readonlys,$preserv); *************** *** 172,175 **** --- 217,237 ---- $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's } + // replace org_name:* id's with all id's of that org + $org_contacts = array(); + foreach($checked as $n => $id) + { + if (substr($id,0,9) == 'org_name:') + { + unset($checked[$n]); + $query = $GLOBALS['egw']->session->appsession('index','addressbook'); + $query['num_rows'] = -1; // all + $query['org_view'] = $id; + $this->get_rows($query,$extra,$readonlys,true); // true = only return the id's + if ($extra[0]) $org_contacts = array_merge($org_contacts,$extra); + } + } + if ($org_contacts) $checked = array_unique($checked ? array_merge($checked,$org_contacts) : $org_contacts); + //_debug_array($checked); return false; + switch($action) { *************** *** 282,290 **** // save the state of the index in the user prefs $state = serialize(array( ! 'filter' => $query['filter'], ! 'cat_id' => $query['cat_id'], ! 'order' => $query['order'], ! 'sort' => $query['sort'], 'col_filter' => array('tid' => $query['col_filter']['tid']), )); if ($state != $this->prefs['index_state']) --- 344,353 ---- // save the state of the index in the user prefs $state = serialize(array( ! 'filter' => $query['filter'], ! 'cat_id' => $query['cat_id'], ! 'order' => $query['order'], ! 'sort' => $query['sort'], 'col_filter' => array('tid' => $query['col_filter']['tid']), + 'org_view' => $query['org_view'], )); if ($state != $this->prefs['index_state']) *************** *** 313,346 **** } } ! // translate the select order to the realy used over all 3 columns ! $sort = $query['sort']; ! switch($query['order']) ! { ! case 'org_name': ! $order = "org_name $sort,n_family $sort,n_given $sort"; ! break; ! default: ! $query['order'] = 'n_family'; ! case 'n_family': ! $order = "n_family $sort,n_given $sort,org_name $sort"; ! break; ! case 'n_given': ! $order = "n_given $sort,n_family $sort,org_name $sort"; ! break; ! case 'n_fileas': ! $order = 'n_fileas '.$sort; ! break; ! } ! if ($query['searchletter']) // only show contacts which ordercriteria starts with the given letter { ! $query['col_filter'][] = $query['order'].' LIKE '.$GLOBALS['egw']->db->quote($query['searchletter'].'%'); } ! else // dont show contacts with empty order criteria { ! $query['col_filter'][] = $query['order']."!=''"; } ! $rows = (array) 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']); ! //echo "<p style='margin-top: 100px;'>".$this->somain->db->Query_ID->sql."</p>\n"; if ($id_only) --- 376,442 ---- } } ! if (isset($this->org_views[(string) $query['org_view']])) // we have an org view { ! $query['template'] = 'addressbook.index.org_rows'; ! ! if ($query['order'] != 'org_name') ! { ! $query['sort'] = 'ASC'; ! $query['order'] = 'org_name'; ! } ! $rows = parent::organisations($query); } ! else // contacts view { ! $query['template'] = 'addressbook.index.rows'; ! ! if ($query['org_view']) // view the contacts of one organisation only ! { ! foreach(explode('|||',$query['org_view']) as $part) ! { ! list($name,$value) = explode(':',$part,2); ! $query['col_filter'][$name] = $value; ! } ! } ! // translate the select order to the realy used over all 3 columns ! $sort = $query['sort']; ! switch($query['order']) ! { ! case 'org_name': ! $order = "org_name $sort,n_family $sort,n_given $sort"; ! break; ! default: ! $query['order'] = 'n_family'; ! case 'n_family': ! $order = "n_family $sort,n_given $sort,org_name $sort"; ! break; ! case 'n_given': ! $order = "n_given $sort,n_family $sort,org_name $sort"; ! break; ! case 'n_fileas': ! $order = 'n_fileas '.$sort; ! break; ! } ! if ($query['searchletter']) // only show contacts which ordercriteria starts with the given letter ! { ! $query['col_filter'][] = $query['order'].' LIKE '.$GLOBALS['egw']->db->quote($query['searchletter'].'%'); ! } ! else // dont show contacts with empty order criteria ! { ! $query['col_filter'][] = $query['order']."!=''"; ! } ! $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 ! { ! foreach((array) $rows as $n => $val) ! { ! if ($val) $ids[] = $val['id']; ! } ! if ($ids) $customfields = $this->read_customfields($ids); ! } } ! if (!$rows) $rows = array(); if ($id_only) *************** *** 352,367 **** return $this->total; // no need to set other fields or $readonlys } - if ($this->prefs['custom_colum'] != 'never' && $rows) // do we need the custom fields - { - foreach($rows as $n => $val) - { - $ids[] = $val['id']; - } - $customfields = $this->read_customfields($ids); - } $order = $query['order']; - if (!$rows) $rows = array(); - $readonlys = array(); $photos = $homeaddress = false; --- 448,453 ---- *************** *** 390,440 **** break; } ! $this->type_icon($row['owner'],$row['private'],$row['tid'],$row['type'],$row['type_label']); ! ! static $tel2show = array('tel_work','tel_cell','tel_home'); ! foreach($tel2show as $name) { ! $row[$name] .= ' '.($row['tel_prefer'] == $name ? '♥' : ''); // .' ' to NOT remove the field ! } ! // allways show the prefered phone, if not already shown ! if (!in_array($row['tel_prefer'],$tel2show) && $row[$row['tel_prefer']]) ! { ! $row['tel_prefered'] = $row[$row['tel_prefer']].' ♥'; } ! foreach(array('email','email_home') as $name) { ! if ($row[$name]) { ! $row[$name.'_link'] = $this->email2link($row[$name]); ! if ($GLOBALS['egw_info']['user']['apps']['felamimail']) { ! $row[$name.'_popup'] = '700x750'; } } ! else { ! $row[$name] = ' '; // to NOT remove the field } ! } ! $readonlys["delete[$row[id]]"] = !$this->check_perms(EGW_ACL_DELETE,$row); ! $readonlys["edit[$row[id]]"] = !$this->check_perms(EGW_ACL_EDIT,$row); ! ! if ($row['photo']) $photos = true; ! ! if (isset($customfields[$row['id']])) ! { ! foreach($this->customfields as $name => $data) { ! $row['customfields'][] = $customfields[$row['id']][$name]; } - } - if ($this->prefs['home_column'] != 'never' && !$homeaddress) - { - foreach(array('adr_two_countryname','adr_two_locality','adr_two_postalcode','adr_two_street','adr_two_street2') as $name) - { - if ($row[$name]) $homeaddress = true; } - } } // disable photo column, if view contains no photo(s) --- 476,536 ---- break; } ! if (isset($this->org_views[(string) $query['org_view']])) { + $row['type'] = 'home'; + $row['type_label'] = lang('Organisation'); ! $readonlys["delete[$row[id]]"] = $query['filter'] && !($this->grants[(int)$query['filter']] & EGW_ACL_DELETE); } ! else { ! $this->type_icon($row['owner'],$row['private'],$row['tid'],$row['type'],$row['type_label']); ! ! static $tel2show = array('tel_work','tel_cell','tel_home'); ! foreach($tel2show as $name) { ! ! $row[$name] .= ' '.($row['tel_prefer'] == $name ? '♥' : ''); // .' ' to NOT remove the field ! } ! // allways show the prefered phone, if not already shown ! if (!in_array($row['tel_prefer'],$tel2show) && $row[$row['tel_prefer']]) ! { ! $row['tel_prefered'] = $row[$row['tel_prefer']].' ♥'; ! } ! foreach(array('email','email_home') as $name) ! { ! if ($row[$name]) { ! $row[$name.'_link'] = $this->email2link($row[$name]); ! if ($GLOBALS['egw_info']['user']['apps']['felamimail']) ! { ! $row[$name.'_popup'] = '700x750'; ! } ! } ! else ! { ! $row[$name] = ' '; // to NOT remove the field } } ! $readonlys["delete[$row[id]]"] = !$this->check_perms(EGW_ACL_DELETE,$row); ! $readonlys["edit[$row[id]]"] = !$this->check_perms(EGW_ACL_EDIT,$row); ! ! if ($row['photo']) $photos = true; ! ! if (isset($customfields[$row['id']])) { ! foreach($this->customfields as $name => $data) ! { ! $row['customfields'][] = $customfields[$row['id']][$name]; ! } } ! if ($this->prefs['home_column'] != 'never' && !$homeaddress) { ! foreach(array('adr_two_countryname','adr_two_locality','adr_two_postalcode','adr_two_street','adr_two_street2') as $name) ! { ! if ($row[$name]) $homeaddress = true; ! } } } } // disable photo column, if view contains no photo(s) *************** *** 449,457 **** $rows['customfields'] = array_values($this->customfields); ! // full app-header with all search criteria for specially for the print $GLOBALS['egw_info']['flags']['app_header'] = lang('addressbook'); ! if ($query['filter'] !== '') { ! $GLOBALS['egw_info']['flags']['app_header'] .= ': '.($query['filter'] == '0' ? lang('accounts') : ($GLOBALS['egw']->accounts->get_type($query['filter']) == 'g' ? lang('Group %1',$GLOBALS['egw']->accounts->id2name($query['filter'])) : --- 545,553 ---- $rows['customfields'] = array_values($this->customfields); ! // full app-header with all search criteria specially for the print $GLOBALS['egw_info']['flags']['app_header'] = lang('addressbook'); ! if ($query['filter'] !== '' && !isset($this->org_views[$query['org_view']])) { ! $GLOBALS['egw_info']['flags']['app_header'] .= ' '.($query['filter'] == '0' ? lang('accounts') : ($GLOBALS['egw']->accounts->get_type($query['filter']) == 'g' ? lang('Group %1',$GLOBALS['egw']->accounts->id2name($query['filter'])) : *************** *** 459,462 **** --- 555,562 ---- (substr($query['filter'],-1) == 'p' ? ' ('.lang('private').')' : ''))); } + if ($query['org_view']) + { + $GLOBALS['egw_info']['flags']['app_header'] .= ': '.$query['org_view_label']; + } if ($query['cat_id']) { *************** *** 595,599 **** $links = $content['link_to']['to_id']; } ! $this->save($content); // writing links for new entry, existing ones are handled by the widget itself if ($links && $content['id']) --- 695,725 ---- $links = $content['link_to']['to_id']; } ! if ($content['id'] && $content['org_name'] && $content['change_org']) ! { ! $old_org_entry = $this->read($content['id']); ! } ! if ($this->save($content)) ! { ! $content['msg'] = lang('Contact saved'); ! if ($content['change_org'] && $old_org_entry && ($changed = $this->changed_fields($old_org_entry,$content,true)) && ! ($members = $this->org_similar($old_org_entry['org_name'],$changed))) ! { ! //foreach($changed as $name => $old_value) echo "<p>$name: '$old_value' --> '{$content[$name]}'</p>\n"; ! list($changed_members,$changed_fields,$failed_members) = $this->change_org($old_org_entry['org_name'],$changed,$content,$members); ! if ($changed_members) ! { ! $content['msg'] .= ', '.lang('%1 fields in %2 other organisation member(s) changed',$changed_fields,$changed_members); ! } ! if ($failed_members) ! { ! $content['msg'] .= ', '.lang('failed to change %1 organisation member(s) (insufficent rights) !!!',$failed_members); ! } ! } ! } ! else ! { ! $content['msg'] = lang('Error saving the contact !!!'); ! $button = 'apply'; // to not leave the dialog ! } // writing links for new entry, existing ones are handled by the widget itself if ($links && $content['id']) *************** *** 604,608 **** { echo "<html><body><script>var referer = opener.location;opener.location.href = referer+(referer.search?'&':'?')+'msg=". ! addslashes(urlencode(lang('Contact saved')))."'; window.close();</script></body></html>\n"; $GLOBALS['egw']->common->egw_exit(); } --- 730,734 ---- { echo "<html><body><script>var referer = opener.location;opener.location.href = referer+(referer.search?'&':'?')+'msg=". ! addslashes(urlencode($content['msg']))."'; window.close();</script></body></html>\n"; $GLOBALS['egw']->common->egw_exit(); } *************** *** 610,623 **** $GLOBALS['egw_info']['flags']['java_script'] .= "<script LANGUAGE=\"JavaScript\"> var referer = opener.location; ! opener.location.href = referer+(referer.search?'&':'?')+'msg=".addslashes(urlencode(lang('Contact saved')))."';</script>"; break; case 'delete': ! if($this->delete($content)); { echo "<html><body><script>var referer = opener.location; opener.location.href = referer+(referer.search?'&':'?')+'msg=". ! addslashes(urlencode(lang('Contact deleted !!!')))."';window.close();</script></body></html>\n"; $GLOBALS['egw']->common->egw_exit(); } break; } --- 736,753 ---- $GLOBALS['egw_info']['flags']['java_script'] .= "<script LANGUAGE=\"JavaScript\"> var referer = opener.location; ! opener.location.href = referer+(referer.search?'&':'?')+'msg=".addslashes(urlencode($content['msg']))."';</script>"; break; case 'delete': ! if($this->delete($content)) { echo "<html><body><script>var referer = opener.location; opener.location.href = referer+(referer.search?'&':'?')+'msg=". ! addslashes(urlencode(lang('Contact deleted')))."';window.close();</script></body></html>\n"; $GLOBALS['egw']->common->egw_exit(); } + else + { + $content['msg'] = lang('Error deleting the contact !!!'); + } break; } *************** *** 636,639 **** --- 766,779 ---- else // not found { + $state = $GLOBALS['egw']->session->appsession('index','addressbook'); + // check if we create the new contact in an existing org + if ($_GET['org']) + { + $content = $this->read_org($_GET['org']); + } + elseif ($state['org_view'] && !isset($this->org_views[$state['org_view']])) + { + $content = $this->read_org($state['org_view']); + } if (isset($_GET['owner']) && $_GET['owner'] !== '') { *************** *** 642,648 **** else { - $state = $GLOBALS['egw']->session->appsession('index','addressbook'); $content['owner'] = $state['filter']; - unset($state); } $content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p'); --- 782,786 ---- *************** *** 659,662 **** --- 797,801 ---- $content['creator'] = $this->user; $content['created'] = $this->now_su; + unset($state); } *************** *** 696,706 **** $sel_options['tz'] = $tz; $content['tz'] = $content['tz'] ? $content['tz'] : 0; ! foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name']; ! foreach($GLOBALS['egw']->acl->get_all_location_rights($GLOBALS['egw']->acl->account_id,'addressbook',true) as $id => $right) { if($id < 0) $sel_options['published_groups'][$id] = $GLOBALS['egw']->accounts->id2name($id); } ! $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); $content['link_to'] = array( 'to_app' => 'addressbook', --- 835,856 ---- $sel_options['tz'] = $tz; $content['tz'] = $content['tz'] ? $content['tz'] : 0; ! if (count($this->content_types) > 1) ! { ! foreach($this->content_types as $type => $data) ! { ! $sel_options['tid'][$type] = $data['name']; ! } ! $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); ! } ! else ! { ! $content['no_tid'] = true; ! } ! /* Conny: what's that? foreach($GLOBALS['egw']->acl->get_all_location_rights($GLOBALS['egw']->acl->account_id,'addressbook',true) as $id => $right) { if($id < 0) $sel_options['published_groups'][$id] = $GLOBALS['egw']->accounts->id2name($id); } ! */ $content['link_to'] = array( 'to_app' => 'addressbook', *************** *** 793,797 **** $GLOBALS['egw']->redirect_link('/index.php',array( 'menuaction' => 'addressbook.uicontacts.index', ! 'msg' => $this->delete($content) ? lang('Something went wrong by deleting this contact') : lang('Contact deleted !!!'), )); } --- 943,947 ---- $GLOBALS['egw']->redirect_link('/index.php',array( 'menuaction' => 'addressbook.uicontacts.index', ! 'msg' => $this->delete($content) ? lang('Error deleting the contact !!!') : lang('Contact deleted'), )); } *************** *** 807,811 **** } } ! foreach((array)$content as $key => $val) { $readonlys[$key] = true; --- 957,961 ---- } } ! foreach(array_keys($this->contact_fields) as $key) { $readonlys[$key] = true; *************** *** 825,829 **** $readonlys['button[delete]'] = !$this->check_perms(EGW_ACL_DELETE,$content); $readonlys['button[edit]'] = !$this->check_perms(EGW_ACL_EDIT,$content); ! $sel_options['fileas_type'][$content['fileas_type']] = $this->fileas($content); $sel_options['owner'] = $this->get_addressbooks(); --- 975,981 ---- $readonlys['button[delete]'] = !$this->check_perms(EGW_ACL_DELETE,$content); $readonlys['button[edit]'] = !$this->check_perms(EGW_ACL_EDIT,$content); ! // ToDo: fix vCard export ! $readonlys['button[vcard]'] = true; ! $sel_options['fileas_type'][$content['fileas_type']] = $this->fileas($content); $sel_options['owner'] = $this->get_addressbooks(); *************** *** 831,846 **** $sel_options['tz'] = $tz; $content['tz'] = $content['tz'] ? $content['tz'] : 0; ! foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name']; foreach(explode(',',$content['published_groups']) as $id) { $sel_options['published_groups'][$id] = $GLOBALS['egw']->accounts->id2name($id); } ! $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); $this->tmpl->read($this->content_types[$content['tid']]['options']['template']); ! foreach(array('email','email_home','url') as $name) { if ($content[$name] ) { ! $url = $name == 'url' ? $content[$name] : $this->email2link($content[$name]); if (!is_array($url)) { --- 983,1010 ---- $sel_options['tz'] = $tz; $content['tz'] = $content['tz'] ? $content['tz'] : 0; ! if (count($this->content_types) > 1) ! { ! foreach($this->content_types as $type => $data) ! { ! $sel_options['tid'][$type] = $data['name']; ! } ! $content['typegfx'] = $GLOBALS['egw']->html->image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); ! } ! else ! { ! $content['no_tid'] = true; ! } ! /* Conny: what's that? foreach(explode(',',$content['published_groups']) as $id) { $sel_options['published_groups'][$id] = $GLOBALS['egw']->accounts->id2name($id); } ! */ $this->tmpl->read($this->content_types[$content['tid']]['options']['template']); ! foreach(array('email','email_home','url','url_home') as $name) { if ($content[$name] ) { ! $url = substr($name,0,3) == 'url' ? $content[$name] : $this->email2link($content[$name]); if (!is_array($url)) { |