« Back to History
users_manage.php
|
20260721_154033.php
Initial Bulk Import
Copy Code
<?php /* ============================================================================= File: /erp/users_manage.php Purpose: Manage Users with Bootstrap UI & Database-driven Roles ========================================================================== */ error_reporting(E_ALL); ini_set('display_errors', 1); require __DIR__ . '/modules/auth/auth.php'; require_login(); $u = auth_user(); $company_id = (int)$u['company_id']; $pdo = $GLOBALS['pdo'] ?? null; if(!$pdo){ require __DIR__ . '/core/db.php'; $pdo = $GLOBALS['pdo']; } require_once __DIR__ . '/modules/activity/activity_logger.php'; /* -------------------- HELPERS -------------------- */ function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } function pv($k,$d=null){ return isset($_POST[$k])?trim((string)$_POST[$k]):$d; } function gv($k,$d=null){ return isset($_GET[$k]) ?trim((string)$_GET[$k]) :$d; } /* -------------------- FETCH ROLES FROM DATABASE -------------------- */ $role_stmt = $pdo->prepare("SELECT id, role_name, company_id FROM user_roles WHERE (company_id = ? OR company_id = 0) AND status = 1 ORDER BY role_name ASC"); $role_stmt->execute([$company_id]); $all_roles = $role_stmt->fetchAll(PDO::FETCH_ASSOC); $role_opts = array_column($all_roles, 'role_name'); /* -------------------- FORM HANDLING (SAVE/UPDATE) -------------------- */ $flash = ''; $err = ''; if($_SERVER['REQUEST_METHOD'] === 'POST' && pv('form') === 'save'){ $id = (int)pv('id', 0); $name = pv('name',''); $username = pv('username',''); $email = pv('email',''); $role = pv('role','Employee'); $is_active = (int)pv('is_active', 1); $password = pv('password',''); // Email handling to avoid "Duplicate entry" error $db_email = ($email !== '') ? $email : null; try { if($name === '' || $username === '') throw new Exception('Name & Username are required.'); // Username uniqueness check $st = $pdo->prepare("SELECT id FROM users WHERE company_id=? AND username=? AND id<>? LIMIT 1"); $st->execute([$company_id, $username, $id]); if($st->fetchColumn()) throw new Exception('Username already exists in this company.'); if($id > 0) { // UPDATE if($password !== '') { $hash = password_hash($password, PASSWORD_BCRYPT); $sql = "UPDATE users SET name=?, username=?, email=?, role=?, is_active=?, password_hash=?, password_plain=? WHERE id=? AND company_id=?"; $pdo->prepare($sql)->execute([$name, $username, $db_email, $role, $is_active, $hash, $password, $id, $company_id]); } else { $sql = "UPDATE users SET name=?, username=?, email=?, role=?, is_active=? WHERE id=? AND company_id=?"; $pdo->prepare($sql)->execute([$name, $username, $db_email, $role, $is_active, $id, $company_id]); } activity_log([ 'company_id' => $company_id, 'user_id' => (int)($u['id'] ?? 0), 'module' => 'users', 'action_name' => 'edit', 'entity_type' => 'user', 'entity_id' => $id, 'remarks' => "Updated user {$username}" ]); $flash = "User updated successfully."; } else { // INSERT $hash = ($password !== '') ? password_hash($password, PASSWORD_BCRYPT) : null; $sql = "INSERT INTO users (company_id, name, username, email, role, is_active, password_hash, password_plain) VALUES (?,?,?,?,?,?,?,?)"; $pdo->prepare($sql)->execute([$company_id, $name, $username, $db_email, $role, $is_active, $hash, $password]); $new_user_id = (int)$pdo->lastInsertId(); activity_log([ 'company_id' => $company_id, 'user_id' => (int)($u['id'] ?? 0), 'module' => 'users', 'action_name' => 'create', 'entity_type' => 'user', 'entity_id' => $new_user_id, 'remarks' => "Created user {$username}" ]); $flash = "User created successfully."; } header("Location: " . $_SERVER['PHP_SELF'] . "?ok=1"); exit; } catch(Throwable $e) { $err = $e->getMessage(); } } // Add New Role if($_SERVER['REQUEST_METHOD'] === 'POST' && pv('form') === 'add_role'){ $new_role = trim(pv('role_name','')); if($new_role !== ''){ try { $chk = $pdo->prepare("SELECT id FROM user_roles WHERE role_name=? AND (company_id=? OR company_id=0) LIMIT 1"); $chk->execute([$new_role, $company_id]); if($chk->fetchColumn()){ $err = 'Role already exists.'; } else { $pdo->prepare("INSERT INTO user_roles (company_id, role_name, status) VALUES (?,?,1)")->execute([$company_id, $new_role]); activity_log([ 'company_id' => $company_id, 'user_id' => (int)($u['id'] ?? 0), 'module' => 'users', 'action_name' => 'create', 'entity_type' => 'user_role', 'entity_id' => (int)$pdo->lastInsertId(), 'remarks' => "Created user role {$new_role}" ]); header("Location: ".$_SERVER['PHP_SELF']."?ok=1"); exit; } } catch(Throwable $e){ $err = $e->getMessage(); } } } // Delete Role if($_SERVER['REQUEST_METHOD'] === 'POST' && pv('form') === 'del_role'){ $rid = (int)pv('role_id',0); if($rid > 0){ $pdo->prepare("DELETE FROM user_roles WHERE id=? AND company_id=?")->execute([$rid, $company_id]); activity_log([ 'company_id' => $company_id, 'user_id' => (int)($u['id'] ?? 0), 'module' => 'users', 'action_name' => 'delete', 'entity_type' => 'user_role', 'entity_id' => $rid, 'remarks' => 'Deleted user role' ]); header("Location: ".$_SERVER['PHP_SELF']."?ok=1"); exit; } } // Toggle Status (Activate/Deactivate) if($_SERVER['REQUEST_METHOD'] === 'POST' && pv('form') === 'toggle'){ $id = (int)pv('id', 0); $to = (int)pv('to', 1); $pdo->prepare("UPDATE users SET is_active=? WHERE id=? AND company_id=?")->execute([$to, $id, $company_id]); activity_log([ 'company_id' => $company_id, 'user_id' => (int)($u['id'] ?? 0), 'module' => 'users', 'action_name' => 'edit', 'entity_type' => 'user', 'entity_id' => $id, 'remarks' => $to ? 'Activated user' : 'Deactivated user' ]); header("Location: " . $_SERVER['PHP_SELF'] . "?ok=1"); exit; } /* -------------------- EDIT LOAD & LIST DATA -------------------- */ $edit_id = (int)gv('edit', 0); $edit = null; if($edit_id > 0) { $st = $pdo->prepare("SELECT * FROM users WHERE id=? AND company_id=?"); $st->execute([$edit_id, $company_id]); $edit = $st->fetch(PDO::FETCH_ASSOC); } $q = gv('q', ''); $sql = "SELECT * FROM users WHERE company_id=? " . ($q !== '' ? "AND (name LIKE ? OR username LIKE ?)" : "") . " ORDER BY id DESC"; $stmt = $pdo->prepare($sql); $q !== '' ? $stmt->execute([$company_id, "%$q%", "%$q%"]) : $stmt->execute([$company_id]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); require __DIR__ . '/partials/header.php'; ?> <div class="container-fluid mt-4" style="max-width: 1200px;"> <div class="card shadow-sm mb-4 border-0"> <div class="card-header bg-primary text-white py-3"> <h5 class="mb-0 fw-bold"><i class="bi bi-person-plus me-2"></i> User Management (Company: <?= $company_id ?>)</h5> </div> <div class="card-body bg-light"> <?php if(gv('ok')): ?><div class="alert alert-success border-0 shadow-sm">Operation Successful!</div><?php endif; ?> <?php if($err): ?><div class="alert alert-danger border-0 shadow-sm"><?= h($err) ?></div><?php endif; ?> <form method="post" autocomplete="off" class="row g-3"> <input type="hidden" name="form" value="save"> <input type="hidden" name="id" value="<?= $edit ? (int)$edit['id'] : 0 ?>"> <div class="col-md-3"> <label class="form-label small fw-bold">Full Name</label> <input name="name" class="form-control" required value="<?= h($edit['name'] ?? '') ?>" placeholder="Enter full name"> </div> <div class="col-md-3"> <label class="form-label small fw-bold">Username</label> <input name="username" class="form-control" required value="<?= h($edit['username'] ?? '') ?>" placeholder="Unique username"> </div> <div class="col-md-3"> <label class="form-label small fw-bold">Email (Optional)</label> <input type="email" name="email" class="form-control" value="<?= h($edit['email'] ?? '') ?>" placeholder="email@example.com"> </div> <div class="col-md-3"> <label class="form-label small fw-bold">Role</label> <select name="role" class="form-select" required> <option value="">-- Select Role --</option> <?php foreach($role_opts as $r): ?> <option value="<?= h($r) ?>" <?= (isset($edit['role']) && $edit['role'] === $r) ? 'selected' : '' ?>><?= h($r) ?></option> <?php endforeach; ?> </select> </div> <div class="col-md-3"> <label class="form-label small fw-bold">Password</label> <input name="password" type="text" class="form-control" placeholder="<?= $edit ? 'Leave blank to keep same' : 'Set password' ?>"> </div> <div class="col-md-3"> <label class="form-label small fw-bold">Status</label> <select name="is_active" class="form-select"> <option value="1" <?= (!isset($edit['is_active']) || $edit['is_active'] == 1) ? 'selected' : '' ?>>Active</option> <option value="0" <?= (isset($edit['is_active']) && $edit['is_active'] == 0) ? 'selected' : '' ?>>Inactive</option> </select> </div> <div class="col-md-12 mt-4"> <button class="btn btn-primary px-4 fw-bold" type="submit"><?= $edit ? 'Update User' : 'Create User' ?></button> <?php if($edit): ?><a href="<?= $_SERVER['PHP_SELF'] ?>" class="btn btn-outline-secondary px-4">Cancel</a><?php endif; ?> </div> </form> </div> </div> <div class="card shadow-sm border-0"> <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center"> <h6 class="mb-0 fw-bold text-dark">User List</h6> <form method="get" class="d-flex gap-2"> <input name="q" class="form-control form-control-sm" style="width: 250px;" placeholder="Search name or username..." value="<?= h($q) ?>"> <button class="btn btn-sm btn-dark px-3">Search</button> <?php if($q !== ''): ?><a href="<?= $_SERVER['PHP_SELF'] ?>" class="btn btn-sm btn-light border">Reset</a><?php endif; ?> </form> </div> <div class="table-responsive"> <table class="table table-hover align-middle mb-0"> <thead class="table-light"> <tr> <th class="ps-3">ID</th> <th>User Details</th> <th>Role</th> <th>Status</th> <th class="text-end pe-3">Actions</th> </tr> </thead> <tbody> <?php if(empty($rows)): ?> <tr><td colspan="5" class="text-center py-4 text-muted">No users found.</td></tr> <?php else: foreach($rows as $r): ?> <tr> <td class="ps-3 text-muted"><?= (int)$r['id'] ?></td> <td> <div class="fw-bold text-dark"><?= h($r['name']) ?></div> <div class="small text-muted">@<?= h($r['username']) ?> <?= $r['email'] ? '| '.h($r['email']) : '' ?></div> </td> <td><span class="badge bg-info text-dark fw-normal px-3 py-2"><?= h($r['role']) ?></span></td> <td> <?= $r['is_active'] ? '<span class="badge bg-success-subtle text-success border border-success-subtle px-3 py-2">Active</span>' : '<span class="badge bg-danger-subtle text-danger border border-danger-subtle px-3 py-2">Inactive</span>' ?> </td> <td class="text-end pe-3"> <div class="d-flex justify-content-end gap-2"> <a href="?edit=<?= $r['id'] ?>" class="btn btn-sm btn-outline-primary px-3">Edit</a> <form method="post" onsubmit="return confirm('Change user status?');" style="margin:0;"> <input type="hidden" name="form" value="toggle"> <input type="hidden" name="id" value="<?= $r['id'] ?>"> <input type="hidden" name="to" value="<?= $r['is_active'] ? 0 : 1 ?>"> <button class="btn btn-sm <?= $r['is_active'] ? 'btn-outline-danger' : 'btn-outline-success' ?> px-3"> <?= $r['is_active'] ? 'Deactivate' : 'Activate' ?> </button> </form> </div> </td> </tr> <?php endforeach; endif; ?> </tbody> </table> </div> </div> </div> <!-- Role Management --> <div class="container-fluid mt-4" style="max-width:1200px;"> <div class="card shadow-sm border-0"> <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center"> <h6 class="mb-0 fw-bold text-dark"><i class="bi bi-tags me-1"></i> Role Management</h6> </div> <div class="card-body"> <!-- Add Role Form --> <form method="post" class="row g-2 align-items-end mb-4"> <input type="hidden" name="form" value="add_role"> <div class="col-auto"> <label class="form-label small fw-bold">New Role Name</label> <input name="role_name" class="form-control" placeholder="e.g. karigar, supervisor" required style="min-width:220px;"> </div> <div class="col-auto"> <button class="btn btn-success px-4" type="submit"><i class="bi bi-plus-circle me-1"></i> Add Role</button> </div> </form> <!-- Role List --> <table class="table table-sm table-bordered align-middle" style="max-width:500px;"> <thead class="table-light"> <tr><th>#</th><th>Role Name</th><th>Scope</th><th class="text-end">Action</th></tr> </thead> <tbody> <?php foreach($all_roles as $ro): ?> <tr> <td class="text-muted"><?= (int)$ro['id'] ?></td> <td class="fw-bold"><?= h($ro['role_name']) ?></td> <td><?= ((int)$ro['company_id'] === 0) ? '<span class="badge bg-secondary">Global</span>' : '<span class="badge bg-primary">This Company</span>' ?></td> <td class="text-end"> <?php if((int)$ro['company_id'] === $company_id): ?> <form method="post" onsubmit="return confirm('Delete role <?= h($ro['role_name']) ?>?');" style="margin:0;display:inline;"> <input type="hidden" name="form" value="del_role"> <input type="hidden" name="role_id" value="<?= (int)$ro['id'] ?>"> <button class="btn btn-sm btn-outline-danger px-3">Delete</button> </form> <?php else: ?> <span class="text-muted small">Global (protected)</span> <?php endif; ?> </td> </tr> <?php endforeach; ?> <?php if(empty($all_roles)): ?> <tr><td colspan="4" class="text-center text-muted">No roles found.</td></tr> <?php endif; ?> </tbody> </table> </div> </div> </div> <?php require __DIR__ . '/partials/footer.php'; ?>