477 lines
17 KiB
PHP
477 lines
17 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of RaspiSMS.
|
|
*
|
|
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
|
|
*
|
|
* This source file is subject to the GPL-3.0 license that is bundled
|
|
* with this source code in the file LICENSE.
|
|
*/
|
|
|
|
namespace controllers\publics;
|
|
|
|
/**
|
|
* Page des users.
|
|
*/
|
|
class User extends \descartes\Controller
|
|
{
|
|
private $internal_user;
|
|
private $internal_quota;
|
|
private $internal_setting;
|
|
|
|
/**
|
|
* Cette fonction est appelée avant toute les autres :
|
|
* Elle vérifie que l'utilisateur est bien connecté.
|
|
*
|
|
* @return void;
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
|
$this->internal_user = new \controllers\internals\User($bdd);
|
|
$this->internal_quota = new \controllers\internals\Quota($bdd);
|
|
$this->internal_setting = new \controllers\internals\Setting($bdd);
|
|
|
|
\controllers\internals\Tool::verifyconnect();
|
|
|
|
if (!\controllers\internals\Tool::is_admin())
|
|
{
|
|
return $this->redirect(\descartes\Router::url('Dashboard', 'show'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cette fonction retourne tous les users, sous forme d'un tableau permettant l'administration de ces users.
|
|
*/
|
|
public function list()
|
|
{
|
|
$this->render('user/list');
|
|
}
|
|
|
|
/**
|
|
* Return users as json.
|
|
*/
|
|
public function list_json()
|
|
{
|
|
$entities = $this->internal_user->list();
|
|
|
|
foreach ($entities as &$entity)
|
|
{
|
|
$quota_percentage = $this->internal_quota->get_usage_percentage($entity['id']);
|
|
$entity['quota_percentage'] = $quota_percentage * 100;
|
|
|
|
$quota = $this->internal_quota->get_user_quota($entity['id']);
|
|
if (!$quota)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (new \DateTime() > new \DateTime($quota['expiration_date']))
|
|
{
|
|
$entity['quota_expired_at'] = $quota['expiration_date'];
|
|
}
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['data' => $entities]);
|
|
}
|
|
|
|
/**
|
|
* Update status of users.
|
|
*
|
|
* @param array int $_GET['user_ids'] : User ids
|
|
* @param mixed $csrf
|
|
* @param int $status : 1 -> active, 0 -> suspended
|
|
*
|
|
* @return boolean;
|
|
*/
|
|
public function update_status($csrf, int $status)
|
|
{
|
|
if (!$this->verify_csrf($csrf))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
if (0 === $status)
|
|
{
|
|
$status = \models\User::STATUS_SUSPENDED;
|
|
}
|
|
else
|
|
{
|
|
$status = \models\User::STATUS_ACTIVE;
|
|
}
|
|
|
|
$ids = $_GET['user_ids'] ?? [];
|
|
foreach ($ids as $id)
|
|
{
|
|
$this->internal_user->update_status($id, $status);
|
|
}
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
/**
|
|
* Cette fonction va supprimer une liste de users.
|
|
*
|
|
* @param array int $_GET['user_ids'] : Les id des useres à supprimer
|
|
* @param mixed $csrf
|
|
*
|
|
* @return boolean;
|
|
*/
|
|
public function delete($csrf)
|
|
{
|
|
if (!$this->verify_csrf($csrf))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
if (!\controllers\internals\Tool::is_admin())
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Vous devez être administrateur pour supprimer un utilisateur !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
$ids = $_GET['user_ids'] ?? [];
|
|
foreach ($ids as $id)
|
|
{
|
|
$this->internal_user->delete($id);
|
|
}
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
/**
|
|
* Cette fonction retourne la page d'ajout d'un user.
|
|
*/
|
|
public function add()
|
|
{
|
|
$now = new \DateTime();
|
|
$now = $now->format('Y-m-d H:i:00');
|
|
|
|
return $this->render('user/add', ['now' => $now]);
|
|
}
|
|
|
|
/**
|
|
* Cette fonction insert un nouveau user.
|
|
*
|
|
* @param $csrf : Le jeton CSRF
|
|
* @param string $_POST['email'] : User email
|
|
* @param optional string $_POST['password'] : User password, (if empty the password is randomly generated)
|
|
* @param optional boolean $_POST['admin'] : If true user is admin
|
|
* @param optional boolean $_POST['quota_enable'] : If true create a quota for the user
|
|
* @param bool $_POST['quota_enable'] : If true create a quota for the user
|
|
* @param optional int $_POST['quota_credit'] : credit for quota
|
|
* @param optional int $_POST['quota_additional'] : additional credit
|
|
* @param optional string $_POST['quota_start_date'] : quota beginning date
|
|
* @param optional string $_POST['quota_renewal_interval'] : period to use on renewal to calculate new expiration date. Also use to calculate first expiration date.
|
|
* @param optional boolean $_POST['quota_auto_renew'] : Should the quota be automatically renewed on expiration
|
|
* @param optional boolean $_POST['quota_report_unused'] : Should unused credit be reported next month
|
|
* @param optional boolean $_POST['quota_report_unused_additional'] : Should unused additional credit be transfered next month
|
|
*/
|
|
public function create($csrf)
|
|
{
|
|
if (!$this->verify_csrf($csrf))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
$email = $_POST['email'] ?? false;
|
|
$password = !empty($_POST['password']) ? $_POST['password'] : \controllers\internals\Tool::generate_password(rand(6, 12));
|
|
$admin = $_POST['admin'] ?? false;
|
|
$status = 'active';
|
|
$quota_enable = $_POST['quota_enable'] ?? false;
|
|
$quota_credit = $_POST['quota_credit'] ?? false;
|
|
$quota_additional = $_POST['quota_additional'] ?? false;
|
|
$quota_start_date = $_POST['quota_start_date'] ?? false;
|
|
$quota_renew_interval = $_POST['quota_renew_interval'] ?? false;
|
|
$quota_auto_renew = $_POST['quota_auto_renew'] ?? false;
|
|
$quota_report_unused = $_POST['quota_report_unused'] ?? false;
|
|
$quota_report_unused_additional = $_POST['quota_report_unused_additional'] ?? false;
|
|
|
|
if (!$email)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Vous devez au moins fournir une adresse e-mail pour l\'utilisateur.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'adresse e-mail n\'est pas valide.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
//Forge quota for user if needed
|
|
$quota = null;
|
|
if ($quota_enable)
|
|
{
|
|
$quota = [];
|
|
$quota['credit'] = (int) $quota_credit;
|
|
$quota['additional'] = (int) $quota_additional;
|
|
|
|
if (false === $quota_start_date || !\controllers\internals\Tool::validate_date($quota_start_date, 'Y-m-d H:i:s'))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Vous devez définir une date de début valide pour le quota.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
$quota['start_date'] = new \DateTime($quota_start_date);
|
|
|
|
if (false === $quota_renew_interval || !\controllers\internals\Tool::validate_period($quota_renew_interval))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Vous devez définir une durée de quota parmis la liste proposée.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
$quota['renew_interval'] = $quota_renew_interval;
|
|
|
|
$quota['expiration_date'] = clone $quota['start_date'];
|
|
$quota['expiration_date']->add(new \DateInterval($quota_renew_interval));
|
|
|
|
$quota['auto_renew'] = (bool) $quota_auto_renew;
|
|
$quota['report_unused'] = (bool) $quota_report_unused;
|
|
$quota['report_unused_additional'] = (bool) $quota_report_unused_additional;
|
|
}
|
|
|
|
$id_user = $this->internal_user->create($email, $password, $admin, null, \models\User::STATUS_ACTIVE, true, $quota);
|
|
if (!$id_user)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer cet utilisateur.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
$mailer = new \controllers\internals\Mailer();
|
|
$email_send = $mailer->enqueue($email, EMAIL_CREATE_USER, ['email' => $email, 'password' => $password]);
|
|
if (!$email_send)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Impossible d\'envoyer l\'e-mail à l\'utilisateur.');
|
|
}
|
|
|
|
\FlashMessage\FlashMessage::push('success', 'L\'utilisateur a bien été créé.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
/**
|
|
* Return the edition page for the users.
|
|
*
|
|
* @param int... $ids : users ids
|
|
*/
|
|
public function edit()
|
|
{
|
|
$ids = $_GET['user_ids'] ?? [];
|
|
$id_user = $_SESSION['user']['id'];
|
|
|
|
$users = $this->internal_user->gets_in_by_id($ids);
|
|
|
|
if (!$users)
|
|
{
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
foreach ($users as &$user)
|
|
{
|
|
$user['quota'] = $this->internal_quota->get_user_quota($user['id']);
|
|
}
|
|
|
|
$now = new \DateTime();
|
|
$now = $now->format('Y-m-d H:i:00');
|
|
|
|
$this->render('user/edit', [
|
|
'users' => $users,
|
|
'now' => $now,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update a list of users.
|
|
*
|
|
* @param $csrf : Le jeton CSRF
|
|
* @param array $_POST['users'] : Array of the users and new values, id as key. Quota may also be defined.
|
|
*/
|
|
public function update($csrf)
|
|
{
|
|
if (!$this->verify_csrf($csrf))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
$nb_update = 0;
|
|
$users = $_POST['users'] ?? [];
|
|
foreach ($users as $id_user => $user)
|
|
{
|
|
$email = $user['email'] ?? false;
|
|
$password = !empty($user['password']) ? $user['password'] : null;
|
|
$admin = $user['admin'] ?? false;
|
|
|
|
$quota_enable = $user['quota_enable'] ?? false;
|
|
$quota_consumed = $user['quota_consumed'] ?? false;
|
|
$quota_credit = $user['quota_credit'] ?? false;
|
|
$quota_additional = $user['quota_additional'] ?? false;
|
|
$quota_start_date = $user['quota_start_date'] ?? false;
|
|
$quota_renew_interval = $user['quota_renew_interval'] ?? false;
|
|
$quota_auto_renew = $user['quota_auto_renew'] ?? false;
|
|
$quota_report_unused = $user['quota_report_unused'] ?? false;
|
|
$quota_report_unused_additional = $user['quota_report_unused_additional'] ?? false;
|
|
|
|
if (!$email)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'utilisateur #' . (int) $id_user . ' n\'as pas pu être mis à jour car l\'adresse e-mail n\'as pas été fournie.');
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'utilisateur #' . (int) $id_user . ' n\'as pas pu être mis à jour car l\'adresse e-mail fournie n\'est pas valide.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'add'));
|
|
}
|
|
|
|
//Forge quota for user if needed
|
|
$quota = false;
|
|
if ($quota_enable)
|
|
{
|
|
$quota = [];
|
|
$quota['credit'] = (int) $quota_credit;
|
|
$quota['consumed'] = (int) $quota_consumed;
|
|
$quota['additional'] = (int) $quota_additional;
|
|
|
|
if (false === $quota_start_date || !\controllers\internals\Tool::validate_date($quota_start_date, 'Y-m-d H:i:s'))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'utilisateur #' . (int) $id_user . ' n\'as pas pu être mis à jour car la date de début du quota associé n\'est pas valide.');
|
|
|
|
continue;
|
|
}
|
|
$quota['start_date'] = new \DateTime($quota_start_date);
|
|
|
|
if (false === $quota_renew_interval || !\controllers\internals\Tool::validate_period($quota_renew_interval))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'utilisateur #' . (int) $id_user . ' n\'as pas pu être mis à jour car la durée du quota associé n\'est pas valide.');
|
|
|
|
continue;
|
|
}
|
|
$quota['renew_interval'] = $quota_renew_interval;
|
|
|
|
$quota['expiration_date'] = clone $quota['start_date'];
|
|
$quota['expiration_date']->add(new \DateInterval($quota_renew_interval));
|
|
|
|
$quota['auto_renew'] = (bool) $quota_auto_renew;
|
|
$quota['report_unused'] = (bool) $quota_report_unused;
|
|
$quota['report_unused_additional'] = (bool) $quota_report_unused_additional;
|
|
|
|
//Format dates
|
|
$quota['start_date'] = $quota['start_date']->format('Y-m-d H:i:s');
|
|
$quota['expiration_date'] = $quota['expiration_date']->format('Y-m-d H:i:s');
|
|
}
|
|
|
|
$updated_user = [
|
|
'email' => $email,
|
|
'admin' => $admin,
|
|
];
|
|
|
|
if ($password)
|
|
{
|
|
$updated_user['password'] = password_hash($password, PASSWORD_DEFAULT);
|
|
}
|
|
|
|
$success = $this->internal_user->update($id_user, $updated_user, $quota);
|
|
if (!$success)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'L\'utilisateur #' . (int) $id_user . ' n\'as pas pu être mis à jour.');
|
|
|
|
continue;
|
|
}
|
|
|
|
++$nb_update;
|
|
}
|
|
|
|
if ($nb_update != count($users))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Certains utilisateurs n\'ont pas pu être mis à jour.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
\FlashMessage\FlashMessage::push('success', 'Tous les utilisateurs ont bien été mis à jour.');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
/**
|
|
* Allow an admin to impersonate a user.
|
|
*
|
|
* @param mixed $csrf
|
|
* @param array int $_GET['user_ids'] : Ids of users to impersonate, the array should actually contain one id only, we keep use of array for simpler compatibility in UI
|
|
*/
|
|
public function impersonate($csrf)
|
|
{
|
|
if (!$this->verify_csrf($csrf))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
if (1 != count($_GET['user_ids']))
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Vous devez séléctionner un et un seul utilisateur à incarner !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
$id_user = (int) $_GET['user_ids'][0];
|
|
|
|
//Check if this user exists
|
|
$user = $this->internal_user->get($id_user);
|
|
if (!$user)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Cet utilisateur n\'existe pas !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
$settings = $this->internal_setting->gets_for_user($id_user);
|
|
if (!$settings)
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Impossible de charger les settings de cet utilisateur !');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
if (\models\User::STATUS_ACTIVE !== $user['status'])
|
|
{
|
|
\FlashMessage\FlashMessage::push('danger', 'Impossible d\'incarner cet utilisateur car il est actuellement suspendu');
|
|
|
|
return $this->redirect(\descartes\Router::url('User', 'list'));
|
|
}
|
|
|
|
$user['settings'] = $settings;
|
|
|
|
//Save old session to get it back later
|
|
$old_session = $_SESSION;
|
|
$_SESSION = [
|
|
'old_session' => $old_session,
|
|
'impersonate' => true,
|
|
'connect' => true,
|
|
'user' => $user,
|
|
];
|
|
|
|
\FlashMessage\FlashMessage::push('success', 'Vous incarnez désormais l\'utilisateur ' . $user['email'] . '.');
|
|
|
|
return $this->redirect(\descartes\Router::url('Dashboard', 'show'));
|
|
}
|
|
}
|