Files
atlhousingreport/classes/Users.php
T
2026-02-14 07:57:18 -05:00

749 lines
24 KiB
PHP

<?php
// ===========
// Users Class
// ===========
class Users extends Base {
// Variables
private $current_user_id = "";
private $current_user_serial = "";
private $current_user_name = "";
private $current_user_client_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_id = $_SESSION[self::USER_ID] ?? "";
$this->current_user_name = $_SESSION[self::USER_NAME] ?? "";
$this->current_user_email = $_SESSION[self::USER_EMAIL] ?? "";
$this->current_user_client_name = $_SESSION[self::USER_CLIENT_NAME] ?? "";
$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_client_name = filter_input(INPUT_POST, "user_client_name") ?: "";
$user_email = filter_input(INPUT_POST, "user_email") ?: "";
$user_role = filter_input(INPUT_POST, "user_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 = (boolean) true;
$user_active = (boolean) true;
// Add the User
$connection = $this->connect();
$SQL = "insert into users
( user_name,
user_email,
user_client_name,
user_password,
user_role,
user_change_password,
user_active,
user_creator,
user_created )
values ( :user_name,
:user_email,
:user_client_name,
:user_password,
:user_role,
:user_change_password,
:user_active,
:user_creator,
:user_created )";
$statement = $connection->prepare($SQL);
$statement->bindValue(":user_name", $user_name);
$statement->bindValue(":user_email", $user_email);
$statement->bindValue(":user_client_name", $user_client_name);
$statement->bindValue(":user_password", $user_temp_password);
$statement->bindValue(":user_role", $user_role);
$statement->bindValue(":user_change_password", $user_change_password, PDO::PARAM_BOOL);
$statement->bindValue(":user_active", $user_active, PDO::PARAM_BOOL);
$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 Email())->emailNewUserCredentials($user, $user_random_password);
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 = (integer) 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_client_name = filter_input(INPUT_POST, "user_client_name") ?: "";
$user_role = filter_input(INPUT_POST, "user_role") ?: "";
$user_active = filter_input(INPUT_POST, "user_active", FILTER_VALIDATE_BOOLEAN) ?: false;
$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_client_name = :user_client_name,
user_role = :user_role,
user_active = :user_active,
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_client_name", $user_client_name);
$statement->bindValue(":user_role", $user_role);
$statement->bindValue(":user_active", $user_active, PDO::PARAM_BOOL);
$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) {
$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) {
$SQL = "select view_users.*
from view_users
where user_name = '{$user_name}'
or user_client_name = '{$user_name}'";
return $this->getTable("user", $SQL);
}
// ======================
// Return a User's Serial
// ======================
public function getUserSerial($user_id = "") {
$users = $this->getUserByUserId($user_id);
return ($users->count() === 0) ? 0 : (integer) $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_client_name regexp :user_client_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_client_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) ? (integer) $recordset["count"] : (integer) 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_client_name regexp :user_client_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_client_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_id = filter_input(INPUT_POST, "user_id") ?: "";
$user_id = strtolower(trim(preg_replace("/\s+/", " ", $user_id)));
$SQL = "select user_id
from view_users
where user_serial != :user_serial
and user_id = :user_id";
$statement = $this->connect()->prepare($SQL);
$statement->bindValue(":user_serial", $user_serial);
$statement->bindValue(":user_id", $user_id);
$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 = (integer) 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);
}
// ========================
// Login to the application
// ========================
public function login() {
$step = filter_input(INPUT_POST, "step") ?: "prompt";
switch ($step) {
case "prompt":
$XSLParms["BTN_SUBMIT"] = "main.php?action=Users.login&step=authenticate";
$XSLParms["INVALID_SIGNIN"] = "FALSE";
echo $this->applyXSL("", $this->getXSL("signIn"), $XSLParms);
exit();
break;
case "authenticate":
$user_name = filter_input(INPUT_POST, "user_name") ?: "";
$user_password = filter_input(INPUT_POST, "user_password") ?: "";
// The User must exist in the Users Table
$user = $this->getUserByUserName($user_name);
// Automatically deny authentication if user is inactive
if ($user->record->user_active == 0) {
$XSLParms["BTN_SUBMIT"] = "main.php?action=Users.signIn&step=authenticate";
$XSLParms["INVALID_SIGNIN"] = "TRUE";
echo $this->applyXSL("", $this->getXSL("signIn"), $XSLParms);
die();
}
if ($user->count() > 0) {
$stored_hashed_password = $user->record->user_password;
// Verify Password
if (password_verify($user_password, $stored_hashed_password)) {
$_SESSION[self::USER_AUTHENTICATED] = true;
$_SESSION[self::USER_SERIAL] = (integer) $user->record->user_serial;
$_SESSION[self::USER_ID] = (string) $user->record->user_id;
$_SESSION[self::USER_NAME] = (string) $user->record->user_name;
$_SESSION[self::USER_EMAIL] = (string) $user->record->user_email;
$_SESSION[self::USER_CLIENT_NAME] = (string) $user->record->user_client_name;
$_SESSION[self::USER_ROLE] = (string) $user->record->user_role;
$this->current_user_id = $_SESSION[self::USER_ID] ?? "";
$this->current_user_serial = $_SESSION[self::USER_SERIAL] ?? 0;
$this->current_user_name = $_SESSION[self::USER_NAME] ?? "";
$this->current_user_email = $_SESSION[self::USER_EMAIL] ?? "";
// Determine if this is a System Administrator
if (count($this->getSettings()->xpath("//SystemAdministrator[. = '{$user_name}']")) > 0) {
$_SESSION[self::USER_ROLE] = "System Administrator";
}
// Create Journal Entry and finish
(new Journal())->journalEntry("{$_SESSION[self::USER_NAME]} logged in ({$_SESSION[self::USER_ROLE]}).");
$this->updateLogin();
header("Location: ./");
exit();
} else {
$XSLParms["BTN_SUBMIT"] = "main.php?action=Users.signIn&step=authenticate";
$XSLParms["INVALID_SIGNIN"] = "TRUE";
echo $this->applyXSL("", $this->getXSL("signIn"), $XSLParms);
die();
}
} else {
$XSLParms["BTN_SUBMIT"] = "main.php?action=Users.signIn&step=authenticate";
$XSLParms["INVALID_SIGNIN"] = "TRUE";
echo $this->applyXSL("", $this->getXSL("signIn"), $XSLParms);
die();
}
break;
default:
// User NOT Validated.
header("Location: ./");
exit();
}
}
// ===============
// Change Password
// ===============
public function changePassword() {
$step = filter_input(INPUT_POST, "step") ?: "prompt";
switch ($step) {
case "prompt":
$popovers = (new Popovers())->getPopovers();
$XML = $this->mergeXML($popovers, "<XML/>");
$content = $this->applyXSL($XML, $this->getXSL("changePassword"));
$this->displayContent($content);
break;
case "change":
$user_serial = $_SESSION[self::USER_SERIAL];
$user_new_password = filter_input(INPUT_POST, "user_new_password") ?: "";
$user_verify_password = filter_input(INPUT_POST, "user_verify_password") ?: "";
if (!$user_new_password == $user_verify_password) {
$this->initializeSession();
}
$user_new_hashed_password = password_hash($user_new_password, PASSWORD_DEFAULT);
// Update User Password
$connection = $this->connect();
$SQL = "update users
set user_password = :user_password,
user_change_password = :user_change_password,
user_changer = :user_changer,
user_changed = :user_changed
where user_serial = :user_serial";
$statement = $connection->prepare($SQL);
$statement->bindValue(":user_serial", $user_serial);
$statement->bindValue(":user_password", $user_new_hashed_password);
$statement->bindValue(":user_change_password", 0);
$statement->bindValue(":user_changer", $this->current_user_name);
$statement->bindValue(":user_changed", $this->getTimestamp());
if (!$statement->execute()) {
$this->debug($statement->errorInfo()[2]);
}
(new Journal())->journalEntry("{$_SESSION[self::USER_NAME]} changed their password.");
break;
default:
$this->displayHome();
}
}
// ==============
// Reset Password
// ==============
public function resetPassword() {
$reset = false;
$user_serial = filter_input(INPUT_POST, "user_serial") ?: "";
$user = $this->getUser($user_serial);
$user_name = $user->record->user_name;
$user_random_password = $this->generateRandomPassword();
$user_temp_password = password_hash($user_random_password, PASSWORD_DEFAULT);
// Update User Password
$connection = $this->connect();
$SQL = "update users
set user_password = :user_password,
user_change_password = :user_change_password
where user_serial = :user_serial";
$statement = $connection->prepare($SQL);
$statement->bindValue(":user_serial", $user_serial);
$statement->bindValue(":user_password", $user_temp_password);
$statement->bindValue(":user_change_password", 1);
if (!$statement->execute()) {
$this->debug($statement->errorInfo()[2]);
} else {
$reset = true;
}
// Send User Credentials
(new Email())->emailUserPasswordResetLink($user, $user_random_password);
(new Journal())->journalEntry("{$_SESSION[self::USER_NAME]} reset {$user_name}'s password.");
echo json_encode($reset);
}
// ===============================================
// Update the Login timestamp for the current User
// ===============================================
public function updateLogin() {
$SQL = "update users
set user_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_SANITIZE_NUMBER_INT) ?: 0;
$SQL = "update users
set user_active = :user_active,
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_active", $user_active);
$statement->bindValue(":user_changed", $this->getTimestamp());
$statement->bindValue(":user_changer", $this->current_user_name);
if (!$statement->execute()) {
error_log($statement->errorInfo()[2]);
}
}
}
?>