forked from extern/egroupware
- 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:
parent
df261614f5
commit
b968f9327c
@ -82,6 +82,14 @@ class bocontacts extends socontacts
|
|||||||
'url',
|
'url',
|
||||||
'tz',
|
'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
|
* @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(
|
$this->contact_fields = array(
|
||||||
'id' => lang('Contact ID'),
|
'id' => lang('Contact ID'),
|
||||||
'tid' => lang('Type'),
|
'tid' => lang('Typ'),
|
||||||
'owner' => lang('Addressbook'),
|
'owner' => lang('Addressbook'),
|
||||||
'private' => lang('private'),
|
'private' => lang('private'),
|
||||||
'cat_id' => lang('Category'),
|
'cat_id' => lang('Category'),
|
||||||
@ -213,6 +221,12 @@ class bocontacts extends socontacts
|
|||||||
'adr_two_countryname' => lang('country').' ('.lang('business').')',
|
'adr_two_countryname' => lang('country').' ('.lang('business').')',
|
||||||
);
|
);
|
||||||
//_debug_array($this->contact_fields);
|
//_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);
|
$contact['n_fn'] = $this->fullname($contact);
|
||||||
if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($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)
|
// 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());
|
$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']);
|
$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'];
|
return $this->error ? false : $contact['id'];
|
||||||
}
|
}
|
||||||
@ -502,7 +534,7 @@ class bocontacts extends socontacts
|
|||||||
$owner = $contact['owner'];
|
$owner = $contact['owner'];
|
||||||
|
|
||||||
// allow the user to edit his own account
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,6 @@ class so_ldap
|
|||||||
{
|
{
|
||||||
return $err;
|
return $err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the existing objectclasses of an entry, none = array() for new ones
|
// check the existing objectclasses of an entry, none = array() for new ones
|
||||||
$oldObjectclasses = array();
|
$oldObjectclasses = array();
|
||||||
$attributes = array('dn','cn','objectClass','uid');
|
$attributes = array('dn','cn','objectClass','uid');
|
||||||
@ -399,7 +398,7 @@ class so_ldap
|
|||||||
$ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] :
|
$ldapContact[$ldapFieldName] = $ldapFieldName == 'jpegphoto' ? $data[$egwFieldName] :
|
||||||
$GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$this->charset,'utf-8');
|
$GLOBALS['egw']->translation->convert(trim($data[$egwFieldName]),$this->charset,'utf-8');
|
||||||
}
|
}
|
||||||
elseif($isUpdate)
|
elseif($isUpdate && isset($data[$egwFieldName]))
|
||||||
{
|
{
|
||||||
$ldapContact[$ldapFieldName] = array();
|
$ldapContact[$ldapFieldName] = array();
|
||||||
}
|
}
|
||||||
@ -411,7 +410,6 @@ class so_ldap
|
|||||||
$this->$egw2objectclass($ldapContact,$data,$isUpdate);
|
$this->$egw2objectclass($ldapContact,$data,$isUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($isUpdate)
|
if($isUpdate)
|
||||||
{
|
{
|
||||||
// update entry
|
// update entry
|
||||||
|
@ -240,7 +240,7 @@ class socontacts
|
|||||||
$this->grants[0] = EGW_ACL_READ;
|
$this->grants[0] = EGW_ACL_READ;
|
||||||
}
|
}
|
||||||
// add account grants for admins
|
// 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
|
$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;
|
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
|
* Read all customfields of the given id's
|
||||||
*
|
*
|
||||||
|
@ -932,6 +932,14 @@ class uicontacts extends bocontacts
|
|||||||
{
|
{
|
||||||
$readonlys[$field] = true;
|
$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;
|
for($i = -23; $i<=23; $i++) $tz[$i] = ($i > 0 ? '+' : '').$i;
|
||||||
$sel_options['tz'] = $tz;
|
$sel_options['tz'] = $tz;
|
||||||
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
|
$content['tz'] = $content['tz'] ? $content['tz'] : 0;
|
||||||
@ -1360,7 +1368,7 @@ $readonlys['button[vcard]'] = true;
|
|||||||
$GLOBALS['egw']->common->egw_header();
|
$GLOBALS['egw']->common->egw_header();
|
||||||
parse_navbar();
|
parse_navbar();
|
||||||
|
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['admin'])
|
if (!$this->is_admin())
|
||||||
{
|
{
|
||||||
echo '<h1>'.lang('Permission denied !!!')."</h1>\n";
|
echo '<h1>'.lang('Permission denied !!!')."</h1>\n";
|
||||||
}
|
}
|
||||||
|
@ -26,3 +26,32 @@ function contact_repositories($config)
|
|||||||
}
|
}
|
||||||
return $options;
|
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);
|
||||||
|
}
|
||||||
|
@ -21,6 +21,17 @@
|
|||||||
<td> {lang_Size_of_popup_(WxH,_eg.400x300,_if_a_popup_should_be_used)}:</td>
|
<td> {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>
|
<td><input name="newsettings[call_popup]" value="{value_call_popup}" size="10"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="th">
|
||||||
|
<td colspan="2">
|
||||||
|
<b>{lang_Allow_users_to_maintain_their_own_account-data}</b>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="row_on">
|
||||||
|
<td> {lang_Fields_the_user_is_allowed_to_edit_himself}</td>
|
||||||
|
<td>
|
||||||
|
{hook_own_account_acl}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr class="th">
|
<tr class="th">
|
||||||
<td colspan="2"> <b>{lang_Contact_repository}</b></td>
|
<td colspan="2"> <b>{lang_Contact_repository}</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
Loading…
Reference in New Issue
Block a user