diff --git a/addressbook/inc/class.bocontacts.inc.php b/addressbook/inc/class.bocontacts.inc.php index 0da128adae..590075137e 100755 --- a/addressbook/inc/class.bocontacts.inc.php +++ b/addressbook/inc/class.bocontacts.inc.php @@ -82,6 +82,14 @@ class bocontacts extends socontacts 'url', 'tz', ); + + /** + * Which fields is a (non-admin) user allowed to edit in his own account + * + * @var array + */ + var $own_account_acl; + /** * @var double $org_common_factor minimum percentage of the contacts with identical values to construct the "common" (virtual) org-entry */ @@ -120,7 +128,7 @@ class bocontacts extends socontacts $this->contact_fields = array( 'id' => lang('Contact ID'), - 'tid' => lang('Type'), + 'tid' => lang('Typ'), 'owner' => lang('Addressbook'), 'private' => lang('private'), 'cat_id' => lang('Category'), @@ -213,6 +221,12 @@ class bocontacts extends socontacts 'adr_two_countryname' => lang('country').' ('.lang('business').')', ); //_debug_array($this->contact_fields); + $this->own_account_acl = unserialize($GLOBALS['egw_info']['server']['own_account_acl']); + // we have only one acl (n_fn) for the whole name, as not all backends store every part in an own field + if ($this->own_account_acl && in_array('n_fn',$this->own_account_acl)) + { + $this->own_account_acl = array_merge($this->own_account_acl,array('n_prefix','n_given','n_middle','n_family','n_suffix')); + } } /** @@ -447,8 +461,20 @@ class bocontacts extends socontacts $contact['n_fn'] = $this->fullname($contact); if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact); } + $to_write = $contact; + // (non-admin) user editing his own account, make sure he does not change fields he is not allowed to (eg. via SyncML or xmlrpc) + if (!$ignore_acl && !$contact['owner'] && !$this->is_admin($contact)) + { + foreach($contact as $field => $value) + { + if (!in_array($field,$this->own_account_acl) && !in_array($field,array('id','owner','account_id','modified','modifier'))) + { + unset($to_write[$field]); // user is now allowed to change that + } + } + } // we dont update the content-history, if we run inside setup (admin-account-creation) - if(!($this->error = parent::save($contact)) && is_object($GLOBALS['egw']->contenthistory)) + if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory)) { $GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time()); @@ -456,6 +482,12 @@ class bocontacts extends socontacts { $GLOBALS['egw']->accounts->cache_invalidate($contact['account_id']); } + // notify interested apps about changes in the account-contact data + if (!$to_write['owner'] && $to_write['account_id']) + { + $to_write['location'] = 'editaccountcontact'; + $GLOBALS['egw']->hooks->process($to_write,False,True); // called for every app now, not only enabled ones)); + } } return $this->error ? false : $contact['id']; } @@ -502,7 +534,7 @@ class bocontacts extends socontacts $owner = $contact['owner']; // allow the user to edit his own account - if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $this->user) + if (!$owner && $needed == EGW_ACL_EDIT && $contact['account_id'] == $this->user && $this->own_account_acl) { return true; } diff --git a/addressbook/inc/class.so_ldap.inc.php b/addressbook/inc/class.so_ldap.inc.php index 9bb3240a43..d4e88ff033 100644 --- a/addressbook/inc/class.so_ldap.inc.php +++ b/addressbook/inc/class.so_ldap.inc.php @@ -349,7 +349,6 @@ class so_ldap { return $err; } - // check the existing objectclasses of an entry, none = array() for new ones $oldObjectclasses = array(); $attributes = array('dn','cn','objectClass','uid'); @@ -399,7 +398,7 @@ class so_ldap $ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] : $GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$this->charset,'utf-8'); } - elseif($isUpdate) + elseif($isUpdate && isset($data[$egwFieldName])) { $ldapContact[$ldapFieldName] = array(); } @@ -411,7 +410,6 @@ class so_ldap $this->$egw2objectclass($ldapContact,$data,$isUpdate); } } - if($isUpdate) { // update entry diff --git a/addressbook/inc/class.socontacts.inc.php b/addressbook/inc/class.socontacts.inc.php index 7375be0dd7..89edcb98ba 100755 --- a/addressbook/inc/class.socontacts.inc.php +++ b/addressbook/inc/class.socontacts.inc.php @@ -240,7 +240,7 @@ class socontacts $this->grants[0] = EGW_ACL_READ; } // add account grants for admins - if (isset($GLOBALS['egw_info']['user']['apps']['admin'])) // admin rights can be limited by ACL! + if ($this->is_admin()) // admin rights can be limited by ACL! { $this->grants[0] = EGW_ACL_READ; // admins always have read-access if (!$GLOBALS['egw']->acl->check('account_access',16,'admin')) $this->grants[0] |= EGW_ACL_EDIT; @@ -268,6 +268,19 @@ class socontacts } } + /** + * Check if the user is an admin (can unconditionally edit accounts) + * + * We check now the admin ACL for edit users, as the admin app does it for editing accounts. + * + * @param array $contact=null for future use, where admins might not be admins for all accounts + * @return boolean + */ + function is_admin($contact=null) + { + return isset($GLOBALS['egw_info']['user']['apps']['admin']) && !$GLOBALS['egw']->acl->check('account_access',16,'admin'); + } + /** * Read all customfields of the given id's * diff --git a/addressbook/inc/class.uicontacts.inc.php b/addressbook/inc/class.uicontacts.inc.php index 5396f4cd99..79a571a733 100644 --- a/addressbook/inc/class.uicontacts.inc.php +++ b/addressbook/inc/class.uicontacts.inc.php @@ -932,6 +932,14 @@ class uicontacts extends bocontacts { $readonlys[$field] = true; } + // for editing the own account (by a non-admin), enable only the fields allowed via the "onw_account_acl" + if (!$content['owner'] && !$this->is_admin($content)) + { + foreach($this->get_fields('supported',$content['id'],$content['owner']) as $field) + { + if (!$this->own_account_acl || !in_array($field,$this->own_account_acl)) $readonlys[$field] = true; + } + } for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i; $sel_options['tz'] = $tz; $content['tz'] = $content['tz'] ? $content['tz'] : 0; @@ -1360,7 +1368,7 @@ $readonlys['button[vcard]'] = true; $GLOBALS['egw']->common->egw_header(); parse_navbar(); - if (!$GLOBALS['egw_info']['user']['apps']['admin']) + if (!$this->is_admin()) { echo '

'.lang('Permission denied !!!')."

\n"; } diff --git a/addressbook/inc/hook_config.inc.php b/addressbook/inc/hook_config.inc.php index 8a9c9790cc..c24d5bb299 100644 --- a/addressbook/inc/hook_config.inc.php +++ b/addressbook/inc/hook_config.inc.php @@ -26,3 +26,32 @@ function contact_repositories($config) } return $options; } + +function own_account_acl($config) +{ + $bocontacts =& CreateObject('addressbook.bocontacts'); + $supported_fields = $bocontacts->get_fields('supported',null,0); // fields supported by the backend (ldap schemas!) + // get the list of account fields + $fields = array(); + foreach($bocontacts->contact_fields as $field => $label) + { + // some fields the user should never be allowed to edit or are covert by an other attribute (n_fn for all n_*) + if (!in_array($field,array('id','tid','owner','created','creator','modified','modifier','private','n_prefix','n_given','n_middle','n_family','n_suffix'))) + { + $fields[$field] = $label; + } + } + if ($config['account_repository'] != 'ldap') // no custom-fields in ldap + { + $custom =& CreateObject('admin.customfields',$contact_app); + foreach($custom->get_customfields() as $name => $data) + { + $fields['#'.$name] = $data['label']; + } + } + if (!is_object($GLOBALS['egw']->html)) + { + $GLOBALS['egw']->html =& CreateObject('phpgwapi.html'); + } + return $GLOBALS['egw']->html->checkbox_multiselect('newsettings[own_account_acl]',$config['own_account_acl'],$fields,true,'',8); +} diff --git a/addressbook/templates/default/config.tpl b/addressbook/templates/default/config.tpl index 7a8f9b8183..69c11a52c8 100644 --- a/addressbook/templates/default/config.tpl +++ b/addressbook/templates/default/config.tpl @@ -21,6 +21,17 @@  {lang_Size_of_popup_(WxH,_eg.400x300,_if_a_popup_should_be_used)}: + + +  {lang_Allow_users_to_maintain_their_own_account-data} + + + +  {lang_Fields_the_user_is_allowed_to_edit_himself} + + {hook_own_account_acl} + +  {lang_Contact_repository}