mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 16:48:49 +01:00
move addresbook_bo to Api\Contacts, ldap to Api\Ldap, ldapserverinfo to Api\Ldap\ServerInfo, bo_tracking to Api\Storage\Tracking, historylog to Api\Storage\History, Api\Customfields to Api\Storage\Customfields
This commit is contained in:
parent
fcca19cfcf
commit
7ada2354d3
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,13 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* SiteMgr contact form for the addressbook
|
||||
*
|
||||
@ -75,7 +77,7 @@ class addressbook_contactform
|
||||
elseif ($content['submitit'])
|
||||
{
|
||||
$submitted = true;
|
||||
$contact = new addressbook_bo();
|
||||
$contact = new Api\Contacts();
|
||||
if ($content['owner']) // save the contact in the addressbook
|
||||
{
|
||||
$content['private'] = 0; // in case default_private is set
|
||||
@ -90,9 +92,9 @@ class addressbook_contactform
|
||||
// the anonymous user to have run rights for addressbook AND
|
||||
// edit rights for the addressbook used to store the new entry,
|
||||
// which is clearly not wanted securitywise
|
||||
egw_vfs::$is_root = true;
|
||||
Api\Vfs::$is_root = true;
|
||||
egw_link::link('addressbook',$id,egw_link::VFS_APPNAME,$value,$name);
|
||||
egw_vfs::$is_root = false;
|
||||
Api\Vfs::$is_root = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,8 +110,7 @@ class addressbook_contactform
|
||||
{
|
||||
if ($content['email_contactform'])
|
||||
{
|
||||
require_once(EGW_INCLUDE_ROOT.'/addressbook/inc/class.addressbook_tracking.inc.php');
|
||||
$tracking = new addressbook_tracking($contact);
|
||||
$tracking = new Api\Contacts\Tracking($contact);
|
||||
}
|
||||
if ($tracking->do_notifications($contact->data2db($content),null))
|
||||
{
|
||||
@ -141,7 +142,7 @@ class addressbook_contactform
|
||||
static $contact;
|
||||
if (is_null($contact))
|
||||
{
|
||||
$contact = new addressbook_bo();
|
||||
$contact = new Api\Contacts();
|
||||
}
|
||||
$content['show']['custom'.$custom] = true;
|
||||
$content['customfield'][$custom] = $name;
|
||||
@ -174,7 +175,7 @@ class addressbook_contactform
|
||||
if ($name[0] == '#') // custom field
|
||||
{
|
||||
static $contact;
|
||||
if (is_null($contact)) $contact = new addressbook_bo();
|
||||
if (is_null($contact)) $contact = new Api\Contacts();
|
||||
$content['show']['custom'.$custom] = true;
|
||||
$content['customfield'][$custom] = $name;
|
||||
$content['customlabel'][$custom] = $contact->customfields[substr($name,1)]['label'];
|
||||
|
@ -7,10 +7,12 @@
|
||||
* @package addressbook
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* EGroupware: GroupDAV access: addressbook handler
|
||||
*
|
||||
@ -953,7 +955,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
if (is_null($non_deleted_tids))
|
||||
{
|
||||
$non_deleted_tids = $this->bo->content_types;
|
||||
unset($non_deleted_tids[addressbook_so::DELETED_TYPE]);
|
||||
unset($non_deleted_tids[Api\Contacts::DELETED_TYPE]);
|
||||
$non_deleted_tids = array_keys($non_deleted_tids);
|
||||
}
|
||||
$contact = $this->bo->read(array(self::$path_attr => $id, 'tid' => $non_deleted_tids));
|
||||
@ -1000,7 +1002,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$contact = null;
|
||||
}
|
||||
|
||||
if ($contact && $contact['tid'] == addressbook_so::DELETED_TYPE)
|
||||
if ($contact && $contact['tid'] == Api\Contacts::DELETED_TYPE)
|
||||
{
|
||||
$contact = null; // handle deleted events, as not existing (404 Not Found)
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* eGroupWare
|
||||
* EGroupware Addressbook
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package importexport
|
||||
* @link http://www.egroupware.org
|
||||
* @author Cornelius Weiss <nelius@cwtech.de>
|
||||
* @copyright Cornelius Weiss <nelius@cwtech.de>
|
||||
* @version $Id: $
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* class import_csv for addressbook
|
||||
@ -29,8 +30,10 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
private $bocontacts;
|
||||
|
||||
/**
|
||||
* For figuring out if a contact has changed
|
||||
*/
|
||||
* For figuring out if a contact has changed
|
||||
*
|
||||
* @var Api\Contacts\Tracking
|
||||
*/
|
||||
protected $tracking;
|
||||
|
||||
/**
|
||||
@ -48,10 +51,10 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
public function init(importexport_definition &$_definition ) {
|
||||
|
||||
// fetch the addressbook bo
|
||||
$this->bocontacts = new addressbook_bo();
|
||||
$this->bocontacts = new Api\Contacts();
|
||||
|
||||
// Get the tracker for changes
|
||||
$this->tracking = new addressbook_tracking($this->bocontacts);
|
||||
$this->tracking = new Api\Contacts\Tracking($this->bocontacts);
|
||||
|
||||
$this->lookups = array(
|
||||
'tid' => array('n'=>'contact')
|
||||
@ -138,10 +141,10 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
// Also handle categories in their own field
|
||||
$record_array = $record->get_record_array();
|
||||
$more_categories = array();
|
||||
foreach($this->definition->plugin_options['field_mapping'] as $number => $field_name) {
|
||||
foreach($this->definition->plugin_options['field_mapping'] as $field_name) {
|
||||
if(!array_key_exists($field_name, $record_array) ||
|
||||
substr($field_name,0,3) != 'cat' || !$record->$field_name || $field_name == 'cat_id') continue;
|
||||
list($cat, $cat_id) = explode('-', $field_name);
|
||||
list(, $cat_id) = explode('-', $field_name);
|
||||
if(is_numeric($record->$field_name) && $record->$field_name != 1) {
|
||||
// Column has a single category ID
|
||||
$more_categories[] = $record->$field_name;
|
||||
@ -175,7 +178,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
if($record_array[$condition['string']]) {
|
||||
$searchcondition = array( $condition['string'] => $record_array[$condition['string']]);
|
||||
// if we use account_id for the condition, we need to set the owner for filtering, as this
|
||||
// enables addressbook_so to decide what backend is to be used
|
||||
// enables Api\Contacts\Storage to decide what backend is to be used
|
||||
if ($condition['string']=='account_id') $searchcondition['owner']=0;
|
||||
$contacts = $this->bocontacts->search(
|
||||
//array( $condition['string'] => $record[$condition['string']],),
|
||||
@ -204,7 +207,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
break;
|
||||
case 'equal':
|
||||
// Match on field
|
||||
$result = $this->equal($record, $condition, $matches);
|
||||
$result = $this->equal($record, $condition);
|
||||
if($result)
|
||||
{
|
||||
// Apply true action to any matching records found
|
||||
@ -270,7 +273,8 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
$old = $this->bocontacts->read($_data['id']);
|
||||
// if we get countrycodes as countryname, try to translate them -> the rest should be handled by bo classes.
|
||||
foreach(array('adr_one_', 'adr_two_') as $c_prefix) {
|
||||
if (strlen(trim($_data[$c_prefix.'countryname']))==2) $_data[$c_prefix.'countryname'] = $GLOBALS['egw']->country->get_full_name(trim($_data[$c_prefix.'countryname']),$translated=true);
|
||||
if (strlen(trim($_data[$c_prefix.'countryname']))==2)
|
||||
$_data[$c_prefix.'countryname'] = $GLOBALS['egw']->country->get_full_name(trim($_data[$c_prefix.'countryname']), true);
|
||||
}
|
||||
// Don't change a user account into a contact
|
||||
if($old['owner'] == 0) {
|
||||
@ -288,7 +292,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
} else {
|
||||
//error_log(__METHOD__.__LINE__.array2string($changed).' Old:'.$old['adr_one_countryname'].' ('.$old['adr_one_countrycode'].') New:'.$_data['adr_one_countryname'].' ('.$_data['adr_one_countryname'].')');
|
||||
}
|
||||
|
||||
|
||||
// Make sure n_fn gets updated
|
||||
unset($_data['n_fn']);
|
||||
|
||||
@ -320,7 +324,7 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
}
|
||||
default:
|
||||
throw new egw_exception('Unsupported action: '. $_action);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,4 +416,3 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv {
|
||||
return $this->results;
|
||||
}
|
||||
} // end of iface_export_plugin
|
||||
?>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1138,9 +1138,9 @@ window.egw_LAB.wait(function() {
|
||||
if ($contact['owner'] || // regular contact or
|
||||
empty($contact['account_id']) || // accounts without account_id
|
||||
// already deleted account (should no longer happen, but needed to allow for cleanup)
|
||||
$contact['tid'] == addressbook_so::DELETED_TYPE)
|
||||
$contact['tid'] == self::DELETED_TYPE)
|
||||
{
|
||||
$Ok = $this->delete($id, $contact['tid'] != addressbook_so::DELETED_TYPE && $contact['account_id']);
|
||||
$Ok = $this->delete($id, $contact['tid'] != self::DELETED_TYPE && $contact['account_id']);
|
||||
}
|
||||
// delete single account --> redirect to admin
|
||||
elseif (count($checked) == 1 && $contact['account_id'])
|
||||
@ -1684,7 +1684,7 @@ window.egw_LAB.wait(function() {
|
||||
{
|
||||
$row['class'] .= 'rowAccount rowNoDelete ';
|
||||
}
|
||||
elseif (!$this->check_perms(EGW_ACL_DELETE,$row) || (!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge' && $query['col_filter']['tid'] == addressbook_so::DELETED_TYPE))
|
||||
elseif (!$this->check_perms(EGW_ACL_DELETE,$row) || (!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge' && $query['col_filter']['tid'] == self::DELETED_TYPE))
|
||||
{
|
||||
$row['class'] .= 'rowNoDelete ';
|
||||
}
|
||||
@ -2274,7 +2274,7 @@ window.egw_LAB.wait(function() {
|
||||
);
|
||||
|
||||
// Links for deleted entries
|
||||
if($content['tid'] == addressbook_so::DELETED_TYPE)
|
||||
if($content['tid'] == self::DELETED_TYPE)
|
||||
{
|
||||
$content['link_to']['show_deleted'] = true;
|
||||
if(!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge')
|
||||
@ -2604,7 +2604,7 @@ window.egw_LAB.wait(function() {
|
||||
'to_id' => $content['id'],
|
||||
);
|
||||
// Links for deleted entries
|
||||
if($content['tid'] == addressbook_so::DELETED_TYPE)
|
||||
if($content['tid'] == self::DELETED_TYPE)
|
||||
{
|
||||
$content['link_to']['show_deleted'] = true;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* eGgroupWare admin - UI for adding custom fields
|
||||
* EGgroupware admin - UI for adding custom fields
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
@ -10,6 +10,8 @@
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* Customfields class - manages customfield definitions in egw_config table
|
||||
*
|
||||
@ -103,10 +105,10 @@ class customfields
|
||||
{
|
||||
if (($this->appname = $appname))
|
||||
{
|
||||
$this->fields = egw_customfields::get($this->appname,true);
|
||||
$this->content_types = config::get_content_types($this->appname);
|
||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||
$this->content_types = Api\Config::get_content_types($this->appname);
|
||||
}
|
||||
$this->so = new so_sql('phpgwapi','egw_customfields',null,'',true);
|
||||
$this->so = new Api\Storage\Base('phpgwapi','egw_customfields',null,'',true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,7 +123,7 @@ class customfields
|
||||
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
|
||||
|
||||
// Read fields, constructor doesn't always know appname
|
||||
$this->fields = egw_customfields::get($this->appname,true);
|
||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||
|
||||
$this->tmpl = new etemplate_new();
|
||||
$this->tmpl->read('admin.customfields');
|
||||
@ -135,7 +137,7 @@ class customfields
|
||||
{
|
||||
if(count($this->content_types) == 0)
|
||||
{
|
||||
$this->content_types = config::get_content_types($this->appname);
|
||||
$this->content_types = Api\Config::get_content_types($this->appname);
|
||||
}
|
||||
if (count($this->content_types)==0)
|
||||
{
|
||||
@ -152,7 +154,7 @@ class customfields
|
||||
}
|
||||
elseif($content['content_types']['create'])
|
||||
{
|
||||
if($new_type = $this->create_content_type($content))
|
||||
if(($new_type = $this->create_content_type($content)))
|
||||
{
|
||||
$content['content_types']['types'] = $this->content_type = $new_type;
|
||||
}
|
||||
@ -214,7 +216,6 @@ class customfields
|
||||
|
||||
$content['type_template'] = $this->appname . '.admin.types';
|
||||
$content['content_types']['appname'] = $this->appname;
|
||||
$content_types = array_keys($this->content_types);
|
||||
|
||||
$content['content_type_options'] = $this->content_types[$this->content_type]['options'];
|
||||
$content['content_type_options']['type'] = $this->types2[$this->content_type];
|
||||
@ -251,6 +252,7 @@ class customfields
|
||||
);
|
||||
|
||||
// Allow extending app a change to change content before display
|
||||
$readonlys = null;
|
||||
static::app_index($content, $sel_options, $readonlys, $preserve);
|
||||
|
||||
// Make sure app css gets loaded, extending app might cause et2 to miss it
|
||||
@ -292,7 +294,7 @@ class customfields
|
||||
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
|
||||
|
||||
// Read fields, constructor doesn't always know appname
|
||||
$this->fields = egw_customfields::get($this->appname,true);
|
||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||
|
||||
// Update based on info returned from template
|
||||
if (is_array($content))
|
||||
@ -328,8 +330,8 @@ class customfields
|
||||
{
|
||||
foreach(explode("\n",trim($content['cf_values'])) as $line)
|
||||
{
|
||||
list($var,$value) = explode('=',trim($line),2);
|
||||
$var = trim($var);
|
||||
list($var_raw,$value) = explode('=',trim($line),2);
|
||||
$var = trim($var_raw);
|
||||
$values[$var] = trim($value)==='' ? $var : $value;
|
||||
}
|
||||
}
|
||||
@ -343,10 +345,10 @@ class customfields
|
||||
$update_content[substr($key,3)] = $value;
|
||||
}
|
||||
}
|
||||
egw_customfields::update($update_content);
|
||||
Api\Storage\Customfields::update($update_content);
|
||||
if(!$cf_id)
|
||||
{
|
||||
$this->fields = egw_customfields::get($this->appname,true);
|
||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||
$cf_id = (int)$this->fields[$content['cf_name']]['id'];
|
||||
}
|
||||
egw_framework::refresh_opener('Saved', 'admin', $cf_id, 'edit');
|
||||
@ -415,7 +417,7 @@ class customfields
|
||||
{
|
||||
if(count($this->content_types) == 0)
|
||||
{
|
||||
$this->content_types = config::get_content_types($this->appname);
|
||||
$this->content_types = Api\Config::get_content_types($this->appname);
|
||||
}
|
||||
if (count($this->content_types)==0)
|
||||
{
|
||||
@ -455,6 +457,7 @@ class customfields
|
||||
*/
|
||||
protected function app_index(&$content, &$sel_options, &$readonlys)
|
||||
{
|
||||
unset($content, $sel_options, $readonlys); // not used, as this is a stub
|
||||
// This is just a stub.
|
||||
}
|
||||
|
||||
@ -494,78 +497,6 @@ class customfields
|
||||
return $actions;
|
||||
}
|
||||
|
||||
function update_fields(&$content)
|
||||
{
|
||||
foreach($content['fields'] as $field)
|
||||
{
|
||||
$name = trim($field['name']);
|
||||
$old_name = $field['old_name'];
|
||||
|
||||
if (!empty($delete) && $delete == $old_name)
|
||||
{
|
||||
unset($this->fields[$old_name]);
|
||||
continue;
|
||||
}
|
||||
if (isset($field['old_name']))
|
||||
{
|
||||
if (empty($name)) // empty name not allowed
|
||||
{
|
||||
$content['error_msg'] = lang('Name must not be empty !!!');
|
||||
$name = $old_name;
|
||||
}
|
||||
if (!empty($name) && $old_name != $name) // renamed
|
||||
{
|
||||
unset($this->fields[$old_name]);
|
||||
}
|
||||
}
|
||||
elseif (empty($name)) // new item and empty ==> ignore it
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$values = array();
|
||||
if (!empty($field['values']))
|
||||
{
|
||||
foreach(explode("\n",$field['values']) as $line)
|
||||
{
|
||||
list($var,$value) = explode('=',trim($line),2);
|
||||
$var = trim($var);
|
||||
$values[$var] = empty($value) ? $var : $value;
|
||||
}
|
||||
}
|
||||
$this->fields[$name] = array(
|
||||
'type' => $field['type'],
|
||||
'type2' => $field['type2'],
|
||||
'label' => empty($field['label']) ? $name : $field['label'],
|
||||
'help' => $field['help'],
|
||||
'values'=> $values,
|
||||
'len' => $field['len'],
|
||||
'rows' => (int)$field['rows'],
|
||||
'order' => (int)$field['order'],
|
||||
'private' => $field['private'],
|
||||
'needed' => $field['needed'],
|
||||
);
|
||||
if(!$this->fields[$name]['type2'] && $this->manage_content_types)
|
||||
{
|
||||
$this->fields[$name]['type2'] = (string)0;
|
||||
}
|
||||
}
|
||||
if (!function_exists('sort_by_order'))
|
||||
{
|
||||
function sort_by_order($arr1,$arr2)
|
||||
{
|
||||
return $arr1['order'] - $arr2['order'];
|
||||
}
|
||||
}
|
||||
uasort($this->fields,sort_by_order);
|
||||
|
||||
$n = 0;
|
||||
foreach($this->fields as $name => $data)
|
||||
{
|
||||
$this->fields[$name]['order'] = ($n += 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update(&$content)
|
||||
{
|
||||
$this->content_types[$this->content_type]['options'] = $content['content_type_options'];
|
||||
@ -627,7 +558,7 @@ class customfields
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($this->content_types as $letter => $type)
|
||||
foreach($this->content_types as $type)
|
||||
{
|
||||
if($type['name'] == $new_name)
|
||||
{
|
||||
@ -640,8 +571,8 @@ class customfields
|
||||
{
|
||||
if (!$this->content_types[chr($i)] &&
|
||||
// skip letter of deleted type for addressbook content-types, as it gives SQL error
|
||||
// content-type are lowercase, addressbook_so::DELETED_TYPE === 'D', but DB is case-insensitive
|
||||
($this->appname !== 'addressbook' || chr($i) !== strtolower(addressbook_so::DELETED_TYPE)))
|
||||
// content-type are lowercase, Api\Contacts::DELETED_TYPE === 'D', but DB is case-insensitive
|
||||
($this->appname !== 'addressbook' || chr($i) !== strtolower(Api\Contacts::DELETED_TYPE)))
|
||||
{
|
||||
$new_type = chr($i);
|
||||
break;
|
||||
@ -664,32 +595,32 @@ class customfields
|
||||
$config->value('types',$this->content_types);
|
||||
$config->save_repository();
|
||||
|
||||
egw_customfields::save($this->appname, $this->fields);
|
||||
Api\Storage\Customfields::save($this->appname, $this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* get customfields of using application
|
||||
*
|
||||
* @deprecated use egw_customfields::get() direct, no need to instanciate this UI class
|
||||
* @deprecated use Api\Storage\Customfields::get() direct, no need to instanciate this UI class
|
||||
* @author Cornelius Weiss
|
||||
* @param boolean $all_private_too=false should all the private fields be returned too
|
||||
* @param boolean $all_private_too =false should all the private fields be returned too
|
||||
* @return array with customfields
|
||||
*/
|
||||
function get_customfields($all_private_too=false)
|
||||
{
|
||||
return egw_customfields::get($this->appname,$all_private_too);
|
||||
return Api\Storage\Customfields::get($this->appname,$all_private_too);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_content_types of using application
|
||||
*
|
||||
* @deprecated use config::get_content_types() direct, no need to instanciate this UI class
|
||||
* @deprecated use Api\Config::get_content_types() direct, no need to instanciate this UI class
|
||||
* @author Cornelius Weiss
|
||||
* @return array with content-types
|
||||
*/
|
||||
function get_content_types()
|
||||
{
|
||||
return config::get_content_types($this->appname);
|
||||
return Api\Config::get_content_types($this->appname);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,13 +228,13 @@ class Config
|
||||
* @param string $app
|
||||
* @param boolean $all_private_too =false should all the private fields be returned too, default no
|
||||
* @param string $only_type2 =null if given only return fields of type2 == $only_type2
|
||||
* @deprecated use Api\Customfields::get()
|
||||
* @deprecated use Api\Storage\Customfields::get()
|
||||
* @return array with customfields
|
||||
*/
|
||||
static function get_customfields($app, $all_private_too=false, $only_type2=null)
|
||||
{
|
||||
//error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use Customfields::get() in ". function_backtrace());
|
||||
return Customfields::get($app, $all_private_too, $only_type2);
|
||||
//error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use Storage\Customfields::get() in ". function_backtrace());
|
||||
return Storage\Customfields::get($app, $all_private_too, $only_type2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
2402
api/src/Contacts.php
Executable file
2402
api/src/Contacts.php
Executable file
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Addressbook - ADS Backend
|
||||
* EGroupware API: Contacts ADS Backend
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <rb@stylite.de>
|
||||
* @package addressbook
|
||||
* @package api
|
||||
* @subpackage contacts
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Contacts;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// explicitly reference classes still in phpgwapi
|
||||
use accounts_ads;
|
||||
|
||||
/**
|
||||
* Active directory backend for accounts (not yet AD contacts)
|
||||
*
|
||||
@ -22,7 +30,7 @@
|
||||
* All values used to construct filters need to run through ldap::quote(),
|
||||
* to be save against LDAP query injection!!!
|
||||
*/
|
||||
class addressbook_ads extends addressbook_ldap
|
||||
class Ads extends Ldap
|
||||
{
|
||||
/**
|
||||
* LDAP searches only a limited set of attributes for performance reasons,
|
||||
@ -74,11 +82,13 @@ class addressbook_ads extends addressbook_ldap
|
||||
/**
|
||||
* constructor of the class
|
||||
*
|
||||
* @param array $ldap_config=null default use from $GLOBALS['egw_info']['server']
|
||||
* @param resource $ds=null ldap connection to use
|
||||
* @param array $ldap_config =null default use from $GLOBALS['egw_info']['server']
|
||||
* @param resource $ds =null ldap connection to use
|
||||
*/
|
||||
function __construct(array $ldap_config=null, $ds=null)
|
||||
{
|
||||
if (false) parent::__construct (); // quiten IDE warning, we are explicitly NOT calling parrent constructor!
|
||||
|
||||
$this->accountName = $GLOBALS['egw_info']['user']['account_lid'];
|
||||
|
||||
if ($ldap_config)
|
||||
@ -103,8 +113,8 @@ class addressbook_ads extends addressbook_ldap
|
||||
{
|
||||
$this->connect();
|
||||
}
|
||||
$this->ldapServerInfo = ldapserverinfo::get($this->ds, $this->ldap_config['ads_host']);
|
||||
$this->is_samba4 = $this->ldapServerInfo->serverType == SAMBA4_LDAPSERVER;
|
||||
$this->ldapServerInfo = Api\Ldap\ServerInfo::get($this->ds, $this->ldap_config['ads_host']);
|
||||
$this->is_samba4 = $this->ldapServerInfo->serverType == Api\Ldap\ServerInfo::SAMBA4;
|
||||
|
||||
// AD seems to use user, instead of inetOrgPerson
|
||||
unset($this->schema2egw['posixaccount']);
|
||||
@ -118,22 +128,24 @@ class addressbook_ads extends addressbook_ldap
|
||||
unset($this->schema2egw['user']['n_fileas']);
|
||||
unset($this->schema2egw['inetorgperson']);
|
||||
|
||||
foreach($this->schema2egw as $schema => $attributes)
|
||||
foreach($this->schema2egw as $attributes)
|
||||
{
|
||||
$this->all_attributes = array_merge($this->all_attributes,array_values($attributes));
|
||||
}
|
||||
$this->all_attributes = array_values(array_unique($this->all_attributes));
|
||||
|
||||
$this->charset = translation::charset();
|
||||
$this->charset = Api\Translation::charset();
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to LDAP server
|
||||
*
|
||||
* @param boolean $admin=false true (re-)connect with admin not user credentials, eg. to modify accounts
|
||||
* @param boolean $admin =false true (re-)connect with admin not user credentials, eg. to modify accounts
|
||||
*/
|
||||
function connect($admin=false)
|
||||
{
|
||||
unset($admin); // not used, but required by function signature
|
||||
|
||||
$this->ds = $this->accounts_ads->ldap_connection();
|
||||
}
|
||||
|
||||
@ -159,21 +171,21 @@ class addressbook_ads extends addressbook_ldap
|
||||
/**
|
||||
* reads contact data
|
||||
*
|
||||
* @param string/array $contact_id contact_id or array with values for id or account_id
|
||||
* @param string/array $_contact_id contact_id or array with values for id or account_id
|
||||
* @return array/boolean data if row could be retrived else False
|
||||
*/
|
||||
function read($contact_id)
|
||||
function read($_contact_id)
|
||||
{
|
||||
if (is_array($contact_id) && isset($contact_id['account_id']) ||
|
||||
!is_array($contact_id) && substr($contact_id,0,8) == 'account:')
|
||||
if (is_array($_contact_id) && isset($_contact_id['account_id']) ||
|
||||
!is_array($_contact_id) && substr($_contact_id,0,8) == 'account:')
|
||||
{
|
||||
$account_id = (int)(is_array($contact_id) ? $contact_id['account_id'] : substr($contact_id,8));
|
||||
$contact_id = $GLOBALS['egw']->accounts->id2name($account_id, 'person_id');
|
||||
$account_id = (int)(is_array($_contact_id) ? $_contact_id['account_id'] : substr($_contact_id,8));
|
||||
$_contact_id = $GLOBALS['egw']->accounts->id2name($account_id, 'person_id');
|
||||
}
|
||||
$contact_id = !is_array($contact_id) ? $contact_id :
|
||||
(isset ($contact_id['id']) ? $contact_id['id'] : $contact_id['uid']);
|
||||
$contact_id = !is_array($_contact_id) ? $_contact_id :
|
||||
(isset ($_contact_id['id']) ? $_contact_id['id'] : $_contact_id['uid']);
|
||||
|
||||
$rows = $this->_searchLDAP($this->allContactsDN, $filter=$this->id_filter($contact_id), $this->all_attributes, ADDRESSBOOK_ALL);
|
||||
$rows = $this->_searchLDAP($this->allContactsDN, $filter=$this->id_filter($contact_id), $this->all_attributes, Ldap::ALL);
|
||||
//error_log(__METHOD__."('$contact_id') _searchLDAP($this->allContactsDN, '$filter',...)=".array2string($rows));
|
||||
return $rows ? $rows[0] : false;
|
||||
}
|
||||
@ -214,5 +226,4 @@ class addressbook_ads extends addressbook_ldap
|
||||
|
||||
parent::sanitize_update($ldapContact);
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Addressbook - LDAP Backend
|
||||
* EGroupware API: Contacts LDAP Backend
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Cornelius Weiss <egw-AT-von-und-zu-weiss.de>
|
||||
* @author Lars Kneschke <l.kneschke-AT-metaways.de>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @package api
|
||||
* @subpackage contacts
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
define('ADDRESSBOOK_ALL',0);
|
||||
define('ADDRESSBOOK_ACCOUNTS',1);
|
||||
define('ADDRESSBOOK_PERSONAL',2);
|
||||
define('ADDRESSBOOK_GROUP',3);
|
||||
namespace EGroupware\Api\Contacts;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// explicitly reference classes still in phpgwapi
|
||||
use common; // randomstring
|
||||
|
||||
/**
|
||||
* LDAP Backend for contacts, compatible with vars and parameters of eTemplate's so_sql.
|
||||
@ -23,8 +26,14 @@ define('ADDRESSBOOK_GROUP',3);
|
||||
* All values used to construct filters need to run through ldap::quote(),
|
||||
* to be save against LDAP query injection!!!
|
||||
*/
|
||||
class addressbook_ldap
|
||||
class Ldap
|
||||
{
|
||||
|
||||
const ALL = 0;
|
||||
const ACCOUNTS = 1;
|
||||
const PERSONAL = 2;
|
||||
const GROUP = 3;
|
||||
|
||||
var $data;
|
||||
|
||||
/**
|
||||
@ -298,7 +307,7 @@ class addressbook_ldap
|
||||
}
|
||||
$this->all_attributes = array_values(array_unique($this->all_attributes));
|
||||
|
||||
$this->charset = translation::charset();
|
||||
$this->charset = Api\Translation::charset();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -414,7 +423,7 @@ class addressbook_ldap
|
||||
$filter = $this->id_filter($contact_id);
|
||||
}
|
||||
$rows = $this->_searchLDAP($this->allContactsDN,
|
||||
$filter, $this->all_attributes, ADDRESSBOOK_ALL, array('_posixaccount2egw'));
|
||||
$filter, $this->all_attributes, self::ALL, array('_posixaccount2egw'));
|
||||
|
||||
return $rows ? $rows[0] : false;
|
||||
}
|
||||
@ -508,7 +517,7 @@ class addressbook_ldap
|
||||
|
||||
if(empty($contactUID))
|
||||
{
|
||||
$ldapContact[$this->dn_attribute] = $this->data[$this->contacts_id] = $contactUID = md5($GLOBALS['egw']->common->randomstring(15));
|
||||
$ldapContact[$this->dn_attribute] = $this->data[$this->contacts_id] = $contactUID = md5(common::randomstring(15));
|
||||
}
|
||||
//error_log(__METHOD__."() contactUID='$contactUID', isUpdate=".array2string($isUpdate).", oldContactInfo=".array2string($oldContactInfo));
|
||||
// add for all supported objectclasses the objectclass and it's attributes
|
||||
@ -537,7 +546,7 @@ class addressbook_ldap
|
||||
{
|
||||
// dont convert the (binary) jpegPhoto!
|
||||
$ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] :
|
||||
translation::convert(trim($data[$egwFieldName]),$this->charset,'utf-8');
|
||||
Api\Translation::convert(trim($data[$egwFieldName]),$this->charset,'utf-8');
|
||||
}
|
||||
elseif($isUpdate && isset($data[$egwFieldName]))
|
||||
{
|
||||
@ -593,7 +602,7 @@ class addressbook_ldap
|
||||
{
|
||||
$result = ldap_read($this->ds, $dn, 'objectclass=*');
|
||||
$entries = ldap_get_entries($this->ds, $result);
|
||||
$oldContact = ldap::result2array($entries[0]);
|
||||
$oldContact = Api\Ldap::result2array($entries[0]);
|
||||
unset($oldContact['dn']);
|
||||
|
||||
$newContact = $oldContact;
|
||||
@ -681,7 +690,7 @@ class addressbook_ldap
|
||||
|
||||
foreach($keys as $entry)
|
||||
{
|
||||
$entry = ldap::quote(is_array($entry) ? $entry['id'] : $entry);
|
||||
$entry = Api\Ldap::quote(is_array($entry) ? $entry['id'] : $entry);
|
||||
if(($result = ldap_search($this->ds, $this->allContactsDN,
|
||||
"(|(entryUUID=$entry)(uid=$entry))", $attributes)))
|
||||
{
|
||||
@ -759,33 +768,33 @@ class addressbook_ldap
|
||||
{
|
||||
if (!($accountName = $GLOBALS['egw']->accounts->id2name($filter['owner']))) return false;
|
||||
|
||||
$searchDN = 'cn='. ldap::quote(strtolower($accountName)) .',';
|
||||
$searchDN = 'cn='. Api\Ldap::quote(strtolower($accountName)) .',';
|
||||
|
||||
if ($filter['owner'] < 0)
|
||||
{
|
||||
$searchDN .= $this->sharedContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_GROUP;
|
||||
$addressbookType = self::GROUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
$searchDN .= $this->personalContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_PERSONAL;
|
||||
$addressbookType = self::PERSONAL;
|
||||
}
|
||||
}
|
||||
elseif (!isset($filter['owner']))
|
||||
{
|
||||
$searchDN = $this->allContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_ALL;
|
||||
$addressbookType = self::ALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$searchDN = $this->accountContactsDN;
|
||||
$addressbookType = ADDRESSBOOK_ACCOUNTS;
|
||||
$addressbookType = self::ACCOUNTS;
|
||||
}
|
||||
// create the search filter
|
||||
switch($addressbookType)
|
||||
{
|
||||
case ADDRESSBOOK_ACCOUNTS:
|
||||
case self::ACCOUNTS:
|
||||
$objectFilter = $this->accountsFilter;
|
||||
break;
|
||||
default:
|
||||
@ -813,8 +822,8 @@ class addressbook_ldap
|
||||
{
|
||||
if(($ldapSearchKey = $mapping[$egwSearchKey]))
|
||||
{
|
||||
$searchString = translation::convert($searchValue,$this->charset,'utf-8');
|
||||
$searchFilter .= '('.$ldapSearchKey.'='.$wildcard.ldap::quote($searchString).$wildcard.')';
|
||||
$searchString = Api\Translation::convert($searchValue,$this->charset,'utf-8');
|
||||
$searchFilter .= '('.$ldapSearchKey.'='.$wildcard.Api\Ldap::quote($searchString).$wildcard.')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -915,7 +924,7 @@ class addressbook_ldap
|
||||
}
|
||||
elseif ($value)
|
||||
{
|
||||
$filters .= '(uidNumber='.ldap::quote($value).')';
|
||||
$filters .= '(uidNumber='.Api\Ldap::quote($value).')';
|
||||
|
||||
}
|
||||
break;
|
||||
@ -935,9 +944,9 @@ class addressbook_ldap
|
||||
if (count($cats) > 1) $filters .= '(|';
|
||||
foreach($cats as $cat)
|
||||
{
|
||||
$catName = translation::convert(
|
||||
$catName = Api\Translation::convert(
|
||||
$GLOBALS['egw']->categories->id2name($cat),$this->charset,'utf-8');
|
||||
$filters .= '(category='.ldap::quote($catName).')';
|
||||
$filters .= '(category='.Api\Ldap::quote($catName).')';
|
||||
}
|
||||
if (count($cats) > 1) $filters .= ')';
|
||||
}
|
||||
@ -965,13 +974,13 @@ class addressbook_ldap
|
||||
{
|
||||
// todo: value = "!''"
|
||||
$filters .= '('.$mapping[$key].'='.($value === "!''" ? '*' :
|
||||
ldap::quote(translation::convert($value,$this->charset,'utf-8'))).')';
|
||||
Api\Ldap::quote(Api\Translation::convert($value,$this->charset,'utf-8'))).')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// filter for letter-search
|
||||
elseif (preg_match("/^([^ ]+) ".preg_quote($GLOBALS['egw']->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE])." '(.*)%'$/",$value,$matches))
|
||||
elseif (preg_match("/^([^ ]+) ".preg_quote($GLOBALS['egw']->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE])." '(.*)%'$/",$value,$matches))
|
||||
{
|
||||
list(,$name,$value) = $matches;
|
||||
if (strpos($name,'.') !== false) list(,$name) = explode('.',$name);
|
||||
@ -979,8 +988,8 @@ class addressbook_ldap
|
||||
{
|
||||
if (isset($mapping[$name]))
|
||||
{
|
||||
$filters .= '('.$mapping[$name].'='.ldap::quote(
|
||||
translation::convert($value,$this->charset,'utf-8')).'*)';
|
||||
$filters .= '('.$mapping[$name].'='.Api\Ldap::quote(
|
||||
Api\Translation::convert($value,$this->charset,'utf-8')).'*)';
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1017,7 +1026,7 @@ class addressbook_ldap
|
||||
|
||||
//error_log(__METHOD__."('$_ldapContext', '$_filter', ".array2string($_attributes).", $_addressbooktype)");
|
||||
|
||||
if($_addressbooktype == ADDRESSBOOK_ALL || $_ldapContext == $this->allContactsDN)
|
||||
if($_addressbooktype == self::ALL || $_ldapContext == $this->allContactsDN)
|
||||
{
|
||||
$result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, 0, $this->ldapLimit);
|
||||
}
|
||||
@ -1048,7 +1057,7 @@ class addressbook_ldap
|
||||
{
|
||||
if(!empty($entry[$ldapFieldName][0]) && !is_int($egwFieldName) && !isset($contact[$egwFieldName]))
|
||||
{
|
||||
$contact[$egwFieldName] = translation::convert($entry[$ldapFieldName][0],'utf-8');
|
||||
$contact[$egwFieldName] = Api\Translation::convert($entry[$ldapFieldName][0],'utf-8');
|
||||
}
|
||||
}
|
||||
$objectclass2egw = '_'.$objectclass.'2egw';
|
||||
@ -1206,7 +1215,7 @@ class addressbook_ldap
|
||||
$ldapContact['category'] = array();
|
||||
foreach(is_array($data['cat_id']) ? $data['cat_id'] : explode(',',$data['cat_id']) as $cat)
|
||||
{
|
||||
$ldapContact['category'][] = translation::convert(
|
||||
$ldapContact['category'][] = Api\Translation::convert(
|
||||
ExecMethod('phpgwapi.categories.id2name',$cat),$this->charset,'utf-8');
|
||||
}
|
||||
}
|
||||
@ -1217,7 +1226,7 @@ class addressbook_ldap
|
||||
{
|
||||
if($value != '$, $$$')
|
||||
{
|
||||
$ldapContact[$attr] = translation::convert($value,$this->charset,'utf-8');
|
||||
$ldapContact[$attr] = Api\Translation::convert($value,$this->charset,'utf-8');
|
||||
}
|
||||
elseif($isUpdate)
|
||||
{
|
||||
@ -1421,6 +1430,6 @@ class addressbook_ldap
|
||||
*/
|
||||
function change_owner($account_id,$new_owner)
|
||||
{
|
||||
error_log("so_ldap::change_owner($account_id,$new_owner) not yet implemented");
|
||||
error_log(__METHOD__."($account_id,$new_owner) not yet implemented");
|
||||
}
|
||||
}
|
@ -1,19 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware : Addressbook - SQL backend
|
||||
* EGroupware API: Contacts - SQL storage
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2006-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package api
|
||||
* @subpackage contacts
|
||||
* @copyright (c) 2006-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Contacts;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// explicitly reference classes still in phpgwapi
|
||||
use common; // common::generate_uid
|
||||
|
||||
/**
|
||||
* SQL storage object of the adressbook
|
||||
* Contacts - SQL storage
|
||||
*/
|
||||
class addressbook_sql extends so_sql_cf
|
||||
class Sql extends Api\Storage
|
||||
{
|
||||
/**
|
||||
* name of custom fields table
|
||||
@ -60,15 +68,15 @@ class addressbook_sql extends so_sql_cf
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param egw_db $db=null
|
||||
* @param Api\Db $db =null
|
||||
*/
|
||||
function __construct(egw_db $db=null)
|
||||
function __construct(Api\Db $db=null)
|
||||
{
|
||||
parent::__construct('phpgwapi', 'egw_addressbook', self::EXTRA_TABLE, 'contact_',
|
||||
$extra_key='_name',$extra_value='_value',$extra_id='_id',$db);
|
||||
parent::__construct('phpgwapi', 'egw_addressbook', self::EXTRA_TABLE,
|
||||
'contact_', '_name', '_value', '_id', $db);
|
||||
|
||||
// Get custom fields from addressbook instead of phpgwapi
|
||||
$this->customfields = config::get_customfields('addressbook');
|
||||
$this->customfields = Api\Storage\Customfields::get('addressbook');
|
||||
|
||||
if ($GLOBALS['egw_info']['server']['account_repository'])
|
||||
{
|
||||
@ -146,7 +154,7 @@ class addressbook_sql extends so_sql_cf
|
||||
}
|
||||
if ($param['searchletter'])
|
||||
{
|
||||
$filter[] = 'org_name '.$this->db->capabilities[egw_db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($param['searchletter'].'%');
|
||||
$filter[] = 'org_name '.$this->db->capabilities[Api\Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($param['searchletter'].'%');
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -169,8 +177,8 @@ class addressbook_sql extends so_sql_cf
|
||||
// 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)" :
|
||||
"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(
|
||||
parent::search($param['search'],array('org_name'),
|
||||
"GROUP BY org_name HAVING $by_expr > 1 ORDER BY org_name $sort", array(
|
||||
"NULL AS $by",
|
||||
'1 AS is_main',
|
||||
'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count',
|
||||
@ -178,8 +186,8 @@ class addressbook_sql extends so_sql_cf
|
||||
"COUNT(DISTINCT CASE WHEN adr_one_locality IS NULL THEN '' ELSE adr_one_locality END) AS adr_one_locality_count",
|
||||
),$wildcard,false,$op/*'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(
|
||||
parent::search($param['search'],array('org_name'),
|
||||
"GROUP BY org_name,$by ORDER BY org_name $sort,$by $sort", array(
|
||||
"CASE WHEN $by IS NULL THEN '' ELSE $by END AS $by",
|
||||
'0 AS is_main',
|
||||
'COUNT(DISTINCT egw_addressbook.contact_id) AS org_count',
|
||||
@ -195,7 +203,7 @@ class addressbook_sql extends so_sql_cf
|
||||
|
||||
// query the values for *_count == 1, to display them instead
|
||||
$filter['org_name'] = $orgs = array();
|
||||
foreach($rows as $n => $row)
|
||||
foreach($rows as $row)
|
||||
{
|
||||
if ($row['org_unit_count'] == 1 || $row['adr_one_locality_count'] == 1)
|
||||
{
|
||||
@ -208,7 +216,8 @@ class addressbook_sql extends so_sql_cf
|
||||
|
||||
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',
|
||||
foreach((array) parent::search(null, array('org_name','org_unit','adr_one_locality'),
|
||||
'GROUP BY org_name,org_unit,adr_one_locality',
|
||||
'',$wildcard,false,$op/*'AND'*/,false,$filter) as $row)
|
||||
{
|
||||
$org_key = $row['org_name'].($by ? '|||'.$row[$by] : '');
|
||||
@ -243,19 +252,19 @@ class addressbook_sql extends so_sql_cf
|
||||
*
|
||||
* 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 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
|
||||
* 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"
|
||||
* @param string $wildcard='' appended befor and after each criteria
|
||||
* @param boolean $empty=false False=empty criteria are ignored in query, True=empty have to be empty in row
|
||||
* @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 $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"
|
||||
* @param string $wildcard ='' appended befor and after each criteria
|
||||
* @param boolean $empty =false False=empty criteria are ignored in query, True=empty have to be empty in row
|
||||
* @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
|
||||
* "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
|
||||
* @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
|
||||
*/
|
||||
function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
|
||||
@ -360,7 +369,9 @@ class addressbook_sql extends so_sql_cf
|
||||
// fall through
|
||||
}
|
||||
// postgres requires that expressions in order by appear in the columns of a distinct select
|
||||
if ($this->db->Type != 'mysql' && preg_match_all("/(#?[a-zA-Z_.]+) *(<> *''|IS NULL|IS NOT NULL)? *(ASC|DESC)?(,|$)/ui",$order_by,$all_matches,PREG_SET_ORDER))
|
||||
$all_matches = null;
|
||||
if ($this->db->Type != 'mysql' && preg_match_all("/(#?[a-zA-Z_.]+) *(<> *''|IS NULL|IS NOT NULL)? *(ASC|DESC)?(,|$)/ui",
|
||||
$order_by, $all_matches, PREG_SET_ORDER))
|
||||
{
|
||||
if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
|
||||
foreach($all_matches as $matches)
|
||||
@ -394,10 +405,12 @@ class addressbook_sql extends so_sql_cf
|
||||
// Understand search by date with wildcard (????.10.??) according to user date preference
|
||||
if(is_string($criteria) && strpos($criteria, '?') !== false)
|
||||
{
|
||||
$date_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'];
|
||||
// First, check for a 'date', with wildcards, in the user's format
|
||||
$date_regex = str_replace(array('Y','m','d','.','-'), array('(?P<Y>(?:\?|\Q){4})','(?P<m>(?:\?|\Q){2})','(?P<d>(?:\?|\Q){2})','\.','\-'),$date_format);
|
||||
$date_regex = str_replace('Q','d',$date_regex);
|
||||
$date_regex = str_replace('Q','d',
|
||||
str_replace(array('Y','m','d','.','-'),
|
||||
array('(?P<Y>(?:\?|\Q){4})','(?P<m>(?:\?|\Q){2})','(?P<d>(?:\?|\Q){2})','\.','\-'),
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['dateformat']));
|
||||
|
||||
if(preg_match_all('$'.$date_regex.'$', $criteria, $matches))
|
||||
{
|
||||
foreach($matches[0] as $m_id => $match)
|
||||
@ -467,7 +480,7 @@ class addressbook_sql extends so_sql_cf
|
||||
{
|
||||
if (!$new_owner) // otherwise we would create an account (contact_owner==0)
|
||||
{
|
||||
throw egw_exception_wrong_parameter(__METHOD__."($account_id, $new_owner) new owner must not be 0!");
|
||||
throw Api\Exception\WrongParameter(__METHOD__."($account_id, $new_owner) new owner must not be 0!");
|
||||
}
|
||||
// contacts
|
||||
$this->db->update($this->table_name,array(
|
||||
@ -496,9 +509,9 @@ class addressbook_sql extends so_sql_cf
|
||||
*
|
||||
* @param array $uids array of user or group id's for $uid_column='list_owners', or values for $uid_column,
|
||||
* or whole where array: column-name => value(s) pairs
|
||||
* @param string $uid_column='list_owner' column-name or null to use $uids as where array
|
||||
* @param string $member_attr=null null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute
|
||||
* @param boolean|int|array $limit_in_ab=false if true only return members from the same owners addressbook,
|
||||
* @param string $uid_column ='list_owner' column-name or null to use $uids as where array
|
||||
* @param string $member_attr =null null: no members, 'contact_uid', 'contact_id', 'caldav_name' return members as that attribute
|
||||
* @param boolean|int|array $limit_in_ab =false if true only return members from the same owners addressbook,
|
||||
* if int|array only return members from the given owners addressbook(s)
|
||||
* @return array with list_id => array(list_id,list_name,list_owner,...) pairs
|
||||
*/
|
||||
@ -547,7 +560,7 @@ class addressbook_sql extends so_sql_cf
|
||||
*
|
||||
* @param string|array $keys list-name or array with column-name => value pairs to specify the list
|
||||
* @param int $owner user- or group-id
|
||||
* @param array $contacts=array() contacts to add (only for not yet existing lists!)
|
||||
* @param array $contacts =array() contacts to add (only for not yet existing lists!)
|
||||
* @param array &$data=array() values for keys 'list_uid', 'list_carddav_name', 'list_name'
|
||||
* @return int|boolean integer list_id or false on error
|
||||
*/
|
||||
@ -606,7 +619,7 @@ class addressbook_sql extends so_sql_cf
|
||||
*
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list list-id
|
||||
* @param array $existing=null array of existing contact-id(s) of list, to not reread it, eg. array()
|
||||
* @param array $existing =null array of existing contact-id(s) of list, to not reread it, eg. array()
|
||||
* @return false on error
|
||||
*/
|
||||
function add2list($contact,$list,array $existing=null)
|
||||
@ -648,7 +661,7 @@ class addressbook_sql extends so_sql_cf
|
||||
* Removes one contact from distribution list(s)
|
||||
*
|
||||
* @param int|array $contact contact_id(s)
|
||||
* @param int $list=null list-id or null to remove from all lists
|
||||
* @param int $list =null list-id or null to remove from all lists
|
||||
* @return false on error
|
||||
*/
|
||||
function remove_from_list($contact,$list=null)
|
||||
@ -690,7 +703,7 @@ class addressbook_sql extends so_sql_cf
|
||||
/**
|
||||
* Deletes a distribution list (incl. it's members)
|
||||
*
|
||||
* @param int/array $list list_id(s)
|
||||
* @param int|array $list list_id(s)
|
||||
* @return number of members deleted or false if list does not exist
|
||||
*/
|
||||
function delete_list($list)
|
||||
@ -705,7 +718,7 @@ class addressbook_sql extends so_sql_cf
|
||||
/**
|
||||
* Get ctag (max list_modified as timestamp) for lists
|
||||
*
|
||||
* @param int|array $owner=null null for all lists user has access too
|
||||
* @param int|array $owner =null null for all lists user has access too
|
||||
* @return int
|
||||
*/
|
||||
function lists_ctag($owner=null)
|
||||
@ -745,7 +758,7 @@ class addressbook_sql extends so_sql_cf
|
||||
}
|
||||
// catch Illegal mix of collations (ascii_general_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '=' (1267)
|
||||
// caused by non-ascii chars compared with ascii field uid
|
||||
catch(egw_exception_db $e) {
|
||||
catch(Api\Db\Exception $e) {
|
||||
_egw_log_exception($e);
|
||||
return false;
|
||||
}
|
||||
@ -762,11 +775,13 @@ class addressbook_sql extends so_sql_cf
|
||||
* 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
|
||||
* @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, $extra_where = NULL)
|
||||
{
|
||||
unset($extra_where); // not used, but required by function signature
|
||||
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) {
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
} else {
|
1138
api/src/Contacts/Storage.php
Executable file
1138
api/src/Contacts/Storage.php
Executable file
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Addressbook - history and notifications
|
||||
* EGroupware API - Contacts history and notifications
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package addressbook
|
||||
* @copyright (c) 2007 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package api
|
||||
* @subpackage contacts
|
||||
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Contacts;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// explicitly reference classes still in phpgwapi
|
||||
use common;
|
||||
|
||||
/**
|
||||
* Addressbook - tracking object
|
||||
* Contacts history and notifications
|
||||
*/
|
||||
class addressbook_tracking extends bo_tracking
|
||||
class Tracking extends Api\Storage\Tracking
|
||||
{
|
||||
/**
|
||||
* Application we are tracking (required!)
|
||||
@ -64,10 +72,10 @@ class addressbook_tracking extends bo_tracking
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param addressbook_bo $bocontacts
|
||||
* @param Api\Contacts $bocontacts
|
||||
* @return tracker_tracking
|
||||
*/
|
||||
function __construct(addressbook_bo $bocontacts)
|
||||
function __construct(Api\Contacts $bocontacts)
|
||||
{
|
||||
$this->contacts = $bocontacts;
|
||||
|
||||
@ -93,17 +101,19 @@ class addressbook_tracking extends bo_tracking
|
||||
/**
|
||||
* Get a notification-config value
|
||||
*
|
||||
* @param string $what
|
||||
* @param string $name
|
||||
* - 'copy' array of email addresses notifications should be copied too, can depend on $data
|
||||
* - 'lang' string lang code for copy mail
|
||||
* - 'sender' string send email address
|
||||
* @param array $data current entry
|
||||
* @param array $old=null old/last state of the entry or null for a new entry
|
||||
* @param array $old =null old/last state of the entry or null for a new entry
|
||||
* @return mixed
|
||||
*/
|
||||
function get_config($name,$data,$old=null)
|
||||
{
|
||||
//echo "<p>addressbook_tracking::get_config($name,".print_r($data,true).",...)</p>\n";
|
||||
unset($old); // not used, but required by function signature
|
||||
|
||||
//echo "<p>".__METHOD__."($name,".print_r($data,true).",...)</p>\n";
|
||||
switch($name)
|
||||
{
|
||||
case 'copy':
|
||||
@ -134,9 +144,9 @@ class addressbook_tracking extends bo_tracking
|
||||
*
|
||||
* @internal use only track($data,$old)
|
||||
* @param array $data current entry
|
||||
* @param array $old=null old/last state of the entry or null for a new entry
|
||||
* @param boolean $deleted=null can be set to true to let the tracking know the item got deleted or undelted
|
||||
* @param array $changed_fields=null changed fields from ealier call to $this->changed_fields($data,$old), to not compute it again
|
||||
* @param array $old =null old/last state of the entry or null for a new entry
|
||||
* @param boolean $deleted =null can be set to true to let the tracking know the item got deleted or undelted
|
||||
* @param array $changed_fields =null changed fields from ealier call to $this->changed_fields($data,$old), to not compute it again
|
||||
* @return int number of log-entries made
|
||||
*/
|
||||
protected function save_history(array $data,array $old=null,$deleted=null,array $changed_fields=null)
|
||||
@ -180,6 +190,8 @@ class addressbook_tracking extends bo_tracking
|
||||
*/
|
||||
protected function get_message($data,$old,$receiver=null)
|
||||
{
|
||||
unset($receiver); // not used, but required by function signature
|
||||
|
||||
if (!$data['modified'] || !$old)
|
||||
{
|
||||
return lang('New contact submitted by %1 at %2',
|
||||
@ -196,12 +208,14 @@ class addressbook_tracking extends bo_tracking
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $old
|
||||
* @param boolean $deleted=null can be set to true to let the tracking know the item got deleted or undelted
|
||||
* @param boolean $deleted =null can be set to true to let the tracking know the item got deleted or undelted
|
||||
* @param int|string $receiver nummeric account_id or email address
|
||||
* @return string
|
||||
*/
|
||||
protected function get_subject($data,$old,$deleted=null,$receiver=null)
|
||||
{
|
||||
unset($old, $deleted, $receiver); // not used, but required by function signature
|
||||
|
||||
if ($data['is_contactform'])
|
||||
{
|
||||
$prefix = ($data['subject_contactform'] ? $data['subject_contactform'] : lang('Contactform')).': ';
|
||||
@ -218,6 +232,8 @@ class addressbook_tracking extends bo_tracking
|
||||
*/
|
||||
function get_details($data,$receiver=null)
|
||||
{
|
||||
unset($receiver); // not used, but required by function signature
|
||||
|
||||
foreach($this->contacts->contact_fields as $name => $label)
|
||||
{
|
||||
if (!$data[$name] && $name != 'owner') continue;
|
@ -1,20 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Addressbook - Univention Backend
|
||||
* EGroupware API: Contacts Univention Backend
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <rb@stylite.de>
|
||||
* @package addressbook
|
||||
* @package api
|
||||
* @subpackage contacts
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Contacts;
|
||||
|
||||
/**
|
||||
* Univention backend for addressbook
|
||||
*
|
||||
* Different mail attribute is only difference to LDAP backend
|
||||
*/
|
||||
class addressbook_univention extends addressbook_ldap
|
||||
class Univention extends Ldap
|
||||
{
|
||||
function __construct($ldap_config = null, $ds = null)
|
||||
{
|
263
api/src/Ldap.php
Normal file
263
api/src/Ldap.php
Normal file
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API - LDAP connection handling
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <l.kneschke@metaways.de>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage ldap
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api;
|
||||
|
||||
/**
|
||||
* LDAP connection handling
|
||||
*
|
||||
* Please note for SSL or TLS connections hostname has to be:
|
||||
* - SSL: "ldaps://host[:port]/"
|
||||
* - TLS: "tls://host[:port]/"
|
||||
* Both require certificats installed on the webserver, otherwise the connection will fail!
|
||||
*
|
||||
* If multiple (space-separated) ldap hosts or urls are given, try them in order and
|
||||
* move first successful one to first place in session, to try not working ones
|
||||
* only once per session.
|
||||
*/
|
||||
class Ldap
|
||||
{
|
||||
/**
|
||||
* Holds the LDAP link identifier
|
||||
*
|
||||
* @var resource $ds
|
||||
*/
|
||||
var $ds;
|
||||
|
||||
/**
|
||||
* Holds the detected information about the connected ldap server
|
||||
*
|
||||
* @var Ldap\ServerInfo $ldapserverinfo
|
||||
*/
|
||||
var $ldapserverinfo;
|
||||
|
||||
/**
|
||||
* Throw Exceptions in ldapConnect instead of echoing error and returning false
|
||||
*
|
||||
* @var boolean $exception_on_error
|
||||
*/
|
||||
var $exception_on_error=false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param boolean $exception_on_error =false true: throw Exceptions in ldapConnect instead of echoing error and returning false
|
||||
*/
|
||||
function __construct($exception_on_error=false)
|
||||
{
|
||||
$this->exception_on_error = $exception_on_error;
|
||||
$this->restoreSessionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about connected ldap server
|
||||
*
|
||||
* @return Ldap\ServerInfo|null
|
||||
*/
|
||||
function getLDAPServerInfo()
|
||||
{
|
||||
return $this->ldapserverinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* escapes a string for use in searchfilters meant for ldap_search.
|
||||
*
|
||||
* Escaped Characters are: '*', '(', ')', ' ', '\', NUL
|
||||
* It's actually a PHP-Bug, that we have to escape space.
|
||||
* For all other Characters, refer to RFC2254.
|
||||
*
|
||||
* @param string|array $string either a string to be escaped, or an array of values to be escaped
|
||||
* @return string
|
||||
*/
|
||||
static function quote($string)
|
||||
{
|
||||
return str_replace(array('\\','*','(',')','\0',' '),array('\\\\','\*','\(','\)','\\0','\20'),$string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a single ldap result into a associative array
|
||||
*
|
||||
* @param array $ldap array with numerical and associative indexes and count's
|
||||
* @return boolean|array with only associative index and no count's or false on error (parm is no array)
|
||||
*/
|
||||
static function result2array($ldap)
|
||||
{
|
||||
if (!is_array($ldap)) return false;
|
||||
|
||||
$arr = array();
|
||||
foreach($ldap as $var => $val)
|
||||
{
|
||||
if (is_int($var) || $var == 'count') continue;
|
||||
|
||||
if (is_array($val) && $val['count'] == 1)
|
||||
{
|
||||
$arr[$var] = $val[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($val)) unset($val['count']);
|
||||
|
||||
$arr[$var] = $val;
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to ldap server and return a handle
|
||||
*
|
||||
* If multiple (space-separated) ldap hosts or urls are given, try them in order and
|
||||
* move first successful one to first place in session, to try not working ones
|
||||
* only once per session.
|
||||
*
|
||||
* @param $host ='' ldap host, default $GLOBALS['egw_info']['server']['ldap_host']
|
||||
* @param $dn ='' ldap dn, default $GLOBALS['egw_info']['server']['ldap_root_dn']
|
||||
* @param $passwd ='' ldap pw, default $GLOBALS['egw_info']['server']['ldap_root_pw']
|
||||
* @return resource|boolean resource from ldap_connect() or false on error
|
||||
* @throws Exception\AssertingFailed 'LDAP support unavailable!' (no ldap extension)
|
||||
*/
|
||||
function ldapConnect($host='', $dn='', $passwd='')
|
||||
{
|
||||
if(!function_exists('ldap_connect'))
|
||||
{
|
||||
if ($this->exception_on_error) throw new Exception\AssertionFailed('LDAP support unavailable!');
|
||||
|
||||
printf('<b>Error: LDAP support unavailable</b><br>',$host);
|
||||
return False;
|
||||
}
|
||||
if (empty($host))
|
||||
{
|
||||
$host = $GLOBALS['egw_info']['server']['ldap_host'];
|
||||
}
|
||||
if (empty($dn))
|
||||
{
|
||||
$dn = $GLOBALS['egw_info']['server']['ldap_root_dn'];
|
||||
$passwd = $GLOBALS['egw_info']['server']['ldap_root_pw'];
|
||||
}
|
||||
|
||||
// if multiple hosts given, try them all, but only once per session!
|
||||
if (isset($_SESSION) && isset($_SESSION['ldapConnect']) && isset($_SESSION['ldapConnect'][$host]))
|
||||
{
|
||||
$host = $_SESSION['ldapConnect'][$host];
|
||||
}
|
||||
foreach($hosts=preg_split('/[ ,;]+/', $host) as $h)
|
||||
{
|
||||
if ($this->_connect($h, $dn, $passwd))
|
||||
{
|
||||
if ($h !== $host)
|
||||
{
|
||||
if (isset($_SESSION)) // store working host as first choice in session
|
||||
{
|
||||
$_SESSION['ldapConnect'][$host] = implode(' ',array_unique(array_merge(array($h),$hosts)));
|
||||
}
|
||||
}
|
||||
return $this->ds;
|
||||
}
|
||||
error_log(__METHOD__."('$h', '$dn', \$passwd) Can't connect/bind to ldap server!".
|
||||
($this->ds ? ' '.ldap_error($this->ds).' ('.ldap_errno($this->ds).')' : '').
|
||||
' '.function_backtrace());
|
||||
}
|
||||
// give visible error, only if we cant connect to any ldap server
|
||||
if ($this->exception_on_error) throw new Exception\NoPermission("Can't connect/bind to LDAP server '$host' and dn='$dn'!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to the ldap server and return a handle
|
||||
*
|
||||
* @param string $host ldap host
|
||||
* @param string $dn ldap dn
|
||||
* @param string $passwd ldap pw
|
||||
* @return resource|boolean resource from ldap_connect() or false on error
|
||||
*/
|
||||
private function _connect($host, $dn, $passwd)
|
||||
{
|
||||
if (($use_tls = substr($host,0,6) == 'tls://'))
|
||||
{
|
||||
$port = parse_url($host,PHP_URL_PORT);
|
||||
$host = parse_url($host,PHP_URL_HOST);
|
||||
}
|
||||
// connect to ldap server (never fails, as connection happens in bind!)
|
||||
if(!($this->ds = !empty($port) ? ldap_connect($host, $port) : ldap_connect($host)))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
// set network timeout to not block for minutes
|
||||
ldap_set_option($this->ds, LDAP_OPT_NETWORK_TIMEOUT, 5);
|
||||
|
||||
if(ldap_set_option($this->ds, LDAP_OPT_PROTOCOL_VERSION, 3))
|
||||
{
|
||||
$supportedLDAPVersion = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
$supportedLDAPVersion = 2;
|
||||
}
|
||||
if ($use_tls) ldap_start_tls($this->ds);
|
||||
|
||||
if (!isset($this->ldapserverinfo) ||
|
||||
!is_a($this->ldapserverinfo,'EGroupware\Ldap\ServerInfo') ||
|
||||
$this->ldapserverinfo->host != $host)
|
||||
{
|
||||
//error_log("no ldap server info found");
|
||||
@ldap_bind($this->ds, $GLOBALS['egw_info']['server']['ldap_root_dn'], $GLOBALS['egw_info']['server']['ldap_root_pw']);
|
||||
|
||||
$this->ldapserverinfo = Ldap\ServerInfo::get($this->ds, $host, $supportedLDAPVersion);
|
||||
$this->saveSessionData();
|
||||
}
|
||||
|
||||
if(!@ldap_bind($this->ds, $dn, $passwd))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
return $this->ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect from the ldap server
|
||||
*/
|
||||
function ldapDisconnect()
|
||||
{
|
||||
if(is_resource($this->ds))
|
||||
{
|
||||
ldap_unbind($this->ds);
|
||||
unset($this->ds);
|
||||
unset($this->ldapserverinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* restore the session data
|
||||
*/
|
||||
function restoreSessionData()
|
||||
{
|
||||
if (isset($GLOBALS['egw']->session)) // no availible in setup
|
||||
{
|
||||
$this->ldapserverinfo = Cache::getSession(__CLASS__, 'ldapServerInfo');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* save the session data
|
||||
*/
|
||||
function saveSessionData()
|
||||
{
|
||||
if (isset($GLOBALS['egw']->session)) // no availible in setup
|
||||
{
|
||||
Cache::getSession(__CLASS__, 'ldapServerInfo', $this->ldapserverinfo);
|
||||
}
|
||||
}
|
||||
}
|
243
api/src/Ldap/ServerInfo.php
Normal file
243
api/src/Ldap/ServerInfo.php
Normal file
@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API - LDAP server information
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Lars Kneschke <l.kneschke@metaways.de>
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage ldap
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Ldap;
|
||||
|
||||
/**
|
||||
* Class to store and retrieve information (eg. supported object classes) of a connected ldap server
|
||||
*/
|
||||
class ServerInfo
|
||||
{
|
||||
/**
|
||||
* Unknown LDAP server
|
||||
*/
|
||||
const UNKNOWN = 0;
|
||||
/**
|
||||
* OpenLDAP server
|
||||
*/
|
||||
const OPENLDAP = 1;
|
||||
/**
|
||||
* Samba4 LDAP server
|
||||
*/
|
||||
const SAMBA4 = 2;
|
||||
|
||||
/**
|
||||
* @var array $namingContext holds the supported namingcontexts
|
||||
*/
|
||||
var $namingContext = array();
|
||||
|
||||
/**
|
||||
* @var string $version holds the LDAP server version
|
||||
*/
|
||||
var $version = 2;
|
||||
|
||||
/**
|
||||
* @var integer $serverType holds the type of LDAP server(OpenLDAP, ADS, NDS, ...)
|
||||
*/
|
||||
var $serverType = 0;
|
||||
|
||||
/**
|
||||
* @var string $_subSchemaEntry the subschema entry DN
|
||||
*/
|
||||
var $subSchemaEntry = '';
|
||||
|
||||
/**
|
||||
* @var array $supportedObjectClasses the supported objectclasses
|
||||
*/
|
||||
var $supportedObjectClasses = array();
|
||||
|
||||
/**
|
||||
* @var array $supportedOIDs the supported OIDs
|
||||
*/
|
||||
var $supportedOIDs = array();
|
||||
|
||||
/**
|
||||
* Name of host
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $host;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $host
|
||||
*/
|
||||
function __construct($host)
|
||||
{
|
||||
$this->host = $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the version
|
||||
*
|
||||
* @return integer the supported ldap version
|
||||
*/
|
||||
function getVersion()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the namingcontexts
|
||||
*
|
||||
* @param array $_namingContext the supported namingcontexts
|
||||
*/
|
||||
function setNamingContexts($_namingContext)
|
||||
{
|
||||
$this->namingContext = $_namingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the type of the ldap server(OpenLDAP, ADS, NDS, ...)
|
||||
*
|
||||
* @param integer $_serverType the type of ldap server
|
||||
*/
|
||||
function setServerType($_serverType)
|
||||
{
|
||||
$this->serverType = $_serverType;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the DN for the subschema entry
|
||||
*
|
||||
* @param string $_subSchemaEntry the subschema entry DN
|
||||
*/
|
||||
function setSubSchemaEntry($_subSchemaEntry)
|
||||
{
|
||||
$this->subSchemaEntry = $_subSchemaEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the supported objectclasses
|
||||
*
|
||||
* @param array $_supportedObjectClasses the supported objectclasses
|
||||
*/
|
||||
function setSupportedObjectClasses($_supportedObjectClasses)
|
||||
{
|
||||
$this->supportedOIDs = $_supportedObjectClasses;
|
||||
$this->supportedObjectClasses = array_flip($_supportedObjectClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the version
|
||||
*
|
||||
* @param integer $_version the supported ldap version
|
||||
*/
|
||||
function setVersion($_version)
|
||||
{
|
||||
$this->version = $_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks for supported objectclasses
|
||||
*
|
||||
* @return bool returns true if the ldap server supports this objectclass
|
||||
*/
|
||||
function supportsObjectClass($_objectClass)
|
||||
{
|
||||
if($this->supportedObjectClasses[strtolower($_objectClass)])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query given ldap connection for available information
|
||||
*
|
||||
* @param resource $ds
|
||||
* @param string $host
|
||||
* @param int $version 2 or 3
|
||||
* @return ldapserverinfo
|
||||
*/
|
||||
public static function get($ds, $host, $version=3)
|
||||
{
|
||||
$filter='(objectclass=*)';
|
||||
$justthese = array('structuralObjectClass','namingContexts','supportedLDAPVersion','subschemaSubentry','vendorname');
|
||||
if(($sr = @ldap_read($ds, '', $filter, $justthese)))
|
||||
{
|
||||
if(($info = ldap_get_entries($ds, $sr)))
|
||||
{
|
||||
$ldapServerInfo = new ServerInfo($host);
|
||||
$ldapServerInfo->setVersion($version);
|
||||
|
||||
// check for naming contexts
|
||||
if($info[0]['namingcontexts'])
|
||||
{
|
||||
for($i=0; $i<$info[0]['namingcontexts']['count']; $i++)
|
||||
{
|
||||
$namingcontexts[] = $info[0]['namingcontexts'][$i];
|
||||
}
|
||||
$ldapServerInfo->setNamingContexts($namingcontexts);
|
||||
}
|
||||
|
||||
// check for ldap server type
|
||||
if($info[0]['structuralobjectclass'])
|
||||
{
|
||||
switch($info[0]['structuralobjectclass'][0])
|
||||
{
|
||||
case 'OpenLDAProotDSE':
|
||||
$ldapServerType = OPENLDAP_LDAPSERVER;
|
||||
break;
|
||||
default:
|
||||
$ldapServerType = UNKNOWN_LDAPSERVER;
|
||||
break;
|
||||
}
|
||||
$ldapServerInfo->setServerType($ldapServerType);
|
||||
}
|
||||
if ($info[0]['vendorname'] && stripos($info[0]['vendorname'][0], 'samba') !== false)
|
||||
{
|
||||
$ldapServerInfo->setServerType(SAMBA4_LDAPSERVER);
|
||||
}
|
||||
|
||||
// check for subschema entry dn
|
||||
if($info[0]['subschemasubentry'])
|
||||
{
|
||||
$subschemasubentry = $info[0]['subschemasubentry'][0];
|
||||
$ldapServerInfo->setSubSchemaEntry($subschemasubentry);
|
||||
}
|
||||
|
||||
// create list of supported objetclasses
|
||||
if(!empty($subschemasubentry))
|
||||
{
|
||||
$filter='(objectclass=*)';
|
||||
$justthese = array('objectClasses');
|
||||
|
||||
if(($sr = ldap_read($ds, $subschemasubentry, $filter, $justthese)))
|
||||
{
|
||||
if(($info = ldap_get_entries($ds, $sr)))
|
||||
{
|
||||
if($info[0]['objectclasses']) {
|
||||
for($i=0; $i<$info[0]['objectclasses']['count']; $i++)
|
||||
{
|
||||
$matches = null;
|
||||
if(preg_match('/^\( (.*) NAME \'(\w*)\' /', $info[0]['objectclasses'][$i], $matches))
|
||||
{
|
||||
#_debug_array($matches);
|
||||
if(count($matches) == 3)
|
||||
{
|
||||
$supportedObjectClasses[$matches[1]] = strtolower($matches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ldapServerInfo->setSupportedObjectClasses($supportedObjectClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ldapServerInfo;
|
||||
}
|
||||
}
|
@ -167,7 +167,7 @@ class Storage extends Storage\Base
|
||||
$this->extra_join_order = " LEFT JOIN $extra_table extra_order ON $table.$this->autoinc_id=extra_order.$this->extra_id";
|
||||
$this->extra_join_filter = " JOIN $extra_table extra_filter ON $table.$this->autoinc_id=extra_filter.$this->extra_id";
|
||||
|
||||
$this->customfields = Customfields::get($app, false, null, $db);
|
||||
$this->customfields = Storage\Customfields::get($app, false, null, $db);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,9 @@
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api;
|
||||
namespace EGroupware\Api\Storage;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// explicitly reference classes still in phpgwapi
|
||||
use common;
|
||||
@ -28,7 +30,7 @@ class Customfields implements \IteratorAggregate
|
||||
/**
|
||||
* Reference to the global db class
|
||||
*
|
||||
* @var Db
|
||||
* @var Api\Db
|
||||
*/
|
||||
static protected $db;
|
||||
|
||||
@ -94,13 +96,13 @@ class Customfields implements \IteratorAggregate
|
||||
*/
|
||||
function getIterator()
|
||||
{
|
||||
return new Db\CallbackIterator($this->iterator, function($_row)
|
||||
return new Api\Db\CallbackIterator($this->iterator, function($_row)
|
||||
{
|
||||
$row = Db::strip_array_keys($_row, 'cf_');
|
||||
$row = Api\Db::strip_array_keys($_row, 'cf_');
|
||||
$row['private'] = $row['private'] ? explode(',', $row['private']) : array();
|
||||
$row['type2'] = $row['type2'] ? explode(',', $row['type2']) : array();
|
||||
$row['values'] = json_decode($row['values'], true);
|
||||
$row['needed'] = Db::from_bool($row['needed']);
|
||||
$row['needed'] = Api\Db::from_bool($row['needed']);
|
||||
|
||||
return $row;
|
||||
}, array(), function($row)
|
||||
@ -137,18 +139,18 @@ class Customfields implements \IteratorAggregate
|
||||
public static function get($app, $all_private_too=false, $only_type2=null, egw_db $db=null)
|
||||
{
|
||||
$cache_key = $app.':'.($all_private_too?'all':$GLOBALS['egw_info']['user']['account_id']).':'.$only_type2;
|
||||
$cfs = Cache::getInstance(__CLASS__, $cache_key);
|
||||
$cfs = Api\Cache::getInstance(__CLASS__, $cache_key);
|
||||
|
||||
if (!isset($cfs))
|
||||
{
|
||||
$cfs = iterator_to_array(new Customfields($app, $all_private_too, $only_type2, 0, null, $db));
|
||||
|
||||
Cache::setInstance(__CLASS__, $cache_key, $cfs);
|
||||
$cached = Cache::getInstance(__CLASS__, $app);
|
||||
Api\Cache::setInstance(__CLASS__, $cache_key, $cfs);
|
||||
$cached = Api\Cache::getInstance(__CLASS__, $app);
|
||||
if (!in_array($cache_key, (array)$cached))
|
||||
{
|
||||
$cached[] = $cache_key;
|
||||
Cache::setInstance(__CLASS__, $app, $cached);
|
||||
Api\Cache::setInstance(__CLASS__, $app, $cached);
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__."('$app', $all_private_too, '$only_type2') returning fields: ".implode(', ', array_keys($cfs)));
|
||||
@ -224,7 +226,7 @@ class Customfields implements \IteratorAggregate
|
||||
case 'date-time':
|
||||
if ($value)
|
||||
{
|
||||
$value = DateTime::to($value, $field['type'] == 'date' ? true : '');
|
||||
$value = Api\DateTime::to($value, $field['type'] == 'date' ? true : '');
|
||||
}
|
||||
break;
|
||||
|
||||
@ -461,13 +463,13 @@ class Customfields implements \IteratorAggregate
|
||||
*/
|
||||
protected static function invalidate_cache($app)
|
||||
{
|
||||
if (($cached = Cache::getInstance(__CLASS__, $app)))
|
||||
if (($cached = Api\Cache::getInstance(__CLASS__, $app)))
|
||||
{
|
||||
foreach($cached as $key)
|
||||
{
|
||||
Cache::unsetInstance(__CLASS__, $key);
|
||||
Api\Cache::unsetInstance(__CLASS__, $key);
|
||||
}
|
||||
Cache::unsetInstance(__CLASS__, $app);
|
||||
Api\Cache::unsetInstance(__CLASS__, $app);
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,7 +534,7 @@ class Customfields implements \IteratorAggregate
|
||||
/**
|
||||
* Initialise our db
|
||||
*
|
||||
* We use a reference here (no clone), as we no longer use Db::row() or Db::next_record()!
|
||||
* We use a reference here (no clone), as we no longer use Api\Db::row() or Api\Db::next_record()!
|
||||
*
|
||||
*/
|
||||
public static function init_static()
|
288
api/src/Storage/History.php
Normal file
288
api/src/Storage/History.php
Normal file
@ -0,0 +1,288 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API - Storage history logging
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Joseph Engo <jengo@phpgroupware.org>
|
||||
* @copyright 2001 by Joseph Engo <jengo@phpgroupware.org>
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> new DB-methods and search
|
||||
*
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage storage
|
||||
* @access public
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Storage;
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* Record history logging service
|
||||
*
|
||||
* This class need to be instanciated for EACH app, which wishes to use it!
|
||||
*/
|
||||
class History
|
||||
{
|
||||
/**
|
||||
* Reference to the global db object
|
||||
*
|
||||
* @var Api\Db
|
||||
*/
|
||||
var $db;
|
||||
const TABLE = 'egw_history_log';
|
||||
/**
|
||||
* App.name this class is instanciated for / working on
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
var $appname;
|
||||
var $user;
|
||||
var $types = array(
|
||||
'C' => 'Created',
|
||||
'D' => 'Deleted',
|
||||
'E' => 'Edited'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $appname app name this instance operates on
|
||||
* @return historylog
|
||||
*/
|
||||
function __construct($appname='',$user=null)
|
||||
{
|
||||
$this->appname = $appname ? $appname : $GLOBALS['egw_info']['flags']['currentapp'];
|
||||
$this->user = !is_null($user) ? $user : $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
if (is_object($GLOBALS['egw_setup']->db))
|
||||
{
|
||||
$this->db = $GLOBALS['egw_setup']->db;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db = $GLOBALS['egw']->db;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the history-log of one or multiple records of $this->appname
|
||||
*
|
||||
* @param int|array $record_id one or more id's of $this->appname, or null to delete ALL records of $this->appname
|
||||
* @return int number of deleted records/rows (0 is not necessaryly an error, it can just mean there's no record!)
|
||||
*/
|
||||
function delete($record_id)
|
||||
{
|
||||
$where = array('history_appname' => $this->appname);
|
||||
|
||||
if (is_array($record_id) || is_numeric($record_id))
|
||||
{
|
||||
$where['history_record_id'] = $record_id;
|
||||
}
|
||||
$this->db->delete(self::TABLE,$where,__LINE__,__FILE__);
|
||||
|
||||
return $this->db->affected_rows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a history record, if $new_value != $old_value
|
||||
*
|
||||
* @param string $status 2 letter code: eg. $this->types: C=Created, D=Deleted, E=Edited
|
||||
* @param int $record_id it of the record in $this->appname (set by the constructor)
|
||||
* @param string $new_value new value
|
||||
* @param string $old_value old value
|
||||
*/
|
||||
function add($status,$record_id,$new_value,$old_value)
|
||||
{
|
||||
if ($new_value != $old_value)
|
||||
{
|
||||
$this->db->insert(self::TABLE,array(
|
||||
'history_record_id' => $record_id,
|
||||
'history_appname' => $this->appname,
|
||||
'history_owner' => $this->user,
|
||||
'history_status' => $status,
|
||||
'history_new_value' => $new_value,
|
||||
'history_old_value' => $old_value,
|
||||
'history_timestamp' => time(),
|
||||
'sessionid' => $GLOBALS['egw']->session->sessionid_access_log,
|
||||
),false,__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to add a history record
|
||||
*/
|
||||
public static function static_add($appname, $id, $user, $field_code, $new_value, $old_value = '')
|
||||
{
|
||||
if ($new_value != $old_value)
|
||||
{
|
||||
$GLOBALS['egw']->db->insert(self::TABLE,array(
|
||||
'history_record_id' => $id,
|
||||
'history_appname' => $appname,
|
||||
'history_owner' => (int)$user,
|
||||
'history_status' => $field_code,
|
||||
'history_new_value' => $new_value,
|
||||
'history_old_value' => $old_value,
|
||||
'history_timestamp' => time(),
|
||||
'sessionid' => $GLOBALS['egw']->session->sessionid_access_log,
|
||||
),false,__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search history-log
|
||||
*
|
||||
* @param array|int $filter array with filters, or int record_id
|
||||
* @param string $order ='history_id' sorting after history_id is identical to history_timestamp
|
||||
* @param string $sort ='DESC'
|
||||
* @param int $limit =null only return this many entries
|
||||
* @return array of arrays with keys id, record_id, appname, owner (account_id), status, new_value, old_value,
|
||||
* timestamp (Y-m-d H:i:s in servertime), user_ts (timestamp in user-time)
|
||||
*/
|
||||
function search($filter,$order='history_id',$sort='DESC',$limit=null)
|
||||
{
|
||||
if (!is_array($filter)) $filter = is_numeric($filter) ? array('history_record_id' => $filter) : array();
|
||||
|
||||
if (!$order || !preg_match('/^[a-z0-9_]+$/i',$order) || !preg_match('/^(asc|desc)?$/i',$sort))
|
||||
{
|
||||
$orderby = 'ORDER BY history_id DESC';
|
||||
}
|
||||
else
|
||||
{
|
||||
$orderby = "ORDER BY $order $sort";
|
||||
}
|
||||
foreach($filter as $col => $value)
|
||||
{
|
||||
if (!is_numeric($col) && substr($col,0,8) != 'history_')
|
||||
{
|
||||
$filter['history_'.$col] = $value;
|
||||
unset($filter[$col]);
|
||||
}
|
||||
}
|
||||
if (!isset($filter['history_appname'])) $filter['history_appname'] = $this->appname;
|
||||
|
||||
// do not try to read all history entries of an app
|
||||
if (!$filter['history_record_id']) return array();
|
||||
|
||||
$rows = array();
|
||||
foreach($this->db->select(self::TABLE, '*', $filter, __LINE__, __FILE__,
|
||||
isset($limit) ? 0 : false, $orderby, 'phpgwapi', $limit) as $row)
|
||||
{
|
||||
$row['user_ts'] = $this->db->from_timestamp($row['history_timestamp']) + 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
|
||||
$rows[] = Api\Db::strip_array_keys($row,'history_');
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a slice of history records
|
||||
*
|
||||
* Similar to search(), except this one can take a start and a number of records
|
||||
*
|
||||
* @see Base::get_rows()
|
||||
*/
|
||||
public static function get_rows(&$query, &$rows)
|
||||
{
|
||||
$filter = array();
|
||||
$rows = array();
|
||||
$filter['history_appname'] = $query['appname'];
|
||||
$filter['history_record_id'] = $query['record_id'];
|
||||
if(is_array($query['colfilter'])) {
|
||||
foreach($query['colfilter'] as $column => $value) {
|
||||
$filter[$column] = $value;
|
||||
}
|
||||
}
|
||||
if ($GLOBALS['egw']->db->Type == 'mysql' && $GLOBALS['egw']->db->ServerInfo['version'] >= 4.0)
|
||||
{
|
||||
$mysql_calc_rows = 'SQL_CALC_FOUND_ROWS ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$total = $GLOBALS['egw']->db->select(self::TABLE,'COUNT(*)',$filter,__LINE__,__FILE__,false,'','phpgwapi',0)->fetchColumn();
|
||||
}
|
||||
// filter out private (or no longer defined) custom fields
|
||||
if ($filter['history_appname'])
|
||||
{
|
||||
$to_or[] = "history_status NOT LIKE '#%'";
|
||||
// explicitly allow "##" used to store iCal/vCard X-attributes
|
||||
if (in_array($filter['history_appname'], array('calendar','infolog','addressbook')))
|
||||
{
|
||||
$to_or[] = "history_status LIKE '##%'";
|
||||
}
|
||||
if (($cfs = Customfields::get($filter['history_appname'])))
|
||||
{
|
||||
$to_or[] = 'history_status IN ('.implode(',', array_map(function($str)
|
||||
{
|
||||
return $GLOBALS['egw']->db->quote('#'.$str);
|
||||
}, array_keys($cfs))).')';
|
||||
}
|
||||
$filter[] = '('.implode(' OR ', $to_or).')';
|
||||
}
|
||||
$_query = array(array(
|
||||
'table' => self::TABLE,
|
||||
'cols' => array('history_id', 'history_record_id','history_appname','history_owner','history_status','history_new_value', 'history_timestamp','history_old_value'),
|
||||
'where' => $filter,
|
||||
));
|
||||
|
||||
// Add in files, if possible
|
||||
if($GLOBALS['egw_info']['user']['apps']['filemanager'] &&
|
||||
$file = Api\Vfs\Sqlfs\StreamWrapper::url_stat("/apps/{$query['appname']}/{$query['record_id']}",STREAM_URL_STAT_LINK))
|
||||
{
|
||||
$_query[] = array(
|
||||
'table' => Api\Vfs\Sqlfs\StreamWrapper::TABLE,
|
||||
'cols' =>array('fs_id', 'fs_dir', "'filemanager'",'COALESCE(fs_modifier,fs_creator)',"'~file~'",'fs_name','fs_modified', 'fs_mime'),
|
||||
'where' => array('fs_dir' => $file['ino'])
|
||||
);
|
||||
}
|
||||
$new_file_id = array();
|
||||
foreach($GLOBALS['egw']->db->union(
|
||||
$_query,
|
||||
__LINE__, __FILE__,
|
||||
' ORDER BY ' . ($query['order'] ? $query['order'] : 'history_timestamp') . ' ' . ($query['sort'] ? $query['sort'] : 'DESC'),
|
||||
$query['start'],
|
||||
$query['num_rows']
|
||||
) as $row)
|
||||
{
|
||||
$row['user_ts'] = $GLOBALS['egw']->db->from_timestamp($row['history_timestamp']) + 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
|
||||
|
||||
// Explode multi-part values
|
||||
foreach(array('history_new_value','history_old_value') as $field)
|
||||
{
|
||||
if(strpos($row[$field],Tracking::ONE2N_SEPERATOR) !== false)
|
||||
{
|
||||
$row[$field] = explode(Tracking::ONE2N_SEPERATOR,$row[$field]);
|
||||
}
|
||||
}
|
||||
// Get information needed for proper display
|
||||
if($row['history_appname'] == 'filemanager')
|
||||
{
|
||||
$new_version = $new_file_id[$row['history_new_value']];
|
||||
$new_file_id[$row['history_new_value']] = count($rows);
|
||||
$path = Api\Vfs\Sqlfs\StreamWrapper::id2path($row['history_id']);
|
||||
|
||||
// Apparently we don't have to do anything with it, just ask...
|
||||
// without this, previous versions are not handled properly
|
||||
Api\Vfs::getExtraInfo($path);
|
||||
|
||||
$row['history_new_value'] = array(
|
||||
'path' => $path,
|
||||
'name' => Api\Vfs::basename($path),
|
||||
'mime' => $row['history_old_value']
|
||||
);
|
||||
$row['history_old_value'] = '';
|
||||
if($new_version !== null)
|
||||
{
|
||||
$rows[$new_version]['old_value'] = $row['history_new_value'];
|
||||
}
|
||||
}
|
||||
$rows[] = Api\Db::strip_array_keys($row,'history_');
|
||||
}
|
||||
if ($mysql_calc_rows)
|
||||
{
|
||||
$total = $GLOBALS['egw']->db->query('SELECT FOUND_ROWS()')->fetchColumn();
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
}
|
1220
api/src/Storage/Tracking.php
Normal file
1220
api/src/Storage/Tracking.php
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,13 @@
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @package setup
|
||||
* @copyright (c) 2007-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* setup command: test or create the ldap connection and hierarchy
|
||||
*
|
||||
@ -121,7 +123,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
{
|
||||
if (!empty($this->domain) && !preg_match('/^([a-z0-9_-]+\.)*[a-z0-9]+/i',$this->domain))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang("'%1' is no valid domain name!",$this->domain));
|
||||
throw new Api\Exception\WrongUserinput(lang("'%1' is no valid domain name!",$this->domain));
|
||||
}
|
||||
if ($this->remote_id && $check_only && !in_array($this->sub_command, array('set_mailbox', 'sid2uidnumber', 'copy2ad')))
|
||||
{
|
||||
@ -186,7 +188,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// check if base does exist
|
||||
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
throw new Api\Exception\WrongUserinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
}
|
||||
|
||||
if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base,
|
||||
@ -194,7 +196,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
array('uidNumber','gidNumber','uid','cn', 'objectClass',self::sambaSID))) ||
|
||||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
|
||||
{
|
||||
throw new egw_exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
|
||||
throw new Api\Exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
|
||||
}
|
||||
$change = $accounts = array();
|
||||
$cmd_change_account_id = 'admin/admin-cli.php --change-account-id <admin>@<domain>,<adminpw>';
|
||||
@ -203,7 +205,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
{
|
||||
if ($key === 'count') continue;
|
||||
|
||||
$entry = ldap::result2array($entry);
|
||||
$entry = Api\Ldap::result2array($entry);
|
||||
$accounts[$entry['dn']] = $entry;
|
||||
//print_r($entry);
|
||||
|
||||
@ -247,7 +249,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
}
|
||||
if (!$check_only && $modify && !ldap_modify($this->test_ldap->ds, $dn, $modify))
|
||||
{
|
||||
throw new egw_exception("Failed to modify ldap: !ldap_modify({$this->test_ldap->ds}, '$dn', ".array2string($modify).") ".ldap_error($this->test_ldap->ds).
|
||||
throw new Api\Exception("Failed to modify ldap: !ldap_modify({$this->test_ldap->ds}, '$dn', ".array2string($modify).") ".ldap_error($this->test_ldap->ds).
|
||||
"\n- ".implode("\n- ", $msg)); // EGroupware change already run successful
|
||||
}
|
||||
if ($modify) ++$changed;
|
||||
@ -313,7 +315,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// check if ads base does exist
|
||||
if (!@ldap_read($ads->ds, $this->ads_context, 'objectClass=*'))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Ads dn "%1" NOT found!',$this->ads_context));
|
||||
throw new Api\Exception\WrongUserInput(lang('Ads dn "%1" NOT found!',$this->ads_context));
|
||||
}
|
||||
|
||||
// connect to source ldap
|
||||
@ -322,7 +324,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// check if ldap base does exist
|
||||
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
}
|
||||
|
||||
if (!($sr = ldap_search($this->test_ldap->ds,$this->ldap_base,
|
||||
@ -330,7 +332,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
'(&(objectClass=posixAccount)('.self::sambaSID.'=*)(!(uid=*$)))', $attrs)) ||
|
||||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
|
||||
{
|
||||
throw new egw_exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
|
||||
throw new Api\Exception(lang('Error searching "dn=%1" for "%2"!',$this->ldap_base, $search));
|
||||
}
|
||||
$changed = 0;
|
||||
$utc_diff = null;
|
||||
@ -338,12 +340,12 @@ class setup_cmd_ldap extends setup_cmd
|
||||
{
|
||||
if ($key === 'count') continue;
|
||||
|
||||
$entry_arr = ldap::result2array($entry);
|
||||
$entry_arr = Api\Ldap::result2array($entry);
|
||||
$uid = $entry_arr['uid'];
|
||||
$entry = array_diff_key($entry_arr, $ignore_attr);
|
||||
|
||||
if (!($sr = ldap_search($ads->ds, $this->ads_context,
|
||||
$search='(&(objectClass=user)(sAMAccountName='.ldap::quote($uid).'))', array('dn'))) ||
|
||||
$search='(&(objectClass=user)(sAMAccountName='.Api\Ldap::quote($uid).'))', array('dn'))) ||
|
||||
!($dest = ldap_get_entries($ads->ds, $sr)))
|
||||
{
|
||||
$msg[] = lang('User "%1" not found!', $uid);
|
||||
@ -591,7 +593,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// should we run any or some addAccount hooks
|
||||
if ($this->add_account_hook)
|
||||
{
|
||||
// setting up egw_info array with new ldap information, so hook can use ldap::ldapConnect()
|
||||
// setting up egw_info array with new ldap information, so hook can use Api\Ldap::ldapConnect()
|
||||
if (!$egw_info_set++)
|
||||
{
|
||||
foreach(array('ldap_host','ldap_root_dn','ldap_root_pw','ldap_context','ldap_group_context','ldap_search_filter','ldap_encryptin_type','mail_suffix','mail_login_type') as $name)
|
||||
@ -798,7 +800,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* @param string $dn =null default $this->ldap_root_dn
|
||||
* @param string $pw =null default $this->ldap_root_pw
|
||||
* @param string $host =null default $this->ldap_host, hostname, ip or ldap-url
|
||||
* @throws egw_exception_wrong_userinput Can not connect to ldap ...
|
||||
* @throws Api\Exception\WrongUserInput Can not connect to ldap ...
|
||||
*/
|
||||
private function connect($dn=null,$pw=null,$host=null)
|
||||
{
|
||||
@ -806,9 +808,9 @@ class setup_cmd_ldap extends setup_cmd
|
||||
if (is_null($pw)) $pw = $this->ldap_root_pw;
|
||||
if (is_null($host)) $host = $this->ldap_host;
|
||||
|
||||
if (!$pw) // ldap::ldapConnect use the current eGW's pw otherwise
|
||||
if (!$pw) // Api\Ldap::ldapConnect use the current eGW's pw otherwise
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('You need to specify a password!'));
|
||||
throw new Api\Exception\WrongUserInput(lang('You need to specify a password!'));
|
||||
}
|
||||
$this->test_ldap = new ldap();
|
||||
|
||||
@ -821,7 +823,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
|
||||
if (!$ds)
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Can not connect to LDAP server on host %1 using DN %2!',
|
||||
throw new Api\Exception\WrongUserInput(lang('Can not connect to LDAP server on host %1 using DN %2!',
|
||||
$host,$dn).($this->test_ldap->ds ? ' ('.ldap_error($this->test_ldap->ds).')' : ''));
|
||||
}
|
||||
return lang('Successful connected to LDAP server on %1 using DN %2.',$this->ldap_host,$dn);
|
||||
@ -831,7 +833,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* Count active (not expired) users
|
||||
*
|
||||
* @return int number of active users
|
||||
* @throws egw_exception_wrong_userinput
|
||||
* @throws Api\Exception\WrongUserInput
|
||||
*/
|
||||
private function users()
|
||||
{
|
||||
@ -840,7 +842,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
$sr = ldap_list($this->test_ldap->ds,$this->ldap_context,'ObjectClass=posixAccount',array('dn','shadowExpire'));
|
||||
if (!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
|
||||
{
|
||||
throw new egw_exception('Error listing "dn=%1"!',$this->ldap_context);
|
||||
throw new Api\Exception('Error listing "dn=%1"!',$this->ldap_context);
|
||||
}
|
||||
$num = 0;
|
||||
foreach($entries as $n => $entry)
|
||||
@ -856,7 +858,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* Check and if does not yet exist create the new database and user
|
||||
*
|
||||
* @return string with success message
|
||||
* @throws egw_exception_wrong_userinput
|
||||
* @throws Api\Exception\WrongUserInput
|
||||
*/
|
||||
private function create()
|
||||
{
|
||||
@ -883,7 +885,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* Delete whole LDAP tree of an instance dn=$this->ldap_base using $this->ldap_admin/_pw
|
||||
*
|
||||
* @return string with success message
|
||||
* @throws egw_exception if dn not found, not listable or delete fails
|
||||
* @throws Api\Exception if dn not found, not listable or delete fails
|
||||
*/
|
||||
private function delete_base()
|
||||
{
|
||||
@ -897,12 +899,12 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// some precausion to not delete whole ldap tree!
|
||||
if (count(explode(',',$this->ldap_base)) < 2)
|
||||
{
|
||||
throw new egw_exception_assertion_failed(lang('Refusing to delete dn "%1"!',$this->ldap_base));
|
||||
throw new Api\Exception\AssertionFailed(lang('Refusing to delete dn "%1"!',$this->ldap_base));
|
||||
}
|
||||
// check if base does exist
|
||||
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
}
|
||||
return lang('LDAP dn="%1" with %2 entries deleted.',
|
||||
$this->ldap_base,$this->rdelete($this->ldap_base));
|
||||
@ -913,14 +915,14 @@ class setup_cmd_ldap extends setup_cmd
|
||||
*
|
||||
* @param string $dn
|
||||
* @return int integer number of deleted entries
|
||||
* @throws egw_exception if dn not listable or delete fails
|
||||
* @throws Api\Exception if dn not listable or delete fails
|
||||
*/
|
||||
private function rdelete($dn)
|
||||
{
|
||||
if (!($sr = ldap_list($this->test_ldap->ds,$dn,'ObjectClass=*',array(''))) ||
|
||||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
|
||||
{
|
||||
throw new egw_exception(lang('Error listing "dn=%1"!',$dn));
|
||||
throw new Api\Exception(lang('Error listing "dn=%1"!',$dn));
|
||||
}
|
||||
$deleted = 0;
|
||||
foreach($entries as $n => $entry)
|
||||
@ -930,7 +932,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
}
|
||||
if (!ldap_delete($this->test_ldap->ds,$dn))
|
||||
{
|
||||
throw new egw_exception(lang('Error deleting "dn=%1"!',$dn));
|
||||
throw new Api\Exception(lang('Error deleting "dn=%1"!',$dn));
|
||||
}
|
||||
return ++$deleted;
|
||||
}
|
||||
@ -944,7 +946,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* @param string $this->mbox_attr ='mailmessagestore' lowercase!!!
|
||||
* @param string $this->mail_login_type ='email' 'email', 'vmailmgr', 'standard' or 'uidNumber'
|
||||
* @return string with success message N entries modified
|
||||
* @throws egw_exception if dn not found, not listable or delete fails
|
||||
* @throws Api\Exception if dn not found, not listable or delete fails
|
||||
*/
|
||||
private function set_mailbox($check_only=false)
|
||||
{
|
||||
@ -958,7 +960,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
// check if base does exist
|
||||
if (!@ldap_read($this->test_ldap->ds,$this->ldap_base,'objectClass=*'))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
throw new Api\Exception\WrongUserInput(lang('Base dn "%1" NOT found!',$this->ldap_base));
|
||||
}
|
||||
$object_class = $this->object_class ? $this->object_class : 'qmailUser';
|
||||
$mbox_attr = $this->mbox_attr ? $this->mbox_attr : 'mailmessagestore';
|
||||
@ -968,7 +970,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
'objectClass='.$object_class,array('mail','uidNumber','uid',$mbox_attr))) ||
|
||||
!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
|
||||
{
|
||||
throw new egw_exception(lang('Error listing "dn=%1"!',$this->ldap_base));
|
||||
throw new Api\Exception(lang('Error listing "dn=%1"!',$this->ldap_base));
|
||||
}
|
||||
$modified = 0;
|
||||
foreach($entries as $n => $entry)
|
||||
@ -987,7 +989,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
$mbox_attr => $mbox,
|
||||
)))
|
||||
{
|
||||
throw new egw_exception(lang("Error modifying dn=%1: %2='%3'!",$entry['dn'],$mbox_attr,$mbox));
|
||||
throw new Api\Exception(lang("Error modifying dn=%1: %2='%3'!",$entry['dn'],$mbox_attr,$mbox));
|
||||
}
|
||||
++$modified;
|
||||
if ($check_only) echo "$modified: $entry[dn]: $mbox_attr={$entry[$mbox_attr][0]} --> $mbox\n";
|
||||
@ -1015,7 +1017,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
* @param string $dn dn to create, eg. "cn=admin,dc=local"
|
||||
* @param array $extra =array() extra attributes to set
|
||||
* @return boolean true if the node was create, false if it was already there
|
||||
* @throws egw_exception_wrong_userinput
|
||||
* @throws Api\Exception\WrongUserinput
|
||||
*/
|
||||
private function _create_node($dn,$extra=array())
|
||||
{
|
||||
@ -1035,7 +1037,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
|
||||
if (!isset(self::$requiredObjectclasses[$name]))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Can not create DN %1!',$dn).' '.
|
||||
throw new Api\Exception\WrongUserinput(lang('Can not create DN %1!',$dn).' '.
|
||||
lang('Supported node types:').implode(', ',array_keys(self::$requiredObjectclasses)));
|
||||
}
|
||||
if ($name == 'dc') $extra['o'] = $value; // required by organisation
|
||||
@ -1046,7 +1048,7 @@ class setup_cmd_ldap extends setup_cmd
|
||||
'objectClass' => self::$requiredObjectclasses[$name],
|
||||
)+$extra))
|
||||
{
|
||||
throw new egw_exception_wrong_userinput(lang('Can not create DN %1!',$dn).
|
||||
throw new Api\Exception\WrongUserinput(lang('Can not create DN %1!',$dn).
|
||||
' ('.ldap_error($this->test_ldap->ds).', attributes='.print_r($attr,true).')');
|
||||
}
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user