fix adding/removing group-memberships were not imported as change is on the group not the user

This commit is contained in:
ralf 2022-07-04 11:18:02 +02:00
parent 2756b9b247
commit 9a407d8ebb

View File

@ -81,7 +81,7 @@ class Import
{
[$created, $updated, $uptodate, $errors, $deleted] = $this->groups(
$initial_import ? null : $GLOBALS['egw_info']['server']['account_import_lastrun'],
$accounts, $accounts_sql, $logger, $delete, $groups);
$accounts, $accounts_sql, $logger, $delete, $groups, $set_members);
}
$filter = [
@ -246,6 +246,11 @@ class Import
}
while ($start[2] !== '');
if ($set_members)
{
$this->setMembers($set_members, $accounts, $accounts_sql, $logger);
}
$last_run = max($start_import-1, $last_modified);
Api\Config::save_value('account_import_lastrun', $last_run, 'phpgwapi');
$str = gmdate('Y-m-d H:i:s', $last_run). ' UTC';
@ -291,15 +296,17 @@ class Import
* We can only delete no longer existing groups, if we query all groups!
* So $delete !== 'no', requires $modified === null.
*
* @param int|null $modified to only query groups modified after given timestamp
* @param Ldap|Ads $accounts
* @param Sql $accounts_sql
* @param callable $logger function($str, $level) level: "debug", "detail", "info", "error" or "fatal"
* @param string $delete what to do with no longer existing groups: "yes": delete incl. data, "deactivate": delete group, "no": do nothing
* @param int|null $modified null: initial import, int: timestamp of last import
* @param array|null &$groups on return all current groups as account_id => account_lid pairs
* @param array|null &$set_members on return, if modified: (sql)account_id => [(ldap)account_id => account_lid] pairs
* @return array with int values [$created, $updated, $uptodate, $errors, $deleted]
*/
protected function groups($modified, object $accounts, Sql $accounts_sql, callable $logger, string $delete, array &$groups=null)
protected function groups(?int $modified, $accounts, Sql $accounts_sql, callable $logger, string $delete, array &$groups=null, array &$set_members=null)
{
// to delete no longer existing groups, we have to query all groups!
if ($delete !== 'no')
@ -308,7 +315,7 @@ class Import
}
// query all groups in SQL
$sql_groups = $groups = [];
$sql_groups = $groups = $set_members = [];
foreach($GLOBALS['egw']->db->select(Sql::TABLE, 'account_id,account_lid', ['account_type' => 'g'], __LINE__, __FILE__) as $row)
{
$sql_groups[-$row['account_id']] = $row['account_lid'];
@ -351,6 +358,7 @@ class Import
{
$logger("Error creating group '$group[account_lid]' (#$account_id)", 'error');
$errors++;
continue;
}
}
elseif (!($sql_group = $accounts_sql->read($sql_id)))
@ -382,6 +390,7 @@ class Import
{
$logger("Error updating group '$group[account_lid]' (#$sql_id)", 'error');
$errors++;
continue;
}
}
else
@ -393,6 +402,12 @@ class Import
unset($sql_groups[$sql_id]);
}
$groups[$sql_id] = $group['account_lid'];
// if we only get modified groups, we need to record and return the id's to update members, AFTER users are created/updated
if ($modified)
{
$set_members[$sql_id] = $accounts->read($group['account_id'])['members'];
}
}
// delete the groups not returned from LDAP, groups can NOT be deactivated, we just delete them in the DB
@ -471,7 +486,7 @@ class Import
if (empty($frequency) && !empty($time) && preg_match('/^\d{2}:\d{2}$/', $time))
{
$frequency = 24;
$frequency = 24.0;
}
if ($frequency > 0.0)
{
@ -563,4 +578,81 @@ class Import
$tailer = new Api\Json\Tail(self::LOG_FILE);
echo $tailer->show();
}
/**
* Set members of a group specified by its (sql)account_id after an incremental update of the groups
*
* We need to take into account:
* - members/users might not yet be added, if visible members are by membership to that group (eg. custom account-filter by membership in Default group)
* - members might not be readable from LDAP, because the are not in account-filter
*
* @param array $set_members (sql)account_id => [(ldap)account_id => account_lid] pairs
* @param Ldap|ADS $accounts
* @param Sql $accounts_sql
* @param callable $logger
* @return void
*/
protected function setMembers(array $set_members, $accounts, Sql $accounts_sql, callable $logger)
{
// setting (new) members
foreach($set_members as $sql_group_id => $members)
{
$group = $accounts_sql->id2name($sql_group_id) ?: '#'.$sql_group_id;
foreach($members as $ldap_id => $account_lid)
{
if (!($account_id = $accounts_sql->name2id($account_lid)))
{
if (!($account = $accounts->read($ldap_id)))
{
$logger("Failed reading user '$account_lid' (#$ldap_id) from LDAP, maybe he is not contained in filter --> ignored", 'detail');
continue;
}
$sql_account = $account;
// check if ldap-id is already taken --> create with own id
if ($accounts_sql->id2name($ldap_id))
{
unset($sql_account['account_id']);
}
if (!($sql_account['account_id'] = $accounts_sql->save($sql_account, true)))
{
$logger("Error creating user '$account_lid' (#$ldap_id)", 'error');
continue;
}
// set memberships using id's in sql (!)
$accounts_sql->set_memberships(array_filter(array_map(static function($account_lid) use ($accounts_sql)
{
return $accounts_sql->name2id($account_lid);
}, $account['memberships'])), $sql_account['account_id']);
}
else
{
if (!($memberships = $accounts_sql->memberships($account_id)))
{
$logger("Error reading memberships of (existing) user '$account_lid' (#$account_id)!", 'error');
continue;
}
if (!isset($memberships[$sql_group_id]))
{
$accounts_sql->set_memberships(array_merge(array_keys($memberships), [$sql_group_id]), $account_id);
$logger("Adding membership of user '$account_lid' (#$account_id) to group '$group' (#$sql_group_id)", 'detail');
}
}
}
// removing no longer set members
if (($sql_members = $accounts_sql->members($sql_group_id)) &&
($removed = array_diff($sql_members, $members)))
{
foreach($removed as $sql_account_id => $sql_account_lid)
{
if (($memberships = $accounts_sql->memberships($sql_account_id)) && isset($memberships[$sql_group_id]))
{
unset($memberships[$sql_group_id]);
$accounts_sql->set_memberships(array_keys($memberships), $sql_account_id);
$logger("Removing membership of user '$sql_account_lid' (#$sql_account_id) from group '$group' (#$sql_group_id)", 'detail');
}
}
}
}
}
}