DSP Project first push, date: 29/01/2026
This commit is contained in:
782
admin/manage_users.php
Normal file
782
admin/manage_users.php
Normal file
@@ -0,0 +1,782 @@
|
||||
<?php
|
||||
// Start session and include necessary files
|
||||
session_start();
|
||||
require_once '../config.php';
|
||||
require_once '../includes/auth.php';
|
||||
require_once '../classes/User.php';
|
||||
|
||||
// Redirect if not logged in or not a DAC Staff
|
||||
redirect_if_not_logged_in('../index.php');
|
||||
redirect_if_not_role('DAC Staff', '../index.php');
|
||||
|
||||
// Initialize User class
|
||||
$userManager = new User($pdo);
|
||||
|
||||
// --- Handle Search and Filter Parameters ---
|
||||
$search_query = trim($_GET['search'] ?? '');
|
||||
$filter_status = trim($_GET['status_filter'] ?? ''); // New filter for user status
|
||||
$filters_active = ($search_query !== '' || $filter_status !== '');
|
||||
|
||||
// Handle form submissions
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action_type = $_POST['action_type'] ?? '';
|
||||
$user_id = $_POST['user_id'] ?? null;
|
||||
|
||||
if ($action_type === 'update_status' && $user_id) {
|
||||
$new_status = $_POST['new_status'] ?? '';
|
||||
$requested_r_access = $_POST['can_run_r'] ?? null;
|
||||
$has_valid_r_flag = in_array($requested_r_access, ['0', '1'], true);
|
||||
|
||||
// Prevent a DAC Staff from deactivating themselves
|
||||
if ($user_id == $_SESSION['user_id'] && $new_status == 'Inactive') {
|
||||
set_message('You cannot deactivate your own account.', 'danger');
|
||||
header('Location: manage_users.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!in_array($new_status, ['DAC Staff', 'Data Contributor', 'Data Owner', 'Data User', 'Inactive'])) {
|
||||
set_message('Invalid user status selected.', 'danger');
|
||||
} else {
|
||||
try {
|
||||
$admin_user_id = (int) $_SESSION['user_id'];
|
||||
$userManager->updateUserStatus($user_id, $new_status, $admin_user_id);
|
||||
|
||||
if ($has_valid_r_flag) {
|
||||
$userManager->updateUserRJupyterAccess($user_id, $requested_r_access === '1', $admin_user_id);
|
||||
|
||||
if ((int)$user_id === (int)$_SESSION['user_id']) {
|
||||
$_SESSION['can_run_r'] = ($requested_r_access === '1');
|
||||
}
|
||||
}
|
||||
|
||||
$message = 'User status updated successfully!';
|
||||
if ($has_valid_r_flag) {
|
||||
$message = 'User status and R/Jupyter access updated successfully!';
|
||||
}
|
||||
set_message($message, 'success');
|
||||
} catch (Exception $e) {
|
||||
set_message('Error updating user status: ' . $e->getMessage(), 'danger');
|
||||
}
|
||||
}
|
||||
} elseif ($action_type === 'reset_password' && $user_id) {
|
||||
$new_password = $_POST['new_password'] ?? '';
|
||||
$confirm_password = $_POST['confirm_password'] ?? '';
|
||||
|
||||
if (empty($new_password) || empty($confirm_password)) {
|
||||
set_message('Please provide and confirm the new password.', 'danger');
|
||||
} elseif ($new_password !== $confirm_password) {
|
||||
set_message('Passwords do not match. Please try again.', 'danger');
|
||||
} elseif (strlen($new_password) < 8) {
|
||||
set_message('Password must be at least 8 characters long.', 'danger');
|
||||
} else {
|
||||
try {
|
||||
$admin_user_id = (int) $_SESSION['user_id'];
|
||||
$userManager->changePassword((int)$user_id, $new_password, $admin_user_id);
|
||||
set_message('Password reset successfully.', 'success');
|
||||
} catch (Exception $e) {
|
||||
set_message('Error resetting password: ' . $e->getMessage(), 'danger');
|
||||
}
|
||||
}
|
||||
} elseif ($action_type === 'add_user') {
|
||||
// --- Handle Add New User Submission ---
|
||||
$id_card = trim($_POST['id_card'] ?? '');
|
||||
$first_name_en = trim($_POST['first_name_en'] ?? '');
|
||||
$last_name_en = trim($_POST['last_name_en'] ?? '');
|
||||
$sex = trim($_POST['sex'] ?? '');
|
||||
$dob = trim($_POST['dob'] ?? '');
|
||||
$phone_number = trim($_POST['phone_number'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$confirm_password = $_POST['confirm_password'] ?? '';
|
||||
$user_role_new = trim($_POST['user_role_new'] ?? 'Data User'); // Role for new user
|
||||
|
||||
// Server-side validation for new user
|
||||
if (empty($first_name_en) || empty($last_name_en) || empty($sex) || empty($dob) || empty($username) || empty($password) || empty($confirm_password)) {
|
||||
set_message("All required fields for new user must be filled.", "danger");
|
||||
} elseif ($password !== $confirm_password) {
|
||||
set_message("Passwords do not match for new user.", "danger");
|
||||
} elseif (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
set_message("Invalid email format for new user.", "danger");
|
||||
} else {
|
||||
// Prepare data for User class
|
||||
$person_data = [
|
||||
'id_card' => $id_card,
|
||||
'first_name_en' => $first_name_en,
|
||||
'last_name_en' => $last_name_en,
|
||||
'sex' => $sex,
|
||||
'dob' => $dob,
|
||||
'pob' => null, // Add if you collect this
|
||||
'nationality' => 'Cambodian', // Default or collect
|
||||
'marital_status' => 'Single', // Default or collect
|
||||
'phone_number' => $phone_number,
|
||||
'email' => $email,
|
||||
'telegram' => null, // Add if you collect this
|
||||
'note' => null // Add if you collect this
|
||||
];
|
||||
|
||||
$user_data = [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'status' => 'Data User', // Default status for new registrations
|
||||
'can_run_r' => !empty($_POST['user_can_run_r'])
|
||||
];
|
||||
|
||||
try {
|
||||
if ($userManager->registerUser($person_data, $user_data)) {
|
||||
set_message("New user '" . htmlspecialchars($username) . "' registered successfully!", "success");
|
||||
} else {
|
||||
// This else might be redundant if registerUser always throws on failure
|
||||
set_message("Failed to register new user due to an unknown error.", "danger");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
set_message('Error registering new user: ' . $e->getMessage(), 'danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to self, preserving search/filter parameters if they exist
|
||||
$redirect_url = 'manage_users.php';
|
||||
$query_params = [];
|
||||
if (!empty($search_query)) {
|
||||
$query_params['search'] = urlencode($search_query);
|
||||
}
|
||||
if (!empty($filter_status)) {
|
||||
$query_params['status_filter'] = urlencode($filter_status);
|
||||
}
|
||||
if (!empty($query_params)) {
|
||||
$redirect_url .= '?' . http_build_query($query_params);
|
||||
}
|
||||
header('Location: ' . $redirect_url);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch users based on search and filter parameters
|
||||
// We will modify getAllUsers in classes/User.php to accept these parameters
|
||||
$users = $userManager->getAllUsers($search_query, $filter_status);
|
||||
|
||||
$totalUsers = count($users);
|
||||
$activeUsers = 0;
|
||||
$inactiveUsers = 0;
|
||||
$dacStaffCount = 0;
|
||||
$ownerCount = 0;
|
||||
$contributorCount = 0;
|
||||
$rAccessCount = 0;
|
||||
|
||||
foreach ($users as $user) {
|
||||
$status = $user['isu_status'] ?? '';
|
||||
$isActive = $status !== 'Inactive';
|
||||
if ($isActive) {
|
||||
$activeUsers++;
|
||||
} else {
|
||||
$inactiveUsers++;
|
||||
}
|
||||
|
||||
if ($status === 'DAC Staff') {
|
||||
$dacStaffCount++;
|
||||
} elseif ($status === 'Data Owner') {
|
||||
$ownerCount++;
|
||||
} elseif ($status === 'Data Contributor') {
|
||||
$contributorCount++;
|
||||
}
|
||||
|
||||
if (!empty($user['isu_can_run_r'])) {
|
||||
$rAccessCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$summaryMetrics = [
|
||||
[
|
||||
'label' => 'Total Users',
|
||||
'value' => $totalUsers,
|
||||
'icon' => 'fa-users',
|
||||
'class' => 'bg-primary-subtle text-primary',
|
||||
'icon_class' => 'text-primary'
|
||||
],
|
||||
[
|
||||
'label' => 'Active Accounts',
|
||||
'value' => $activeUsers,
|
||||
'icon' => 'fa-user-check',
|
||||
'class' => 'bg-success-subtle text-success',
|
||||
'icon_class' => 'text-success'
|
||||
],
|
||||
[
|
||||
'label' => 'With R/Jupyter',
|
||||
'value' => $rAccessCount,
|
||||
'icon' => 'fa-flask',
|
||||
'class' => 'bg-info-subtle text-info',
|
||||
'icon_class' => 'text-info'
|
||||
],
|
||||
[
|
||||
'label' => 'Inactive',
|
||||
'value' => $inactiveUsers,
|
||||
'icon' => 'fa-user-slash',
|
||||
'class' => 'bg-warning-subtle text-warning',
|
||||
'icon_class' => 'text-warning'
|
||||
],
|
||||
];
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!-- Header -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/header_admin.php");
|
||||
?>
|
||||
<style>
|
||||
.summary-cards .card {
|
||||
border: none;
|
||||
border-left: 4px solid rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
.summary-cards .card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 0.75rem 1.5rem rgba(15, 68, 130, 0.15);
|
||||
}
|
||||
.summary-icon {
|
||||
font-size: 1.75rem;
|
||||
width: 3.25rem;
|
||||
height: 3.25rem;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 0.85rem;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.summary-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-badges .badge {
|
||||
font-weight: 600;
|
||||
padding: 0.45rem 0.65rem;
|
||||
}
|
||||
.table thead th {
|
||||
background-color: #f1f5f9;
|
||||
border-bottom: none;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.table-hover tbody tr:hover {
|
||||
background-color: rgba(20, 86, 185, 0.05);
|
||||
}
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.table-responsive {
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.table-responsive::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
.table-responsive::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
.btn-action-group .btn {
|
||||
min-width: 9rem;
|
||||
}
|
||||
@media (max-width: 767.98px) {
|
||||
.summary-value {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
.btn-action-group .btn {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<?php
|
||||
// Include header file for admin pages
|
||||
include_once("../includes/nav_admin.php");
|
||||
?>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="main-content">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Manage Users</a>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="navbar-text d-none d-md-inline">
|
||||
Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!
|
||||
</span>
|
||||
<button class="btn btn-outline-primary btn-sm d-md-none" type="button" data-bs-toggle="collapse" data-bs-target="#manageUsersToolbar" aria-expanded="false" aria-controls="manageUsersToolbar">
|
||||
<i class="fas fa-sliders-h"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// Display session messages
|
||||
if (isset($_SESSION['message'])) {
|
||||
echo '<div class="alert alert-' . $_SESSION['message_type'] . ' alert-dismissible fade show rounded" role="alert">' . htmlspecialchars($_SESSION['message']) . '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>';
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="summary-cards row g-3 mb-3">
|
||||
<?php foreach ($summaryMetrics as $metric): ?>
|
||||
<div class="col-12 col-md-6 col-xl-3">
|
||||
<div class="card shadow-sm rounded-4 <?php echo $metric['class']; ?>">
|
||||
<div class="card-body d-flex align-items-center gap-3">
|
||||
<div class="summary-icon <?php echo htmlspecialchars($metric['icon_class']); ?>">
|
||||
<i class="fas <?php echo htmlspecialchars($metric['icon']); ?>"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="summary-value"><?php echo number_format($metric['value']); ?></div>
|
||||
<div class="summary-label text-secondary-emphasis">
|
||||
<?php echo htmlspecialchars($metric['label']); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="status-badges d-flex flex-wrap gap-2 mb-4">
|
||||
<span class="badge bg-primary-subtle text-primary">DAC Staff: <?php echo number_format($dacStaffCount); ?></span>
|
||||
<span class="badge bg-info-subtle text-info">Data Owners: <?php echo number_format($ownerCount); ?></span>
|
||||
<span class="badge bg-primary-subtle text-primary">Contributors: <?php echo number_format($contributorCount); ?></span>
|
||||
<span class="badge bg-success-subtle text-success">With R/Jupyter: <?php echo number_format($rAccessCount); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">All Registered Users</h5>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-outline-light d-none d-md-inline-flex rounded" data-bs-toggle="collapse" data-bs-target="#manageUsersToolbar" aria-expanded="<?php echo $filters_active ? 'true' : 'false'; ?>" aria-controls="manageUsersToolbar">
|
||||
<i class="fas fa-filter me-2"></i>Filters
|
||||
</button>
|
||||
<button type="button" class="btn btn-success rounded" data-bs-toggle="modal" data-bs-target="#addUserModal">
|
||||
<i class="fas fa-user-plus me-2"></i> Add New User
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Search and Filter Form -->
|
||||
<div class="collapse<?php echo $filters_active ? ' show' : ''; ?>" id="manageUsersToolbar">
|
||||
<form action="manage_users.php" method="GET" class="mb-4">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-12 col-md-5">
|
||||
<label for="searchUserInput" class="form-label visually-hidden">Search Users</label>
|
||||
<div class="input-group shadow-sm rounded-pill overflow-hidden">
|
||||
<span class="input-group-text bg-white border-0 text-muted">
|
||||
<i class="fas fa-magnifying-glass"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-0" id="searchUserInput" name="search" placeholder="Search by username, name, email..." value="<?= htmlspecialchars($search_query) ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<label for="statusFilter" class="form-label visually-hidden">Filter by Role</label>
|
||||
<div class="input-group shadow-sm rounded-pill overflow-hidden">
|
||||
<span class="input-group-text bg-white border-0 text-muted">
|
||||
<i class="fas fa-layer-group"></i>
|
||||
</span>
|
||||
<select class="form-select border-0" id="statusFilter" name="status_filter">
|
||||
<option value="">All Roles</option>
|
||||
<option value="DAC Staff" <?= ($filter_status == 'DAC Staff' ? 'selected' : '') ?>>DAC Staff</option>
|
||||
<option value="Data Contributor" <?= ($filter_status == 'Data Contributor' ? 'selected' : '') ?>>Data Contributor</option>
|
||||
<option value="Data Owner" <?= ($filter_status == 'Data Owner' ? 'selected' : '') ?>>Data Owner</option>
|
||||
<option value="Data User" <?= ($filter_status == 'Data User' ? 'selected' : '') ?>>Data User</option>
|
||||
<option value="Inactive" <?= ($filter_status == 'Inactive' ? 'selected' : '') ?>>Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="d-flex gap-2 justify-content-md-end">
|
||||
<button type="submit" class="btn btn-info rounded-pill flex-fill flex-md-grow-0 px-md-4">
|
||||
<i class="fas fa-filter me-2"></i>Apply
|
||||
</button>
|
||||
<a href="manage_users.php" class="btn btn-outline-secondary rounded-pill flex-fill flex-md-grow-0 px-md-4">
|
||||
<i class="fas fa-sync-alt me-2"></i>Reset
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No.</th>
|
||||
<th>Username</th>
|
||||
<th>Full Name</th>
|
||||
<th>Email</th>
|
||||
<th>Phone</th>
|
||||
<th>Current Role</th>
|
||||
<th>R/Jupyter</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($users)): ?>
|
||||
<?php $rowNumber = 1; ?>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<td><?php echo $rowNumber++; ?></td>
|
||||
<td><?php echo htmlspecialchars($user['isu_name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['isp_firstname_en'] . ' ' . $user['isp_lastname_en']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['isp_email'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['isp_phone_number'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$roleClass = 'bg-secondary-subtle text-secondary';
|
||||
if ($user['isu_status'] == 'DAC Staff') {
|
||||
$roleClass = 'bg-danger-subtle text-danger';
|
||||
} elseif ($user['isu_status'] == 'Data Owner') {
|
||||
$roleClass = 'bg-info-subtle text-info';
|
||||
} elseif ($user['isu_status'] == 'Data User') {
|
||||
$roleClass = 'bg-success-subtle text-success';
|
||||
} elseif ($user['isu_status'] == 'Data Contributor') {
|
||||
$roleClass = 'bg-primary-subtle text-primary';
|
||||
}
|
||||
?>
|
||||
<span class="badge rounded-pill <?php echo $roleClass; ?>">
|
||||
<?php echo htmlspecialchars($user['isu_status']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!empty($user['isu_can_run_r'])): ?>
|
||||
<span class="badge rounded-pill bg-success-subtle text-success">Enabled</span>
|
||||
<?php else: ?>
|
||||
<span class="badge rounded-pill bg-secondary-subtle text-secondary">Disabled</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-wrap gap-2 btn-action-group">
|
||||
<button type="button"
|
||||
class="btn btn-outline-primary rounded-pill"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#editUserModal"
|
||||
data-bs-tooltip="true"
|
||||
title="Change role or adjust R/Jupyter access"
|
||||
data-user-id="<?php echo htmlspecialchars($user['pkisu_id']); ?>"
|
||||
data-username="<?php echo htmlspecialchars($user['isu_name']); ?>"
|
||||
data-current-status="<?php echo htmlspecialchars($user['isu_status']); ?>"
|
||||
data-can-run-r="<?php echo !empty($user['isu_can_run_r']) ? '1' : '0'; ?>">
|
||||
<i class="fas fa-user-gear"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-outline-danger rounded-pill"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#resetPasswordModal"
|
||||
data-bs-tooltip="true"
|
||||
title="Set a new password for this account"
|
||||
data-user-id="<?php echo htmlspecialchars($user['pkisu_id']); ?>"
|
||||
data-username="<?php echo htmlspecialchars($user['isu_name']); ?>">
|
||||
<i class="fas fa-key"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-4 text-muted">No users match the current filters.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit User Role Modal -->
|
||||
<div class="modal fade" id="editUserModal" tabindex="-1" aria-labelledby="editUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded shadow-lg">
|
||||
<div class="modal-header text-white rounded-top" style="background-color: #28a745;">
|
||||
<h5 class="modal-title" id="editUserModalLabel">Change User Role</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form action="manage_users.php" method="POST">
|
||||
<input type="hidden" name="action_type" value="update_status">
|
||||
<input type="hidden" name="user_id" id="modalUserId">
|
||||
<div class="mb-3">
|
||||
<label for="modalUsername" class="form-label">Username</label>
|
||||
<input type="text" class="form-control rounded" id="modalUsername" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="modalCurrentStatus" class="form-label">Current Role</label>
|
||||
<input type="text" class="form-control rounded" id="modalCurrentStatus" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newStatus" class="form-label">New Role</label>
|
||||
<select class="form-select rounded" id="newStatus" name="new_status" required>
|
||||
<option value="Data User">Data User</option>
|
||||
<option value="Data Contributor">Data Contributor</option>
|
||||
<option value="Data Owner">Data Owner</option>
|
||||
<option value="DAC Staff">DAC Staff</option>
|
||||
<option value="Inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="modalRAccess" class="form-label">R/Jupyter Access</label>
|
||||
<select class="form-select rounded" id="modalRAccess" name="can_run_r" required>
|
||||
<option value="1">Enabled</option>
|
||||
<option value="0">Disabled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary rounded">Update Role</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Password Modal -->
|
||||
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded shadow-lg">
|
||||
<div class="modal-header text-white rounded-top" style="background-color: #28a745;">
|
||||
<h5 class="modal-title" id="resetPasswordModalLabel">Reset User Password</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form action="manage_users.php" method="POST" id="resetPasswordForm" autocomplete="off">
|
||||
<input type="hidden" name="action_type" value="reset_password">
|
||||
<input type="hidden" name="user_id" id="resetUserId">
|
||||
<div class="mb-3">
|
||||
<label for="resetUsername" class="form-label">Username</label>
|
||||
<input type="text" class="form-control rounded" id="resetUsername" readonly>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newPassword" class="form-label">New Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control rounded" id="newPassword" name="new_password" required minlength="8">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirmNewPassword" class="form-label">Confirm New Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control rounded" id="confirmNewPassword" name="confirm_password" required minlength="8">
|
||||
</div>
|
||||
<div class="alert alert-warning rounded d-flex align-items-start gap-2">
|
||||
<i class="fas fa-exclamation-triangle mt-1"></i>
|
||||
<span>Resetting the password will immediately replace the user's existing credentials. Provide the new password to the user securely.</span>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary rounded"><i class="fas fa-key me-2"></i>Reset Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add New User Modal -->
|
||||
<div class="modal fade" id="addUserModal" tabindex="-1" aria-labelledby="addUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content rounded shadow-lg">
|
||||
<div class="modal-header text-white rounded-top" style="background-color: #28a745;">
|
||||
<h5 class="modal-title" id="addUserModalLabel">Add New User</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form action="manage_users.php" method="POST" id="addUserForm">
|
||||
<input type="hidden" name="action_type" value="add_user">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3 text-primary">Personal Information</h6>
|
||||
<div class="mb-3">
|
||||
<label for="addFirstName" class="form-label">First Name (EN) <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control rounded" id="addFirstName" name="first_name_en" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addLastName" class="form-label">Last Name (EN) <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control rounded" id="addLastName" name="last_name_en" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addSex" class="form-label">Sex <span class="text-danger">*</span></label>
|
||||
<select class="form-select rounded" id="addSex" name="sex" required>
|
||||
<option value="">Select...</option>
|
||||
<option value="Male">Male</option>
|
||||
<option value="Female">Female</option>
|
||||
<option value="Other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addDob" class="form-label">Date of Birth <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control rounded" id="addDob" name="dob" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addPob" class="form-label">Place of Birth</label>
|
||||
<input type="text" class="form-control rounded" id="addPob" name="pob">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addNationality" class="form-label">Nationality</label>
|
||||
<input type="text" class="form-control rounded" id="addNationality" name="nationality" value="Cambodian">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="mb-3 text-primary">Contact Information</h6>
|
||||
<div class="mb-3">
|
||||
<label for="addPhoneNumber" class="form-label">Phone Number</label>
|
||||
<input type="tel" class="form-control rounded" id="addPhoneNumber" name="phone_number">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addEmail" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control rounded" id="addEmail" name="email">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addTelegram" class="form-label">Telegram</label>
|
||||
<input type="text" class="form-control rounded" id="addTelegram" name="telegram">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addNote" class="form-label">Note</label>
|
||||
<textarea class="form-control rounded" id="addNote" name="note" rows="2"></textarea>
|
||||
</div>
|
||||
<h6 class="mb-3 text-primary">Account Information</h6>
|
||||
<div class="mb-3">
|
||||
<label for="addUsername" class="form-label">Username <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control rounded" id="addUsername" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addPassword" class="form-label">Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control rounded" id="addPassword" name="password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addConfirmPassword" class="form-label">Confirm Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control rounded" id="addConfirmPassword" name="confirm_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="addUserRoleNew" class="form-label">Assign Role</label>
|
||||
<select class="form-select rounded" id="addUserRoleNew" name="user_role_new" required>
|
||||
<option value="Data User">Data User</option>
|
||||
<option value="Data Contributor">Data Contributor</option>
|
||||
<option value="Data Owner">Data Owner</option>
|
||||
<option value="DAC Staff">DAC Staff</option>
|
||||
<option value="Inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="addUserRAccess" name="user_can_run_r" value="1">
|
||||
<label class="form-check-label" for="addUserRAccess">Allow R/Jupyter Access</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-grid mt-4">
|
||||
<button type="submit" class="btn btn-primary rounded">Add User</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-tooltip="true"]'));
|
||||
tooltipTriggerList.forEach(function (tooltipTriggerEl) {
|
||||
if (window.bootstrap && bootstrap.Tooltip) {
|
||||
new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
}
|
||||
});
|
||||
|
||||
// JavaScript to populate the modal fields when "Change Role" button is clicked
|
||||
var editUserModal = document.getElementById('editUserModal');
|
||||
if (editUserModal) {
|
||||
editUserModal.addEventListener('show.bs.modal', function (event) {
|
||||
var button = event.relatedTarget; // Button that triggered the modal
|
||||
var userId = button.getAttribute('data-user-id');
|
||||
var username = button.getAttribute('data-username');
|
||||
var currentStatus = button.getAttribute('data-current-status');
|
||||
var canRunR = button.getAttribute('data-can-run-r') || '0';
|
||||
|
||||
var modalUserId = editUserModal.querySelector('#modalUserId');
|
||||
var modalUsername = editUserModal.querySelector('#modalUsername');
|
||||
var modalCurrentStatus = editUserModal.querySelector('#modalCurrentStatus');
|
||||
var newStatusSelect = editUserModal.querySelector('#newStatus');
|
||||
var modalRAccess = editUserModal.querySelector('#modalRAccess');
|
||||
|
||||
modalUserId.value = userId;
|
||||
modalUsername.value = username;
|
||||
modalCurrentStatus.value = currentStatus;
|
||||
newStatusSelect.value = currentStatus; // Set default selected option to current status
|
||||
if (modalRAccess) {
|
||||
modalRAccess.value = canRunR;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// JavaScript for password confirmation in Add New User Modal
|
||||
var addUserForm = document.getElementById('addUserForm');
|
||||
if (addUserForm) {
|
||||
addUserForm.addEventListener('submit', function(event) {
|
||||
var password = document.getElementById('addPassword').value;
|
||||
var confirmPassword = document.getElementById('addConfirmPassword').value;
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
alert('Passwords do not match!');
|
||||
event.preventDefault(); // Prevent form submission
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Populate Reset Password modal
|
||||
var resetPasswordModal = document.getElementById('resetPasswordModal');
|
||||
if (resetPasswordModal) {
|
||||
resetPasswordModal.addEventListener('show.bs.modal', function (event) {
|
||||
var trigger = event.relatedTarget;
|
||||
var userIdField = document.getElementById('resetUserId');
|
||||
var usernameField = document.getElementById('resetUsername');
|
||||
var newPasswordField = document.getElementById('newPassword');
|
||||
var confirmPasswordField = document.getElementById('confirmNewPassword');
|
||||
|
||||
if (trigger && userIdField && usernameField) {
|
||||
userIdField.value = trigger.getAttribute('data-user-id') || '';
|
||||
usernameField.value = trigger.getAttribute('data-username') || '';
|
||||
}
|
||||
if (newPasswordField) newPasswordField.value = '';
|
||||
if (confirmPasswordField) confirmPasswordField.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
var resetPasswordForm = document.getElementById('resetPasswordForm');
|
||||
if (resetPasswordForm) {
|
||||
resetPasswordForm.addEventListener('submit', function (event) {
|
||||
var newPassword = document.getElementById('newPassword').value;
|
||||
var confirmPassword = document.getElementById('confirmNewPassword').value;
|
||||
if (newPassword !== confirmPassword) {
|
||||
alert('Passwords do not match!');
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
if (newPassword.length < 8) {
|
||||
alert('Password must be at least 8 characters.');
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Footer -->
|
||||
<?php
|
||||
// Include Footer file for owner pages
|
||||
include_once("../includes/footer_admin.php");
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user