2007-11-27 04:20:28 +01:00
|
|
|
<?php
|
|
|
|
/**
|
2016-04-27 21:12:20 +02:00
|
|
|
* EGroupware admin - admin command: delete an account (user or group)
|
2007-11-27 04:20:28 +01:00
|
|
|
*
|
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
|
|
|
* @package admin
|
2019-02-27 11:59:05 +01:00
|
|
|
* @copyright (c) 2007-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
2007-11-27 04:20:28 +01:00
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
*/
|
|
|
|
|
2016-04-27 21:12:20 +02:00
|
|
|
use EGroupware\Api;
|
|
|
|
|
2007-11-27 04:20:28 +01:00
|
|
|
/**
|
|
|
|
* admin command: delete an account (user or group)
|
|
|
|
*/
|
2014-05-16 15:32:49 +02:00
|
|
|
class admin_cmd_delete_account extends admin_cmd
|
2007-11-27 04:20:28 +01:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
2016-04-27 21:12:20 +02:00
|
|
|
* @param string|int|array $account account name or id, or array with all parameters
|
2019-02-27 11:59:05 +01:00
|
|
|
* or string "--not-existing" to delete all, in account repository no longer existing, accounts
|
2016-04-27 21:12:20 +02:00
|
|
|
* @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
|
2018-08-23 12:11:33 +02:00
|
|
|
* @param array $extra =array() values for requested(_email), comment, ...
|
2007-11-27 04:20:28 +01:00
|
|
|
*/
|
2018-08-23 12:11:33 +02:00
|
|
|
function __construct($account, $new_user=null, $is_user=true, array $extra=array())
|
2007-11-27 04:20:28 +01:00
|
|
|
{
|
|
|
|
if (!is_array($account))
|
|
|
|
{
|
|
|
|
$account = array(
|
|
|
|
'account' => $account,
|
|
|
|
'new_user' => $new_user,
|
|
|
|
'is_user' => $is_user,
|
2018-08-23 12:11:33 +02:00
|
|
|
)+$extra;
|
2007-11-27 04:20:28 +01:00
|
|
|
}
|
|
|
|
admin_cmd::__construct($account);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* delete an account (user or group)
|
2014-05-16 15:32:49 +02:00
|
|
|
*
|
2016-04-27 21:12:20 +02:00
|
|
|
* @param boolean $check_only =false only run the checks (and throw the exceptions), but not the command itself
|
2007-11-27 04:20:28 +01:00
|
|
|
* @return string success message
|
2016-04-27 21:12:20 +02:00
|
|
|
* @throws Api\Exception\NoPermission\Admin
|
|
|
|
* @throws Api\Exception\WrongUserinput(lang("Unknown account: %1 !!!",$this->account),15);
|
|
|
|
* @throws Api\Exception\WrongUserinput(lang('Error changing the password for %1 !!!',$this->account),99);
|
2007-11-27 04:20:28 +01:00
|
|
|
*/
|
|
|
|
protected function exec($check_only=false)
|
|
|
|
{
|
2019-02-27 11:59:05 +01:00
|
|
|
// 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);
|
|
|
|
}
|
2007-11-27 04:20:28 +01:00
|
|
|
$account_id = admin_cmd::parse_account($this->account,$this->is_user);
|
|
|
|
admin_cmd::_instanciate_accounts();
|
|
|
|
$account_lid = admin_cmd::$accounts->id2name($account_id);
|
2014-10-29 17:03:22 +01:00
|
|
|
|
2007-11-27 04:20:28 +01:00
|
|
|
if ($this->is_user && $this->new_user)
|
|
|
|
{
|
|
|
|
$new_user = admin_cmd::parse_account($this->new_user,true); // true = user, no group
|
|
|
|
}
|
2019-02-27 11:59:05 +01:00
|
|
|
if ($check_only) return true;
|
|
|
|
|
|
|
|
$this->delete_account($this->is_user, $account_id, $account_lid, $new_user);
|
|
|
|
|
|
|
|
if ($account_id < 0)
|
|
|
|
{
|
|
|
|
return lang("Group '%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";
|
2014-10-29 17:03:22 +01:00
|
|
|
|
2007-11-27 04:20:28 +01:00
|
|
|
if ($check_only) return true;
|
2014-10-29 17:03:22 +01:00
|
|
|
|
2019-02-27 11:59:05 +01:00
|
|
|
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)
|
|
|
|
{
|
2007-11-27 04:20:28 +01:00
|
|
|
// 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
|
2019-02-27 11:59:05 +01:00
|
|
|
'location' => $is_user ? 'deleteaccount' : 'deletegroup',
|
2007-11-27 04:20:28 +01:00
|
|
|
);
|
2019-07-19 22:31:27 +02:00
|
|
|
// First do apps that were not selected
|
|
|
|
$skip_apps = array();
|
2019-11-04 22:13:23 +01:00
|
|
|
$do_last = array('preferences','admin','api');
|
|
|
|
foreach(array_diff(array_keys($GLOBALS['egw_info']['apps']), array_merge($this->change_apps,$do_last)) as $app)
|
2019-07-19 22:31:27 +02:00
|
|
|
{
|
2019-11-04 22:13:23 +01:00
|
|
|
$skip_apps[] = $app;
|
|
|
|
Api\Hooks::single(array_merge($GLOBALS['hook_values'], array('new_owner' => 0)), $app, true);
|
2019-07-19 22:31:27 +02:00
|
|
|
}
|
2019-11-06 17:49:33 +01:00
|
|
|
|
|
|
|
// Filemanager is a special case, since the hook is in API not filemanager
|
|
|
|
$vfs_new_owner = in_array('filemanager', $this->change_apps) ? $new_user : 0;
|
|
|
|
Api\Vfs\Hooks::deleteAccount(array_merge($GLOBALS['hook_values'], array('new_owner' => $vfs_new_owner)));
|
2019-11-04 22:13:23 +01:00
|
|
|
|
|
|
|
// first all other apps, then preferences, admin & api
|
2019-07-19 22:31:27 +02:00
|
|
|
foreach(array_merge($this->change_apps,$do_last) as $app)
|
2007-11-27 04:20:28 +01:00
|
|
|
{
|
2019-02-27 11:59:05 +01:00
|
|
|
Api\Hooks::single($GLOBALS['hook_values'], $app, true);
|
2014-10-29 17:03:22 +01:00
|
|
|
}
|
2018-08-23 12:11:33 +02:00
|
|
|
// store old content at time of deletion
|
|
|
|
$this->old = $GLOBALS['egw']->accounts->read($account_id);
|
|
|
|
|
2015-12-02 23:17:01 +01:00
|
|
|
$GLOBALS['egw']->accounts->delete($account_id);
|
2007-11-27 04:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-03-19 15:34:44 +01:00
|
|
|
* Return (human readable) labels for keys of changes
|
|
|
|
*
|
|
|
|
* Reading them from admin.account template
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
function get_etemplate_name()
|
|
|
|
{
|
|
|
|
return $this->is_user ? 'admin.account':
|
|
|
|
($GLOBALS['egw_info']['apps']['stylite'] ? 'stylite' : 'groups').'.group.edit';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return widget types (indexed by field key) for changes
|
|
|
|
*
|
|
|
|
* Used by historylog widget to show the changes the command recorded.
|
|
|
|
*/
|
|
|
|
function get_change_labels()
|
|
|
|
{
|
|
|
|
$widgets = parent::get_change_labels();
|
|
|
|
|
|
|
|
$widgets['account_id'] = 'numerical ID'; // normaly not displayed
|
|
|
|
|
|
|
|
return $widgets;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return widget types (indexed by field key) for changes
|
|
|
|
*
|
|
|
|
* Used by historylog widget to show the changes the command recorded.
|
|
|
|
*/
|
|
|
|
function get_change_widgets()
|
|
|
|
{
|
|
|
|
$widgets = parent::get_change_widgets();
|
|
|
|
|
|
|
|
$widgets['account_id'] = 'integer'; // normaly not displayed
|
|
|
|
|
|
|
|
return $widgets;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the whole object-data as array, it's a cast of the object to an array
|
|
|
|
*
|
|
|
|
* Reimplement to supress data not relevant for groups, but historically stored
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
function as_array()
|
|
|
|
{
|
|
|
|
$data = parent::as_array();
|
|
|
|
|
|
|
|
if (!$this->is_user)
|
|
|
|
{
|
|
|
|
$data['old'] = array_diff_key($data['old'], array_flip([
|
|
|
|
'account_pwd', 'account_status',
|
|
|
|
'account_expires', 'account_primary_group',
|
|
|
|
'account_lastlogin', 'account_lastloginfrom',
|
|
|
|
'account_lastpwd_change', 'members-active',
|
|
|
|
'account_firstname', 'account_lastname', 'account_fullname',
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
unset($data['old']['account_type']);
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
}
|
2007-11-27 04:20:28 +01:00
|
|
|
* Return a title / string representation for a given command, eg. to display it
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function __tostring()
|
|
|
|
{
|
2019-03-19 15:34:44 +01:00
|
|
|
return lang('Delete account %1',
|
|
|
|
// use own data to display deleted name of user/group
|
|
|
|
$this->old['account_lid'] ? ($this->is_user ? lang('User') : lang('Group')).' '.$this->old['account_lid'] :
|
|
|
|
admin_cmd::display_account($this->account));
|
2007-11-27 04:20:28 +01:00
|
|
|
}
|
|
|
|
}
|