Zombie users management: allow to disable old users #4652
parent
34ea55889b
commit
da0df39794
@ -0,0 +1,168 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/** |
||||||
|
* ResultSet |
||||||
|
* |
||||||
|
* @license see /license.txt |
||||||
|
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva |
||||||
|
*/ |
||||||
|
class ResultSet implements Countable, Iterator |
||||||
|
{ |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @param string $sql |
||||||
|
* @return ResultSet |
||||||
|
*/ |
||||||
|
static function create($sql) |
||||||
|
{ |
||||||
|
return new self($sql); |
||||||
|
} |
||||||
|
|
||||||
|
protected $sql = ''; |
||||||
|
protected $handle = null; |
||||||
|
protected $current = false; |
||||||
|
protected $index = -1; |
||||||
|
protected $count = false; |
||||||
|
protected $limit_count = null; |
||||||
|
protected $limit_offset = null; |
||||||
|
protected $orderby_column = null; |
||||||
|
protected $orderby_direction = null; |
||||||
|
|
||||||
|
function __construct($sql, $limit_count = null, $limit_offset = null, $orderby_column = null, $orderby_direction = null) |
||||||
|
{ |
||||||
|
$this->sql = $sql; |
||||||
|
$this->limit_count = $limit_count; |
||||||
|
$this->limit_offset = $limit_offset; |
||||||
|
$this->orderby_column = $orderby_column; |
||||||
|
$this->orderby_direction = $direction; |
||||||
|
} |
||||||
|
|
||||||
|
public function sql() |
||||||
|
{ |
||||||
|
$sql = $this->sql; |
||||||
|
|
||||||
|
$column = $this->orderby_column; |
||||||
|
$direction = $this->orderby_direction; |
||||||
|
|
||||||
|
$offset = $this->limit_offset; |
||||||
|
$count = $this->limit_count; |
||||||
|
if (is_null($column) && is_null($count) && is_null($offset)) { |
||||||
|
return $sql; |
||||||
|
} |
||||||
|
|
||||||
|
if (strpos($sql, ' ORDER ') || strpos($sql, ' LIMIT ') || strpos($sql, ' OFFSET ')) { |
||||||
|
$sql = "SELECT * FROM ($sql) AS dat "; |
||||||
|
}else |
||||||
|
{ |
||||||
|
$sql .= ' '; |
||||||
|
} |
||||||
|
|
||||||
|
if ($column) { |
||||||
|
$sql .= "ORDER BY $column $direction "; |
||||||
|
} |
||||||
|
|
||||||
|
if ($count) { |
||||||
|
$sql .= "LIMIT $count "; |
||||||
|
} |
||||||
|
if ($offset) { |
||||||
|
$sql .= "OFFSET $offset"; |
||||||
|
} |
||||||
|
|
||||||
|
return $sql; |
||||||
|
} |
||||||
|
|
||||||
|
protected function handle() |
||||||
|
{ |
||||||
|
if (is_null($this->handle)) { |
||||||
|
$this->handle = Database::query($this->sql()); |
||||||
|
} |
||||||
|
|
||||||
|
return $this->handle; |
||||||
|
} |
||||||
|
|
||||||
|
public function count() |
||||||
|
{ |
||||||
|
if ($this->count === false) { |
||||||
|
$sql = $this->sql(); |
||||||
|
$sql = "SELECT COUNT(*) AS alpha FROM ($sql) AS dat "; |
||||||
|
$rs = Database :: query($sql); |
||||||
|
$data = Database::fetch_array($rs); |
||||||
|
$count = $data ? $data['alpha'] : 0; |
||||||
|
$this->count = (int) $count; |
||||||
|
} |
||||||
|
return $this->count; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @param int $count |
||||||
|
* @param int $from |
||||||
|
* @return ResultSet |
||||||
|
*/ |
||||||
|
public function limit($count, $from = 0) |
||||||
|
{ |
||||||
|
$result = clone($this); |
||||||
|
$result->limit_offset = $from; |
||||||
|
$result->limit_count = $count; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @param int $column |
||||||
|
* @param int $dir |
||||||
|
* @return ResultSet |
||||||
|
*/ |
||||||
|
public function orderby($column, $dir = 'ASC') |
||||||
|
{ |
||||||
|
$result = clone($this); |
||||||
|
$result->orderby_column = $column; |
||||||
|
$result->orderby_direction = $dir; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
public function current() |
||||||
|
{ |
||||||
|
return $this->current; |
||||||
|
} |
||||||
|
|
||||||
|
public function key() |
||||||
|
{ |
||||||
|
return $this->index; |
||||||
|
} |
||||||
|
|
||||||
|
public function next() |
||||||
|
{ |
||||||
|
$this->current = Database::fetch_assoc($this->handle()); |
||||||
|
$this->index++; |
||||||
|
return $this->current; |
||||||
|
} |
||||||
|
|
||||||
|
public function rewind() |
||||||
|
{ |
||||||
|
$this->handle = null; |
||||||
|
$this->current = false; |
||||||
|
$this->index = -1; |
||||||
|
$this->next(); |
||||||
|
} |
||||||
|
|
||||||
|
public function valid() |
||||||
|
{ |
||||||
|
return !empty($this->current); |
||||||
|
} |
||||||
|
|
||||||
|
function __clone() |
||||||
|
{ |
||||||
|
$this->reset(); |
||||||
|
} |
||||||
|
|
||||||
|
function reset() |
||||||
|
{ |
||||||
|
$this->handle = null; |
||||||
|
$this->current = false; |
||||||
|
$this->index = -1; |
||||||
|
$this->count = false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/** |
||||||
|
* ZombieQuery |
||||||
|
* |
||||||
|
* @copyright (c) 2012 University of Geneva |
||||||
|
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html |
||||||
|
* @author Laurent Opprecht <laurent@opprecht.info> |
||||||
|
*/ |
||||||
|
class ZombieManager |
||||||
|
{ |
||||||
|
|
||||||
|
static function last_year() |
||||||
|
{ |
||||||
|
$today = time(); |
||||||
|
$day = date('j', $today); |
||||||
|
$month = date('n', $today); |
||||||
|
$year = date('Y', $today) - 1; |
||||||
|
return mktime(0, 0, 0, $month, $day, $year); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns users whose last login is prior from $ceiling |
||||||
|
* |
||||||
|
* @param int|string $ceiling last login date |
||||||
|
* @param bool $active_only if true returns only active users. Otherwise returns all users. |
||||||
|
* @return ResultSet |
||||||
|
*/ |
||||||
|
static function list_zombies($ceiling, $active_only = true) |
||||||
|
{ |
||||||
|
$ceiling = is_numeric($ceiling) ? (int) $ceiling : strtotime($ceiling); |
||||||
|
$ceiling = date('Y-m-d H:i:s', $ceiling); |
||||||
|
|
||||||
|
$user_table = Database::get_main_table(TABLE_MAIN_USER); |
||||||
|
$login_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||||||
|
|
||||||
|
$sql = 'SELECT |
||||||
|
user.user_id, |
||||||
|
user.firstname, |
||||||
|
user.lastname, |
||||||
|
user.username, |
||||||
|
user.auth_source, |
||||||
|
user.email, |
||||||
|
user.status, |
||||||
|
user.registration_date, |
||||||
|
user.active, |
||||||
|
access.login_date'; |
||||||
|
|
||||||
|
global $_configuration; |
||||||
|
if ($_configuration['multiple_access_urls']) { |
||||||
|
|
||||||
|
$access_url_rel_user_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||||||
|
$current_url_id = api_get_current_access_url_id(); |
||||||
|
|
||||||
|
$sql .= " FROM $user_table as user, $login_table as access, $access_url_rel_user_table as url |
||||||
|
WHERE |
||||||
|
access.login_date = (SELECT MAX(a.login_date) |
||||||
|
FROM $login_table as a |
||||||
|
WHERE a.login_user_id = user.user_id |
||||||
|
) AND |
||||||
|
access.login_date <= '$ceiling' AND |
||||||
|
user.user_id = access.login_user_id AND |
||||||
|
url.login_user_id = user.user_id AND url.access_url_id=$current_url_id"; |
||||||
|
} else { |
||||||
|
$sql .= " FROM $user_table as user, $login_table as access |
||||||
|
WHERE |
||||||
|
access.login_date = (SELECT MAX(a.login_date) |
||||||
|
FROM $login_table as a |
||||||
|
WHERE a.login_user_id = user.user_id |
||||||
|
) AND |
||||||
|
access.login_date <= '$ceiling' AND |
||||||
|
user.user_id = access.login_user_id"; |
||||||
|
} |
||||||
|
if($active_only) |
||||||
|
{ |
||||||
|
$sql .= ' AND user.active = 1'; |
||||||
|
} |
||||||
|
|
||||||
|
return ResultSet::create($sql); |
||||||
|
} |
||||||
|
|
||||||
|
static function deactivate_zombies($ceiling) |
||||||
|
{ |
||||||
|
$zombies = self::list_zombies($ceiling); |
||||||
|
$ids = array(); |
||||||
|
foreach($zombies as $zombie) |
||||||
|
{ |
||||||
|
$ids[] = $zombie['user_id']; |
||||||
|
} |
||||||
|
UserManager::deactivate_users($ids); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,323 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/** |
||||||
|
* Description of zombie_report |
||||||
|
* |
||||||
|
* @copyright (c) 2012 University of Geneva |
||||||
|
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html |
||||||
|
* @author Laurent Opprecht <laurent@opprecht.info> |
||||||
|
*/ |
||||||
|
class ZombieReport implements Countable |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @return ZombieReport |
||||||
|
*/ |
||||||
|
static function create($additional_parameters = array()) |
||||||
|
{ |
||||||
|
return new self($additional_parameters); |
||||||
|
} |
||||||
|
|
||||||
|
protected $additional_parameters = array(); |
||||||
|
|
||||||
|
function __construct($additional_parameters = array()) |
||||||
|
{ |
||||||
|
$this->additional_parameters = $additional_parameters; |
||||||
|
} |
||||||
|
|
||||||
|
function get_additional_parameters() |
||||||
|
{ |
||||||
|
return $this->additional_parameters; |
||||||
|
} |
||||||
|
|
||||||
|
function get_parameters() |
||||||
|
{ |
||||||
|
|
||||||
|
$result = array( |
||||||
|
'name' => 'zombie_report_parameters', |
||||||
|
'method' => 'GET', |
||||||
|
'attributes' => array('class' => 'well form-horizontal form-search'), |
||||||
|
'items' => array( |
||||||
|
array( |
||||||
|
'name' => 'ceiling', |
||||||
|
'label' => get_lang('LastAccess'), |
||||||
|
'type' => 'datepickerdate', |
||||||
|
'default' => $this->get_ceiling(), |
||||||
|
'rules' => array( |
||||||
|
// array( |
||||||
|
// 'type' => 'required', |
||||||
|
// 'message' => get_lang('Required') |
||||||
|
// ), |
||||||
|
array( |
||||||
|
'type' => 'date', |
||||||
|
'message' => get_lang('Date') |
||||||
|
) |
||||||
|
) |
||||||
|
), |
||||||
|
array( |
||||||
|
'name' => 'active_only', |
||||||
|
'label' => get_lang('ActiveOnly'), |
||||||
|
'type' => 'checkbox', |
||||||
|
'default' => $this->get_active_only() |
||||||
|
), |
||||||
|
array( |
||||||
|
'name' => 'submit_button', |
||||||
|
'type' => 'style_submit_button', |
||||||
|
'value' => get_lang('Search'), |
||||||
|
'attributes' => array('class' => 'search') |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
$additional_parameters = $this->get_additional_parameters(); |
||||||
|
foreach ($additional_parameters as $key => $value) { |
||||||
|
$result['items'][] = array( |
||||||
|
'type' => 'hidden', |
||||||
|
'name' => $key, |
||||||
|
'value' => $value |
||||||
|
); |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
protected $parameters_form = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @return FormValidator |
||||||
|
*/ |
||||||
|
function get_parameters_form() |
||||||
|
{ |
||||||
|
$parameters = $this->get_parameters(); |
||||||
|
if (empty($parameters)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (empty($this->parameters_form)) { |
||||||
|
$this->parameters_form = FormValidator::create($parameters); |
||||||
|
} |
||||||
|
|
||||||
|
return $this->parameters_form; |
||||||
|
} |
||||||
|
|
||||||
|
function display_parameters($return = false) |
||||||
|
{ |
||||||
|
$form = $this->get_parameters_form(); |
||||||
|
if (empty($form)) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
$result = $form->return_form(); |
||||||
|
if ($return) { |
||||||
|
return $result; |
||||||
|
} else { |
||||||
|
echo $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function is_valid() |
||||||
|
{ |
||||||
|
$form = $this->get_parameters_form(); |
||||||
|
if (empty($form)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return $form->isSubmitted() == false || $form->validate(); |
||||||
|
} |
||||||
|
|
||||||
|
function get_ceiling() |
||||||
|
{ |
||||||
|
$result = Request::get('ceiling'); |
||||||
|
$result = $result ? $result : ZombieManager::last_year(); |
||||||
|
|
||||||
|
$result = is_array($result) && count($result) == 1 ? reset($result) : $result; |
||||||
|
$result = is_array($result) ? mktime(0, 0, 0, $result['F'], $result['d'], $result['Y']) : $result; |
||||||
|
$result = is_numeric($result) ? (int) $result : $result; |
||||||
|
$result = is_string($result) ? strtotime($result) : $result; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
function get_active_only() |
||||||
|
{ |
||||||
|
$result = Request::get('active_only', false); |
||||||
|
$result = $result === 'true' ? true : $result; |
||||||
|
$result = $result === 'false' ? false : $result; |
||||||
|
$result = (bool) $result; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
function get_action() |
||||||
|
{ |
||||||
|
|
||||||
|
/** |
||||||
|
* todo check token |
||||||
|
*/ |
||||||
|
$check = Security::check_token('post'); |
||||||
|
Security::clear_token(); |
||||||
|
if (!$check) { |
||||||
|
return 'display'; |
||||||
|
} |
||||||
|
return Request::post('action', 'display'); |
||||||
|
} |
||||||
|
|
||||||
|
function perform_action() |
||||||
|
{ |
||||||
|
$ids = Request::post('id'); |
||||||
|
if (empty($ids)) { |
||||||
|
return $ids; |
||||||
|
} |
||||||
|
|
||||||
|
$action = $this->get_action(); |
||||||
|
$f = array($this, 'action_' . $action); |
||||||
|
if (is_callable($f)) { |
||||||
|
return call_user_func($f, $ids); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
function action_deactivate($ids) |
||||||
|
{ |
||||||
|
return UserManager::deactivate_users($ids); |
||||||
|
} |
||||||
|
|
||||||
|
function action_activate($ids) |
||||||
|
{ |
||||||
|
return UserManager::activate_users($ids); |
||||||
|
} |
||||||
|
|
||||||
|
function action_delete($ids) |
||||||
|
{ |
||||||
|
return UserManager::delete_users($ids); |
||||||
|
} |
||||||
|
|
||||||
|
function count() |
||||||
|
{ |
||||||
|
if (!$this->is_valid()) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
$ceiling = $this->get_ceiling(); |
||||||
|
$active_only = $this->get_active_only(); |
||||||
|
$items = ZombieManager::list_zombies($ceiling, $active_only); |
||||||
|
return count($items); |
||||||
|
} |
||||||
|
|
||||||
|
function get_data($from, $count, $column, $direction) |
||||||
|
{ |
||||||
|
if (!$this->is_valid()) { |
||||||
|
return array(); |
||||||
|
} |
||||||
|
|
||||||
|
$ceiling = $this->get_ceiling(); |
||||||
|
$active_only = $this->get_active_only(); |
||||||
|
$items = ZombieManager::list_zombies($ceiling, $active_only)->limit($count, $from)->orderby($column, $direction); |
||||||
|
$result = array(); |
||||||
|
foreach ($items as $item) { |
||||||
|
$row = array(); |
||||||
|
$row[] = $item['user_id']; |
||||||
|
$row[] = $item['code']; |
||||||
|
$row[] = $item['firstname']; |
||||||
|
$row[] = $item['lastname']; |
||||||
|
$row[] = $item['username']; |
||||||
|
$row[] = $item['email']; |
||||||
|
$row[] = $item['status']; |
||||||
|
$row[] = $item['auth_source']; |
||||||
|
$row[] = api_format_date($item['registration_date'], DATE_FORMAT_SHORT); |
||||||
|
$row[] = api_format_date($item['login_date'], DATE_FORMAT_SHORT); |
||||||
|
$row[] = $item['active']; |
||||||
|
$result[] = $row; |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
function display_data($return = false) |
||||||
|
{ |
||||||
|
|
||||||
|
$count = array($this, 'count'); |
||||||
|
$data = array($this, 'get_data'); |
||||||
|
|
||||||
|
$parameters = array(); |
||||||
|
$parameters['sec_token'] = Security::get_token(); |
||||||
|
$parameters['ceiling'] = $this->get_ceiling(); |
||||||
|
$parameters['active_only'] = $this->get_active_only() ? 'true' : 'false'; |
||||||
|
$additional_parameters = $this->get_additional_parameters(); |
||||||
|
$parameters = array_merge($additional_parameters, $parameters); |
||||||
|
|
||||||
|
$table = new SortableTable('users', $count, $data, 1, 50); |
||||||
|
$table->set_additional_parameters($parameters); |
||||||
|
|
||||||
|
$col = 0; |
||||||
|
$table->set_header($col++, '', false); |
||||||
|
$table->set_header($col++, get_lang('Code')); |
||||||
|
$table->set_header($col++, get_lang('FirstName')); |
||||||
|
$table->set_header($col++, get_lang('LastName')); |
||||||
|
$table->set_header($col++, get_lang('LoginName')); |
||||||
|
$table->set_header($col++, get_lang('Email')); |
||||||
|
$table->set_header($col++, get_lang('Profile')); |
||||||
|
$table->set_header($col++, get_lang('Authentication')); |
||||||
|
$table->set_header($col++, get_lang('Registered')); |
||||||
|
$table->set_header($col++, get_lang('LastAccess'), false); |
||||||
|
$table->set_header($col++, get_lang('Active'), false); |
||||||
|
|
||||||
|
$table->set_column_filter(5, array($this, 'format_email')); |
||||||
|
$table->set_column_filter(6, array($this, 'format_status')); |
||||||
|
$table->set_column_filter(10, array($this, 'format_active')); |
||||||
|
|
||||||
|
$table->set_form_actions(array( |
||||||
|
'activate' => get_lang('Activate'), |
||||||
|
'deactivate' => get_lang('Deactivate'), |
||||||
|
'delete' => get_lang('Delete') |
||||||
|
)); |
||||||
|
|
||||||
|
if ($return) { |
||||||
|
return $table->return_table(); |
||||||
|
} else { |
||||||
|
echo $table->return_table(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Table formatter for the active column. |
||||||
|
* |
||||||
|
* @param string $active |
||||||
|
* @return string |
||||||
|
*/ |
||||||
|
function format_active($active) |
||||||
|
{ |
||||||
|
$active = ($active == '1'); |
||||||
|
if ($active) { |
||||||
|
$image = 'accept'; |
||||||
|
$text = get_lang('Yes'); |
||||||
|
} else { |
||||||
|
$image = 'error'; |
||||||
|
$text = get_lang('No'); |
||||||
|
} |
||||||
|
|
||||||
|
$result = Display::return_icon($image . '.png', $text); |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
function format_status($status) |
||||||
|
{ |
||||||
|
$statusname = api_get_status_langvars(); |
||||||
|
return $statusname[$status]; |
||||||
|
} |
||||||
|
|
||||||
|
function format_email($email) |
||||||
|
{ |
||||||
|
return Display :: encrypted_mailto_link($email, $email); |
||||||
|
} |
||||||
|
|
||||||
|
function display($return = false) |
||||||
|
{ |
||||||
|
$result = $this->display_parameters($return); |
||||||
|
if ($this->perform_action()) { |
||||||
|
if ($return) { |
||||||
|
$result = Display::return_confirmation_message(get_lang('Done')); |
||||||
|
} else { |
||||||
|
Display::display_confirmation_message(get_lang('Done')); |
||||||
|
} |
||||||
|
} |
||||||
|
$result = $this->display_data($return); |
||||||
|
if ($return) { |
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue