Initialized migrating modals into entity folders and modals out of ajax and start working on moving admin items to new admin directory

This commit is contained in:
johnnyq 2025-07-27 21:24:14 -04:00
parent 699546f531
commit 4906e06bf1
37 changed files with 2046 additions and 37 deletions

53
admin/includes/footer.php Normal file
View File

@ -0,0 +1,53 @@
<?php
require_once "../includes/inc_confirm_modal.php";
?>
<?php
if (str_contains(basename($_SERVER["PHP_SELF"]), "admin_")) { ?>
<p class="text-right font-weight-light">ITFlow <?php echo APP_VERSION ?> &nbsp; · &nbsp; <a target="_blank" href="https://docs.itflow.org">Docs</a> &nbsp; · &nbsp; <a target="_blank" href="https://forum.itflow.org">Forum</a> &nbsp; · &nbsp; <a target="_blank" href="https://services.itflow.org">Services</a></p>
<br>
<?php } ?>
</div><!-- /.container-fluid -->
</div> <!-- /.content -->
</div> <!-- /.content-wrapper -->
</div> <!-- ./wrapper -->
<!-- Set the browser window title to the clients name -->
<script>document.title = <?php echo json_encode("$tab_title - $page_title"); ?>;</script>
<!-- REQUIRED SCRIPTS -->
<!-- Bootstrap 4 -->
<script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom js-->
<script src="../plugins/moment/moment.min.js"></script>
<script src="../plugins/chart.js/Chart.min.js"></script>
<script src="../plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
<script src='../plugins/daterangepicker/daterangepicker.js'></script>
<script src='../plugins/select2/js/select2.min.js'></script>
<script src='../plugins/inputmask/jquery.inputmask.min.js'></script>
<script src="../plugins/tinymce/tinymce.min.js" referrerpolicy="origin"></script>
<script src="../plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
<script src="../plugins/clipboardjs/clipboard.min.js"></script>
<script src="../js/keepalive.js"></script>
<script src="../plugins/DataTables/datatables.min.js"></script>
<script src="../plugins/intl-tel-input/js/intlTelInput.min.js"></script>
<!-- AdminLTE App -->
<script src="../plugins/adminlte/js/adminlte.min.js"></script>
<script src="../js/app.js"></script>
<script src="../js/ajax_modal.js"></script>
<script src="../js/confirm_modal.js"></script>
</body>
</html>
<?php
// Calculate Execution time Uncomment for test
//$time_end = microtime(true);
//$execution_time = ($time_end - $time_start);
//echo '<h2>Total Execution Time: '.number_format((float) $execution_time, 10) .' seconds</h2>';

54
admin/includes/header.php Normal file
View File

@ -0,0 +1,54 @@
<?php
// Calculate Execution time start
// uncomment for test
// $time_start = microtime(true);
header("X-Frame-Options: DENY");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="robots" content="noindex">
<title><?php echo $session_company_name; ?></title>
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('../uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="/uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
<!-- Custom Style Sheet -->
<link href="../plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet" type="text/css">
<link href="../plugins/select2/css/select2.min.css" rel="stylesheet" type="text/css">
<link href="../plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css" rel="stylesheet" type="text/css">
<link href='../plugins/daterangepicker/daterangepicker.css' rel='stylesheet' />
<link href="../plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="../plugins/DataTables/datatables.min.css" rel="stylesheet">
<link href="../plugins/intl-tel-input/css/intlTelInput.min.css" rel="stylesheet">
<!-- CSS to allow regular button to show as block button in mobile response view using the class btn-responsive -->
<link href="../css/itflow_custom.css" rel="stylesheet">
<!-- Theme style -->
<link rel="stylesheet" href="../plugins/adminlte/css/adminlte.min.css">
<!-- jQuery -->
<script src="../plugins/jquery/jquery.min.js"></script>
<script src="../plugins/toastr/toastr.min.js"></script>
</head>
<body class="
hold-transition sidebar-mini layout-fixed layout-navbar-fixed
accent-<?php if (isset($_GET['client_id'])) { echo "blue"; } else { echo nullable_htmlentities($config_theme); } ?>
<?php if ($config_theme_dark) { echo "dark-mode"; } ?>
">
<div class="wrapper text-sm">

View File

@ -0,0 +1,16 @@
<?php
require_once "../config.php";
require_once "../functions.php";
require_once "../includes/check_login.php";
require_once "../includes/page_title.php";
if (!isset($session_is_admin) || !$session_is_admin) {
exit(WORDING_ROLECHECK_FAILED . "<br>Tell your admin: Your role does not have admin access.");
}
require_once "includes/header.php";
require_once "../includes/top_nav.php";
require_once "includes/side_nav.php";
require_once "../includes/inc_wrapper.php";
require_once "../includes/inc_alert_feedback.php";
require_once "../includes/filter_header.php";
require_once "../includes/app_version.php";

View File

@ -0,0 +1,9 @@
<script src="js/app.js"></script>
<script src="plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
<?php
$content = ob_get_clean();
// Return the title and content as a JSON response
echo json_encode(['content' => $content]);
?>

View File

@ -0,0 +1,13 @@
<?php
require_once "../../../config.php";
require_once "../../../functions.php";
require_once "../../../includes/check_login.php";
header('Content-Type: application/json');
// Check for the 'id' parameter
//if (!isset($_GET['id'])) {
// echo json_encode(['error' => 'ID missing.']);
// exit;
//}

305
admin/includes/side_nav.php Normal file
View File

@ -0,0 +1,305 @@
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-<?php echo nullable_htmlentities($config_theme); ?> d-print-none">
<a class="brand-link pb-1 mt-1" href="clients.php">
<p class="h6">
<i class="nav-icon fas fa-arrow-left ml-3 mr-2"></i>
<span class="brand-text">
Back | <strong>Administration</strong>
</span>
</p>
</a>
<!-- Sidebar -->
<div class="sidebar">
<!-- Sidebar Menu -->
<nav>
<ul class="nav nav-pills nav-sidebar flex-column mt-2" data-widget="treeview" data-accordion="false">
<!-- ACCESS Section -->
<li class="nav-item">
<a href="users.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "users.php") {echo "active";} ?>">
<i class="nav-icon fas fa-users"></i>
<p>Users</p>
</a>
</li>
<li class="nav-item">
<a href="roles.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "roles.php") {echo "active";} ?>">
<i class="nav-icon fas fa-user-shield"></i>
<p>Roles</p>
</a>
</li>
<li class="nav-item">
<a href="admin_api.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "admin_api.php") {echo "active";} ?>">
<i class="nav-icon fas fa-key"></i>
<p>API Keys</p>
</a>
</li>
<li class="nav-header">TAGS & CATEGORIES</li>
<li class="nav-item">
<a href="admin_tag.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_tag.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-tags"></i>
<p>Tags</p>
</a>
</li>
<li class="nav-item">
<a href="admin_category.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_category.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-list-ul"></i>
<p>Categories</p>
</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a href="admin_tax.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_tax.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-balance-scale"></i>
<p>Taxes</p>
</a>
</li>
<li class="nav-item">
<a href="admin_payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_payment_method.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-hand-holding-usd"></i>
<p>Payment Methods</p>
</a>
</li>
<li class="nav-item">
<a href="admin_payment_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_payment_provider.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Payment Providers</p>
</a>
</li>
<li class="nav-item">
<a href="admin_saved_payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_saved_payment_method.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Saved Payments</p>
</a>
</li>
<li class="nav-item">
<a href="admin_ai_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_ai_provider.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-robot"></i>
<p>AI Providers</p>
</a>
</li>
<li class="nav-item">
<a href="admin_ai_model.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_ai_model.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-robot"></i>
<p>AI Models</p>
</a>
</li>
<?php } ?>
<?php if ($config_module_enable_ticketing) { ?>
<li class="nav-item">
<a href="admin_ticket_status.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_ticket_status.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-info-circle"></i>
<p>Ticket Statuses</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="admin_custom_link.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_custom_link.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-external-link-alt"></i>
<p>Custom Links</p>
</a>
</li>
<?php if ($config_module_enable_itdoc) { ?>
<li class="nav-header">TEMPLATES</li>
<li class="nav-item">
<a href="admin_project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['admin_project_template.php', 'admin_project_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>Project Templates</p>
</a>
</li>
<li class="nav-item">
<a href="admin_ticket_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['admin_ticket_template.php', 'admin_ticket_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Ticket Templates</p>
</a>
</li>
<li class="nav-item">
<a href="admin_vendor_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_vendor_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-building"></i>
<p>Vendor Templates</p>
</a>
</li>
<li class="nav-item">
<a href="admin_software_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_software_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-rocket"></i>
<p>License Templates</p>
</a>
</li>
<li class="nav-item">
<a href="admin_document_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['admin_document_template.php', 'admin_document_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file"></i>
<p>Document Templates</p>
</a>
</li>
<?php } ?>
<li class="nav-header">MAINTENANCE</li>
<li class="nav-item">
<a href="admin_mail_queue.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_mail_queue.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-mail-bulk"></i>
<p>Mail Queue</p>
</a>
</li>
<li class="nav-item">
<a href="admin_audit_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_audit_log.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-history"></i>
<p>Audit Logs</p>
</a>
</li>
<li class="nav-item">
<a href="admin_app_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_app_log.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-history"></i>
<p>App Logs</p>
</a>
</li>
<li class="nav-item">
<a href="admin_backup.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_backup.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cloud-upload-alt"></i>
<p>Backup</p>
</a>
</li>
<li class="nav-item">
<a href="admin_debug.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_debug.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-bug"></i>
<p>Debug</p>
</a>
</li>
<li class="nav-item">
<a href="admin_update.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_update.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-download"></i>
<p>Update</p>
</a>
</li>
<!-- SETTINGS Section -->
<li class="nav-item has-treeview mt-2 <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['admin_settings_company.php', 'admin_settings_localization.php', 'admin_settings_theme.php', 'admin_settings_security.php', 'admin_settings_mail.php', 'admin_settings_notification.php', 'admin_settings_default.php', 'admin_settings_invoice.php', 'admin_settings_quote.php', 'admin_settings_online_payment.php', 'admin_settings_online_payment_clients.php', 'admin_settings_project.php', 'admin_settings_ticket.php', 'admin_settings_ai.php', 'admin_identity_provider.php', 'admin_settings_telemetry.php', 'admin_settings_module.php']) ? 'menu-open' : ''); ?>">
<a href="#" class="nav-link">
<p>
SETTINGS
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="admin_settings_company.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_company.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-briefcase"></i>
<p>Company Details</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_localization.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_localization.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-globe"></i>
<p>Localization</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_theme.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_theme.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-paint-brush"></i>
<p>Theme</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_security.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_security.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-shield-alt"></i>
<p>Security</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_mail.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_mail.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-envelope"></i>
<p>Mail</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_notification.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_notification.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-bell"></i>
<p>Notifications</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_default.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_default.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cogs"></i>
<p>Defaults</p>
</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a href="admin_settings_invoice.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_invoice.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file-invoice"></i>
<p>Invoice</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_quote.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_quote.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-comment-dollar"></i>
<p>Quote</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_online_payment.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_online_payment.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Online Payment</p>
</a>
</li>
<?php if ($config_stripe_enable) { ?>
<li class="nav-item">
<a href="admin_settings_online_payment_clients.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_online_payment_clients.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Payment/Stripe Clients</p>
</a>
</li>
<?php } ?>
<?php } ?>
<?php if ($config_module_enable_ticketing) { ?>
<li class="nav-item">
<a href="admin_settings_project.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_project.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>Project</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_ticket.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_ticket.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Ticket</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="admin_settings_ai.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_ai.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-robot"></i>
<p>AI</p>
</a>
</li>
<!-- Currently the only integration is the client portal SSO -->
<?php if ($config_client_portal_enable) { ?>
<li class="nav-item">
<a href="admin_identity_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_identity_provider.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-fingerprint"></i>
<p>Identity Provider</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="admin_settings_telemetry.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_telemetry.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-satellite-dish"></i>
<p>Telemetry</p>
</a>
</li>
<li class="nav-item">
<a href="admin_settings_module.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'admin_settings_module.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cube"></i>
<p>Modules</p>
</a>
</li>
</ul>
</li>
</ul>
</nav>
<!-- /.sidebar-menu -->
<div class="mb-3"></div>
</div>
<!-- /.sidebar -->
</aside>

View File

@ -0,0 +1,58 @@
<div class="modal" id="addRoleModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-user-shield mr-2"></i>Add new role</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body bg-white">
<div class="tab-content">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<input type="text" class="form-control" name="role_name" placeholder="Role Name" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-chevron-right"></i></span>
</div>
<input type="text" class="form-control" name="role_description" placeholder="Role Description" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Admin Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tools"></i></span>
</div>
<select class="form-control select2" name="role_is_admin" required>
<option value="0">No - edit after creation to set permissions</option>
<option value="1">Yes - this role should have full admin access</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer bg-white">
<button type="submit" name="add_role" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,153 @@
<?php
require_once '../includes/ajax_header.php';
$role_id = intval($_GET['id']);
$sql = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_id = $role_id LIMIT 1");
$row = mysqli_fetch_array($sql);
$role_name = nullable_htmlentities($row['role_name']);
$role_description = nullable_htmlentities($row['role_description']);
$role_admin = intval($row['role_is_admin']);
// Count number of users that have each role
$sql_role_user_count = mysqli_query($mysqli, "SELECT COUNT(user_id) FROM users WHERE user_role_id = $role_id AND user_archived_at IS NULL");
$role_user_count = mysqli_fetch_row($sql_role_user_count)[0];
$sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE user_role_id = $role_id AND user_archived_at IS NULL");
// Initialize an empty array to hold user names
$user_names = [];
// Fetch each row and store the user_name in the array
while($row = mysqli_fetch_assoc($sql_users)) {
$user_names[] = nullable_htmlentities($row['user_name']);
}
// Convert the array of user names to a comma-separated string
$user_names_string = implode(",", $user_names) ;
if (empty($user_names_string)) {
$user_names_string = "-";
}
// Generate the HTML form content using output buffering.
ob_start();
?>
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-user-shield mr-2"></i>Editing role:
<strong><?php echo $role_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="role_id" value="<?php echo $role_id; ?>">
<div class="modal-body bg-white">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-role-details<?php echo $role_id; ?>">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-role-access<?php echo $role_id; ?>">Access</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-role-details<?php echo $role_id; ?>">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<input type="text" class="form-control" name="role_name" placeholder="Role Name" maxlength="200" value="<?php echo $role_name; ?>" required>
</div>
</div>
<div class="form-group">
<label>Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-chevron-right"></i></span>
</div>
<input type="text" class="form-control" name="role_description" placeholder="Role Description" maxlength="200" value="<?php echo $role_description; ?>" required>
</div>
</div>
<div class="form-group">
<label>Admin Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tools"></i></span>
</div>
<select class="form-control select2" name="role_is_admin" required>
<option value="1" <?php if ($role_admin) { echo 'selected'; } ?> >Yes - this role should have full admin access</option>
<option value="0" <?php if (!$role_admin) { echo 'selected'; } ?>>No - use permissions on the next tab</option>
</select>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-role-access<?php echo $role_id; ?>">
<?php if ($role_admin) { ?>
<div class="alert alert-warning"><strong>Module permissions do not apply to Admins.</strong></div>
<?php } ?>
<?php
// Enumerate modules
$sql_modules = mysqli_query($mysqli, "SELECT * FROM modules");
while ($row_modules = mysqli_fetch_array($sql_modules)) {
$module_id = intval($row_modules['module_id']);
$module_name = nullable_htmlentities($row_modules['module_name']);
$module_name_display = ucfirst(str_replace("module_","",$module_name));
$module_description = nullable_htmlentities($row_modules['module_description']);
// Get permission level for module
$module_permission_row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT user_role_permission_level FROM user_role_permissions WHERE module_id = $module_id AND user_role_id = $role_id LIMIT 1"));
$module_permission = 0;
if ($module_permission_row) {
$module_permission = $module_permission_row['user_role_permission_level'];
}
?>
<div class="form-group">
<label> <?php echo $module_name_display ?> <strong class="text-danger">*</strong></label>
<div class="input-group">
<select class="form-control select2" name="<?php echo "$module_id##$module_name" ?>" required>
<option value="0" <?php if ($module_permission == 0) { echo 'selected'; } ?> >None</option>
<option value="1" <?php if ($module_permission == 1) { echo 'selected'; } ?> >Read</option>
<option value="2" <?php if ($module_permission == 2) { echo 'selected'; } ?>>Modify (Read, Edit, Archive)</option>
<option value="3" <?php if ($module_permission == 3) { echo 'selected'; } ?>>Full (Read, Edit, Archive, Delete)</option>
</select>
</div>
<small class="form-text text-muted"><?php echo $module_description ?></small>
</div>
<?php } // End while ?>
</div>
</div>
</div>
<div class="modal-footer bg-white">
<button type="submit" name="edit_role" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once "../includes/ajax_footer.php";

View File

@ -0,0 +1,156 @@
<div class="modal" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus mr-2"></i>New User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post/user.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body bg-white">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-user-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-user-access">Restrict Access</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-user-details">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Full Name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Password <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="password" id="password" placeholder="Enter a Password" autocomplete="new-password" minlength="8" required>
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<div class="input-group-append">
<span class="btn btn-default"><i class="fa fa-fw fa-question" onclick="generatePassword()"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<?php
$sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_archived_at IS NULL");
while ($row = mysqli_fetch_array($sql_user_roles)) {
$role_id = intval($row['role_id']);
$role_name = nullable_htmlentities($row['role_name']);
?>
<option value="<?php echo $role_id; ?>"><?php echo $role_name; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*" name="file">
</div>
<div class="form-group" <?php if(empty($config_smtp_host)) { echo "hidden"; } ?>>
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="sendEmailCheckBox" name="send_email" value="" checked>
<label for="sendEmailCheckBox" class="custom-control-label">
Send user e-mail with login details?
</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="forceMFACheckBox" name="force_mfa" value=1>
<label for="forceMFACheckBox" class="custom-control-label">
Force MFA
</label>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-user-access">
<div class="alert alert-info">
Check boxes to authorize user client access. No boxes grant full client access. Admin users are unaffected.
</div>
<ul class="list-group">
<li class="list-group-item bg-dark">
<div class="form-check">
<input type="checkbox" class="form-check-input" onclick="this.closest('.tab-pane').querySelectorAll('.client-checkbox').forEach(checkbox => checkbox.checked = this.checked);">
<label class="form-check-label ml-3"><strong>Restrict Access to Clients</strong></label>
</div>
</li>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input client-checkbox" name="clients[]" value="<?php echo $client_id; ?>">
<label class="form-check-label ml-3"><?php echo $client_name; ?></label>
</div>
</li>
<?php } ?>
</ul>
</div>
</div>
</div>
<div class="modal-footer bg-white">
<button type="submit" name="add_user" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,31 @@
<div class="modal" id="resetAllUserPassModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<div class="mb-4" style="text-align: center;">
<i class="far fas fa-10x fa-skull-crossbones text-danger mb-3 mt-3"></i>
<h2>Incident Response: Agent Password Reset</h2>
<br>
<div class="alert alert-danger" role="alert">
<b>This is a potentially destructive function.<br>It is intended to be used as part of a potential security incident.</b>
</div>
<h6 class="mb-4 text-secondary"><b>All ITFlow agent passwords will be reset and shown to you </b><i>(except yours - change yours first!)</i>.<br/><br/>You should communicate temporary passwords to agents out of band (e.g. via a phone call) and require they are changed ASAP.</h6>
<form action="post.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="row col-7 offset-4">
<div class="input-group">
<div class="input-group-prepend">
<input type="password" class="form-control" placeholder="Enter your account password to continue" name="admin_password" required>
</div>
</div>
</div>
<br>
<button class="btn btn-danger" type="submit" name="ir_reset_user_password"><i class="fas fa-fw fa-key mr-2"></i>Reset passwords</button>
</form>
</div>
<button type="button" class="btn btn-outline-secondary btn-lg px-5 mr-4" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
<div class="modal" id="archiveUserModal<?php echo $user_id; ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="mb-4" style="text-align: center;">
<i class="far fa-10x fa-times-circle text-danger mb-3 mt-3"></i>
<h2>Are you sure?</h2>
<h6 class="mb-4 text-secondary">Do you really want to <b>archive <?php echo $user_name; ?></b>? This process cannot be undone.</h6>
<h6 class="mb-4 text-secondary"><?php echo $user_name ?> will no longer be able to log in or use ITFlow, but all associated content will remain accessible.</h6>
<button type="button" class="btn btn-outline-secondary btn-lg px-5 mr-4" data-dismiss="modal">Cancel</button>
<a class="btn btn-danger btn-lg px-5" href="post.php?archive_user=<?php echo $user_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">Yes, archive!</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,204 @@
<?php
require_once '../../includes/modal_header.php';
$user_id = intval($_GET['id']);
$sql = mysqli_query($mysqli, "SELECT * FROM users
LEFT JOIN user_settings ON users.user_id = user_settings.user_id
WHERE users.user_id = $user_id LIMIT 1"
);
$row = mysqli_fetch_array($sql);
$user_name = nullable_htmlentities($row['user_name']);
$user_email = nullable_htmlentities($row['user_email']);
$user_avatar = nullable_htmlentities($row['user_avatar']);
$user_token = nullable_htmlentities($row['user_token']);
$user_config_force_mfa = intval($row['user_config_force_mfa']);
$user_role_id = intval($row['user_role_id']);
$user_initials = nullable_htmlentities(initials($user_name));
// Get User Client Access Permissions
$user_client_access_sql = mysqli_query($mysqli,"SELECT client_id FROM user_client_permissions WHERE user_id = $user_id");
$client_access_array = [];
while ($row = mysqli_fetch_assoc($user_client_access_sql)) {
$client_access_array[] = intval($row['client_id']);
}
// Generate the HTML form content using output buffering.
ob_start();
?>
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-user-edit mr-2"></i>Editing user:
<strong><?php echo $user_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="user_id" value="<?php echo $user_id; ?>">
<div class="modal-body bg-white">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-user-details<?php echo $user_id; ?>">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-user-access<?php echo $user_id; ?>">Restrict Access</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-user-details<?php echo $user_id; ?>">
<center class="mb-3">
<?php if (!empty($user_avatar)) { ?>
<img class="img-fluid" src="<?php echo "uploads/users/$user_id/$user_avatar"; ?>">
<?php } else { ?>
<span class="fa-stack fa-4x">
<i class="fa fa-circle fa-stack-2x text-secondary"></i>
<span class="fa fa-stack-1x text-white"><?php echo $user_initials; ?></span>
</span>
<?php } ?>
</center>
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Full Name" maxlength="200"
value="<?php echo $user_name; ?>" required>
</div>
</div>
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200"
value="<?php echo $user_email; ?>" required>
</div>
</div>
<div class="form-group">
<label>New Password</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="new_password"
placeholder="Leave Blank For No Password Change" autocomplete="new-password">
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<?php
$sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_archived_at IS NULL");
while ($row = mysqli_fetch_array($sql_user_roles)) {
$role_id = intval($row['role_id']);
$role_name = nullable_htmlentities($row['role_name']);
?>
<option <?php if ($role_id == $user_role_id) {echo "selected";} ?> value="<?php echo $role_id; ?>"><?php echo $role_name; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*" name="file">
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="forceMFACheckBox<?php echo $user_id; ?>" name="force_mfa" value="1" <?php if($user_config_force_mfa == 1){ echo "checked"; } ?>>
<label for="forceMFACheckBox<?php echo $user_id; ?>" class="custom-control-label">
Force MFA
</label>
</div>
</div>
<?php if (!empty($user_token)) { ?>
<div class="form-group">
<label>2FA</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-id-card"></i></span>
</div>
<select class="form-control" name="2fa">
<option value="">Keep enabled</option>
<option value="disable">Disable</option>
</select>
</div>
</div>
<?php } ?>
</div>
<div class="tab-pane fade" id="pills-user-access<?php echo $user_id; ?>">
<div class="alert alert-info">
Check boxes to authorize user client access. No boxes grant full client access. Admin users are unaffected.
</div>
<ul class="list-group">
<li class="list-group-item bg-dark">
<div class="form-check">
<input type="checkbox" class="form-check-input" onclick="this.closest('.tab-pane').querySelectorAll('.client-checkbox').forEach(checkbox => checkbox.checked = this.checked);">
<label class="form-check-label ml-3"><strong>Restrict Access to Clients</strong></label>
</div>
</li>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id_select = intval($row['client_id']);
$client_name_select = nullable_htmlentities($row['client_name']);
?>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input client-checkbox" name="clients[]" value="<?php echo $client_id_select; ?>" <?php if (in_array($client_id_select, $client_access_array)) { echo "checked"; } ?>>
<label class="form-check-label ml-2"><?php echo $client_name_select; ?></label>
</div>
</li>
<?php } ?>
</ul>
</div>
</div>
</div>
<div class="modal-footer bg-white">
<button type="submit" name="edit_user" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once "../../includes/modal_footer.php";

View File

@ -0,0 +1,21 @@
<div class="modal" id="exportUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-download mr-2"></i>Export Users to CSV</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body bg-white">
</div>
<div class="modal-footer bg-white">
<button type="submit" name="export_users_csv" class="btn btn-primary text-bold"><i class="fas fa-fw fa-download mr-2"></i>Download CSV</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,45 @@
<div class="modal" id="userInviteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus"></i>Invite User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body bg-white">
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<!-- //TODO: Pull from roles -->
</select>
</div>
</div>
</div>
<div class="modal-footer bg-white">
<button type="submit" name="invite_user" class="btn btn-primary text-bold"><i class="fas fa-paper-plane mr-2"></i>Send Invite</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>

89
admin/post/role.php Normal file
View File

@ -0,0 +1,89 @@
<?php
/*
* ITFlow - GET/POST request handler for roles
*/
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
if (isset($_POST['add_role'])) {
validateCSRFToken($_POST['csrf_token']);
$name = sanitizeInput($_POST['role_name']);
$description = sanitizeInput($_POST['role_description']);
$admin = intval($_POST['role_is_admin']);
mysqli_query($mysqli, "INSERT INTO user_roles SET role_name = '$name', role_description = '$description', role_is_admin = $admin");
$role_id = mysqli_insert_id($mysqli);
// Logging
logAction("User Role", "Create", "$session_name created user role $name", 0, $role_id);
$_SESSION['alert_message'] = "User Role <strong$name</strong> created";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_POST['edit_role'])) {
validateCSRFToken($_POST['csrf_token']);
// Update role metadata
$role_id = sanitizeInput($_POST['role_id']);
$name = sanitizeInput($_POST['role_name']);
$description = sanitizeInput($_POST['role_description']);
$admin = intval($_POST['role_is_admin']);
mysqli_query($mysqli, "UPDATE user_roles SET role_name = '$name', role_description = '$description', role_is_admin = $admin WHERE role_id = $role_id");
// Update role access levels
mysqli_query($mysqli, "DELETE FROM user_role_permissions WHERE user_role_id = $role_id");
foreach ($_POST as $key => $value) {
if (str_contains($key, '##module_')){
$module_id = intval(explode('##', $key)[0]);
$access_level = intval($value);
if ($access_level > 0) {
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = $role_id, module_id = $module_id, user_role_permission_level = $access_level");
}
}
}
// Logging
logAction("User Role", "Edit", "$session_name edited user role $name", 0, $role_id);
$_SESSION['alert_message'] = "User Role <strong>$name</strong> edited";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_GET['archive_role'])) {
validateCSRFToken($_GET['csrf_token']);
$role_id = intval($_GET['archive_role']);
// Check role isn't in use
$sql_role_user_count = mysqli_query($mysqli, "SELECT COUNT(user_id) FROM users WHERE user_role_id = $role_id AND user_archived_at IS NULL");
$role_user_count = mysqli_fetch_row($sql_role_user_count)[0];
if ($role_user_count != 0) {
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "Role must not in use to archive it";
header("Location: " . $_SERVER["HTTP_REFERER"]);
exit();
}
mysqli_query($mysqli, "UPDATE user_roles SET role_archived_at = NOW() WHERE role_id = $role_id");
// Logging
$role_details = mysqli_fetch_array(mysqli_query($mysqli, "SELECT role_name FROM user_roles WHERE role_id = $role_id LIMIT 1"));
$role_name = sanitizeInput($role_details['role_name']);
logAction("User Role", "Archive", "$session_name archived user role $role_name", 0, $role_id);
$_SESSION['alert_message'] = "User Role archived";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}

373
admin/post/user.php Normal file
View File

@ -0,0 +1,373 @@
<?php
/*
* ITFlow - GET/POST request handler for user (agent) management
*/
require_once "../../config.php";
require_once "../../functions.php";
require_once "../../includes/check_login.php";
if (isset($_POST['add_user'])) {
validateCSRFToken($_POST['csrf_token']);
require_once 'user_model.php';
$password = password_hash(trim($_POST['password']), PASSWORD_DEFAULT);
$user_specific_encryption_ciphertext = encryptUserSpecificKey(trim($_POST['password']));
mysqli_query($mysqli, "INSERT INTO users SET user_name = '$name', user_email = '$email', user_password = '$password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext', user_role_id = $role");
$user_id = mysqli_insert_id($mysqli);
// Add Client Access Permissions if set
if (isset($_POST['clients'])) {
foreach($_POST['clients'] as $client_id) {
$client_id = intval($client_id);
mysqli_query($mysqli,"INSERT INTO user_client_permissions SET user_id = $user_id, client_id = $client_id");
}
}
if (!file_exists("uploads/users/$user_id/")) {
mkdir("uploads/users/$user_id");
}
// Check for and process image/photo
$extended_alert_description = '';
if (isset($_FILES['file']['tmp_name'])) {
if ($new_file_name = checkFileUpload($_FILES['file'], array('jpg', 'jpeg', 'gif', 'png', 'webp'))) {
$file_tmp_path = $_FILES['file']['tmp_name'];
// directory in which the uploaded file will be moved
$upload_file_dir = "../uploads/users/$user_id/";
$dest_path = $upload_file_dir . $new_file_name;
move_uploaded_file($file_tmp_path, $dest_path);
// Set Avatar
mysqli_query($mysqli, "UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = $user_id");
$extended_alert_description = '. File successfully uploaded.';
}
}
// Create Settings
mysqli_query($mysqli, "INSERT INTO user_settings SET user_id = $user_id, user_config_force_mfa = $force_mfa");
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
$row = mysqli_fetch_array($sql);
$company_name = sanitizeInput($row['company_name']);
// Sanitize Config vars from get_settings.php
$config_mail_from_name = sanitizeInput($config_mail_from_name);
$config_mail_from_email = sanitizeInput($config_mail_from_email);
$config_ticket_from_email = sanitizeInput($config_ticket_from_email);
$config_login_key_secret = mysqli_real_escape_string($mysqli, $config_login_key_secret);
$config_base_url = sanitizeInput($config_base_url);
// Send user e-mail, if specified
if (isset($_POST['send_email']) && !empty($config_smtp_host) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
$password = mysqli_real_escape_string($mysqli, $_POST['password']);
$subject = "Your new $company_name ITFlow account";
$body = "Hello $name,<br><br>An ITFlow account has been setup for you. Please change your password upon login. <br><br>Username: $email <br>Password: $password<br>Login URL: https://$config_base_url/login.php?key=$config_login_key_secret<br><br>--<br>$company_name - Support<br>$config_ticket_from_email";
$data = [
[
'from' => $config_mail_from_email,
'from_name' => $config_mail_from_name,
'recipient' => $email,
'recipient_name' => $name,
'subject' => $subject,
'body' => $body
]
];
$mail = addToMailQueue($data);
if ($mail !== true) {
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Mail', notification = 'Failed to send email to $email'");
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Mail', log_action = 'Error', log_description = 'Failed to send email to $email regarding $subject. $mail', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id, log_entity_id = $user_id");
}
}
// Logging
logAction("User", "Create", "$session_name created user $name", 0, $user_id);
$_SESSION['alert_message'] = "User <strong>$name</strong> created" . $extended_alert_description;
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_POST['edit_user'])) {
validateCSRFToken($_POST['csrf_token']);
require_once 'post/admin/admin_user_model.php';
$user_id = intval($_POST['user_id']);
$new_password = trim($_POST['new_password']);
// Update Client Access
mysqli_query($mysqli,"DELETE FROM user_client_permissions WHERE user_id = $user_id");
if (isset($_POST['clients'])) {
foreach($_POST['clients'] as $client_id) {
$client_id = intval($client_id);
mysqli_query($mysqli,"INSERT INTO user_client_permissions SET user_id = $user_id, client_id = $client_id");
}
}
// Get current Avatar
$sql = mysqli_query($mysqli, "SELECT user_avatar FROM users WHERE user_id = $user_id");
$row = mysqli_fetch_array($sql);
$existing_file_name = sanitizeInput($row['user_avatar']);
$extended_log_description = '';
if (!empty($_POST['2fa'])) {
$two_fa = $_POST['2fa'];
}
if (!file_exists("uploads/users/$user_id/")) {
mkdir("uploads/users/$user_id");
}
// Check for and process image/photo
$extended_alert_description = '';
if (isset($_FILES['file']['tmp_name'])) {
if ($new_file_name = checkFileUpload($_FILES['file'], array('jpg', 'jpeg', 'gif', 'png', 'webp'))) {
$file_tmp_path = $_FILES['file']['tmp_name'];
// directory in which the uploaded file will be moved
$upload_file_dir = "uploads/users/$user_id/";
$dest_path = $upload_file_dir . $new_file_name;
move_uploaded_file($file_tmp_path, $dest_path);
// Delete old file
unlink("../uploads/users/$user_id/$existing_file_name");
// Set Avatar
mysqli_query($mysqli, "UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = $user_id");
$extended_alert_description = '. File successfully uploaded.';
}
}
mysqli_query($mysqli, "UPDATE users SET user_name = '$name', user_email = '$email', user_role_id = $role WHERE user_id = $user_id");
if (!empty($new_password)) {
$new_password = password_hash($new_password, PASSWORD_DEFAULT);
$user_specific_encryption_ciphertext = encryptUserSpecificKey(trim($_POST['new_password']));
mysqli_query($mysqli, "UPDATE users SET user_password = '$new_password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext' WHERE user_id = $user_id");
//Extended Logging
$extended_log_description .= ", password changed";
}
if (!empty($two_fa) && $two_fa == 'disable') {
mysqli_query($mysqli, "UPDATE users SET user_token = '' WHERE user_id = '$user_id'");
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'User', log_action = 'Modify', log_description = '$session_name disabled 2FA for $name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id");
}
//Update User Settings
mysqli_query($mysqli, "UPDATE user_settings SET user_config_force_mfa = $force_mfa WHERE user_id = $user_id");
// Logging
logAction("User", "Edit", "$session_name edited user $name", 0, $user_id);
$_SESSION['alert_message'] = "User <strong>$name</strong> updated" . $extended_alert_description;
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_GET['activate_user'])) {
validateCSRFToken($_GET['csrf_token']);
$user_id = intval($_GET['activate_user']);
// Get User Name
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $user_id");
$row = mysqli_fetch_array($sql);
$user_name = sanitizeInput($row['user_name']);
mysqli_query($mysqli, "UPDATE users SET user_status = 1 WHERE user_id = $user_id");
// Logging
logAction("User", "Activate", "$session_name activated user $user_name", 0, $user_id);
$_SESSION['alert_message'] = "User <strong>$user_name</strong> activated";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_GET['disable_user'])) {
validateCSRFToken($_GET['csrf_token']);
$user_id = intval($_GET['disable_user']);
// Get User Name
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $user_id");
$row = mysqli_fetch_array($sql);
$user_name = sanitizeInput($row['user_name']);
mysqli_query($mysqli, "UPDATE users SET user_status = 0 WHERE user_id = $user_id");
// Un-assign tickets
mysqli_query($mysqli, "UPDATE tickets SET ticket_assigned_to = 0 WHERE ticket_assigned_to = $user_id AND ticket_closed_at IS NULL");
mysqli_query($mysqli, "UPDATE recurring_tickets SET recurring_ticket_assigned_to = 0 WHERE recurring_ticket_assigned_to = $user_id");
// Logging
logAction("User", "Disable", "$session_name disabled user $name", 0, $user_id);
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "User <strong>$user_name</strong> disabled";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_GET['revoke_remember_me'])) {
validateCSRFToken($_GET['csrf_token']);
$user_id = intval($_GET['revoke_remember_me']);
// Get User Name
$row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $user_id"));
$user_name = sanitizeInput($row['user_name']);
mysqli_query($mysqli, "DELETE FROM remember_tokens WHERE remember_token_user_id = $user_id");
// Logging
logAction("User", "Edit", "$session_name revoked all remember me tokens for user $user_name", 0, $user_id);
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "User <strong>$user_name</strong> remember me tokens revoked";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_GET['archive_user'])) {
validateCSRFToken($_GET['csrf_token']);
// Variables from GET
$user_id = intval($_GET['archive_user']);
$password = password_hash(randomString(), PASSWORD_DEFAULT);
// Get user details
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $user_id");
$row = mysqli_fetch_array($sql);
$name = sanitizeInput($row['user_name']);
// Archive user query
mysqli_query($mysqli, "UPDATE users SET user_name = '$name (archived)', user_password = '$password', user_status = 0, user_specific_encryption_ciphertext = '', user_archived_at = NOW() WHERE user_id = $user_id");
// Logging
logAction("User", "Archive", "$session_name archived user $name", 0, $user_id);
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "User <strong>$name</strong> archived";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_POST['export_users_csv'])) {
//get records from database
$sql = mysqli_query($mysqli, "SELECT * FROM users LEFT JOIN user_roles ON user_role_id = role_id ORDER BY user_name ASC");
$count = mysqli_num_rows($sql);
if ($count > 0) {
$delimiter = ",";
$filename = "Users-" . date('Y-m-d') . ".csv";
//create a file pointer
$f = fopen('php://memory', 'w');
//set column headers
$fields = array('Name', 'Email', 'Role', 'Status', 'Creation Date');
fputcsv($f, $fields, $delimiter);
//output each row of the data, format line as csv and write to file pointer
while($row = $sql->fetch_assoc()) {
$user_status = intval($row['user_status']);
if ($user_status == 2) {
$user_status_display = "Invited";
} elseif ($user_status == 1) {
$user_status_display = "Active";
} else{
$user_status_display = "Disabled";
}
$lineData = array($row['user_name'], $row['user_email'], $row['role_name'], $user_status_display, $row['user_created_at']);
fputcsv($f, $lineData, $delimiter);
}
//move back to beginning of file
fseek($f, 0);
//set headers to download file rather than displayed
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="' . $filename . '";');
//output all remaining data on a file pointer
fpassthru($f);
// Logging
logAction("User", "Export", "$session_name exported $count user(s) to a CSV file");
}
exit;
}
if (isset($_POST['ir_reset_user_password'])) {
// Incident response: allow mass reset of agent passwords
validateCSRFToken($_POST['csrf_token']);
// Confirm logged-in user password, for security
$admin_password = $_POST['admin_password'];
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $session_user_id");
$userRow = mysqli_fetch_array($sql);
if (!password_verify($admin_password, $userRow['user_password'])) {
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "Incorrect password.";
header("Location: " . $_SERVER["HTTP_REFERER"]);
exit;
}
// Get agents/users, other than the current user
$sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE (user_archived_at IS NULL AND user_id != $session_user_id)");
// Reset passwords
while ($row = mysqli_fetch_array($sql_users)) {
$user_id = intval($row['user_id']);
$user_email = sanitizeInput($row['user_email']);
$new_password = randomString();
$user_specific_encryption_ciphertext = encryptUserSpecificKey(trim($new_password));
echo $user_email . " -- " . $new_password; // Show
$new_password = password_hash($new_password, PASSWORD_DEFAULT);
mysqli_query($mysqli, "UPDATE users SET user_password = '$new_password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext' WHERE user_id = $user_id");
echo "<br><br>";
}
// Logging
logAction("User", "Edit", "$session_name reset ALL user passwords");
exit; // Stay on the plain text password page
}

View File

@ -0,0 +1,6 @@
<?php
$name = sanitizeInput($_POST['name']);
$email = sanitizeInput($_POST['email']);
$role = intval($_POST['role']);
$force_mfa = intval($_POST['force_mfa'] ?? 0);

151
admin/roles.php Normal file
View File

@ -0,0 +1,151 @@
<?php
// Default Column Sortby Filter
$sort = "role_is_admin";
$order = "DESC";
require_once "includes/inc_all_admin.php";
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM user_roles
WHERE (role_name LIKE '%$q%' OR role_description LIKE '%$q%')
AND role_archived_at IS NULL
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="alert alert-info text-center"><strong>Roles are still in development. Permissions may not be fully enforced.</strong></div>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-user-shield mr-2"></i>Roles</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addRoleModal">
<i class="fas fa-fw fa-user-plus mr-2"></i>New Role
</button>
</div>
</div>
</div>
<div class="card-body">
<form class="mb-4" autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) {echo stripslashes(nullable_htmlentities($q));} ?>" placeholder="Search Roles">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=role_name&order=<?php echo $disp; ?>">
Role <?php if ($sort == 'role_name') { echo $order_icon; } ?>
</a>
</th>
<th>Members</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=role_is_admin&order=<?php echo $disp; ?>">
Admin <?php if ($sort == 'role_is_admin') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$role_id = intval($row['role_id']);
$role_name = nullable_htmlentities($row['role_name']);
$role_description = nullable_htmlentities($row['role_description']);
$role_admin = intval($row['role_is_admin']);
$role_archived_at = nullable_htmlentities($row['role_archived_at']);
// Count number of users that have each role
$sql_role_user_count = mysqli_query($mysqli, "SELECT COUNT(user_id) FROM users WHERE user_role_id = $role_id AND user_archived_at IS NULL");
$role_user_count = mysqli_fetch_row($sql_role_user_count)[0];
$sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE user_role_id = $role_id AND user_archived_at IS NULL");
// Initialize an empty array to hold user names
$user_names = [];
// Fetch each row and store the user_name in the array
while($row = mysqli_fetch_assoc($sql_users)) {
$user_names[] = nullable_htmlentities($row['user_name']);
}
// Convert the array of user names to a comma-separated string
$user_names_string = implode(",", $user_names);
if (empty($user_names_string)) {
$user_names_string = "-";
}
?>
<tr>
<td>
<a class="text-dark text-bold" href="#" data-toggle="modal" data-target="#editRoleModal<?php echo $role_id; ?>">
<?php echo $role_name; ?>
</a>
<div class="text-secondary"><?php echo $role_description; ?></div>
</td>
<td><?php echo $user_names_string; ?></td>
<td><?php echo $role_admin ? 'Yes' : 'No' ; ?></td>
<td>
<?php if ($role_id !== 3) { ?>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#"
data-toggle="ajax-modal"
data-ajax-url="ajax/ajax_role_edit.php"
data-ajax-id="<?php echo $role_id; ?>"
>
<i class="fas fa-fw fa-user-edit mr-2"></i>Edit
</a>
<?php if (empty($role_archived_at) && $role_user_count == 0) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_role=<?php echo $role_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
</div>
</div>
<?php } ?>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php require_once "includes/filter_footer.php";
?>
</div>
</div>
<?php
require_once "modals/admin_role_add_modal.php";
require_once "includes/footer.php";

239
admin/users.php Normal file
View File

@ -0,0 +1,239 @@
<?php
// Default Column Sortby Filter
$sort = "user_name";
$order = "ASC";
require_once "includes/inc_all_admin.php";
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM users
LEFT JOIN user_roles ON user_role_id = role_id
LEFT JOIN user_settings ON users.user_id = user_settings.user_id
WHERE (user_name LIKE '%$q%' OR user_email LIKE '%$q%')
AND user_type = 1
AND user_archived_at IS NULL
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-users mr-2"></i>Users</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addUserModal">
<i class="fas fa-fw fa-user-plus mr-2"></i>New User
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<!--<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#userInviteModal"><i class="fas fa-paper-plane mr-2"></i>Invite User</a>-->
<?php if ($num_rows[0] > 1) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportUserModal"><i class="fa fa-fw fa-download mr-2"></i>Export</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#" data-toggle="modal" data-target="#resetAllUserPassModal"><i class="fas fa-skull-crossbones mr-2"></i>IR</a>
<?php } ?>
</div>
</div>
</div>
</div>
<div class="card-body">
<form class="mb-4" autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) {echo stripslashes(nullable_htmlentities($q));} ?>" placeholder="Search Users">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-8">
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<th class="text-center">
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=user_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'user_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=user_email&order=<?php echo $disp; ?>">
Email <?php if ($sort == 'user_email') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=role_name&order=<?php echo $disp; ?>">
Role <?php if ($sort == 'role_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=user_status&order=<?php echo $disp; ?>">
Status <?php if ($sort == 'user_status') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">MFA</th>
<th>
Last Login
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$user_id = intval($row['user_id']);
$user_name = nullable_htmlentities($row['user_name']);
$user_email = nullable_htmlentities($row['user_email']);
$user_status = intval($row['user_status']);
if ($user_status == 2) {
$user_status_display = "<span class='text-info'>Invited</span>";
} elseif ($user_status == 1) {
$user_status_display = "<span class='text-success'>Active</span>";
} else{
$user_status_display = "<span class='text-danger'>Disabled</span>";
}
$user_avatar = nullable_htmlentities($row['user_avatar']);
$user_token = nullable_htmlentities($row['user_token']);
if(empty($user_token)) {
$mfa_status_display = "<i class='fas fa-fw fa-unlock text-danger'></i>";
} else {
$mfa_status_display = "<i class='fas fa-fw fa-lock text-success'></i>";
}
$user_config_force_mfa = intval($row['user_config_force_mfa']);
$user_role = intval($row['user_role_id']);
$user_role_display = nullable_htmlentities($row['role_name']);
$user_initials = nullable_htmlentities(initials($user_name));
$sql_last_login = mysqli_query(
$mysqli,
"SELECT * FROM logs
WHERE log_user_id = $user_id AND log_type = 'Login'
ORDER BY log_id DESC LIMIT 1"
);
if (mysqli_num_rows($sql_last_login) == 0) {
$last_login = "<span class='text-bold'>Never logged in</span>";
} else {
$row = mysqli_fetch_array($sql_last_login);
$log_created_at = nullable_htmlentities($row['log_created_at']);
$log_ip = nullable_htmlentities($row['log_ip']);
$log_user_agent = nullable_htmlentities($row['log_user_agent']);
$log_user_os = getOS($log_user_agent);
$log_user_browser = getWebBrowser($log_user_agent);
$last_login = "$log_created_at<small class='text-secondary'><div class='mt-1'>$log_user_os</div><div class='mt-1'>$log_user_browser</div><div class='mt-1'><i class='fa fa-fw fa-globe'></i> $log_ip</div></small>";
}
// Get User Client Access Permissions
$user_client_access_sql = mysqli_query($mysqli,"SELECT client_id FROM user_client_permissions WHERE user_id = $user_id");
$client_access_array = [];
while ($row = mysqli_fetch_assoc($user_client_access_sql)) {
$client_access_array[] = intval($row['client_id']);
}
$sql_remember_tokens = mysqli_query($mysqli, "SELECT * FROM remember_tokens WHERE remember_token_user_id = $user_id");
$remember_token_count = mysqli_num_rows($sql_remember_tokens);
?>
<tr>
<td class="text-center">
<a class="text-dark" href="#"
<?php if ($user_id !== $session_user_id) { // Prevent modifying self ?>
data-toggle="ajax-modal"
data-ajax-url="modals/users/user_edit.php"
data-ajax-id="<?php echo $user_id; ?>"
<?php } ?>
>
<?php if (!empty($user_avatar)) { ?>
<img class="img-size-50 img-circle" src="<?php echo "uploads/users/$user_id/$user_avatar"; ?>">
<?php } else { ?>
<span class="fa-stack fa-2x">
<i class="fa fa-circle fa-stack-2x text-secondary"></i>
<span class="fa fa-stack-1x text-white"><?php echo $user_initials; ?></span>
</span>
<br>
<?php } ?>
<div class="text-secondary"><?php echo $user_name; ?></div>
</a>
</td>
<td><a href="mailto:<?php echo $user_email; ?>"><?php echo $user_email; ?></a></td>
<td><?php echo $user_role_display; ?></td>
<td><?php echo $user_status_display; ?></td>
<td class="text-center"><?php echo $mfa_status_display; ?></td>
<td><?php echo $last_login; ?></td>
<td>
<?php if ($user_id !== $session_user_id) { // Prevent modifying self ?>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#"
data-toggle="ajax-modal"
data-ajax-url="modals/users/user_edit.php"
data-ajax-id="<?php echo $user_id; ?>"
>
<i class="fas fa-fw fa-user-edit mr-2"></i>Edit
</a>
<?php if ($remember_token_count > 0) { ?>
<a class="dropdown-item" href="post.php?revoke_remember_me=<?php echo $user_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>"><i class="fas fa-fw fa-ban mr-2"></i>Revoke <?php echo $remember_token_count; ?> Remember Tokens
</a>
<?php } ?>
<?php if ($user_status == 0) { ?>
<a class="dropdown-item text-success" href="post.php?activate_user=<?php echo $user_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-user-check mr-2"></i>Activate
</a>
<?php }elseif ($user_status == 1) { ?>
<a class="dropdown-item text-danger" href="post.php?disable_user=<?php echo $user_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-user-slash mr-2"></i>Disable
</a>
<?php } ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#" data-toggle="modal" data-target="#archiveUserModal<?php echo $user_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
</div>
</div>
<?php } ?>
</td>
</tr>
<?php
require "modals/users/user_archive.php";
}
?>
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
</div>
</div>
<script>
function generatePassword() {
document.getElementById("password").value = "<?php echo randomString() ?>"
}
</script>
<?php
require_once "modals/users/user_add.php";
require_once "modals/users/user_invite.php";
require_once "modals/users/user_export.php";
require_once "modals/users/user_all_reset_password.php";
require_once "includes/footer.php";

View File

@ -563,7 +563,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<span class="text-secondary">Paid</span> <?php echo numfmt_format_currency($currency_format, $amount_paid, $session_company_currency); ?>
</div>
<div>
<span class="text-secondary mr-2">Credit</span><span class="text-success"><?php echo numfmt_format_currency($currency_format, $credit_total, $session_company_currency); ?></span>
<span class="text-secondary mr-2">Credit</span><span class="text-success"><?php echo numfmt_format_currency($currency_format, $credit_balance, $session_company_currency); ?></span>
</div>
<div>
<span class="text-secondary">Monthly</span> <?php echo numfmt_format_currency($currency_format, $recurring_monthly, $session_company_currency); ?>
@ -584,7 +584,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="dropdown-menu">
<a class="dropdown-item" href="#"
data-toggle="ajax-modal"
data-ajax-url="ajax/ajax_client_edit.php"
data-ajax-url="modals/clients/client_edit.php"
data-ajax-id="<?php echo $client_id; ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
@ -613,11 +613,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</table>
</div>
<?php
require_once "modals/client_bulk_edit_industry_modal.php";
require_once "modals/client_bulk_edit_referral_modal.php";
require_once "modals/client_bulk_edit_hourly_rate_modal.php";
require_once "modals/client_bulk_assign_tags_modal.php";
require_once "modals/client_bulk_email_modal.php";
require_once "modals/clients/client_bulk_edit_industry.php";
require_once "modals/clients/client_bulk_edit_referral.php";
require_once "modals/clients/client_bulk_edit_hourly_rate.php";
require_once "modals/clients/client_bulk_assign_tags.php";
require_once "modals/clients/client_bulk_email.php";
?>
</form>
<!-- Ends Card Body -->
@ -628,7 +628,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<script src="js/bulk_actions.js"></script>
<?php
require_once "modals/client_add_modal.php";
require_once "modals/client_import_modal.php";
require_once "modals/client_export_modal.php";
require_once "modals/clients/client_add.php";
require_once "modals/clients/client_import.php";
require_once "modals/clients/client_export.php";
require_once "includes/footer.php";

View File

@ -1,8 +1,8 @@
<?php
require_once "../config.php";
require_once "../functions.php";
require_once "check_login.php";
require_once "../../config.php";
require_once "../../functions.php";
require_once "../../includes/check_login.php";
header('Content-Type: application/json');

View File

@ -0,0 +1,9 @@
<script src="js/app.js"></script>
<script src="plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
<?php
$content = ob_get_clean();
// Return the title and content as a JSON response
echo json_encode(['content' => $content]);
?>

13
includes/modal_header.php Normal file
View File

@ -0,0 +1,13 @@
<?php
require_once "../../config.php";
require_once "../../functions.php";
require_once "../../includes/check_login.php";
header('Content-Type: application/json');
// Check for the 'id' parameter
//if (!isset($_GET['id'])) {
// echo json_encode(['error' => 'ID missing.']);
// exit;
//}

View File

@ -1,6 +1,6 @@
<?php
require_once '../includes/ajax_header.php';
require_once '../../includes/modal_header.php';
$client_id = intval($_GET['id']);
@ -42,24 +42,22 @@ ob_start();
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<ul class="modal-header nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-client-details<?php echo $client_id; ?>">Details</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-client-billing<?php echo $client_id; ?>">Billing</a>
</li>
<?php } ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-client-notes<?php echo $client_id; ?>">Notes</a>
</li>
</ul>
<div class="modal-body">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-client-details<?php echo $client_id; ?>">Details</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-client-billing<?php echo $client_id; ?>">Billing</a>
</li>
<?php } ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-client-notes<?php echo $client_id; ?>">Notes</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-client-details<?php echo $client_id; ?>">
@ -129,7 +127,7 @@ ob_start();
<button class="btn btn-secondary" type="button"
data-toggle="ajax-modal"
data-modal-size="sm"
data-ajax-url="ajax/ajax_category_add.php?category=Referral">
data-ajax-url="../../ajax/ajax_category_add.php?category=Referral">
<i class="fas fa-fw fa-plus"></i>
</button>
</div>
@ -169,7 +167,7 @@ ob_start();
<button class="btn btn-secondary" type="button"
data-toggle="ajax-modal"
data-modal-size="sm"
data-ajax-url="ajax/ajax_tag_add.php"
data-ajax-url="../../ajax/ajax_tag_add.php"
data-ajax-id="1">
<i class="fas fa-fw fa-plus"></i>
</button>
@ -265,4 +263,4 @@ ob_start();
</form>
<?php
require_once "../includes/ajax_footer.php";
require_once '../../includes/modal_footer.php';

View File

@ -5,9 +5,7 @@
*/
require_once "config.php";
require_once "functions.php";
require_once "includes/check_login.php";
// Define a variable that we can use to only allow running post files via inclusion (prevents people/bots poking them)

View File

@ -1,3 +1,2 @@
User-agent: *
Disallow: /
Disallow: /