new admin-cli.php --delete-user parameter --not-existing to delete all no longer existing accounts

This commit is contained in:
Ralf Becker 2019-02-27 11:59:05 +01:00
parent b4d5584fe7
commit d44cffbf8b
4 changed files with 155 additions and 30 deletions

View File

@ -152,6 +152,7 @@ function run_command(admin_cmd $cmd)
break; break;
case '--try-run': // only run checks case '--try-run': // only run checks
case '--dry-run': // only run checks
$dry_run = true; $dry_run = true;
break; break;
@ -177,7 +178,8 @@ function run_command(admin_cmd $cmd)
} }
//_debug_array($cmd); //_debug_array($cmd);
try { try {
print_r($cmd->run($time, true, $skip_checks, $dry_run)); $msg = $cmd->run($time, true, $skip_checks, $dry_run);
if (!is_bool($msg) && $msg) print_r($msg);
// cli can NOT clear instance cache of APC(u), as cli uses different shared memory then webserver // cli can NOT clear instance cache of APC(u), as cli uses different shared memory then webserver
// --> we use a webservice call to clear cache (might fail if no domain in specified in webserver_url or on command line) // --> we use a webservice call to clear cache (might fail if no domain in specified in webserver_url or on command line)
@ -327,6 +329,7 @@ function usage($action=null,$ret=0)
echo " Change/set the password for a given user\n"; echo " Change/set the password for a given user\n";
echo "--delete-user admin-account[@domain],admin-password,account-to-delete[,account-to-move-data]\n"; echo "--delete-user admin-account[@domain],admin-password,account-to-delete[,account-to-move-data]\n";
echo " Deletes a user from EGroupware. It's data can be moved to an other user or it get deleted too.\n"; echo " Deletes a user from EGroupware. It's data can be moved to an other user or it get deleted too.\n";
echo " You can use '--not-existing' for accounts-to-delete, to delete all no (longer) existing users and groups.\n";
echo "--edit-group admin-account[@domain],admin-password,group[=new-group-name],email[,members,...]\n"; echo "--edit-group admin-account[@domain],admin-password,group[=new-group-name],email[,members,...]\n";
echo " Edit or add a group to EGroupware. If you specify members, they *replace* the exiting members!\n"; echo " Edit or add a group to EGroupware. If you specify members, they *replace* the exiting members!\n";
echo "--delete-group admin-account[@domain],admin-password,group-to-delete\n"; echo "--delete-group admin-account[@domain],admin-password,group-to-delete\n";

View File

@ -5,7 +5,7 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin * @package admin
* @copyright (c) 2007-18 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/ */
@ -37,13 +37,13 @@ class admin_cmd_change_account_id extends admin_cmd
} }
/** /**
* Query changes from all apps * Query account columns from all apps
* *
* Apps mark columns containing account-ids in "meta" attribute as (account|user|group)[-(abs|commasep|serialized)] * Apps mark columns containing account-ids in "meta" attribute as (account|user|group)[-(abs|commasep|serialized)]
* *
* @return array appname => array( table => array(column(s))) * @return array appname => array( table => array(column(s)))
*/ */
private function get_changes() public static function get_account_colums()
{ {
// happens if one used "root_admin" and config-password // happens if one used "root_admin" and config-password
if (empty($GLOBALS['egw_info']['apps'])) if (empty($GLOBALS['egw_info']['apps']))
@ -145,7 +145,7 @@ class admin_cmd_change_account_id extends admin_cmd
{ {
throw new Api\Exception\WrongUserinput(implode("\n", $errors), 16); throw new Api\Exception\WrongUserinput(implode("\n", $errors), 16);
} }
$columns2change = $this->get_changes(); $columns2change = self::get_account_colums();
$total = 0; $total = 0;
foreach($columns2change as $app => $data) foreach($columns2change as $app => $data)
{ {

View File

@ -5,9 +5,8 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin * @package admin
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/ */
/** /**
@ -40,7 +39,8 @@ class admin_cmd_check_acl extends admin_cmd
admin_cmd::_instanciate_accounts(); admin_cmd::_instanciate_accounts();
$deleted = 0; $deleted = 0;
if (($all_accounts = admin_cmd::$accounts->search(array('type'=>'both')))) // get all accounts: users+groups and also non-active ones (not yet deleted!)
if (($all_accounts = admin_cmd::$accounts->search(array('type'=>'both','active'=>false))))
{ {
$ids = array(); $ids = array();
foreach($all_accounts as $account) foreach($all_accounts as $account)

View File

@ -5,9 +5,8 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin * @package admin
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/ */
use EGroupware\Api; use EGroupware\Api;
@ -21,6 +20,7 @@ class admin_cmd_delete_account extends admin_cmd
* Constructor * Constructor
* *
* @param string|int|array $account account name or id, or array with all parameters * @param string|int|array $account account name or id, or array with all parameters
* or string "--not-existing" to delete all, in account repository no longer existing, accounts
* @param string $new_user =null if specified, account to transfer the data to (users only) * @param string $new_user =null if specified, account to transfer the data to (users only)
* @param string $is_user =true type of the account: true=user, false=group * @param string $is_user =true type of the account: true=user, false=group
* @param array $extra =array() values for requested(_email), comment, ... * @param array $extra =array() values for requested(_email), comment, ...
@ -49,6 +49,13 @@ class admin_cmd_delete_account extends admin_cmd
*/ */
protected function exec($check_only=false) protected function exec($check_only=false)
{ {
// check creator is still admin and not explicitly forbidden to edit accounts
if ($this->creator) $this->_check_admin($this->is_user ? 'account_access' : 'group_access',32);
if ($this->account === '--not-existing')
{
return $this->delete_not_existing($check_only);
}
$account_id = admin_cmd::parse_account($this->account,$this->is_user); $account_id = admin_cmd::parse_account($this->account,$this->is_user);
admin_cmd::_instanciate_accounts(); admin_cmd::_instanciate_accounts();
$account_lid = admin_cmd::$accounts->id2name($account_id); $account_lid = admin_cmd::$accounts->id2name($account_id);
@ -57,28 +64,9 @@ class admin_cmd_delete_account extends admin_cmd
{ {
$new_user = admin_cmd::parse_account($this->new_user,true); // true = user, no group $new_user = admin_cmd::parse_account($this->new_user,true); // true = user, no group
} }
// check creator is still admin and not explicitly forbidden to edit accounts
if ($this->creator) $this->_check_admin($this->is_user ? 'account_access' : 'group_access',32);
if ($check_only) return true; if ($check_only) return true;
// delete the account $this->delete_account($this->is_user, $account_id, $account_lid, $new_user);
$GLOBALS['hook_values'] = array(
'account_id' => $account_id,
'account_lid' => $account_lid,
'account_name'=> $account_lid, // depericated name for deletegroup hook
'new_owner' => (int)$new_user, // deleteaccount only
'location' => $this->is_user ? 'deleteaccount' : 'deletegroup',
);
// first all other apps, then preferences and admin
foreach(array_merge(array_diff(array_keys($GLOBALS['egw_info']['apps']),array('preferences','admin')),array('preferences','admin')) as $app)
{
Api\Hooks::single($GLOBALS['hook_values'],$app);
}
// store old content at time of deletion
$this->old = $GLOBALS['egw']->accounts->read($account_id);
$GLOBALS['egw']->accounts->delete($account_id);
if ($account_id < 0) if ($account_id < 0)
{ {
@ -87,6 +75,140 @@ class admin_cmd_delete_account extends admin_cmd
return lang("Account '%1' deleted.",$account_lid)."\n\n"; return lang("Account '%1' deleted.",$account_lid)."\n\n";
} }
/**
* Delete all in account repository no longer existing accounts
*
* @param boolean $check_only =false only run the checks (and throw the exceptions), but not the command itself
* @return string with success message
*/
protected function delete_not_existing($check_only=false)
{
admin_cmd::_instanciate_accounts();
$repo_ids = array();
if (($all_accounts = admin_cmd::$accounts->search(array('type'=>'both','active'=>false))))
{
foreach($all_accounts as $account)
{
$repo_ids[] = $account['account_id'];
}
}
//print_r($repo_ids);
static $ignore = array(
'egw_admin_queue' => array('cmd_account'), // contains also deleted accounts / admin history
);
$account_ids = array();
$account_cols = admin_cmd_change_account_id::get_account_colums();
//print_r($account_cols);
foreach($account_cols as $app => $data)
{
if (!isset($GLOBALS['egw_info']['apps'][$app])) continue; // $app is not installed
$db = clone($GLOBALS['egw']->db);
$db->set_app($app);
if ($check_only) $db->log_updates = $db->readonly = true;
foreach($data as $table => $columns)
{
$db->column_definitions = $db->get_table_definitions($app,$table);
$db->column_definitions = $db->column_definitions['fd'];
if (!$columns || substr($table, 0, 4) != 'egw_')
{
//echo "$app: $table no columns with account-id's\n";
continue; // noting to do for this table
}
// never check / use accounts-table (not used for LDAP/AD, all in for SQL)
if ($table == 'egw_accounts') continue;
if (!is_array($columns)) $columns = array($columns);
foreach($columns as $column)
{
$type = $where = null;
if (is_array($column))
{
$type = $column['.type'];
unset($column['.type']);
$where = $column;
$column = array_shift($where);
}
if (in_array($type, array('abs','prefs'))) // would need special handling
{
continue;
}
if (isset($ignore[$table]) && in_array($column, $ignore[$table]))
{
continue;
}
if ($table == 'egw_acl' && $column == 'acl_location')
{
$where[] = "acl_appname='phpgw_group'";
}
$ids = array();
foreach($rs=$db->select($table, 'DISTINCT '.$column, $where, __LINE__, __FILE__) as $row)
{
foreach(explode(',', $row[$column]) as $account_id)
{
if ($account_id && is_numeric($account_id) && !in_array($account_id, $repo_ids))
{
$account_ids[$account_id] = $ids[] = $account_id;
}
}
}
if ($ids) echo $rs->sql.": ".implode(', ', $ids)."\n";
}
}
}
//print_r($account_ids);
asort($account_ids, SORT_NUMERIC);
echo count($account_ids)." not existing account_id's found in EGroupware, ".count($repo_ids)." exist in account repository\n".
"--> following should be deleted: ".implode(', ', $account_ids)."\n";
if ($check_only) return true;
if ($this->new_user)
{
$new_user = admin_cmd::parse_account($this->new_user,true); // true = user, no group
}
foreach($account_ids as $account_id)
{
$this->delete_account($account_id > 0, $account_id, 'account'.$account_id, $account_id > 0 ? $new_user : null);
}
Api\Cache::flush(Api\Cache::INSTANCE);
return lang("Total of %1 accounts deleted.", count($account_ids))."\n";
}
/**
* Delete account incl. calling all necessary hooks
*
* @param boolean $is_user true: user, false: group
* @param int $account_id numerical account_id of use to delete
* @param string $account_lid =null account_lid of user to delete
* @param int $new_user =null if given account_id to transfer data to
*/
protected function delete_account($is_user, $account_id, $account_lid=null, $new_user=null)
{
// delete the account
$GLOBALS['hook_values'] = array(
'account_id' => $account_id,
'account_lid' => $account_lid,
'account_name'=> $account_lid, // depericated name for deletegroup hook
'new_owner' => (int)$new_user, // deleteaccount only
'location' => $is_user ? 'deleteaccount' : 'deletegroup',
);
// first all other apps, then preferences and admin
foreach(array_merge(array_diff(array_keys($GLOBALS['egw_info']['apps']),array('preferences','admin')),array('preferences','admin')) as $app)
{
Api\Hooks::single($GLOBALS['hook_values'], $app, true);
}
// store old content at time of deletion
$this->old = $GLOBALS['egw']->accounts->read($account_id);
$GLOBALS['egw']->accounts->delete($account_id);
}
/** /**
* Return a title / string representation for a given command, eg. to display it * Return a title / string representation for a given command, eg. to display it
* *