- ACL to allow non-admin users to edit certain (explicitly allowed) fields in their own account contact data

- new hook editaccountcontact to sync other apps with these data
- admin ACL "edit users" is now respected by the contact class for account-contact-data too (you can deny admins to edit accounts)
- fixed bug in ldap-backend: it was deleting all not set contact fields
This commit is contained in:
Ralf Becker 2006-09-15 07:16:07 +00:00
parent df261614f5
commit b968f9327c
6 changed files with 99 additions and 8 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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
*

View File

@ -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 '<h1>'.lang('Permission denied !!!')."</h1>\n";
}

View File

@ -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);
}

View File

@ -21,6 +21,17 @@
<td>&nbsp;{lang_Size_of_popup_(WxH,_eg.400x300,_if_a_popup_should_be_used)}:</td>
<td><input name="newsettings[call_popup]" value="{value_call_popup}" size="10"></td>
</tr>
<tr class="th">
<td colspan="2">
&nbsp;<b>{lang_Allow_users_to_maintain_their_own_account-data}</b>
</td>
</tr>
<tr class="row_on">
<td>&nbsp;{lang_Fields_the_user_is_allowed_to_edit_himself}</td>
<td>
{hook_own_account_acl}
</td>
</tr>
<tr class="th">
<td colspan="2">&nbsp;<b>{lang_Contact_repository}</b></td>
</tr>