Compare commits
No commits in common. "ai-dev" and "master" have entirely different histories.
224
add-asset.php
224
add-asset.php
@ -1,224 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'asset', 'create')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$allowed_fields_str = can($_SESSION['user_role_id'], 'asset', 'create');
|
||||
$allowed_fields = ($allowed_fields_str === '*') ? ['name', 'status', 'location_id', 'manufacturer', 'model', 'purchase_date', 'category_id', 'assigned_to'] : explode(',', $allowed_fields_str);
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
$categories = [];
|
||||
$locations = [];
|
||||
$users = [];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
// Fetch categories for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM categories ORDER BY name");
|
||||
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
// Fetch locations for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM locations ORDER BY name");
|
||||
$locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
// Fetch users for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM users ORDER BY name");
|
||||
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$data = [];
|
||||
$placeholders = [];
|
||||
$columns = [];
|
||||
|
||||
// Generate new asset tag
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT asset_tag FROM assets WHERE asset_tag LIKE 'ASSET-%' ORDER BY CAST(SUBSTRING(asset_tag, 7) AS UNSIGNED) DESC LIMIT 1");
|
||||
$last_asset_tag = $stmt->fetchColumn();
|
||||
|
||||
if ($last_asset_tag) {
|
||||
$last_number = (int) substr($last_asset_tag, 6);
|
||||
$new_number = $last_number + 1;
|
||||
} else {
|
||||
$new_number = 1;
|
||||
}
|
||||
|
||||
$new_asset_tag = 'ASSET-' . str_pad($new_number, 3, '0', STR_PAD_LEFT);
|
||||
|
||||
$data = [$new_asset_tag];
|
||||
$columns = ['asset_tag'];
|
||||
$placeholders = '?';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Error generating asset tag: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
foreach ($allowed_fields as $field) {
|
||||
if (isset($_POST[$field])) {
|
||||
$value = $_POST[$field];
|
||||
if (($field === 'category_id' || $field === 'location_id' || $field === 'assigned_to') && $value === '') {
|
||||
$value = null;
|
||||
}
|
||||
$data[] = $value;
|
||||
$columns[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($data) <= 1) { // Only asset tag is present
|
||||
$error_message = 'No data submitted.';
|
||||
} else {
|
||||
try {
|
||||
$sql = sprintf("INSERT INTO assets (%s) VALUES (%s)", implode(', ', $columns), implode(', ', array_fill(0, count($columns), '?')));
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($data);
|
||||
|
||||
header("Location: index.php?success=asset_added");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add New Asset - IC-Inventory</title>
|
||||
<meta name="description" content="Add a new asset to the inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Add New Asset</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="add-asset.php" method="post">
|
||||
<div class="row">
|
||||
<?php if (in_array('name', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Asset Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('status', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option>In Service</option>
|
||||
<option>Under Repair</option>
|
||||
<option>Retired</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('category_id', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="category_id" class="form-label">Category</label>
|
||||
<select class="form-select" id="category_id" name="category_id">
|
||||
<option value="">No Category</option>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>">
|
||||
<?php echo htmlspecialchars($category['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('location_id', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="location_id" class="form-label">Location</label>
|
||||
<select class="form-select" id="location_id" name="location_id">
|
||||
<option value="">No Location</option>
|
||||
<?php foreach ($locations as $location): ?>
|
||||
<option value="<?php echo $location['id']; ?>">
|
||||
<?php echo htmlspecialchars($location['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('assigned_to', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="assigned_to" class="form-label">Assigned To</label>
|
||||
<select class="form-select" id="assigned_to" name="assigned_to">
|
||||
<option value="">Unassigned</option>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<option value="<?php echo $user['id']; ?>">
|
||||
<?php echo htmlspecialchars($user['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('manufacturer', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="manufacturer" class="form-label">Manufacturer</label>
|
||||
<input type="text" class="form-control" id="manufacturer" name="manufacturer">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('model', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="model" class="form-label">Model</label>
|
||||
<input type="text" class="form-control" id="model" name="model">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (in_array('purchase_date', $allowed_fields)): ?>
|
||||
<div class="mb-3">
|
||||
<label for="purchase_date" class="form-label">Purchase Date*</label>
|
||||
<input type="date" class="form-control" id="purchase_date" name="purchase_date" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Add Asset</button>
|
||||
<a href="index.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="assets/js/choices.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'category', 'create')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the category name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM categories WHERE name = ?');
|
||||
$stmt->execute([$name]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A category with this name already exists.';
|
||||
} else {
|
||||
$sql = "INSERT INTO categories (name) VALUES (?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name]);
|
||||
|
||||
header("Location: categories.php?success=category_added");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add New Category - IC-Inventory</title>
|
||||
<meta name="description" content="Add a new category.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Add New Category</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="add-category.php" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Category Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Add Category</button>
|
||||
<a href="categories.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'location', 'create')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the location name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM locations WHERE name = ?');
|
||||
$stmt->execute([$name]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A location with this name already exists.';
|
||||
} else {
|
||||
$sql = "INSERT INTO locations (name) VALUES (?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name]);
|
||||
|
||||
header("Location: locations.php?success=location_added");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add New Location - IC-Inventory</title>
|
||||
<meta name="description" content="Add a new location.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Add New Location</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="add-location.php" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Location Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Add Location</button>
|
||||
<a href="locations.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
94
add-role.php
94
add-role.php
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'role', 'create')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the role name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM roles WHERE name = ?');
|
||||
$stmt->execute([$name]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A role with this name already exists.';
|
||||
} else {
|
||||
$sql = "INSERT INTO roles (name) VALUES (?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name]);
|
||||
|
||||
header("Location: roles.php?success=role_added");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add New Role - IC-Inventory</title>
|
||||
<meta name="description" content="Add a new role.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Add New Role</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="add-role.php" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Role Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Add Role</button>
|
||||
<a href="roles.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
137
add-user.php
137
add-user.php
@ -1,137 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'user', 'create')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$roles = [];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT id, name FROM roles ORDER BY name');
|
||||
$roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
if ($roles === false) {
|
||||
throw new Exception("Failed to fetch roles from the database.");
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log('PDO Error in add-user.php: ' . $e->getMessage());
|
||||
die("Error: A database error occurred while trying to fetch roles. Please check the logs. Message: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
die("Error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
$role_id = $_POST['role_id'] ?? null;
|
||||
|
||||
if (empty($name) || empty($email) || empty($password) || empty($role_id)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$error_message = 'Invalid email format.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = ?');
|
||||
$stmt->execute([$email]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A user with this email address already exists.';
|
||||
} else {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$sql = "INSERT INTO users (name, email, password, role_id) VALUES (?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name, $email, $hashed_password, $role_id]);
|
||||
|
||||
header("Location: users.php?success=user_added");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add New User - IC-Inventory</title>
|
||||
<meta name="description" content="Add a new user.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Add New User</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="add-user.php" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Full Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="email" class="form-label">Email Address*</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="password" class="form-label">Password*</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="role_id" class="form-label">Role</label>
|
||||
<select class="form-select" id="role_id" name="role_id" required>
|
||||
<option value="">Select a role</option>
|
||||
<?php foreach ($roles as $role): ?>
|
||||
<option value="<?php echo htmlspecialchars($role['id']); ?>">
|
||||
<?php echo htmlspecialchars($role['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Add User</button>
|
||||
<a href="users.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,125 +0,0 @@
|
||||
/* General Styles */
|
||||
:root {
|
||||
--primary-color: #4A90E2;
|
||||
--secondary-color: #50E3C2;
|
||||
--light-bg: #F7F9FC;
|
||||
--light-surface: #FFFFFF;
|
||||
--light-text: #333333;
|
||||
--dark-bg: #121212;
|
||||
--dark-surface: #1E1E1E;
|
||||
--dark-text: #E0E0E0;
|
||||
--border-radius: 8px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
/* Light Mode */
|
||||
body {
|
||||
background-color: var(--light-bg);
|
||||
color: var(--light-text);
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
body.dark-mode {
|
||||
background-color: var(--dark-bg);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
.surface {
|
||||
background-color: var(--light-surface);
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
body.dark-mode .surface {
|
||||
background-color: var(--dark-surface);
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.wrapper {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
width: 250px;
|
||||
background-color: var(--light-surface);
|
||||
transition: background-color 0.3s;
|
||||
padding: 20px;
|
||||
box-shadow: 2px 0 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
body.dark-mode #sidebar {
|
||||
background-color: var(--dark-surface);
|
||||
box-shadow: 2px 0 5px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
#content {
|
||||
flex-grow: 1;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Theme Switcher */
|
||||
.theme-switcher {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Asset Table */
|
||||
.asset-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.asset-table th, .asset-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
body.dark-mode .asset-table th, body.dark-mode .asset-table td {
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
.asset-table th {
|
||||
background-color: var(--light-bg);
|
||||
}
|
||||
|
||||
body.dark-mode .asset-table th {
|
||||
background-color: var(--dark-bg);
|
||||
}
|
||||
|
||||
.status {
|
||||
padding: 5px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-in-service { background-color: #d4edda; color: #155724; }
|
||||
.status-under-repair { background-color: #fff3cd; color: #856404; }
|
||||
.status-retired { background-color: #f8d7da; color: #721c24; }
|
||||
|
||||
/* Sidebar */
|
||||
#sidebar .nav-link {
|
||||
color: var(--light-text);
|
||||
}
|
||||
body.dark-mode #sidebar .nav-link {
|
||||
color: var(--dark-text);
|
||||
}
|
||||
#sidebar .nav-link.active {
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const assignedTo = document.getElementById('assigned_to');
|
||||
if (assignedTo) {
|
||||
new Choices(assignedTo, {
|
||||
removeItemButton: true,
|
||||
});
|
||||
}
|
||||
|
||||
const category = document.getElementById('category_id');
|
||||
if (category) {
|
||||
new Choices(category, {
|
||||
removeItemButton: true,
|
||||
});
|
||||
}
|
||||
|
||||
const location = document.getElementById('location_id');
|
||||
if (location) {
|
||||
new Choices(location, {
|
||||
removeItemButton: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,17 +0,0 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const themeSwitcher = document.getElementById('theme-switcher');
|
||||
const currentTheme = localStorage.getItem('theme');
|
||||
|
||||
if (currentTheme === 'dark') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
themeSwitcher.addEventListener('click', () => {
|
||||
document.body.classList.toggle('dark-mode');
|
||||
let theme = 'light';
|
||||
if (document.body.classList.contains('dark-mode')) {
|
||||
theme = 'dark';
|
||||
}
|
||||
localStorage.setItem('theme', theme);
|
||||
});
|
||||
});
|
||||
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
function can($role_id, $resource, $action) {
|
||||
static $permissions = null;
|
||||
|
||||
if ($permissions === null) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT * FROM role_permissions');
|
||||
$all_permissions = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$permissions = [];
|
||||
foreach ($all_permissions as $p) {
|
||||
$permissions[$p['role_id']][$p['resource']][$p['action']] = $p['fields'] ?? '*';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Handle database errors, maybe return false or log the error
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($permissions[$role_id][$resource][$action])) {
|
||||
if (in_array($action, ['read', 'update', 'create'])) {
|
||||
return $permissions[$role_id][$resource][$action];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
118
categories.php
118
categories.php
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
// Permissions check
|
||||
if (!can($_SESSION['user_role_id'], 'category', 'read')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
function get_categories() {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM categories ORDER BY name ASC");
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$categories = get_categories();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Category Management - IC-Inventory</title>
|
||||
<meta name="description" content="Category management for IC-Inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Category Management</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role_id'], 'category', 'create')): ?>
|
||||
<a href="add-category.php" class="btn btn-primary">Add New Category</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php
|
||||
if ($_GET['success'] === 'category_added') echo 'Category successfully added!';
|
||||
if ($_GET['success'] === 'category_updated') echo 'Category successfully updated!';
|
||||
if ($_GET['success'] === 'category_deleted') echo 'Category successfully deleted!';
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if (isset($categories['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($categories['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($categories)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No categories found.</h4>
|
||||
<?php if (can($_SESSION['user_role_id'], 'category', 'create')): ?>
|
||||
<p>Get started by adding your first category.</p>
|
||||
<a href="add-category.php" class="btn btn-primary">Add Category</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($category['name']); ?></td>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role_id'], 'category', 'update')): ?>
|
||||
<a href="edit-category.php?id=<?php echo $category['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'category', 'delete')): ?>
|
||||
<a href="delete-category.php?id=<?php echo $category['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this category?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,5 +0,0 @@
|
||||
# Netscape HTTP Cookie File
|
||||
# https://curl.se/docs/http-cookies.html
|
||||
# This file was generated by libcurl! Edit at your own risk.
|
||||
|
||||
localhost FALSE / FALSE 0 PHPSESSID m0fvo87s169e7d06irv43qqhfn
|
||||
@ -6,22 +6,12 @@ define('DB_USER', 'app_31009');
|
||||
define('DB_PASS', '2c66b530-2a65-423a-a106-6760b49ad1a2');
|
||||
|
||||
function db() {
|
||||
static $pdo;
|
||||
if ($pdo) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
// If the database doesn't exist, we can't run migrations.
|
||||
// The error will be caught and displayed on the page.
|
||||
throw $e;
|
||||
}
|
||||
|
||||
|
||||
return $pdo;
|
||||
static $pdo;
|
||||
if (!$pdo) {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
}
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `assets` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`asset_tag` VARCHAR(255) UNIQUE NOT NULL,
|
||||
`serial_number` VARCHAR(255),
|
||||
`model` VARCHAR(255),
|
||||
`manufacturer` VARCHAR(255),
|
||||
`category` VARCHAR(255),
|
||||
`status` VARCHAR(50) NOT NULL,
|
||||
`location` VARCHAR(255),
|
||||
`purchase_date` DATE,
|
||||
`purchase_cost` DECIMAL(10, 2),
|
||||
`warranty_end` DATE,
|
||||
`vendor` VARCHAR(255),
|
||||
`assigned_to` INT,
|
||||
`notes` TEXT,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Seed data
|
||||
INSERT INTO `assets` (`name`, `asset_tag`, `status`, `location`, `purchase_date`, `assigned_to`, `manufacturer`, `model`) VALUES
|
||||
('Laptop', 'ASSET-001', 'In Service', 'Office A', '2023-01-15', 1, 'Dell', 'XPS 15'),
|
||||
('Monitor', 'ASSET-002', 'In Service', 'Office A', '2023-01-15', 1, 'Dell', 'UltraSharp 27'),
|
||||
('Keyboard', 'ASSET-003', 'In Service', 'Office B', '2023-02-20', 2, 'Logitech', 'MX Keys'),
|
||||
('Mouse', 'ASSET-004', 'Under Repair', 'IT Department', '2023-02-20', NULL, 'Logitech', 'MX Master 3'),
|
||||
('Projector', 'ASSET-005', 'Retired', 'Storage', '2020-05-10', NULL, 'Epson', 'PowerLite 1781W');
|
||||
@ -1,14 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`role` enum('Admin','Asset Manager','IT Technician','Employee') NOT NULL DEFAULT 'Employee',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Seed with a default admin user
|
||||
INSERT INTO `users` (`name`, `email`, `password`, `role`) VALUES
|
||||
('Admin User', 'admin@example.com', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'Admin'); -- password is 'password'
|
||||
@ -1,40 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `role_permissions` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`role` varchar(255) NOT NULL,
|
||||
`resource` varchar(255) NOT NULL,
|
||||
`action` varchar(255) NOT NULL,
|
||||
`fields` text DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `role_resource_action` (`role`,`resource`,`action`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Default Permissions
|
||||
|
||||
-- Admin: Can do everything
|
||||
INSERT INTO `role_permissions` (`role`, `resource`, `action`, `fields`) VALUES
|
||||
('Admin', 'asset', 'create', '*'),
|
||||
('Admin', 'asset', 'read', '*'),
|
||||
('Admin', 'asset', 'update', '*'),
|
||||
('Admin', 'asset', 'delete', '*'),
|
||||
('Admin', 'user', 'create', '*'),
|
||||
('Admin', 'user', 'read', '*'),
|
||||
('Admin', 'user', 'update', '*'),
|
||||
('Admin', 'user', 'delete', '*');
|
||||
|
||||
-- Asset Manager: Can manage assets
|
||||
INSERT INTO `role_permissions` (`role`, `resource`, `action`, `fields`) VALUES
|
||||
('Asset Manager', 'asset', 'create', '*'),
|
||||
('Asset Manager', 'asset', 'read', '*'),
|
||||
('Asset Manager', 'asset', 'update', '*'),
|
||||
('Asset Manager', 'asset', 'delete', '*');
|
||||
|
||||
-- IT Technician: Can manage assets
|
||||
INSERT INTO `role_permissions` (`role`, `resource`, `action`, `fields`) VALUES
|
||||
('IT Technician', 'asset', 'create', '*'),
|
||||
('IT Technician', 'asset', 'read', '*'),
|
||||
('IT Technician', 'asset', 'update', '*'),
|
||||
('IT Technician', 'asset', 'delete', '*');
|
||||
|
||||
-- Employee: Can only read some asset fields
|
||||
INSERT INTO `role_permissions` (`role`, `resource`, `action`, `fields`) VALUES
|
||||
('Employee', 'asset', 'read', 'name,asset_tag,status,location,manufacturer,model');
|
||||
@ -1,5 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `categories` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=INNODB;
|
||||
@ -1,2 +0,0 @@
|
||||
ALTER TABLE `assets` ADD COLUMN `category_id` INT NULL AFTER `status`;
|
||||
ALTER TABLE `assets` ADD FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL;
|
||||
@ -1,5 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `locations` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@ -1 +0,0 @@
|
||||
ALTER TABLE `assets` ADD COLUMN `location_id` INT NULL, ADD FOREIGN KEY (`location_id`) REFERENCES `locations`(`id`) ON DELETE SET NULL;
|
||||
@ -1,14 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `roles` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Seed with existing roles
|
||||
INSERT INTO `roles` (`name`) VALUES
|
||||
('Admin'),
|
||||
('Asset Manager'),
|
||||
('IT Technician'),
|
||||
('Employee');
|
||||
@ -1,16 +0,0 @@
|
||||
-- Add role_id column
|
||||
ALTER TABLE `users` ADD COLUMN `role_id` INT(11) NULL AFTER `password`;
|
||||
|
||||
-- Update role_id from existing role name
|
||||
UPDATE `users` u
|
||||
JOIN `roles` r ON u.role = r.name
|
||||
SET u.role_id = r.id;
|
||||
|
||||
-- Make role_id not nullable
|
||||
ALTER TABLE `users` MODIFY `role_id` INT(11) NOT NULL;
|
||||
|
||||
-- Add foreign key constraint
|
||||
ALTER TABLE `users` ADD CONSTRAINT `fk_user_role` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- Drop the old role column
|
||||
ALTER TABLE `users` DROP COLUMN `role`;
|
||||
@ -1,22 +0,0 @@
|
||||
-- Add role_id column
|
||||
ALTER TABLE `role_permissions` ADD COLUMN `role_id` INT(11) NULL AFTER `id`;
|
||||
|
||||
-- Update role_id from existing role name
|
||||
UPDATE `role_permissions` rp
|
||||
JOIN `roles` r ON rp.role = r.name
|
||||
SET rp.role_id = r.id;
|
||||
|
||||
-- Make role_id not nullable
|
||||
ALTER TABLE `role_permissions` MODIFY `role_id` INT(11) NOT NULL;
|
||||
|
||||
-- Drop the old unique key
|
||||
ALTER TABLE `role_permissions` DROP INDEX `role_resource_action`;
|
||||
|
||||
-- Drop the old role column
|
||||
ALTER TABLE `role_permissions` DROP COLUMN `role`;
|
||||
|
||||
-- Add new unique key with role_id
|
||||
ALTER TABLE `role_permissions` ADD UNIQUE KEY `role_resource_action` (`role_id`, `resource`, `action`);
|
||||
|
||||
-- Add foreign key to roles table
|
||||
ALTER TABLE `role_permissions` ADD CONSTRAINT `fk_permission_role` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1 +0,0 @@
|
||||
INSERT INTO `role_permissions` (`role_id`, `resource`, `action`) VALUES (1, 'permission', 'update');
|
||||
@ -1 +0,0 @@
|
||||
DROP TABLE IF EXISTS `permissions`;
|
||||
@ -1,12 +0,0 @@
|
||||
-- Grant all permissions on roles and permissions to Super Admin (role_id = 1)
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `resource`, `action`) VALUES
|
||||
-- Roles
|
||||
(1, 'role', 'create'),
|
||||
(1, 'role', 'read'),
|
||||
(1, 'role', 'update'),
|
||||
(1, 'role', 'delete'),
|
||||
-- Permissions
|
||||
(1, 'permission', 'read'),
|
||||
(1, 'permission', 'update')
|
||||
ON DUPLICATE KEY UPDATE `role_id` = `role_id`; -- Do nothing if the permission already exists
|
||||
@ -1,24 +0,0 @@
|
||||
-- Grant remaining permissions to Super Admin (role_id = 1)
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `resource`, `action`) VALUES
|
||||
-- Assets
|
||||
(1, 'asset', 'create'),
|
||||
(1, 'asset', 'read'),
|
||||
(1, 'asset', 'update'),
|
||||
(1, 'asset', 'delete'),
|
||||
-- Categories
|
||||
(1, 'category', 'create'),
|
||||
(1, 'category', 'read'),
|
||||
(1, 'category', 'update'),
|
||||
(1, 'category', 'delete'),
|
||||
-- Locations
|
||||
(1, 'location', 'create'),
|
||||
(1, 'location', 'read'),
|
||||
(1, 'location', 'update'),
|
||||
(1, 'location', 'delete'),
|
||||
-- Users
|
||||
(1, 'user', 'create'),
|
||||
(1, 'user', 'read'),
|
||||
(1, 'user', 'update'),
|
||||
(1, 'user', 'delete')
|
||||
ON DUPLICATE KEY UPDATE `role_id` = `role_id`; -- Do nothing if the permission already exists
|
||||
@ -1,11 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
setting_key VARCHAR(255) NOT NULL UNIQUE,
|
||||
setting_value TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Insert Google API credentials (initially empty)
|
||||
INSERT INTO settings (setting_key, setting_value) VALUES ('google_client_id', '') ON DUPLICATE KEY UPDATE setting_key = 'google_client_id';
|
||||
INSERT INTO settings (setting_key, setting_value) VALUES ('google_client_secret', '') ON DUPLICATE KEY UPDATE setting_key = 'google_client_secret';
|
||||
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SHOW TABLES');
|
||||
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
echo "<pre>";
|
||||
print_r($tables);
|
||||
echo "</pre>";
|
||||
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$asset_id = $_GET['id'];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM assets WHERE id = ?");
|
||||
$stmt->execute([$asset_id]);
|
||||
|
||||
header("Location: index.php?success=asset_deleted");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
header("Location: index.php?error=db_error");
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'category', 'delete')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$category_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$category_id) {
|
||||
header('Location: categories.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Set category_id to NULL for assets associated with this category
|
||||
$stmt = $pdo->prepare('UPDATE assets SET category_id = NULL WHERE category_id = ?');
|
||||
$stmt->execute([$category_id]);
|
||||
|
||||
// Delete the category
|
||||
$stmt = $pdo->prepare('DELETE FROM categories WHERE id = ?');
|
||||
$stmt->execute([$category_id]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
header("Location: categories.php?success=category_deleted");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
// In a real app, log this error.
|
||||
header("Location: categories.php?error=db_error");
|
||||
exit;
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'location', 'delete')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$location_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$location_id) {
|
||||
header('Location: locations.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Set location_id to NULL for assets associated with this location
|
||||
$stmt = $pdo->prepare('UPDATE assets SET location_id = NULL WHERE location_id = ?');
|
||||
$stmt->execute([$location_id]);
|
||||
|
||||
// Delete the location
|
||||
$stmt = $pdo->prepare('DELETE FROM locations WHERE id = ?');
|
||||
$stmt->execute([$location_id]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
header("Location: locations.php?success=location_deleted");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
// In a real app, log this error.
|
||||
header("Location: locations.php?error=db_error");
|
||||
exit;
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'role', 'delete')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$role_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$role_id) {
|
||||
header('Location: roles.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Check if any user is assigned to this role
|
||||
$stmt = $pdo->prepare('SELECT id FROM users WHERE role_id = ?');
|
||||
$stmt->execute([$role_id]);
|
||||
if ($stmt->fetch()) {
|
||||
header("Location: roles.php?error=role_in_use");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Delete the role
|
||||
$stmt = $pdo->prepare('DELETE FROM roles WHERE id = ?');
|
||||
$stmt->execute([$role_id]);
|
||||
|
||||
header("Location: roles.php?success=role_deleted");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error.
|
||||
header("Location: roles.php?error=db_error");
|
||||
exit;
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
|
||||
// Only Admins can access this page
|
||||
if ($_SESSION['user_role'] !== 'Admin') {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$user_id) {
|
||||
header('Location: users.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prevent user from deleting themselves
|
||||
if ($user_id == $_SESSION['user_id']) {
|
||||
header('Location: users.php?error=self_delete');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('DELETE FROM users WHERE id = ?');
|
||||
$stmt->execute([$user_id]);
|
||||
|
||||
header("Location: users.php?success=user_deleted");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error.
|
||||
header("Location: users.php?error=db_error");
|
||||
exit;
|
||||
}
|
||||
229
edit-asset.php
229
edit-asset.php
@ -1,229 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'asset', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$allowed_fields_str = can($_SESSION['user_role_id'], 'asset', 'update');
|
||||
$allowed_fields = ($allowed_fields_str === '*') ? ['name', 'asset_tag', 'status', 'location_id', 'manufacturer', 'model', 'purchase_date', 'assigned_to', 'category_id'] : explode(',', $allowed_fields_str);
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
$asset = null;
|
||||
$users = [];
|
||||
$categories = [];
|
||||
$locations = [];
|
||||
|
||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$asset_id = $_GET['id'];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM assets WHERE id = ?");
|
||||
$stmt->execute([$asset_id]);
|
||||
$asset = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$asset) {
|
||||
header("Location: index.php?error=not_found");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch users for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM users ORDER BY name");
|
||||
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch categories for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM categories ORDER BY name");
|
||||
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch locations for dropdown
|
||||
$stmt = $pdo->query("SELECT id, name FROM locations ORDER BY name");
|
||||
$locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$data = [];
|
||||
$set_parts = [];
|
||||
|
||||
foreach ($allowed_fields as $field) {
|
||||
if (isset($_POST[$field])) {
|
||||
$value = $_POST[$field];
|
||||
if (($field === 'assigned_to' || $field === 'category_id' || $field === 'location_id') && $value === '') {
|
||||
$value = null;
|
||||
}
|
||||
$data[] = $value;
|
||||
$set_parts[] = "$field = ?";
|
||||
}
|
||||
}
|
||||
$data[] = $asset_id;
|
||||
|
||||
if (empty($set_parts)) {
|
||||
$error_message = 'No data submitted.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = sprintf("UPDATE assets SET %s WHERE id = ?", implode(', ', $set_parts));
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($data);
|
||||
|
||||
header("Location: index.php?success=asset_updated");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Asset - IC-Inventory</title>
|
||||
<meta name="description" content="Edit an existing asset in the inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Edit Asset</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($asset): ?>
|
||||
<form action="edit-asset.php?id=<?php echo $asset_id; ?>" method="post">
|
||||
<div class="row">
|
||||
<?php if (in_array('name', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Asset Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($asset['name']); ?>" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('asset_tag', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="asset_tag" class="form-label">Asset Tag*</label>
|
||||
<input type="text" class="form-control" id="asset_tag" name="asset_tag" value="<?php echo htmlspecialchars($asset['asset_tag']); ?>" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('status', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option <?php if ($asset['status'] === 'In Service') echo 'selected'; ?>>In Service</option>
|
||||
<option <?php if ($asset['status'] === 'Under Repair') echo 'selected'; ?>>Under Repair</option>
|
||||
<option <?php if ($asset['status'] === 'Retired') echo 'selected'; ?>>Retired</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('category_id', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="category_id" class="form-label">Category</label>
|
||||
<select class="form-select" id="category_id" name="category_id">
|
||||
<option value="">No Category</option>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>" <?php if ($asset['category_id'] == $category['id']) echo 'selected'; ?>>
|
||||
<?php echo htmlspecialchars($category['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('location_id', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="location_id" class="form-label">Location</label>
|
||||
<select class="form-select" id="location_id" name="location_id">
|
||||
<option value="">No Location</option>
|
||||
<?php foreach ($locations as $location): ?>
|
||||
<option value="<?php echo $location['id']; ?>" <?php if ($asset['location_id'] == $location['id']) echo 'selected'; ?>>
|
||||
<?php echo htmlspecialchars($location['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('manufacturer', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="manufacturer" class="form-label">Manufacturer</label>
|
||||
<input type="text" class="form-control" id="manufacturer" name="manufacturer" value="<?php echo htmlspecialchars($asset['manufacturer']); ?>">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('model', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="model" class="form-label">Model</label>
|
||||
<input type="text" class="form-control" id="model" name="model" value="<?php echo htmlspecialchars($asset['model']); ?>">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('purchase_date', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="purchase_date" class="form-label">Purchase Date*</label>
|
||||
<input type="date" class="form-control" id="purchase_date" name="purchase_date" value="<?php echo htmlspecialchars($asset['purchase_date']); ?>" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('assigned_to', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="assigned_to" class="form-label">Assigned To</label>
|
||||
<select class="form-select" id="assigned_to" name="assigned_to">
|
||||
<option value="">Unassigned</option>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<option value="<?php echo $user['id']; ?>" <?php if ($asset['assigned_to'] == $user['id']) echo 'selected'; ?>>
|
||||
<?php echo htmlspecialchars($user['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update Asset</button>
|
||||
<a href="index.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="assets/js/choices.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,116 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'category', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$category_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$category_id) {
|
||||
header('Location: categories.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT id, name FROM categories WHERE id = ?');
|
||||
$stmt->execute([$category_id]);
|
||||
$category = $stmt->fetch();
|
||||
|
||||
if (!$category) {
|
||||
header('Location: categories.php');
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the category name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM categories WHERE name = ? AND id != ?');
|
||||
$stmt->execute([$name, $category_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A category with this name already exists.';
|
||||
} else {
|
||||
$sql = "UPDATE categories SET name = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name, $category_id]);
|
||||
|
||||
header("Location: categories.php?success=category_updated");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Category - IC-Inventory</title>
|
||||
<meta name="description" content="Edit an existing category.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Edit Category</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($category): ?>
|
||||
<form action="edit-category.php?id=<?php echo $category['id']; ?>" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Category Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($category['name']); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update Category</button>
|
||||
<a href="categories.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,116 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'location', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$location_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$location_id) {
|
||||
header('Location: locations.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT id, name FROM locations WHERE id = ?');
|
||||
$stmt->execute([$location_id]);
|
||||
$location = $stmt->fetch();
|
||||
|
||||
if (!$location) {
|
||||
header('Location: locations.php');
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the location name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM locations WHERE name = ? AND id != ?');
|
||||
$stmt->execute([$name, $location_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A location with this name already exists.';
|
||||
} else {
|
||||
$sql = "UPDATE locations SET name = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name, $location_id]);
|
||||
|
||||
header("Location: locations.php?success=location_updated");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Location - IC-Inventory</title>
|
||||
<meta name="description" content="Edit an existing location.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Edit Location</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($location): ?>
|
||||
<form action="edit-location.php?id=<?php echo $location['id']; ?>" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Location Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($location['name']); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update Location</button>
|
||||
<a href="locations.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
116
edit-role.php
116
edit-role.php
@ -1,116 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'role', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$role_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$role_id) {
|
||||
header('Location: roles.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT id, name FROM roles WHERE id = ?');
|
||||
$stmt->execute([$role_id]);
|
||||
$role = $stmt->fetch();
|
||||
|
||||
if (!$role) {
|
||||
header('Location: roles.php');
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
$error_message = 'Please fill in the role name.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM roles WHERE name = ? AND id != ?');
|
||||
$stmt->execute([$name, $role_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A role with this name already exists.';
|
||||
} else {
|
||||
$sql = "UPDATE roles SET name = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$name, $role_id]);
|
||||
|
||||
header("Location: roles.php?success=role_updated");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Role - IC-Inventory</title>
|
||||
<meta name="description" content="Edit an existing role.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Edit Role</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($role): ?>
|
||||
<form action="edit-role.php?id=<?php echo $role['id']; ?>" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Role Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($role['name']); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update Role</button>
|
||||
<a href="roles.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
158
edit-user.php
158
edit-user.php
@ -1,158 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
if (!can($_SESSION['user_role_id'], 'user', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
$allowed_fields_str = can($_SESSION['user_role_id'], 'user', 'update');
|
||||
$allowed_fields = ($allowed_fields_str === '*') ? ['name', 'email', 'role_id'] : explode(',', $allowed_fields_str);
|
||||
|
||||
$error_message = '';
|
||||
$user_id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$user_id) {
|
||||
header('Location: users.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT id, name, email, role_id FROM users WHERE id = ?');
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
header('Location: users.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch all roles for the dropdown
|
||||
$roles_stmt = $pdo->query('SELECT id, name FROM roles ORDER BY name');
|
||||
$roles = $roles_stmt->fetchAll();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$data = [];
|
||||
$set_parts = [];
|
||||
|
||||
foreach ($allowed_fields as $field) {
|
||||
if (isset($_POST[$field])) {
|
||||
$data[] = $_POST[$field];
|
||||
$set_parts[] = "$field = ?";
|
||||
}
|
||||
}
|
||||
$data[] = $user_id;
|
||||
|
||||
if (empty($set_parts)) {
|
||||
$error_message = 'No data submitted.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Check if email already exists for another user
|
||||
if (in_array('email', $allowed_fields)) {
|
||||
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = ? AND id != ?');
|
||||
$stmt->execute([$_POST['email'], $user_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'A user with this email address already exists.';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error_message) {
|
||||
$sql = sprintf("UPDATE users SET %s WHERE id = ?", implode(', ', $set_parts));
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($data);
|
||||
|
||||
header("Location: users.php?success=user_updated");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit User - IC-Inventory</title>
|
||||
<meta name="description" content="Edit an existing user.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Edit User</h1>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($user): ?>
|
||||
<form action="edit-user.php?id=<?php echo $user['id']; ?>" method="post">
|
||||
<div class="row">
|
||||
<?php if (in_array('name', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Full Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($user['name']); ?>" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('email', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="email" class="form-label">Email Address*</label>
|
||||
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($user['email']); ?>" required>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if (in_array('role_id', $allowed_fields)): ?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="role_id" class="form-label">Role</label>
|
||||
<select class="form-select" id="role_id" name="role_id">
|
||||
<?php foreach ($roles as $role): ?>
|
||||
<option value="<?php echo $role['id']; ?>" <?php echo ($user['role_id'] == $role['id']) ? 'selected' : ''; ?>><?php echo htmlspecialchars($role['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update User</button>
|
||||
<a href="users.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,122 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Fetch Google credentials from settings
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT setting_key, setting_value FROM settings WHERE setting_key IN ('google_client_id', 'google_client_secret')");
|
||||
$settings_raw = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
$google_client_id = $settings_raw['google_client_id'] ?? '';
|
||||
$google_client_secret = $settings_raw['google_client_secret'] ?? '';
|
||||
} catch (PDOException $e) {
|
||||
die('Database error fetching Google credentials.');
|
||||
}
|
||||
|
||||
if (empty($google_client_id) || empty($google_client_secret)) {
|
||||
die('Google API credentials are not configured. Please ask an administrator to set them up.');
|
||||
}
|
||||
|
||||
if (!isset($_GET['code'])) {
|
||||
header('Location: login.php?error=google_auth_failed');
|
||||
exit;
|
||||
}
|
||||
|
||||
$code = $_GET['code'];
|
||||
$redirect_uri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/google-callback.php';
|
||||
|
||||
// 1. Exchange authorization code for an access token
|
||||
$token_url = 'https://oauth2.googleapis.com/token';
|
||||
$token_params = [
|
||||
'code' => $code,
|
||||
'client_id' => $google_client_id,
|
||||
'client_secret' => $google_client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_type' => 'authorization_code'
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $token_url);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($token_params));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$token_data = json_decode($response, true);
|
||||
|
||||
if (!isset($token_data['access_token'])) {
|
||||
// Log error: print_r($token_data);
|
||||
header('Location: login.php?error=google_token_exchange_failed');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. Get user info from Google
|
||||
$userinfo_url = 'https://www.googleapis.com/oauth2/v2/userinfo';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $userinfo_url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $token_data['access_token']]);
|
||||
$userinfo_response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$userinfo = json_decode($userinfo_response, true);
|
||||
|
||||
if (!isset($userinfo['email'])) {
|
||||
// Log error: print_r($userinfo);
|
||||
header('Location: login.php?error=google_userinfo_failed');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_email = $userinfo['email'];
|
||||
$user_name = $userinfo['name'] ?? 'Google User';
|
||||
|
||||
// 3. Check if user exists in the database
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT u.*, r.name as role_name FROM users u JOIN roles r ON u.role_id = r.id WHERE u.email = ?");
|
||||
$stmt->execute([$user_email]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// 4. If user exists, log them in
|
||||
if ($user) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_name'] = $user['name'];
|
||||
$_SESSION['user_role_id'] = $user['role_id'];
|
||||
$_SESSION['user_role_name'] = $user['role_name'];
|
||||
$_SESSION['user_role'] = $user['role_name']; // Backwards compatibility
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 5. If user does not exist, create a new user with the "Employee" role
|
||||
$employee_role_id = 3; // Default to 'Employee' role (assuming ID 3)
|
||||
$stmt_role = $pdo->prepare("SELECT id FROM roles WHERE name = ?");
|
||||
$stmt_role->execute(['Employee']);
|
||||
$role_id_from_db = $stmt_role->fetchColumn();
|
||||
if ($role_id_from_db) {
|
||||
$employee_role_id = $role_id_from_db;
|
||||
}
|
||||
|
||||
// Generate a random password as it's required by the schema
|
||||
$random_password = password_hash(bin2hex(random_bytes(16)), PASSWORD_DEFAULT);
|
||||
|
||||
$insert_stmt = $pdo->prepare("INSERT INTO users (name, email, password, role_id) VALUES (?, ?, ?, ?)");
|
||||
$insert_stmt->execute([$user_name, $user_email, $random_password, $employee_role_id]);
|
||||
$new_user_id = $pdo->lastInsertId();
|
||||
|
||||
// Log the new user in
|
||||
$_SESSION['user_id'] = $new_user_id;
|
||||
$_SESSION['user_name'] = $user_name;
|
||||
$_SESSION['user_role_id'] = $employee_role_id;
|
||||
$_SESSION['user_role_name'] = 'Employee';
|
||||
$_SESSION['user_role'] = 'Employee';
|
||||
|
||||
header('Location: index.php?new_user=true');
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Log error: $e->getMessage();
|
||||
die('Database error during user processing. Please try again.');
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Fetch Google Client ID from settings
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT setting_value FROM settings WHERE setting_key = 'google_client_id'");
|
||||
$google_client_id = $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
die('Database error fetching Google Client ID. Please configure it in the settings.');
|
||||
}
|
||||
|
||||
if (empty($google_client_id)) {
|
||||
die('Google Client ID is not configured. Please ask an administrator to set it up.');
|
||||
}
|
||||
|
||||
$redirect_uri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/google-callback.php';
|
||||
|
||||
$auth_url = 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query([
|
||||
'client_id' => $google_client_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'response_type' => 'code',
|
||||
'scope' => 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
|
||||
'access_type' => 'offline',
|
||||
'prompt' => 'select_account'
|
||||
]);
|
||||
|
||||
header('Location: ' . $auth_url);
|
||||
exit;
|
||||
475
index.php
475
index.php
@ -1,341 +1,150 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
|
||||
// Store role name in session if not already set
|
||||
if (isset($_SESSION['user_role_id']) && !isset($_SESSION['user_role_name'])) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT name FROM roles WHERE id = :role_id");
|
||||
$stmt->execute([':role_id' => $_SESSION['user_role_id']]);
|
||||
$role = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($role) {
|
||||
$_SESSION['user_role_name'] = $role['name'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Could not fetch role name, do nothing, the check later will handle it
|
||||
}
|
||||
}
|
||||
|
||||
// Get allowed fields for the current user
|
||||
$allowed_fields_str = can($_SESSION['user_role_id'], 'asset', 'read');
|
||||
$allowed_fields = [];
|
||||
if ($allowed_fields_str === '*') {
|
||||
// Wildcard means all fields
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM assets");
|
||||
$allowed_fields = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
} catch (PDOException $e) {
|
||||
// Handle error, maybe log it
|
||||
$allowed_fields = [];
|
||||
}
|
||||
} elseif ($allowed_fields_str) {
|
||||
$allowed_fields = explode(',', $allowed_fields_str);
|
||||
}
|
||||
|
||||
// Function to count total assets
|
||||
function count_assets($search = '', $status = '') {
|
||||
$sql = "SELECT COUNT(*) FROM assets";
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
// Role-based filtering for 'Employee'
|
||||
if (isset($_SESSION['user_role_name']) && strtolower($_SESSION['user_role_name']) === 'employee' && isset($_SESSION['user_id'])) {
|
||||
$where[] = "assigned_to = :user_id";
|
||||
$params[':user_id'] = $_SESSION['user_id'];
|
||||
}
|
||||
|
||||
if (!empty($search)) {
|
||||
$where[] = "name LIKE :search";
|
||||
$params[':search'] = "%$search%";
|
||||
}
|
||||
|
||||
if (!empty($status)) {
|
||||
$where[] = "status = :status";
|
||||
$params[':status'] = $status;
|
||||
}
|
||||
|
||||
if (!empty($where)) {
|
||||
$sql .= " WHERE " . implode(' AND ', $where);
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to execute query and return results
|
||||
function get_assets($fields, $search = '', $status = '', $limit = 10, $offset = 0, $sort_by = 'created_at', $sort_order = 'DESC') {
|
||||
if (empty($fields)) {
|
||||
return []; // No read permission
|
||||
}
|
||||
// Always include id for edit/delete links
|
||||
if (!in_array('id', $fields)) {
|
||||
$fields[] = 'id';
|
||||
}
|
||||
|
||||
$select_fields = [];
|
||||
$join_users = in_array('assigned_to', $fields);
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if ($field === 'assigned_to') {
|
||||
// Use a different alias for the user name to avoid conflict with the original column name
|
||||
$select_fields[] = 'users.name AS assigned_to_name';
|
||||
}
|
||||
// Always select the original assigned_to field for reference if needed
|
||||
$select_fields[] = 'assets.' . $field;
|
||||
}
|
||||
|
||||
// Remove duplicates that might be caused by adding assets.id and assets.assigned_to
|
||||
$select_fields = array_unique($select_fields);
|
||||
|
||||
$select_fields_sql = implode(', ', $select_fields);
|
||||
|
||||
$sql = "SELECT $select_fields_sql FROM assets";
|
||||
|
||||
if ($join_users) {
|
||||
$sql .= " LEFT JOIN users ON assets.assigned_to = users.id";
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
// Role-based filtering for 'Employee'
|
||||
if (isset($_SESSION['user_role_name']) && strtolower($_SESSION['user_role_name']) === 'employee' && isset($_SESSION['user_id'])) {
|
||||
$where[] = "assets.assigned_to = :user_id";
|
||||
$params[':user_id'] = $_SESSION['user_id'];
|
||||
}
|
||||
|
||||
if (!empty($search)) {
|
||||
// Assuming 'name' is a field that can be searched.
|
||||
if (in_array('name', $fields)) {
|
||||
$where[] = "assets.name LIKE :search";
|
||||
$params[':search'] = "%$search%";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($status)) {
|
||||
if (in_array('status', $fields)) {
|
||||
$where[] = "assets.status = :status";
|
||||
$params[':status'] = $status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where)) {
|
||||
$sql .= " WHERE " . implode(' AND ', $where);
|
||||
}
|
||||
|
||||
// Whitelist sortable columns
|
||||
$sortable_columns = array_merge($fields, ['created_at']);
|
||||
if ($sort_by === 'assigned_to') {
|
||||
$sort_by = 'assigned_to_name'; // Sort by the alias
|
||||
} elseif (in_array($sort_by, $fields)) {
|
||||
$sort_by = 'assets.' . $sort_by;
|
||||
} elseif (!in_array($sort_by, $sortable_columns)) {
|
||||
$sort_by = 'assets.created_at';
|
||||
}
|
||||
|
||||
$sort_order = strtoupper($sort_order) === 'ASC' ? 'ASC' : 'DESC';
|
||||
|
||||
$sql .= " ORDER BY $sort_by $sort_order LIMIT :limit OFFSET :offset";
|
||||
$params[':limit'] = $limit;
|
||||
$params[':offset'] = $offset;
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare($sql);
|
||||
// Bind parameters separately to handle integer binding for LIMIT and OFFSET
|
||||
foreach ($params as $key => &$val) {
|
||||
if ($key === ':limit' || $key === ':offset') {
|
||||
$stmt->bindParam($key, $val, PDO::PARAM_INT);
|
||||
} else {
|
||||
$stmt->bindParam($key, $val);
|
||||
}
|
||||
}
|
||||
$stmt->execute();
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
$sort_by = $_GET['sort_by'] ?? 'created_at';
|
||||
$sort_order = $_GET['sort_order'] ?? 'DESC';
|
||||
|
||||
$total_assets = count_assets($search, $status);
|
||||
$total_pages = ceil($total_assets / $limit);
|
||||
|
||||
$assets = get_assets($allowed_fields, $search, $status, $limit, $offset, $sort_by, $sort_order);
|
||||
|
||||
function getStatusClass($status) {
|
||||
switch (strtolower($status)) {
|
||||
case 'in service':
|
||||
return 'status-in-service';
|
||||
case 'under repair':
|
||||
return 'status-under-repair';
|
||||
case 'retired':
|
||||
return 'status-retired';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>IC-Inventory</title>
|
||||
<meta name="description" content="Built with Flatlogic Generator">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Asset Dashboard</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role_id'], 'asset', 'create')): ?>
|
||||
<a href="add-asset.php" class="btn btn-primary">Add New Asset</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success']) && $_GET['success'] === 'asset_added'): ?>
|
||||
<div class="alert alert-success">Asset successfully added!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'asset_updated'): ?>
|
||||
<div class="alert alert-success">Asset successfully updated!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'asset_deleted'): ?>
|
||||
<div class="alert alert-success">Asset successfully deleted!</div>
|
||||
<?php elseif (isset($_GET['error']) && $_GET['error'] === 'access_denied'): ?>
|
||||
<div class="alert alert-danger">You do not have permission to access that page.</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<form method="get" class="row g-3 mb-4">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control" placeholder="Search by asset name..." value="<?php echo htmlspecialchars($search); ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select name="status" class="form-select">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="In Service" <?php echo ($status === 'In Service') ? 'selected' : ''; ?>>In Service</option>
|
||||
<option value="Under Repair" <?php echo ($status === 'Under Repair') ? 'selected' : ''; ?>>Under Repair</option>
|
||||
<option value="Retired" <?php echo ($status === 'Retired') ? 'selected' : ''; ?>>Retired</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php if (isset($assets['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($assets['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($assets)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No assets found.</h4>
|
||||
<?php if (can($_SESSION['user_role_id'], 'asset', 'create')): ?>
|
||||
<p>Get started by adding your first company asset.</p>
|
||||
<a href="add-asset.php" class="btn btn-primary">Add Asset</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
$new_sort_order = ($sort_order === 'DESC') ? 'ASC' : 'DESC';
|
||||
foreach ($allowed_fields as $field): if($field === 'id') continue;
|
||||
?>
|
||||
<th>
|
||||
<a href="?page=<?php echo $page; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $field; ?>&sort_order=<?php echo $new_sort_order; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $field)); ?>
|
||||
<?php if ($sort_by === $field): ?>
|
||||
<i data-feather="<?php echo ($sort_order === 'DESC') ? 'arrow-down' : 'arrow-up'; ?>"></i>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($assets as $asset): ?>
|
||||
<tr>
|
||||
<?php foreach ($allowed_fields as $field): if($field === 'id') continue; ?>
|
||||
<td>
|
||||
<?php if ($field === 'status'): ?>
|
||||
<span class="status <?php echo getStatusClass($asset[$field]); ?>"><?php echo htmlspecialchars($asset[$field]); ?></span>
|
||||
<?php elseif ($field === 'assigned_to'): ?>
|
||||
<?php echo htmlspecialchars($asset['assigned_to_name'] ?? ($asset['assigned_to'] ?? '')); ?>
|
||||
<?php else: ?>
|
||||
<?php echo htmlspecialchars($asset[$field] ?? ''); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role_id'], 'asset', 'update')): ?>
|
||||
<a href="edit-asset.php?id=<?php echo $asset['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'asset', 'delete')): ?>
|
||||
<a href="delete-asset.php?id=<?php echo $asset['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this asset?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
<?php if ($page > 1): ?>
|
||||
<li class="page-item"><a class="page-link" href="?page=<?php echo $page - 1; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>">Previous</a></li>
|
||||
<?php endif; ?>
|
||||
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
||||
<li class="page-item <?php echo ($i == $page) ? 'active' : ''; ?>"><a class="page-link" href="?page=<?php echo $i; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>"><?php echo $i; ?></a></li>
|
||||
<?php endfor; ?>
|
||||
<?php if ($page < $total_pages): ?>
|
||||
<li class="page-item"><a class="page-link" href="?page=<?php echo $page + 1; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>">Next</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
273
index.php.bak
273
index.php.bak
@ -1,273 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
// Get allowed fields for the current user
|
||||
$allowed_fields_str = can($_SESSION['user_role'], 'asset', 'read');
|
||||
$allowed_fields = $allowed_fields_str ? explode(',', $allowed_fields_str) : [];
|
||||
|
||||
// Function to count total assets
|
||||
function count_assets($search = '', $status = '') {
|
||||
$sql = "SELECT COUNT(*) FROM assets";
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
if (!empty($search)) {
|
||||
$where[] = "name LIKE :search";
|
||||
$params[':search'] = "%$search%";
|
||||
}
|
||||
|
||||
if (!empty($status)) {
|
||||
$where[] = "status = :status";
|
||||
$params[':status'] = $status;
|
||||
}
|
||||
|
||||
if (!empty($where)) {
|
||||
$sql .= " WHERE " . implode(' AND ', $where);
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetchColumn();
|
||||
} catch (PDOException $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to execute query and return results
|
||||
function get_assets($fields, $search = '', $status = '', $limit = 10, $offset = 0, $sort_by = 'created_at', $sort_order = 'DESC') {
|
||||
if (empty($fields)) {
|
||||
return []; // No read permission
|
||||
}
|
||||
// Always include id for edit/delete links
|
||||
if (!in_array('id', $fields)) {
|
||||
$fields[] = 'id';
|
||||
}
|
||||
|
||||
$select_fields = implode(', ', $fields);
|
||||
|
||||
$sql = "SELECT $select_fields FROM assets";
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
if (!empty($search)) {
|
||||
// Assuming 'name' is a field that can be searched.
|
||||
if (in_array('name', $fields)) {
|
||||
$where[] = "name LIKE :search";
|
||||
$params[':search'] = "%$search%";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($status)) {
|
||||
if (in_array('status', $fields)) {
|
||||
$where[] = "status = :status";
|
||||
$params[':status'] = $status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where)) {
|
||||
$sql .= " WHERE " . implode(' AND ', $where);
|
||||
}
|
||||
|
||||
// Whitelist sortable columns
|
||||
$sortable_columns = array_merge($fields, ['created_at']);
|
||||
if (!in_array($sort_by, $sortable_columns)) {
|
||||
$sort_by = 'created_at';
|
||||
}
|
||||
$sort_order = strtoupper($sort_order) === 'ASC' ? 'ASC' : 'DESC';
|
||||
|
||||
$sql .= " ORDER BY $sort_by $sort_order LIMIT :limit OFFSET :offset";
|
||||
$params[':limit'] = $limit;
|
||||
$params[':offset'] = $offset;
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare($sql);
|
||||
// Bind parameters separately to handle integer binding for LIMIT and OFFSET
|
||||
foreach ($params as $key => &$val) {
|
||||
if ($key === ':limit' || $key === ':offset') {
|
||||
$stmt->bindParam($key, $val, PDO::PARAM_INT);
|
||||
} else {
|
||||
$stmt->bindParam($key, $val);
|
||||
}
|
||||
}
|
||||
$stmt->execute();
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
$sort_by = $_GET['sort_by'] ?? 'created_at';
|
||||
$sort_order = $_GET['sort_order'] ?? 'DESC';
|
||||
|
||||
$total_assets = count_assets($search, $status);
|
||||
$total_pages = ceil($total_assets / $limit);
|
||||
|
||||
$assets = get_assets($allowed_fields, $search, $status, $limit, $offset, $sort_by, $sort_order);
|
||||
|
||||
function getStatusClass($status) {
|
||||
switch (strtolower($status)) {
|
||||
case 'in service':
|
||||
return 'status-in-service';
|
||||
case 'under repair':
|
||||
return 'status-under-repair';
|
||||
case 'retired':
|
||||
return 'status-retired';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>IC-Inventory</title>
|
||||
<meta name="description" content="Built with Flatlogic Generator">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Asset Dashboard</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role'], 'asset', 'create')): ?>
|
||||
<a href="add-asset.php" class="btn btn-primary">Add New Asset</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success']) && $_GET['success'] === 'asset_added'): ?>
|
||||
<div class="alert alert-success">Asset successfully added!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'asset_updated'): ?>
|
||||
<div class="alert alert-success">Asset successfully updated!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'asset_deleted'): ?>
|
||||
<div class="alert alert-success">Asset successfully deleted!</div>
|
||||
<?php elseif (isset($_GET['error']) && $_GET['error'] === 'access_denied'): ?>
|
||||
<div class="alert alert-danger">You do not have permission to access that page.</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<form method="get" class="row g-3 mb-4">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control" placeholder="Search by asset name..." value="<?php echo htmlspecialchars($search); ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select name="status" class="form-select">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="In Service" <?php echo ($status === 'In Service') ? 'selected' : ''; ?>>In Service</option>
|
||||
<option value="Under Repair" <?php echo ($status === 'Under Repair') ? 'selected' : ''; ?>>Under Repair</option>
|
||||
<option value="Retired" <?php echo ($status === 'Retired') ? 'selected' : ''; ?>>Retired</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php if (isset($assets['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($assets['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($assets)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No assets found.</h4>
|
||||
<?php if (can($_SESSION['user_role'], 'asset', 'create')): ?>
|
||||
<p>Get started by adding your first company asset.</p>
|
||||
<a href="add-asset.php" class="btn btn-primary">Add Asset</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
$new_sort_order = ($sort_order === 'DESC') ? 'ASC' : 'DESC';
|
||||
foreach ($allowed_fields as $field): if($field === 'id') continue;
|
||||
?>
|
||||
<th>
|
||||
<a href="?page=<?php echo $page; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $field; ?>&sort_order=<?php echo $new_sort_order; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $field)); ?>
|
||||
<?php if ($sort_by === $field): ?>
|
||||
<i data-feather="<?php echo ($sort_order === 'DESC') ? 'arrow-down' : 'arrow-up'; ?>"></i>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($assets as $asset): ?>
|
||||
<tr>
|
||||
<?php foreach ($allowed_fields as $field): if($field === 'id') continue; ?>
|
||||
<td>
|
||||
<?php if ($field === 'status'): ?>
|
||||
<span class="status <?php echo getStatusClass($asset[$field]); ?>"><?php echo htmlspecialchars($asset[$field]); ?></span>
|
||||
<?php else: ?>
|
||||
<?php echo htmlspecialchars($asset[$field] ?? ''); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role'], 'asset', 'update')): ?>
|
||||
<a href="edit-asset.php?id=<?php echo $asset['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role'], 'asset', 'delete')): ?>
|
||||
<a href="delete-asset.php?id=<?php echo $asset['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this asset?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
<?php if ($page > 1): ?>
|
||||
<li class="page-item"><a class="page-link" href="?page=<?php echo $page - 1; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>">Previous</a></li>
|
||||
<?php endif; ?>
|
||||
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
||||
<li class="page-item <?php echo ($i == $page) ? 'active' : ''; ?>"><a class="page-link" href="?page=<?php echo $i; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>"><?php echo $i; ?></a></li>
|
||||
<?php endfor; ?>
|
||||
<?php if ($page < $total_pages): ?>
|
||||
<li class="page-item"><a class="page-link" href="?page=<?php echo $page + 1; ?>&search=<?php echo urlencode($search); ?>&status=<?php echo urlencode($status); ?>&sort_by=<?php echo $sort_by; ?>&sort_order=<?php echo $sort_order; ?>">Next</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
118
locations.php
118
locations.php
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
// Permissions check
|
||||
if (!can($_SESSION['user_role_id'], 'location', 'read')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
function get_locations() {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM locations ORDER BY name ASC");
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$locations = get_locations();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Location Management - IC-Inventory</title>
|
||||
<meta name="description" content="Location management for IC-Inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Location Management</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role_id'], 'location', 'create')): ?>
|
||||
<a href="add-location.php" class="btn btn-primary">Add New Location</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php
|
||||
if ($_GET['success'] === 'location_added') echo 'Location successfully added!';
|
||||
if ($_GET['success'] === 'location_updated') echo 'Location successfully updated!';
|
||||
if ($_GET['success'] === 'location_deleted') echo 'Location successfully deleted!';
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if (isset($locations['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($locations['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($locations)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No locations found.</h4>
|
||||
<?php if (can($_SESSION['user_role_id'], 'location', 'create')): ?>
|
||||
<p>Get started by adding your first location.</p>
|
||||
<a href="add-location.php" class="btn btn-primary">Add Location</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($locations as $location): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($location['name']); ?></td>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role_id'], 'location', 'update')): ?>
|
||||
<a href="edit-location.php?id=<?php echo $location['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'location', 'delete')): ?>
|
||||
<a href="delete-location.php?id=<?php echo $location['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this location?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
97
login.php
97
login.php
@ -1,97 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
$error_message = '';
|
||||
|
||||
// If user is already logged in, redirect to dashboard
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$email = $_POST['email'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if (empty($email) || empty($password)) {
|
||||
$error_message = 'Please enter both email and password.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT u.*, r.name as role_name FROM users u JOIN roles r ON u.role_id = r.id WHERE u.email = ?");
|
||||
$stmt->execute([$email]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_name'] = $user['name'];
|
||||
$_SESSION['user_role_id'] = $user['role_id'];
|
||||
$_SESSION['user_role_name'] = $user['role_name'];
|
||||
// For backwards compatibility with old code expecting a role name
|
||||
$_SESSION['user_role'] = $user['role_name'];
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
} else {
|
||||
$error_message = 'Invalid email or password.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - IC-Inventory</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background-color: #f7f9fc;
|
||||
}
|
||||
.login-card {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="card login-card shadow-sm">
|
||||
<div class="card-body p-5">
|
||||
<h1 class="card-title text-center mb-4">IC-Inventory</h1>
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
<form action="login.php" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Login</button>
|
||||
</form>
|
||||
<div class="divider d-flex align-items-center my-4">
|
||||
<p class="text-center fw-bold mx-3 mb-0 text-muted">OR</p>
|
||||
</div>
|
||||
<a class="btn btn-danger w-100" href="google-login.php" role="button">
|
||||
<i class="fab fa-google me-2"></i>Sign in with Google
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
?>
|
||||
126
roles.php
126
roles.php
@ -1,126 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
// Permissions check
|
||||
if (!can($_SESSION['user_role_id'], 'role', 'read')) {
|
||||
// First, check if the user has permissions for this resource
|
||||
$user_role_id = $_SESSION['user_role'];
|
||||
$sql = "SELECT 1 FROM role_permissions WHERE role_id = :role_id AND resource = 'role' AND action = 'read'";
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute(['role_id' => $user_role_id]);
|
||||
if ($stmt->rowCount() == 0) {
|
||||
// If no permissions, redirect
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function get_roles() {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM roles ORDER BY name ASC");
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$roles = get_roles();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Role Management - IC-Inventory</title>
|
||||
<meta name="description" content="Role management for IC-Inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Role Management</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role_id'], 'role', 'create')): ?>
|
||||
<a href="add-role.php" class="btn btn-primary">Add New Role</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php
|
||||
if ($_GET['success'] === 'role_added') echo 'Role successfully added!';
|
||||
if ($_GET['success'] === 'role_updated') echo 'Role successfully updated!';
|
||||
if ($_GET['success'] === 'role_deleted') echo 'Role successfully deleted!';
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if (isset($roles['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($roles['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($roles)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No roles found.</h4>
|
||||
<?php if (can($_SESSION['user_role_id'], 'role', 'create')): ?>
|
||||
<p>Get started by adding your first role.</p>
|
||||
<a href="add-role.php" class="btn btn-primary">Add Role</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($roles as $role): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($role['name']); ?></td>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role_id'], 'role', 'update')): ?>
|
||||
<a href="edit-role.php?id=<?php echo $role['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'role', 'delete')): ?>
|
||||
<a href="delete-role.php?id=<?php echo $role['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this role?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// 1. Create migrations table if it doesn't exist
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS migrations (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
migration_file VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY (migration_file)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||
|
||||
// 2. Pre-populate with migrations that are known to have run already
|
||||
$known_migrations = [
|
||||
'001_create_assets_table.sql',
|
||||
'002_create_users_table.sql',
|
||||
'003_create_permissions_table.sql',
|
||||
'004_create_categories_table.sql',
|
||||
'005_add_category_id_to_assets.sql'
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT IGNORE INTO migrations (migration_file) VALUES (?)");
|
||||
foreach ($known_migrations as $migration) {
|
||||
$stmt->execute([$migration]);
|
||||
}
|
||||
|
||||
// 3. Get all migrations that have already been run
|
||||
$ran_migrations_stmt = $pdo->query("SELECT migration_file FROM migrations");
|
||||
$ran_migrations = $ran_migrations_stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
// 4. Get all available migration files
|
||||
$migration_files = glob('db/migrations/*.sql');
|
||||
sort($migration_files);
|
||||
|
||||
// 5. Determine which migrations to run
|
||||
$migrations_to_run = [];
|
||||
foreach ($migration_files as $file) {
|
||||
if (!in_array(basename($file), $ran_migrations)) {
|
||||
$migrations_to_run[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($migrations_to_run)) {
|
||||
echo "Database is already up to date.\n";
|
||||
} else {
|
||||
// 6. Run the new migrations
|
||||
foreach ($migrations_to_run as $file) {
|
||||
try {
|
||||
$sql = file_get_contents($file);
|
||||
if (empty(trim($sql))) {
|
||||
echo "Skipping empty migration file: $file\n";
|
||||
$stmt = $pdo->prepare("INSERT INTO migrations (migration_file) VALUES (?)");
|
||||
$stmt->execute([basename($file)]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$pdo->exec($sql);
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO migrations (migration_file) VALUES (?)");
|
||||
$stmt->execute([basename($file)]);
|
||||
|
||||
echo "Successfully ran migration: " . basename($file) . "\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo "Error running migration " . basename($file) . ": " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
echo "All new migrations ran successfully.\n";
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
241
settings.php
241
settings.php
@ -1,241 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
// Only Super Admins can manage settings
|
||||
$is_super_admin = ($_SESSION['user_role_id'] == 1);
|
||||
|
||||
if (!$is_super_admin) {
|
||||
// Redirect non-super-admins or users who can't update permissions
|
||||
if (!can($_SESSION['user_role_id'], 'permission', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
$pdo = db();
|
||||
|
||||
// Handle Google Settings form submission
|
||||
if ($is_super_admin && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_google_settings'])) {
|
||||
$google_client_id = $_POST['google_client_id'] ?? '';
|
||||
$google_client_secret = $_POST['google_client_secret'] ?? '';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare('UPDATE settings SET setting_value = ? WHERE setting_key = ?');
|
||||
$stmt->execute([$google_client_id, 'google_client_id']);
|
||||
$stmt->execute([$google_client_secret, 'google_client_secret']);
|
||||
$success_message = 'Google settings updated successfully!';
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Database error updating Google settings: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Permissions form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_permissions'])) {
|
||||
if (!can($_SESSION['user_role_id'], 'permission', 'update')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$permissions = $_POST['permissions'] ?? [];
|
||||
$stmt_roles = $pdo->query('SELECT id FROM roles');
|
||||
$db_roles_ids = $stmt_roles->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$delete_stmt = $pdo->prepare('DELETE FROM role_permissions WHERE role_id = ?');
|
||||
$insert_stmt = $pdo->prepare('INSERT INTO role_permissions (role_id, resource, action, fields) VALUES (?, ?, ?, ?)');
|
||||
|
||||
foreach ($db_roles_ids as $role_id) {
|
||||
$delete_stmt->execute([$role_id]);
|
||||
if (isset($permissions[$role_id])) {
|
||||
foreach (['asset', 'user', 'category', 'location', 'role', 'permission'] as $resource) {
|
||||
foreach (['create', 'read', 'update', 'delete'] as $action) {
|
||||
if (isset($permissions[$role_id][$resource][$action]['enabled']) && $permissions[$role_id][$resource][$action]['enabled'] == '1') {
|
||||
$fields = (in_array($action, ['read', 'update', 'create'])) ? ($permissions[$role_id][$resource][$action]['fields'] ?? '*') : null;
|
||||
if (empty($fields)) $fields = '*';
|
||||
$insert_stmt->execute([$role_id, $resource, $action, $fields]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
$success_message = 'Permissions updated successfully!';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
$error_message = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch data for display
|
||||
$google_settings = [];
|
||||
if ($is_super_admin) {
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT setting_key, setting_value FROM settings WHERE setting_key IN ('google_client_id', 'google_client_secret')");
|
||||
$google_settings_raw = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($google_settings_raw as $row) {
|
||||
$google_settings[$row['setting_key']] = $row['setting_value'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Database error fetching Google settings: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$roles_stmt = $pdo->query('SELECT * FROM roles ORDER BY name');
|
||||
$roles = $roles_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Database error fetching roles: " . $e->getMessage();
|
||||
$roles = [];
|
||||
}
|
||||
|
||||
$resources = ['asset', 'user', 'category', 'location', 'role', 'permission'];
|
||||
$actions = ['create', 'read', 'update', 'delete'];
|
||||
|
||||
function get_permissions() {
|
||||
try {
|
||||
$pdo_func = db();
|
||||
$stmt = $pdo_func->query('SELECT * FROM role_permissions ORDER BY role_id, resource, action');
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$permissions_from_db = get_permissions();
|
||||
$grouped_permissions = [];
|
||||
if (!isset($permissions_from_db['error'])) {
|
||||
foreach ($permissions_from_db as $p) {
|
||||
$grouped_permissions[$p['role_id']][$p['resource']][$p['action']] = $p['fields'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Settings - IC-Inventory</title>
|
||||
<meta name="description" content="Manage application settings, including Google OAuth and role permissions.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>Settings</h1>
|
||||
</div>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo htmlspecialchars($success_message); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($is_super_admin): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h3>Google OAuth 2.0 Settings</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>These credentials are required for Google Login. You can get them from the <a href="https://console.cloud.google.com/apis/credentials" target="_blank">Google Cloud Console</a>.</p>
|
||||
<p>The authorized redirect URI is: <code><?php echo htmlspecialchars(str_replace('settings.php', 'google-callback.php', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'])); ?></code></p>
|
||||
<form action="settings.php" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="google_client_id" class="form-label">Client ID</label>
|
||||
<input type="text" class="form-control" id="google_client_id" name="google_client_id" value="<?php echo htmlspecialchars($google_settings['google_client_id'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="google_client_secret" class="form-label">Client Secret</label>
|
||||
<input type="password" class="form-control" id="google_client_secret" name="google_client_secret" value="<?php echo htmlspecialchars($google_settings['google_client_secret'] ?? ''); ?>">
|
||||
</div>
|
||||
<button type="submit" name="save_google_settings" class="btn btn-primary">Save Google Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (can($_SESSION['user_role_id'], 'permission', 'update')): ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>Role Permissions</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="settings.php" method="post">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered permission-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Resource</th>
|
||||
<th>Create</th>
|
||||
<th>Read (Fields)</th>
|
||||
<th>Update (Fields)</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($roles as $role): ?>
|
||||
<?php foreach ($resources as $resource_idx => $resource): ?>
|
||||
<tr>
|
||||
<?php if ($resource_idx === 0): ?>
|
||||
<td rowspan="<?php echo count($resources); ?>" class="align-middle">
|
||||
<strong><?php echo htmlspecialchars($role['name']); ?></strong>
|
||||
<?php if ($role['id'] == 1): ?>
|
||||
<span class="badge bg-primary">Super Admin</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="align-middle"><?php echo ucfirst($resource); ?></td>
|
||||
|
||||
<?php foreach ($actions as $action):
|
||||
$is_checked = isset($grouped_permissions[$role['id']][$resource]) && array_key_exists($action, $grouped_permissions[$role['id']][$resource]);
|
||||
?>
|
||||
<td class="align-middle">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="permissions[<?php echo $role['id']; ?>][<?php echo $resource; ?>][<?php echo $action; ?>][enabled]" value="1" <?php echo $is_checked ? 'checked' : ''; ?>>
|
||||
</div>
|
||||
<?php if (in_array($action, ['read', 'update', 'create'])): ?>
|
||||
<input type="text" class="form-control form-control-sm mt-1" name="permissions[<?php echo $role['id']; ?>][<?php echo $resource; ?>][<?php echo $action; ?>][fields]" placeholder="* for all" value="<?php echo htmlspecialchars($grouped_permissions[$role['id']][$resource][$action] ?? '*'); ?>">
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button type="submit" name="save_permissions" class="btn btn-primary">Save Permissions</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
$current_page = basename($_SERVER['PHP_SELF']);
|
||||
?>
|
||||
<nav id="sidebar" class="d-flex flex-column flex-shrink-0 p-3">
|
||||
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-decoration-none">
|
||||
<span class="fs-4">IC-Inventory</span>
|
||||
</a>
|
||||
<hr>
|
||||
<ul class="nav nav-pills flex-column mb-auto">
|
||||
<li class="nav-item">
|
||||
<a href="index.php" class="nav-link <?php echo ($current_page === 'index.php') ? 'active' : ''; ?>" aria-current="page">
|
||||
<i data-feather="home" class="me-2"></i>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.php" class="nav-link <?php echo ($current_page === 'add-asset.php' || $current_page === 'edit-asset.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="box" class="me-2"></i>
|
||||
Assets
|
||||
</a>
|
||||
</li>
|
||||
<?php if (can($_SESSION['user_role_id'], 'user', 'read')): ?>
|
||||
<li>
|
||||
<a href="users.php" class="nav-link <?php echo ($current_page === 'users.php' || $current_page === 'add-user.php' || $current_page === 'edit-user.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="users" class="me-2"></i>
|
||||
Users
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'category', 'read')): ?>
|
||||
<li>
|
||||
<a href="categories.php" class="nav-link <?php echo ($current_page === 'categories.php' || $current_page === 'add-category.php' || $current_page === 'edit-category.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="grid" class="me-2"></i>
|
||||
Categories
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'location', 'read')): ?>
|
||||
<li>
|
||||
<a href="locations.php" class="nav-link <?php echo ($current_page === 'locations.php' || $current_page === 'add-location.php' || $current_page === 'edit-location.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="map-pin" class="me-2"></i>
|
||||
Locations
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'role', 'read')): ?>
|
||||
<li>
|
||||
<a href="roles.php" class="nav-link <?php echo ($current_page === 'roles.php' || $current_page === 'add-role.php' || $current_page === 'edit-role.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="shield" class="me-2"></i>
|
||||
Roles
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'permission', 'update')): ?>
|
||||
<li>
|
||||
<a href="settings.php" class="nav-link <?php echo ($current_page === 'settings.php') ? 'active' : ''; ?>">
|
||||
<i data-feather="settings" class="me-2"></i>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<hr>
|
||||
<div>
|
||||
<span class="d-flex align-items-center text-decoration-none"><strong><?php echo htmlspecialchars($_SESSION['user_name']); ?></strong></span>
|
||||
<a href="logout.php" class="d-flex align-items-center text-decoration-none">
|
||||
<i data-feather="log-out" class="me-2"></i>
|
||||
<strong>Logout</strong>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
165
users.php
165
users.php
@ -1,165 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'auth-check.php';
|
||||
require_once 'auth-helpers.php';
|
||||
|
||||
|
||||
|
||||
// Only Admins can access this page
|
||||
if (!can($_SESSION['user_role_id'], 'user', 'read')) {
|
||||
header('Location: index.php?error=access_denied');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get allowed fields for the current user
|
||||
$allowed_fields_str = can($_SESSION['user_role_id'], 'user', 'read');
|
||||
$allowed_fields = ($allowed_fields_str && $allowed_fields_str !== '*') ? explode(',', $allowed_fields_str) : [];
|
||||
|
||||
if ($allowed_fields_str === '*') {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM users");
|
||||
$columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
// Exclude sensitive fields like password
|
||||
$allowed_fields = array_diff($columns, ['password']);
|
||||
} catch (PDOException $e) {
|
||||
// Handle error, maybe default to a safe subset of fields
|
||||
$allowed_fields = ['id', 'name', 'email', 'role'];
|
||||
}
|
||||
}
|
||||
|
||||
function get_users($fields) {
|
||||
if (empty($fields)) {
|
||||
return []; // No read permission
|
||||
}
|
||||
|
||||
// Always include id for edit/delete links
|
||||
if (!in_array('id', $fields)) {
|
||||
$fields[] = 'id';
|
||||
}
|
||||
|
||||
// Replace role_id with a join to get the role name
|
||||
$select_parts = [];
|
||||
foreach ($fields as $field) {
|
||||
if ($field === 'role_id') {
|
||||
$select_parts[] = 'r.name as role_name';
|
||||
} else {
|
||||
$select_parts[] = 'u.' . $field;
|
||||
}
|
||||
}
|
||||
$select_fields = implode(', ', $select_parts);
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "SELECT $select_fields
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
ORDER BY u.created_at DESC";
|
||||
$stmt = $pdo->query($sql);
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
return ['error' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
$users = get_users($allowed_fields);
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>User Management - IC-Inventory</title>
|
||||
<meta name="description" content="User management for IC-Inventory.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/feather-icons"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<?php require_once 'templates/sidebar.php'; ?>
|
||||
|
||||
<main id="content">
|
||||
<div class="header">
|
||||
<h1>User Management</h1>
|
||||
<div>
|
||||
<?php if (can($_SESSION['user_role_id'], 'user', 'create')): ?>
|
||||
<a href="add-user.php" class="btn btn-primary">Add New User</a>
|
||||
<?php endif; ?>
|
||||
<div class="theme-switcher" id="theme-switcher">
|
||||
<i data-feather="moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success']) && $_GET['success'] === 'user_added'): ?>
|
||||
<div class="alert alert-success">User successfully added!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'user_updated'): ?>
|
||||
<div class="alert alert-success">User successfully updated!</div>
|
||||
<?php elseif (isset($_GET['success']) && $_GET['success'] === 'user_deleted'): ?>
|
||||
<div class="alert alert-success">User successfully deleted!</div>
|
||||
<?php elseif (isset($_GET['error']) && $_GET['error'] === 'self_delete'): ?>
|
||||
<div class="alert alert-danger">You cannot delete your own account.</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="surface p-4">
|
||||
<?php if (isset($users['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo htmlspecialchars($users['error']); ?>
|
||||
</div>
|
||||
<?php elseif (empty($users)): ?>
|
||||
<div class="text-center p-5">
|
||||
<h4>No users found.</h4>
|
||||
<?php if (can($_SESSION['user_role_id'], 'user', 'create')): ?>
|
||||
<p>Get started by adding your first user.</p>
|
||||
<a href="add-user.php" class="btn btn-primary">Add User</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach ($allowed_fields as $field): if($field === 'id') continue; ?>
|
||||
<th><?php echo ucfirst(str_replace('_', ' ', ($field === 'role_id' ? 'role' : $field))); ?></th>
|
||||
<?php endforeach; ?>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<?php foreach ($allowed_fields as $field): if($field === 'id') continue; ?>
|
||||
<td><?php echo htmlspecialchars($user[$field === 'role_id' ? 'role_name' : $field]); ?></td>
|
||||
<?php endforeach; ?>
|
||||
<td>
|
||||
<?php if (can($_SESSION['user_role_id'], 'user', 'update')): ?>
|
||||
<a href="edit-user.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<?php endif; ?>
|
||||
<?php if (can($_SESSION['user_role_id'], 'user', 'delete')): ?>
|
||||
<a href="delete-user.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this user?');">Delete</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user