mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
WIP contact sharing
This commit is contained in:
parent
855d6defc9
commit
1f7ce98c50
@ -2070,6 +2070,30 @@ class addressbook_ui extends addressbook_bo
|
||||
{
|
||||
if (is_array($content))
|
||||
{
|
||||
// sync $content['shared'] with $content['shared_values']
|
||||
foreach($content['shared'] as $key => $shared)
|
||||
{
|
||||
$shared_value = $shared['shared_id'].':'.$shared['shared_with'].':'.$shared['shared_by'].':'.$shared['shared_writable'];
|
||||
if (($k = array_search($shared_value, $content['shared_values'])) === false)
|
||||
{
|
||||
unset($content['shared'][$key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($content['shared_values'][$k]);
|
||||
}
|
||||
}
|
||||
foreach($content['shared_values'] as $account_id)
|
||||
{
|
||||
$content['shared'][] = [
|
||||
'shared_with' => $account_id,
|
||||
'shared_by' => $this->user,
|
||||
'shared_at' => new Api\DateTime(),
|
||||
'shared_writable' => (int)(bool)$content['shared_writable'],
|
||||
];
|
||||
}
|
||||
unset($content['shared_values']);
|
||||
|
||||
$button = @key($content['button']);
|
||||
unset($content['button']);
|
||||
$content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p');
|
||||
@ -2403,6 +2427,20 @@ class addressbook_ui extends addressbook_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
// set $content[shared_options/_values] from $content[shared]
|
||||
$content['shared_options'] = [];
|
||||
foreach((array)$content['shared'] as $shared)
|
||||
{
|
||||
$content['shared_options'][$shared['shared_id'].':'.$shared['shared_with'].':'.$shared['shared_by'].':'.$shared['shared_writable']] = [
|
||||
'label' => Accounts::username($shared['shared_with']),
|
||||
'title' => lang('%1 shared this contact on %2 with %3 %4',
|
||||
Accounts::username($shared['shared_by']), Api\DateTime::to($shared['shared_at']),
|
||||
Accounts::username($shared['shared_with']), $shared['shared_writable'] ? lang('writable') : lang('readonly')),
|
||||
'icon' => $shared['shared_writable'] ? 'edit' : 'view',
|
||||
];
|
||||
}
|
||||
$content['shared_values'] = array_keys($content['shared_options']);
|
||||
|
||||
if ($content['id'])
|
||||
{
|
||||
// last and next calendar date
|
||||
|
@ -8,6 +8,7 @@
|
||||
%1 public keys added. addressbook de %1 öffentliche Schlüssel gespeichert.
|
||||
%1 records imported addressbook de %1 Datensätze importiert
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook de %1 Datensätze gelesen (noch nicht importiert, sie können %2zurück%3 gehen und Test-Import ausschalten)
|
||||
%1 shared this contact on %2 with %3 %4 addressbook de %1 teilte diesen Kontakt am %2 mit %3 %4
|
||||
%1 starts with '%2' addressbook de %1 beginnt mit '%2'
|
||||
%s please calculate the result addressbook de %s Bitte berechnen Sie das Ergebnis
|
||||
(e.g. 1969) addressbook de (z.B. 1969)
|
||||
@ -454,6 +455,7 @@ send succeeded to %1 common de erfolgreich versandt an
|
||||
seperator addressbook de Feldtrenner
|
||||
set full name and file as field in contacts of all users (either all or only empty values) admin de Setzt vollen Namen und eigene Sortierung in Kontakten aller Benutzer (entweder alle oder nur leere Werte)
|
||||
set only full name addressbook de Nur vollen Namen setzen
|
||||
shared with addressbook de Geteilt mit
|
||||
should the columns photo and home address always be displayed, even if they are empty. addressbook de Sollen die Spalten Foto und Privatadresse immer angezeigt werden, auch wenn sie leer sind?
|
||||
show addressbook de Anzeigen
|
||||
show active accounts addressbook de Zeigt nur aktive Benutzer an
|
||||
|
@ -8,6 +8,7 @@
|
||||
%1 public keys added. addressbook en %1 public keys added.
|
||||
%1 records imported addressbook en %1 records imported.
|
||||
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) addressbook en %1 records read. Not yet imported, you may go %2back%3 and un-check Test import.
|
||||
%1 shared this contact on %2 with %3 %4 addressbook en %1 shared this contact on %2 with %3 %4
|
||||
%1 starts with '%2' addressbook en %1 starts with '%2'
|
||||
%s please calculate the result addressbook en %s please calculate the result
|
||||
(e.g. 1969) addressbook en (e.g. 1969)
|
||||
@ -454,6 +455,7 @@ send succeeded to %1 common en Send succeeded to %1
|
||||
seperator addressbook en Separator
|
||||
set full name and file as field in contacts of all users (either all or only empty values) admin en Set full name and 'fileas' field in contacts of all users. Either all or only empty values.
|
||||
set only full name addressbook en Set only full name
|
||||
shared with addressbook en Shared with
|
||||
should the columns photo and home address always be displayed, even if they are empty. addressbook en Are photo and home address always displayed, even if columns are empty.
|
||||
show addressbook en Show
|
||||
show active accounts addressbook en Show active accounts
|
||||
|
@ -143,6 +143,11 @@
|
||||
</hbox>
|
||||
<description/>
|
||||
</row>
|
||||
<row>
|
||||
<description for="shared" value="Shared with"/>
|
||||
<taglist-account id="shared_values" multiple="true" select_options="@shared_options" span="4"/>
|
||||
<checkbox id="shared_writable" label="writable" statustext="Create new shares writable"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</template>
|
||||
|
@ -1233,6 +1233,19 @@ class Contacts extends Contacts\Storage
|
||||
$access = ($grants[$owner] & $needed) &&
|
||||
(!$contact['private'] || ($grants[$owner] & Acl::PRIVAT) || in_array($owner,$memberships));
|
||||
}
|
||||
// check if we might have access via sharing (not for delete)
|
||||
if ($access === false && !empty($contact['shared']) && $needed != Acl::DELETE)
|
||||
{
|
||||
foreach($contact['shared'] as $shared)
|
||||
{
|
||||
if (isset($grants[$shared['shared_with']]) && ($shared['shared_writable'] || !($needed & Acl::EDIT)))
|
||||
{
|
||||
$access = true;
|
||||
error_log(__METHOD__."($needed,$contact[id],$deny_account_delete,$user) shared=".json_encode($shared)." returning ".array2string($access));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__."($needed,$contact[id],$deny_account_delete,$user) returning ".array2string($access));
|
||||
return $access;
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ class Sql extends Api\Storage
|
||||
const EXTRA_TABLE = 'egw_addressbook_extra';
|
||||
const EXTRA_VALUE = 'contact_value';
|
||||
|
||||
const SHARED_TABLE = 'egw_addressbook_shared';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -497,6 +499,11 @@ class Sql extends Api\Storage
|
||||
unset($filter['cat_id']);
|
||||
}
|
||||
|
||||
// SQL to get all shared contacts to be OR-ed into ACL filter
|
||||
// ToDo: do we need a sharing filter for $ignore_acl
|
||||
$shared_sql = 'contact_id IN (SELECT contact_id FROM '.self::SHARED_TABLE.' WHERE '.
|
||||
$this->db->expression(self::SHARED_TABLE, ['shared_with' => $filter['owner'] ?? array_keys($this->grants)]).')';
|
||||
|
||||
// add filter for read ACL in sql, if user is NOT the owner of the addressbook
|
||||
if (isset($this->grants) && !$ignore_acl &&
|
||||
!(isset($filter['owner']) && $filter['owner'] == $GLOBALS['egw_info']['user']['account_id']))
|
||||
@ -524,18 +531,21 @@ class Sql extends Api\Storage
|
||||
if (!array_intersect((array)$filter['owner'],array_keys($this->grants)))
|
||||
{
|
||||
if (!isset($groupmember_sql)) return false;
|
||||
$filter[] = substr($groupmember_sql,4);
|
||||
$filter[] = '('.substr($groupmember_sql,4)." OR $shared_sql)";
|
||||
unset($filter['owner']);
|
||||
}
|
||||
// for an owner filter, which does NOT include current user, filter out private entries
|
||||
elseif (!in_array($GLOBALS['egw_info']['user']['account_id'], (array)$filter['owner']))
|
||||
{
|
||||
$filter['private'] = 0;
|
||||
$filter[] = '('.$this->db->expression($this->table_name, $this->table_name.'.', ['contact_owner' => $filter['owner'], 'contact_private' => 0]).
|
||||
" OR $shared_sql)";
|
||||
unset($filter['owner']);
|
||||
}
|
||||
// if multiple addressbooks (incl. current owner) are searched, we need full acl filter
|
||||
elseif(is_array($filter['owner']) && count($filter['owner']) > 1)
|
||||
{
|
||||
$filter[] = "($this->table_name.contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id'].
|
||||
" OR $shared_sql".
|
||||
" OR contact_private=0 AND $this->table_name.contact_owner IN (".
|
||||
implode(',',array_keys($this->grants)).") $groupmember_sql OR $this->table_name.contact_owner IS NULL)";
|
||||
}
|
||||
@ -547,6 +557,7 @@ class Sql extends Api\Storage
|
||||
$filter[] = $this->table_name.'.contact_owner != 0'; // in case there have been accounts in sql previously
|
||||
}
|
||||
$filter[] = "($this->table_name.contact_owner=".(int)$GLOBALS['egw_info']['user']['account_id'].
|
||||
" OR $shared_sql".
|
||||
($this->grants ? " OR contact_private=0 AND $this->table_name.contact_owner IN (".
|
||||
implode(',',array_keys($this->grants)).")" : '').
|
||||
$groupmember_sql." OR $this->table_name.contact_owner IS NULL)";
|
||||
@ -1009,9 +1020,62 @@ class Sql extends Api\Storage
|
||||
|| strlen($contact['uid']) < $minimum_uid_length)) {
|
||||
parent::update(array('uid' => Api\CalDAV::generate_uid('addressbook',$contact['id'])));
|
||||
}
|
||||
if (is_array($contact))
|
||||
{
|
||||
$contact['shared'] = $this->read_shared($contact['id']);
|
||||
}
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read sharing information of a contact
|
||||
*
|
||||
* @param int $id contact_id to read
|
||||
* @return array of array with values for keys "shared_(with|writable|by|at|id)"
|
||||
*/
|
||||
function read_shared($id)
|
||||
{
|
||||
$shared = [];
|
||||
foreach($this->db->select(self::SHARED_TABLE, '*', ['contact_id' => $id],
|
||||
__LINE__, __FILE__, false) as $row)
|
||||
{
|
||||
$row['shared_at'] = Api\DateTime::server2user($row['shared_at'], 'object');
|
||||
$shared[] = $row;
|
||||
}
|
||||
return $shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param array $shared array of array with values for keys "shared_(with|writable|by|at|id)"
|
||||
* @return array of array with values for keys "shared_(with|writable|by|at|id)"
|
||||
*/
|
||||
function save_shared($id, array $shared)
|
||||
{
|
||||
$ids = [];
|
||||
foreach($shared as &$data)
|
||||
{
|
||||
if (empty($data['shared_id']))
|
||||
{
|
||||
unset($data['shared_id']);
|
||||
$data['contact_id'] = $id;
|
||||
$data['shared_at'] = Api\DateTime::user2server($data['shared_at'] ?: 'now');
|
||||
$data['shared_by'] = $data['shared_by'] ?: $GLOBALS['egw_info']['user']['account_id'];
|
||||
$this->db->insert(self::SHARED_TABLE, $data, false, __LINE__, __FILE__);
|
||||
$data['shared_id'] = $this->db->get_last_insert_id(self::SHARED_TABLE, 'share_id');
|
||||
}
|
||||
$ids[] = (int)$data['shared_id'];
|
||||
}
|
||||
$delete = ['contact_id' => $id];
|
||||
if ($ids) $delete[] = 'shared_id NOT IN ('.implode(',', $ids).')';
|
||||
$this->db->delete(self::SHARED_TABLE, $delete, __LINE__, __FILE__);
|
||||
foreach($shared as &$data)
|
||||
{
|
||||
$data['shared_at'] = Api\DateTime::server2user($data['shared_at'], 'object');
|
||||
}
|
||||
return $shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a contact, reimplemented to check a given etag and set a uid
|
||||
*
|
||||
@ -1095,6 +1159,11 @@ class Sql extends Api\Storage
|
||||
{
|
||||
parent::update($update);
|
||||
}
|
||||
// save sharing information
|
||||
if (!$err)
|
||||
{
|
||||
$this->data['shared'] = $this->save_shared($this->data['id'], (array)$this->data['shared']);
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
|
@ -608,7 +608,7 @@ class Storage
|
||||
$contact_id = array('account_id' => (int) substr($contact_id,8));
|
||||
}
|
||||
// read main data
|
||||
$backend =& $this->get_backend($contact_id);
|
||||
$backend = $this->get_backend($contact_id);
|
||||
if (!($contact = $backend->read($contact_id)))
|
||||
{
|
||||
return $contact;
|
||||
|
Loading…
Reference in New Issue
Block a user