generated from jric11/baseProject
587 lines
19 KiB
PHP
587 lines
19 KiB
PHP
<?php
|
|
|
|
// ===========
|
|
// Users Class
|
|
// ===========
|
|
|
|
class Users extends Base {
|
|
|
|
// Variables
|
|
|
|
|
|
private $current_user_serial = "";
|
|
private $current_user_name = "";
|
|
private $current_user_email = "";
|
|
private $pagination_size = 20;
|
|
private $pagination_page = 1;
|
|
|
|
// ================================
|
|
// __construct : Class Constructor.
|
|
// ================================
|
|
|
|
public function __construct() {
|
|
|
|
set_error_handler(array($this, "displayError"));
|
|
|
|
date_default_timezone_set(self::TIMEZONE);
|
|
|
|
$this->current_user_serial = (int) ($_SESSION[self::USER_SERIAL] ?? 0);
|
|
$this->current_user_name = $_SESSION[self::USER_NAME] ?? "";
|
|
$this->current_user_email = $_SESSION[self::USER_EMAIL] ?? "";
|
|
$this->pagination_page = $_SESSION[self::PAGINATION_PAGE] ?? 1;
|
|
}
|
|
|
|
// ===========
|
|
// Setup Users
|
|
// ===========
|
|
|
|
public function setupUsers() {
|
|
|
|
$users = $this->getUsersPage();
|
|
$popovers = (new Popovers())->getPopovers();
|
|
|
|
$XML = $this->mergeXML($users, "<XML/>");
|
|
$XML = $this->mergeXML($popovers, $XML);
|
|
|
|
$html = $this->applyXSL($XML, $this->getXSL("setupUsers"));
|
|
|
|
$this->displayContent($html);
|
|
}
|
|
|
|
// ============
|
|
// User Summary
|
|
// ============
|
|
|
|
public function userSummary() {
|
|
|
|
$user_serial = filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
|
|
$user = $this->getUser($user_serial);
|
|
|
|
if ($user->count() == 0) {
|
|
$this->logError("Invalid User ({$user_serial}). " . __METHOD__);
|
|
}
|
|
|
|
$notes = (new Notes())->getAllNotes($user_serial);
|
|
$subscriptions = (new Subscriptions())->getAllUsersSubscriptions($user_serial);
|
|
|
|
$XML = $this->mergeXML($user, "<XML/>");
|
|
$XML = $this->mergeXML($subscriptions, $XML);
|
|
$XML = $this->mergeXML($notes, $XML);
|
|
|
|
$content = $this->applyXSL($XML, $this->getXSL("userSummary"));
|
|
|
|
$this->displayContent($content);
|
|
}
|
|
|
|
// ========
|
|
// Add User
|
|
// ========
|
|
|
|
public function addUser() {
|
|
|
|
$step = filter_input(INPUT_POST, "step") ?: "prompt";
|
|
|
|
switch ($step) {
|
|
|
|
case "prompt":
|
|
|
|
$popovers = (new Popovers())->getPopovers();
|
|
$constants = $this->getConstants();
|
|
|
|
$XML = $this->mergeXML($popovers, "<XML/>");
|
|
$XML = $this->mergeXML($constants, $XML);
|
|
|
|
$content = $this->applyXSL($XML, $this->getXSL("addUser"));
|
|
|
|
$this->displayContent($content);
|
|
|
|
break;
|
|
|
|
case "add":
|
|
|
|
$user_name = filter_input(INPUT_POST, "user_name") ?: "";
|
|
$user_first_name = filter_input(INPUT_POST, "user_first_name") ?: "";
|
|
$user_email = filter_input(INPUT_POST, "user_email") ?: "";
|
|
$user_role = filter_input(INPUT_POST, "user_role") ?: "";
|
|
if (!in_array($user_role, ['User', 'Guest', 'Administrator'], true) || !filter_var($user_email, FILTER_VALIDATE_EMAIL) || strlen($user_email) > 100 || !preg_match('/\A[A-Za-z0-9_.-]{3,64}\z/', $user_name)) {
|
|
http_response_code(422); exit('Enter a valid username, email address and role.');
|
|
}
|
|
|
|
|
|
$user_name = strtoupper(preg_replace("/\s+/", " ", $user_name));
|
|
|
|
$user_random_password = $this->generateRandomPassword();
|
|
$user_temp_password = password_hash($user_random_password, PASSWORD_DEFAULT);
|
|
|
|
$user_change_password = (int) true;
|
|
$user_active = 'active';
|
|
|
|
// Add the User
|
|
|
|
$connection = $this->connect();
|
|
|
|
$SQL = "insert into users
|
|
|
|
( user_name,
|
|
user_email,
|
|
user_first_name,
|
|
user_password_hash,
|
|
user_role,
|
|
user_change_password,
|
|
user_status,
|
|
user_creator,
|
|
user_created )
|
|
|
|
values ( :user_name,
|
|
:user_email,
|
|
:user_first_name,
|
|
:user_password_hash,
|
|
:user_role,
|
|
:user_change_password,
|
|
:user_status,
|
|
:user_creator,
|
|
:user_created )";
|
|
|
|
$statement = $connection->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_name", $user_name);
|
|
$statement->bindValue(":user_email", $user_email);
|
|
$statement->bindValue(":user_first_name", $user_first_name);
|
|
$statement->bindValue(":user_password_hash", $user_temp_password);
|
|
$statement->bindValue(":user_role", $user_role);
|
|
$statement->bindValue(":user_change_password", $user_change_password, PDO::PARAM_BOOL);
|
|
$statement->bindValue(":user_status", $user_active);
|
|
$statement->bindValue(":user_creator", $this->current_user_name);
|
|
$statement->bindValue(":user_created", $this->getTimestamp());
|
|
|
|
if (!$statement->execute()) {
|
|
trigger_error($statement->errorInfo()[2]);
|
|
}
|
|
|
|
$user = $this->getUserByUserName($user_name);
|
|
|
|
// Send User Credentials
|
|
|
|
(new AuthService())->requestReset($user_email);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$this->displayHome();
|
|
}
|
|
}
|
|
|
|
// ===========
|
|
// Delete User
|
|
// ===========
|
|
|
|
public function deleteUser() {
|
|
|
|
$user_serial = filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
|
|
$users = $this->getUser($user_serial);
|
|
|
|
if ($users->count() == 0) {
|
|
$this->logError("Invalid User ({$user_serial}): " . __METHOD__);
|
|
}
|
|
|
|
$SQL = "delete from users
|
|
where user_serial = {$user_serial}";
|
|
|
|
$this->executeSQL($SQL);
|
|
}
|
|
|
|
// =========
|
|
// Edit User
|
|
// =========
|
|
|
|
public function editUser() {
|
|
|
|
$step = filter_input(INPUT_POST, "step") ?: "prompt";
|
|
|
|
switch ($step) {
|
|
|
|
case "prompt":
|
|
|
|
$user_serial = (int) filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
|
|
$user = $this->getUser($user_serial);
|
|
|
|
if ($user->count() === 0) {
|
|
$this->logError("Invalid User ({$user_serial}): " . __METHOD__);
|
|
}
|
|
|
|
$popovers = (new Popovers())->getPopovers();
|
|
$constants = $this->getConstants();
|
|
|
|
$XML = $this->mergeXML($user, "<XML/>");
|
|
$XML = $this->mergeXML($popovers, $XML);
|
|
$XML = $this->mergeXML($constants, $XML);
|
|
|
|
$content = $this->applyXSL($XML, $this->getXSL("editUser"));
|
|
|
|
$this->displayContent($content);
|
|
|
|
break;
|
|
|
|
case "update":
|
|
|
|
$user_serial = filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
$user_name = filter_input(INPUT_POST, "user_name") ?: "";
|
|
$user_email = filter_input(INPUT_POST, "user_email") ?: "";
|
|
$user_first_name = filter_input(INPUT_POST, "user_first_name") ?: "";
|
|
$user_role = filter_input(INPUT_POST, "user_role") ?: "";
|
|
if (!in_array($user_role, ['User', 'Guest', 'Administrator'], true) || !filter_var($user_email, FILTER_VALIDATE_EMAIL) || strlen($user_email) > 100 || !preg_match('/\A[A-Za-z0-9_.-]{3,64}\z/', $user_name)) {
|
|
http_response_code(422); exit('Enter a valid username, email address and role.');
|
|
}
|
|
|
|
$user_active = filter_input(INPUT_POST, 'user_active', FILTER_VALIDATE_BOOLEAN) ? 'active' : 'inactive';
|
|
|
|
$users = $this->getUser($user_serial);
|
|
|
|
if ($users->count() == 0) {
|
|
$this->logError("Invalid User ({$user_serial}): " . __METHOD__);
|
|
}
|
|
|
|
// Update the User
|
|
|
|
$SQL = "update users
|
|
set user_name = :user_name,
|
|
user_email = :user_email,
|
|
user_first_name = :user_first_name,
|
|
user_role = :user_role,
|
|
user_auth_version = user_auth_version + 1,
|
|
user_status = :user_status,
|
|
user_changer = :user_changer,
|
|
user_changed = :user_changed
|
|
where user_serial = :user_serial";
|
|
|
|
$statement = $this->connect()->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_serial", $user_serial);
|
|
$statement->bindValue(":user_name", $user_name);
|
|
$statement->bindValue(":user_email", $user_email);
|
|
$statement->bindValue(":user_first_name", $user_first_name);
|
|
$statement->bindValue(":user_role", $user_role);
|
|
$statement->bindValue(":user_status", $user_active);
|
|
$statement->bindValue(":user_changer", $this->current_user_name);
|
|
$statement->bindValue(":user_changed", $this->getTimestamp());
|
|
|
|
$statement->execute();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$this->displayHome();
|
|
}
|
|
}
|
|
|
|
// ====================
|
|
// Return a User Object
|
|
// ====================
|
|
|
|
public function getUser($user_serial = 0) {
|
|
$user_serial = (int) $user_serial;
|
|
|
|
$SQL = "select view_users.*
|
|
from view_users
|
|
where user_serial = {$user_serial}";
|
|
|
|
return $this->getTable("users", $SQL);
|
|
}
|
|
|
|
// ====================
|
|
// Return a User Object
|
|
// ====================
|
|
|
|
public function getUserByUserName($user_name) {
|
|
$stmt = $this->connect()->prepare('SELECT * FROM view_users WHERE user_name = :name');
|
|
$stmt->execute([':name' => $user_name]);
|
|
return $this->getTableXML('users', $stmt);
|
|
}
|
|
|
|
// =====================
|
|
// Return a Users Serial
|
|
// =====================
|
|
|
|
public function getUserSerial($user_name = "") {
|
|
|
|
$users = $this->getUserByUserId($user_name);
|
|
|
|
return ($users->count() === 0) ? 0 : (int) $users->record->user_serial;
|
|
}
|
|
|
|
// =====================
|
|
// Return a Users Object
|
|
// =====================
|
|
|
|
public function getUsers() {
|
|
|
|
$SQL = "select view_users.* from view_users";
|
|
|
|
return $this->getTable("users", $SQL);
|
|
}
|
|
|
|
// ==========================
|
|
// Return a Users Page Object
|
|
// ==========================
|
|
|
|
public function getUsersPage() {
|
|
|
|
// Find Criteria
|
|
|
|
$find_user = filter_input(INPUT_POST, "find_user") ?: "";
|
|
$find_user = $this->sanitizeString($find_user);
|
|
|
|
$find_words = implode("|", explode(" ", $find_user));
|
|
|
|
// Record Count
|
|
|
|
$connection = $this->connect();
|
|
|
|
$SQL = "select count(*) as count
|
|
from view_users
|
|
where user_name regexp :user_name
|
|
or user_first_name regexp :user_first_name
|
|
or user_email regexp :user_email
|
|
or user_role regexp :user_role";
|
|
|
|
$statement = $connection->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_name", $find_words);
|
|
$statement->bindValue(":user_first_name", $find_words);
|
|
$statement->bindValue(":user_email", $find_words);
|
|
$statement->bindValue(":user_role", $find_words);
|
|
|
|
$statement->execute();
|
|
|
|
$recordset = $statement->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$count = (count($recordset) > 0) ? (int) $recordset["count"] : (int) 0;
|
|
|
|
// Pagination
|
|
|
|
$pagination = filter_input(INPUT_POST, "pagination") ?: "";
|
|
|
|
switch ($pagination) {
|
|
|
|
case "first" : $this->pagination_page = 1;
|
|
break;
|
|
case "previous" : $this->pagination_page = max(($this->pagination_page - 1), 1);
|
|
break;
|
|
case "next" : $this->pagination_page = ($this->pagination_page + 1);
|
|
break;
|
|
case "last" : $this->pagination_page = ($count / $this->pagination_size);
|
|
break;
|
|
}
|
|
|
|
$offset = (($this->pagination_page * $this->pagination_size) - $this->pagination_size);
|
|
$start = ($offset + 1);
|
|
$end = min($count, (($start + $this->pagination_size) - 1));
|
|
|
|
// Data
|
|
|
|
$SQL = "select view_users.*
|
|
from view_users
|
|
where user_name regexp :user_name
|
|
or user_first_name regexp :user_first_name
|
|
or user_email regexp :user_email
|
|
or user_role regexp :user_role
|
|
limit {$this->pagination_size}
|
|
offset {$offset}";
|
|
|
|
$statement = $connection->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_name", $find_words);
|
|
$statement->bindValue(":user_first_name", $find_words);
|
|
$statement->bindValue(":user_email", $find_words);
|
|
$statement->bindValue(":user_role", $find_words);
|
|
|
|
$statement->execute();
|
|
|
|
$users = $this->getTableXML("users", $statement);
|
|
|
|
// Insert Pagination Attributes
|
|
|
|
$users->addAttribute("count", $count);
|
|
$users->addAttribute("start", $start);
|
|
$users->addAttribute("end", $end);
|
|
$users->addAttribute("page", $this->pagination_page);
|
|
|
|
$_SESSION[self::PAGINATION_PAGE] = $this->pagination_page;
|
|
|
|
return $users;
|
|
}
|
|
|
|
// ===========================
|
|
// Return an User Object(AJAX)
|
|
// ===========================
|
|
|
|
public function getUser_AJAX($user_name = "") {
|
|
|
|
$user_name = filter_input(INPUT_POST, "user_name") ?: $user_name;
|
|
|
|
$users = $this->getUserByUserName($user_name);
|
|
|
|
// Create the User Object.
|
|
|
|
$User = array();
|
|
|
|
$User["exists"] = ($users->count() > 0) ? true : false;
|
|
|
|
if ($_SESSION[self::AJAX]) {
|
|
echo json_encode($User);
|
|
} else {
|
|
return $User;
|
|
}
|
|
}
|
|
|
|
// ==========================
|
|
// Determine if a User Exists
|
|
// ==========================
|
|
|
|
public function userExists() {
|
|
|
|
$user_serial = filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
$user_name = filter_input(INPUT_POST, "user_name") ?: "";
|
|
|
|
$user_name = strtolower(trim(preg_replace("/\s+/", " ", $user_name)));
|
|
|
|
$SQL = "select user_name
|
|
from view_users
|
|
where user_serial != :user_serial
|
|
and user_name = :user_name";
|
|
|
|
$statement = $this->connect()->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_serial", $user_serial);
|
|
$statement->bindValue(":user_name", $user_name);
|
|
|
|
$statement->execute();
|
|
|
|
$recordset = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$exists = (count($recordset) > 0) ? true : false;
|
|
|
|
echo json_encode($exists);
|
|
}
|
|
|
|
// =============================
|
|
// Determine if a User is Active
|
|
// =============================
|
|
|
|
public function userActive() {
|
|
|
|
$user_serial = (int) filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
|
|
$SQL = "select request_serial
|
|
from requests
|
|
where request_user = {$user_serial}";
|
|
|
|
$requests = $this->getTable("requests", $SQL);
|
|
|
|
$active = ($requests->count() > 0) ? true : $active;
|
|
|
|
echo json_encode($active);
|
|
}
|
|
|
|
// ===============
|
|
// Change Password
|
|
// ===============
|
|
|
|
public function changePassword() {
|
|
$params = ['PASSWORD_ERROR' => ''];
|
|
if (($_POST['step'] ?? '') === 'change') {
|
|
$this->requireCsrf();
|
|
try {
|
|
$auth = new AuthService();
|
|
if (!$auth->allowAttempt('change-password', (string) $_SESSION[self::USER_SERIAL], 10, 900)) {
|
|
throw new InvalidArgumentException('Too many attempts. Please try again later.');
|
|
}
|
|
if (!$auth->changePassword((int) $_SESSION[self::USER_SERIAL], $_POST['user_current_password'] ?? '', $_POST['user_new_password'] ?? '', $_POST['user_verify_password'] ?? '')) {
|
|
throw new InvalidArgumentException('Your current password is incorrect or your session has expired.');
|
|
}
|
|
$this->logoutSession();
|
|
header('Location: main.php', true, 303);
|
|
exit;
|
|
} catch (InvalidArgumentException $e) { $params['PASSWORD_ERROR'] = $e->getMessage(); }
|
|
}
|
|
$this->displayContent($this->applyXSL('<XML/>', $this->getXSL('changePassword'), $params));
|
|
}
|
|
|
|
public function resetPassword() {
|
|
$this->requireCsrf();
|
|
$stmt = $this->connect()->prepare('SELECT user_email FROM users WHERE user_serial = :id');
|
|
$stmt->execute([':id' => (int) ($_POST['user_serial'] ?? 0)]);
|
|
$email = $stmt->fetchColumn();
|
|
if ($email) (new AuthService())->requestReset($email);
|
|
header('Content-Type: application/json');
|
|
echo json_encode(true);
|
|
}
|
|
|
|
// ===============================================
|
|
// Update the Login timestamp for the current User
|
|
// ===============================================
|
|
|
|
public function updateLogin() {
|
|
|
|
$SQL = "update users
|
|
set user_last_login = :user_login
|
|
where user_serial = :user_serial";
|
|
|
|
$statement = $this->connect()->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_login", $this->getTimestamp());
|
|
$statement->bindValue(":user_serial", $this->current_user_serial);
|
|
|
|
$statement->execute();
|
|
}
|
|
|
|
// ====================
|
|
// Update Active Status
|
|
// ====================
|
|
|
|
public function updateActiveStatus() {
|
|
|
|
$user_serial = filter_input(INPUT_POST, "user_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0;
|
|
$user_active = filter_input(INPUT_POST, 'user_active', FILTER_VALIDATE_BOOLEAN) ? 'active' : 'inactive';
|
|
|
|
$SQL = "update users
|
|
set user_status = :user_status,
|
|
user_auth_version = user_auth_version + 1,
|
|
user_changed = :user_changed,
|
|
user_changer = :user_changer
|
|
where user_serial = :user_serial";
|
|
|
|
$statement = $this->connect()->prepare($SQL);
|
|
|
|
$statement->bindValue(":user_serial", $user_serial);
|
|
$statement->bindValue(":user_status", $user_active);
|
|
$statement->bindValue(":user_changed", $this->getTimestamp());
|
|
$statement->bindValue(":user_changer", $this->current_user_name);
|
|
|
|
if (!$statement->execute()) {
|
|
error_log($statement->errorInfo()[2]);
|
|
}
|
|
}
|
|
|
|
// ====================================
|
|
// Return a Users Login Activity Object
|
|
// ====================================
|
|
|
|
public function getLoginActivity($userserial) {
|
|
|
|
$SQL = "select view_journal.journal_timestamp_verbose, view_journal.journal_ip
|
|
from view_journal
|
|
where view_journal.journal_origin = '{$userserial}'
|
|
and view_journal.journal_entry like '{$userserial} %logged in%'";
|
|
|
|
return $this->getTable("loginactivity", $SQL);
|
|
}
|
|
}
|
|
|
|
?>
|