Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8418da20d2 | ||
|
|
67d514f354 | ||
|
|
27345b3175 | ||
|
|
9fa23089ba | ||
|
|
7c1bf16409 | ||
|
|
d4e364826a |
79
all_requests.php
Normal file
79
all_requests.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'includes/helpers.php';
|
||||||
|
|
||||||
|
// Admin-only view
|
||||||
|
if ($_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: index.php"); // Redirect non-admins
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'All Change Requests';
|
||||||
|
|
||||||
|
// Fetch all requests from the database
|
||||||
|
try {
|
||||||
|
$pdoconn = db();
|
||||||
|
$stmt = $pdoconn->prepare('SELECT cr.*, u.username as requester_name, cr.related_cr_no FROM change_requests cr JOIN users u ON cr.requester_id = u.id ORDER BY cr.created_at DESC');
|
||||||
|
$stmt->execute();
|
||||||
|
$requests = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$requests = [];
|
||||||
|
error_log("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><?= htmlspecialchars($pageTitle) ?></title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2>All Submitted Requests</h2>
|
||||||
|
<hr>
|
||||||
|
<?php if (empty($requests)): ?>
|
||||||
|
<div class="alert alert-info">No requests have been submitted yet.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Related CR No.</th>
|
||||||
|
<th>Change Title</th>
|
||||||
|
<th>Requester</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Submitted On</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($requests as $request): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($request['id']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['related_cr_no']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['change_title']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['requester_name']) ?></td>
|
||||||
|
<td><?= displayStatusBadge($request['status']) ?></td>
|
||||||
|
<td><?= htmlspecialchars(date('Y-m-d H:i', strtotime($request['created_at']))) ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="view_request.php?id=<?= $request['id'] ?>" class="btn btn-sm btn-primary">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
assets/css/custom.css
Normal file
39
assets/css/custom.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
body {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 2rem;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 2px solid #0d6efd;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-history-table th,
|
||||||
|
.approval-history-table td {
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stamp-cell {
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
BIN
assets/pasted-20251205-060902-d519a095.png
Normal file
BIN
assets/pasted-20251205-060902-d519a095.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
47
auth.php
Normal file
47
auth.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$username = $_POST['username'] ?? '';
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
if (empty($username) || empty($password)) {
|
||||||
|
$_SESSION['error_message'] = 'Please enter both username and password.';
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
|
||||||
|
$stmt->execute([':username' => $username]);
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($user && password_verify($password, $user['password'])) {
|
||||||
|
// Password is correct, start session
|
||||||
|
session_regenerate_id(); // Prevents session fixation
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['username'] = $user['username'];
|
||||||
|
$_SESSION['role'] = $user['role'];
|
||||||
|
$_SESSION['full_name'] = $user['full_name'];
|
||||||
|
$_SESSION['department'] = $user['department'];
|
||||||
|
|
||||||
|
header("Location: index.php");
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_message'] = 'Invalid username or password.';
|
||||||
|
header("Location: login.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// In a real app, you'd log this error
|
||||||
|
// error_log("Login error: " . $e->getMessage());
|
||||||
|
$_SESSION['error_message'] = 'A database error occurred. Please try again later.';
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
10
auth_check.php
Normal file
10
auth_check.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user is not logged in, redirect to login page
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: login.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
110
create_user.php
Normal file
110
create_user.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$username = trim($_POST['username']);
|
||||||
|
$password = $_POST['password'];
|
||||||
|
$full_name = trim($_POST['full_name']);
|
||||||
|
$department = trim($_POST['department']);
|
||||||
|
$position = trim($_POST['position']);
|
||||||
|
$role = $_POST['role'];
|
||||||
|
|
||||||
|
if (empty($username) || empty($password) || empty($role)) {
|
||||||
|
$error = 'Username, password and role are required.';
|
||||||
|
} else {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = :username');
|
||||||
|
$stmt->execute(['username' => $username]);
|
||||||
|
if ($stmt->fetch()) {
|
||||||
|
$error = 'Username already exists.';
|
||||||
|
} else {
|
||||||
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO users (username, password, full_name, department, position, role) VALUES (:username, :password, :full_name, :department, :position, :role)');
|
||||||
|
$params = [
|
||||||
|
'username' => $username,
|
||||||
|
'password' => $hashed_password,
|
||||||
|
'full_name' => $full_name,
|
||||||
|
'department' => $department,
|
||||||
|
'position' => $position,
|
||||||
|
'role' => $role
|
||||||
|
];
|
||||||
|
if ($stmt->execute($params)) {
|
||||||
|
$success = 'User created successfully.';
|
||||||
|
} else {
|
||||||
|
$error = 'Failed to create user.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2>Create User</h2>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($success): ?>
|
||||||
|
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="create_user.php" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" name="username" class="form-control" id="username" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_name">Full Name</label>
|
||||||
|
<input type="text" name="full_name" class="form-control" id="full_name">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="department">Department</label>
|
||||||
|
<select name="department" class="form-control" id="department">
|
||||||
|
<option value="RSS JP Sales">RSS JP Sales</option>
|
||||||
|
<option value="RSS EA Sales">RSS EA Sales</option>
|
||||||
|
<option value="RSI Sales">RSI Sales</option>
|
||||||
|
<option value="RSM Sales">RSM Sales</option>
|
||||||
|
<option value="RSP Sales">RSP Sales</option>
|
||||||
|
<option value="RSS ACC">RSS ACC</option>
|
||||||
|
<option value="RSS HRADM">RSS HRADM</option>
|
||||||
|
<option value="RSS WH">RSS WH</option>
|
||||||
|
<option value="RSS SA">RSS SA</option>
|
||||||
|
<option value="RSS IT">RSS IT</option>
|
||||||
|
<option value="RSS QA">RSS QA</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="position">Position</label>
|
||||||
|
<input type="text" name="position" class="form-control" id="position">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="password" class="form-control" id="password" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="role">Role</label>
|
||||||
|
<select name="role" class="form-control" id="role">
|
||||||
|
<option value="Requestor">Requestor</option>
|
||||||
|
<option value="Approver">Approver</option>
|
||||||
|
<option value="admin">Admin</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Create User</button>
|
||||||
|
<a href="manage_users.php" class="btn btn-secondary">Back to Manage Users</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
23
db/migrate.php
Normal file
23
db/migrate.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
echo "Connected to database successfully.\n";
|
||||||
|
|
||||||
|
$migration_files = glob(__DIR__ . '/migrations/*.sql');
|
||||||
|
sort($migration_files);
|
||||||
|
|
||||||
|
foreach ($migration_files as $file) {
|
||||||
|
echo "Applying migration: " . basename($file) . "...\n";
|
||||||
|
$sql = file_get_contents($file);
|
||||||
|
$pdo->exec($sql);
|
||||||
|
echo "Applied successfully.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "All migrations applied.\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Database error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
16
db/migrations/001_create_change_requests_table.sql
Normal file
16
db/migrations/001_create_change_requests_table.sql
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `change_requests` (
|
||||||
|
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
`request_date` DATE,
|
||||||
|
`requester_dept` VARCHAR(255),
|
||||||
|
`requester_name` VARCHAR(255),
|
||||||
|
`requester_ext` VARCHAR(50),
|
||||||
|
`related_request_no` VARCHAR(255),
|
||||||
|
`system_name` VARCHAR(255),
|
||||||
|
`program_name` VARCHAR(255),
|
||||||
|
`change_category` VARCHAR(50),
|
||||||
|
`reason_for_change` TEXT,
|
||||||
|
`description_of_change` TEXT,
|
||||||
|
`status` VARCHAR(50) DEFAULT 'draft',
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
11
db/migrations/002_create_users_table.sql
Normal file
11
db/migrations/002_create_users_table.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- 002_create_users_table.sql
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
username VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
full_name VARCHAR(100),
|
||||||
|
department VARCHAR(100),
|
||||||
|
position VARCHAR(100),
|
||||||
|
role ENUM('requester', 'approver', 'admin') NOT NULL DEFAULT 'requester',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
-- 003_add_requester_id_to_change_requests.sql
|
||||||
|
ALTER TABLE change_requests
|
||||||
|
ADD COLUMN requester_id INT NULL,
|
||||||
|
ADD CONSTRAINT fk_requester_id
|
||||||
|
FOREIGN KEY (requester_id)
|
||||||
|
REFERENCES users(id)
|
||||||
|
ON DELETE SET NULL;
|
||||||
8
db/migrations/004_update_change_requests_table.sql
Normal file
8
db/migrations/004_update_change_requests_table.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-- Add change_title and admin_comment columns
|
||||||
|
ALTER TABLE `change_requests`
|
||||||
|
ADD COLUMN `change_title` VARCHAR(255) NOT NULL AFTER `program_name`,
|
||||||
|
ADD COLUMN `admin_comment` TEXT AFTER `description_of_change`;
|
||||||
|
|
||||||
|
-- Modify status column
|
||||||
|
ALTER TABLE `change_requests`
|
||||||
|
MODIFY COLUMN `status` ENUM('Pending', 'Approved', 'In Development', 'Completed', 'Rejected') NOT NULL DEFAULT 'Pending';
|
||||||
6
db/migrations/005_add_fields_to_users_table.sql
Normal file
6
db/migrations/005_add_fields_to_users_table.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
-- Add full_name, department, position, and role to the users table
|
||||||
|
ALTER TABLE `users`
|
||||||
|
ADD COLUMN `full_name` VARCHAR(255) NULL,
|
||||||
|
ADD COLUMN `department` VARCHAR(255) NULL,
|
||||||
|
ADD COLUMN `position` VARCHAR(255) NULL,
|
||||||
|
ADD COLUMN `role` VARCHAR(255) NULL;
|
||||||
49
db/seed_users.php
Normal file
49
db/seed_users.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
// Default users
|
||||||
|
$users = [
|
||||||
|
[
|
||||||
|
'username' => 'admin',
|
||||||
|
'password' => password_hash('admin_password', PASSWORD_DEFAULT),
|
||||||
|
'full_name' => 'Admin User',
|
||||||
|
'department' => 'RSS SA',
|
||||||
|
'position' => 'System Administrator',
|
||||||
|
'role' => 'admin'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'username' => 'requester',
|
||||||
|
'password' => password_hash('requester_password', PASSWORD_DEFAULT),
|
||||||
|
'full_name' => 'Regular User',
|
||||||
|
'department' => 'RSS JP Sales',
|
||||||
|
'position' => 'Sales Rep',
|
||||||
|
'role' => 'requester'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"INSERT INTO users (username, password, full_name, department, position, role)
|
||||||
|
VALUES (:username, :password, :full_name, :department, :position, :role)
|
||||||
|
ON DUPLICATE KEY UPDATE password=VALUES(password), full_name=VALUES(full_name), role=VALUES(role);"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$stmt->execute([
|
||||||
|
':username' => $user['username'],
|
||||||
|
':password' => $user['password'],
|
||||||
|
':full_name' => $user['full_name'],
|
||||||
|
':department' => $user['department'],
|
||||||
|
':position' => $user['position'],
|
||||||
|
':role' => $user['role']
|
||||||
|
]);
|
||||||
|
echo "User '{$user['username']}' seeded successfully.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Error seeding users: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
36
delete_user.php
Normal file
36
delete_user.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_GET['id'] ?? null;
|
||||||
|
if (!$user_id) {
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent admin from deleting their own account
|
||||||
|
if ($user_id == $_SESSION['user_id']) {
|
||||||
|
$_SESSION['error_message'] = 'You cannot delete your own account.';
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdoconfig = db();
|
||||||
|
$pdo = new PDO($pdoconfig['dsn'], $pdoconfig['user'], $pdoconfig['pass'], $pdoconfig['options']);
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('DELETE FROM users WHERE id = :id');
|
||||||
|
if ($stmt->execute(['id' => $user_id])) {
|
||||||
|
$_SESSION['success_message'] = 'User deleted successfully.';
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_message'] = 'Failed to delete user.';
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
126
edit_user.php
Normal file
126
edit_user.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_GET['id'] ?? null;
|
||||||
|
if (!$user_id) {
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$username = trim($_POST['username']);
|
||||||
|
$full_name = trim($_POST['full_name']);
|
||||||
|
$department = trim($_POST['department']);
|
||||||
|
$position = trim($_POST['position']);
|
||||||
|
$role = $_POST['role'];
|
||||||
|
$password = $_POST['password'];
|
||||||
|
|
||||||
|
if (empty($username) || empty($role)) {
|
||||||
|
$error = 'Username and role are required.';
|
||||||
|
} else {
|
||||||
|
$sql = 'UPDATE users SET username = :username, full_name = :full_name, department = :department, position = :position, role = :role';
|
||||||
|
$params = [
|
||||||
|
'username' => $username,
|
||||||
|
'full_name' => $full_name,
|
||||||
|
'department' => $department,
|
||||||
|
'position' => $position,
|
||||||
|
'role' => $role,
|
||||||
|
'id' => $user_id
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($password)) {
|
||||||
|
$sql .= ', password = :password';
|
||||||
|
$params['password'] = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= ' WHERE id = :id';
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
if ($stmt->execute($params)) {
|
||||||
|
$success = 'User updated successfully.';
|
||||||
|
} else {
|
||||||
|
$error = 'Failed to update user.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT username, full_name, department, position, role FROM users WHERE id = :id');
|
||||||
|
$stmt->execute(['id' => $user_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2>Edit User</h2>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($success): ?>
|
||||||
|
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_user.php?id=<?php echo $user_id; ?>" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" name="username" class="form-control" id="username" value="<?php echo htmlspecialchars($user['username']); ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_name">Full Name</label>
|
||||||
|
<input type="text" name="full_name" class="form-control" id="full_name" value="<?php echo htmlspecialchars($user['full_name'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="department">Department</label>
|
||||||
|
<select name="department" class="form-control" id="department">
|
||||||
|
<?php
|
||||||
|
$departments = [
|
||||||
|
"RSS JP Sales", "RSS EA Sales", "RSI Sales", "RSM Sales", "RSP Sales",
|
||||||
|
"RSS ACC", "RSS HRADM", "RSS WH", "RSS SA", "RSS IT", "RSS QA"
|
||||||
|
];
|
||||||
|
foreach ($departments as $dept) {
|
||||||
|
$selected = ($user['department'] === $dept) ? 'selected' : '';
|
||||||
|
echo "<option value=\"$dept\" $selected>" . htmlspecialchars($dept) . "</option>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="position">Position</label>
|
||||||
|
<input type="text" name="position" class="form-control" id="position" value="<?php echo htmlspecialchars($user['position'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password">Password (leave blank to keep current password)</label>
|
||||||
|
<input type="password" name="password" class="form-control" id="password">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="role">Role</label>
|
||||||
|
<select name="role" class="form-control" id="role">
|
||||||
|
<option value="Requestor" <?php echo ($user['role'] === 'Requestor') ? 'selected' : ''; ?>>Requestor</option>
|
||||||
|
<option value="Approver" <?php echo ($user['role'] === 'Approver') ? 'selected' : ''; ?>>Approver</option>
|
||||||
|
<option value="Admin" <?php echo ($user['role'] === 'Admin') ? 'selected' : ''; ?>>Admin</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Update User</button>
|
||||||
|
<a href="manage_users.php" class="btn btn-secondary">Back to Manage Users</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
6
footer.php
Normal file
6
footer.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
</div>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
69
header.php
Normal file
69
header.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
$is_logged_in = isset($_SESSION["user_id"]);
|
||||||
|
$username = $is_logged_in ? $_SESSION["username"] : "";
|
||||||
|
$is_admin = $is_logged_in && $_SESSION['role'] === 'admin';
|
||||||
|
$page_title = basename($_SERVER['PHP_SELF'], '.php');
|
||||||
|
$page_title = str_replace('_', ' ', $page_title);
|
||||||
|
$page_title = ucwords($page_title);
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<title><?php echo $page_title; ?> - Change Request System</title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Change Request System</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav mr-auto">
|
||||||
|
<?php if ($is_logged_in): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="index.php">Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="request_form.php">New Request</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="my_requests.php">My Requests</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="search.php">Search</a>
|
||||||
|
</li>
|
||||||
|
<?php if ($is_admin): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="all_requests.php">All Requests</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="manage_users.php">Manage Users</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<?php if ($is_logged_in): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<span class="navbar-text">Welcome, <?= htmlspecialchars($username) ?></span>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item ml-2">
|
||||||
|
<a href="logout.php" class="btn btn-outline-danger">Logout</a>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="login.php" class="btn btn-primary">Login</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
22
includes/helpers.php
Normal file
22
includes/helpers.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
function displayStatusBadge($status) {
|
||||||
|
$badgeClass = 'badge-secondary'; // Default
|
||||||
|
switch ($status) {
|
||||||
|
case 'Pending':
|
||||||
|
$badgeClass = 'badge-warning';
|
||||||
|
break;
|
||||||
|
case 'Approved':
|
||||||
|
$badgeClass = 'badge-success';
|
||||||
|
break;
|
||||||
|
case 'In Development':
|
||||||
|
$badgeClass = 'badge-primary';
|
||||||
|
break;
|
||||||
|
case 'Completed':
|
||||||
|
$badgeClass = 'badge-dark';
|
||||||
|
break;
|
||||||
|
case 'Rejected':
|
||||||
|
$badgeClass = 'badge-danger';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return '<span class="badge badge-pill ' . $badgeClass . '">' . htmlspecialchars(ucfirst($status)) . '</span>';
|
||||||
|
}
|
||||||
165
index.php
165
index.php
@ -1,150 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
require_once __DIR__ . '/auth_check.php';
|
||||||
@ini_set('display_errors', '1');
|
$pageTitle = "Dashboard";
|
||||||
@error_reporting(E_ALL);
|
|
||||||
@date_default_timezone_set('UTC');
|
|
||||||
|
|
||||||
$phpVersion = PHP_VERSION;
|
|
||||||
$now = date('Y-m-d H:i:s');
|
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>New Style</title>
|
<title><?= htmlspecialchars($pageTitle) ?></title>
|
||||||
<?php
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
// Read project preview data from environment
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
$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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<?php include 'header.php'; ?>
|
||||||
<div class="card">
|
|
||||||
<h1>Analyzing your requirements and generating your website…</h1>
|
<div class="container mt-5">
|
||||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
<div class="card">
|
||||||
<span class="sr-only">Loading…</span>
|
<div class="card-body">
|
||||||
</div>
|
<h1 class="card-title">Dashboard</h1>
|
||||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
<p>Welcome to your Approval Workflow Application.</p>
|
||||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
<a href="request_form.php" class="btn btn-primary">Create New Request</a>
|
||||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
<a href="my_requests.php" class="btn btn-secondary">View My Requests</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
|
||||||
<footer>
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
</footer>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
66
login.php
Normal file
66
login.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// If user is already logged in, redirect to index.php
|
||||||
|
if (isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: index.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$error_message = '';
|
||||||
|
if (isset($_SESSION['error_message'])) {
|
||||||
|
$error_message = $_SESSION['error_message'];
|
||||||
|
unset($_SESSION['error_message']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Login</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<div class="card mt-5">
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title text-center mb-4">Login</h3>
|
||||||
|
|
||||||
|
<?php if ($error_message): ?>
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<?php echo htmlspecialchars($error_message); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="auth.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">Username</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" 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>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-center">
|
||||||
|
<p class="text-muted small mb-0">Default users:</p>
|
||||||
|
<p class="text-muted small mb-0">admin / admin_password</p>
|
||||||
|
<p class="text-muted small mb-0">requester / requester_password</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
logout.php
Normal file
21
logout.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// Unset all of the session variables.
|
||||||
|
$_SESSION = array();
|
||||||
|
|
||||||
|
// If it's desired to kill the session, also delete the session cookie.
|
||||||
|
if (ini_get("session.use_cookies")) {
|
||||||
|
$params = session_get_cookie_params();
|
||||||
|
setcookie(session_name(), '', time() - 42000,
|
||||||
|
$params["path"], $params["domain"],
|
||||||
|
$params["secure"], $params["httponly"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, destroy the session.
|
||||||
|
session_destroy();
|
||||||
|
|
||||||
|
// Redirect to login page
|
||||||
|
header("Location: login.php");
|
||||||
|
exit();
|
||||||
84
manage_users.php
Normal file
84
manage_users.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'includes/helpers.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$users = $pdo->query('SELECT id, username, role FROM users')->fetchAll();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Manage Users</h2>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
if (isset($_SESSION['upload_success']) && $_SESSION['upload_success']) {
|
||||||
|
echo '<div class="alert alert-success">' . $_SESSION['upload_success'] . '</div>';
|
||||||
|
unset($_SESSION['upload_success']);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION['upload_error']) && $_SESSION['upload_error']) {
|
||||||
|
echo '<div class="alert alert-danger">' . $_SESSION['upload_error'] . '</div>';
|
||||||
|
unset($_SESSION['upload_error']);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION['success_message']) && $_SESSION['success_message']) {
|
||||||
|
echo '<div class="alert alert-success">' . $_SESSION['success_message'] . '</div>';
|
||||||
|
unset($_SESSION['success_message']);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION['error_message']) && $_SESSION['error_message']) {
|
||||||
|
echo '<div class="alert alert-danger">' . $_SESSION['error_message'] . '</div>';
|
||||||
|
unset($_SESSION['error_message']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">Create Users</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<a href="create_user.php" class="btn btn-success">Create Single User</a>
|
||||||
|
<hr>
|
||||||
|
<h5>Upload CSV to Create Users</h5>
|
||||||
|
<form action="upload_users_csv.php" method="post" enctype="multipart/form-data">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="csv_file">Select CSV file</label>
|
||||||
|
<input type="file" name="csv_file" class="form-control-file" id="csv_file" accept=".csv" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Upload and Create</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Existing Users</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($users as $user): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($user['role']); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="edit_user.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-warning">Edit</a>
|
||||||
|
<a href="delete_user.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this user?');">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php include 'footer.php'; // Assuming you have a footer file ?>
|
||||||
71
my_requests.php
Normal file
71
my_requests.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'includes/helpers.php';
|
||||||
|
|
||||||
|
$pageTitle = 'My Change Requests';
|
||||||
|
$userId = $_SESSION['user_id'];
|
||||||
|
|
||||||
|
// Fetch requests for the logged-in user
|
||||||
|
try {
|
||||||
|
$pdoconn = db();
|
||||||
|
$stmt = $pdoconn->prepare('SELECT id, change_title, related_cr_no, status, created_at FROM change_requests WHERE requester_id = :requester_id ORDER BY created_at DESC');
|
||||||
|
$stmt->bindParam(':requester_id', $userId, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$requests = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Handle DB error
|
||||||
|
$requests = [];
|
||||||
|
error_log("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><?= htmlspecialchars($pageTitle) ?></title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'header.php'; // Use a shared header ?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2>My Submitted Requests</h2>
|
||||||
|
<hr>
|
||||||
|
<?php if (empty($requests)): ?>
|
||||||
|
<div class="alert alert-info">You have not submitted any requests yet.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Change Title</th>
|
||||||
|
<th>Related CR No.</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Submitted On</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($requests as $request): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($request['id']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['change_title']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['related_cr_no'] ?? 'N/A') ?></td>
|
||||||
|
<td><?= displayStatusBadge($request['status']) ?></td>
|
||||||
|
<td><?= htmlspecialchars(date('Y-m-d H:i', strtotime($request['created_at']))) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
|
<a href="request_form.php" class="btn btn-primary">Submit New Request</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
155
request_form.php
Normal file
155
request_form.php
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/auth_check.php';
|
||||||
|
|
||||||
|
$pageTitle = "Program Change Request Form";
|
||||||
|
$username = $_SESSION['username'] ?? 'User';
|
||||||
|
$full_name = $_SESSION['full_name'] ?? '';
|
||||||
|
$department = $_SESSION['department'] ?? '';
|
||||||
|
|
||||||
|
// Autogenerate Related Change Request No.
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$year = date('Y');
|
||||||
|
$month = date('m');
|
||||||
|
|
||||||
|
$prefix = "$department/$year/$month/";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT related_request_no FROM change_requests WHERE related_request_no LIKE ? ORDER BY related_request_no DESC LIMIT 1");
|
||||||
|
$stmt->execute([$prefix . '%']);
|
||||||
|
$lastRequest = $stmt->fetch();
|
||||||
|
|
||||||
|
$running_no = 1;
|
||||||
|
if ($lastRequest) {
|
||||||
|
$last_no = (int)substr($lastRequest['related_request_no'], strlen($prefix));
|
||||||
|
$running_no = $last_no + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$related_request_no = $prefix . str_pad($running_no, 3, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?= htmlspecialchars($pageTitle) ?></title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-3">
|
||||||
|
<?php if (isset($_SESSION['success_message'])): ?>
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<?= htmlspecialchars($_SESSION['success_message']); ?>
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php unset($_SESSION['success_message']); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_SESSION['error_message'])): ?>
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<?= htmlspecialchars($_SESSION['error_message']); ?>
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php unset($_SESSION['error_message']); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container form-container">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="section-title">Program Change Request / プログラム作成・変更依頼書</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="submit_request.php" method="POST">
|
||||||
|
<!-- Requester Info -->
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="requestDate" class="form-label">Request Date / 依頼日</label>
|
||||||
|
<input type="date" class="form-control" id="requestDate" name="request_date" value="<?= date('Y-m-d'); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="relatedRequestNo" class="form-label">Related Change Request No. / 関連依頼No.</label>
|
||||||
|
<input type="text" class="form-control" id="relatedRequestNo" name="related_request_no" value="<?= htmlspecialchars($related_request_no); ?>" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="requesterDept" class="form-label">Department / 所属</label>
|
||||||
|
<input type="text" class="form-control" id="requesterDept" name="requester_dept" value="<?= htmlspecialchars($department); ?>" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="requesterName" class="form-label">Requester Name / 依頼者氏名</label>
|
||||||
|
<input type="text" class="form-control" id="requesterName" name="requester_name" value="<?= htmlspecialchars($full_name); ?>" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="requesterTel" class="form-label">TEL</label>
|
||||||
|
<input type="text" class="form-control" id="requesterTel" name="requester_ext">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Change Details -->
|
||||||
|
<div class="form-section">
|
||||||
|
<h2 class="section-title">Change Details / 変更内容</h2>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="systemName" class="form-label">System Name / システム名</label>
|
||||||
|
<input type="text" class="form-control" id="systemName" name="system_name">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="programName" class="form-label">Program Name / プログラム名</label>
|
||||||
|
<input type="text" class="form-control" id="programName" name="program_name">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label for="changeTitle" class="form-label">Change Title / 変更の件名</label>
|
||||||
|
<input type="text" class="form-control" id="changeTitle" name="change_title">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Change Category / 作成・変更区分</label>
|
||||||
|
<div>
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input class="form-check-input" type="radio" name="change_category" id="newProgram" value="New" checked>
|
||||||
|
<label class="form-check-label" for="newProgram">New / 新規</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input class="form-check-input" type="radio" name="change_category" id="modifyProgram" value="Modification">
|
||||||
|
<label class="form-check-label" for="modifyProgram">Modification / 変更</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input class="form-check-input" type="radio" name="change_category" id="bugFix" value="Bug Fix">
|
||||||
|
<label class="form-check-label" for="bugFix">Bug Fix / 不具合</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="reasonForChange" class="form-label">Reason for Change / 理由</label>
|
||||||
|
<textarea class="form-control" id="reasonForChange" name="reason_for_change" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="descriptionOfChange" class="form-label">Description of Change / 内容</label>
|
||||||
|
<textarea class="form-control" id="descriptionOfChange" name="description_of_change" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="submit" name="submit_action" value="Submit" class="btn btn-primary">Submit / 提出</button>
|
||||||
|
<button type="submit" name="submit_action" value="Draft" class="btn btn-secondary">Save as Draft / 下書き保存</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
search.php
Normal file
87
search.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'includes/helpers.php';
|
||||||
|
|
||||||
|
$pageTitle = 'Search Requests';
|
||||||
|
$searchTerm = filter_input(INPUT_GET, 'q', FILTER_SANITIZE_STRING);
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
if ($searchTerm) {
|
||||||
|
try {
|
||||||
|
$pdoconn = db();
|
||||||
|
$stmt = $pdoconn->prepare("SELECT cr.*, u.username as requester_name FROM change_requests cr JOIN users u ON cr.requester_id = u.id WHERE cr.program_name LIKE :term OR cr.system_name LIKE :term ORDER BY cr.created_at DESC");
|
||||||
|
$stmt->bindValue(':term', '%' . $searchTerm . '%', PDO::PARAM_STR);
|
||||||
|
$stmt->execute();
|
||||||
|
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$results = [];
|
||||||
|
error_log("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><?= htmlspecialchars($pageTitle) ?></title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2>Search Change Requests</h2>
|
||||||
|
<hr>
|
||||||
|
<form action="search.php" method="GET" class="mb-4">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="q" class="form-control" placeholder="Search by Program or System Name..." value="<?= htmlspecialchars($searchTerm) ?>">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button type="submit" class="btn btn-primary">Search</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php if ($searchTerm): ?>
|
||||||
|
<h3>Results for "<?= htmlspecialchars($searchTerm) ?>"</h3>
|
||||||
|
<?php if (empty($results)): ?>
|
||||||
|
<div class="alert alert-info">No requests found matching your search term.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Change Title</th>
|
||||||
|
<th>Requester</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Submitted On</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($results as $request): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($request['id']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['change_title']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($request['requester_name']) ?></td>
|
||||||
|
<td><?= displayStatusBadge($request['status']) ?></td>
|
||||||
|
<td><?= htmlspecialchars(date('Y-m-d H:i', strtotime($request['created_at']))) ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="view_request.php?id=<?= $request['id'] ?>" class="btn btn-sm btn-primary">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.b.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
72
submit_request.php
Normal file
72
submit_request.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: request_form.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$status = 'Pending';
|
||||||
|
|
||||||
|
$requester_id = $_SESSION['user_id'] ?? null;
|
||||||
|
|
||||||
|
$sql = "INSERT INTO change_requests (
|
||||||
|
requester_id,
|
||||||
|
request_date,
|
||||||
|
requester_dept,
|
||||||
|
requester_name,
|
||||||
|
requester_ext,
|
||||||
|
related_request_no,
|
||||||
|
system_name,
|
||||||
|
program_name,
|
||||||
|
change_title,
|
||||||
|
change_category,
|
||||||
|
reason_for_change,
|
||||||
|
description_of_change,
|
||||||
|
status
|
||||||
|
) VALUES (
|
||||||
|
:requester_id,
|
||||||
|
:request_date,
|
||||||
|
:requester_dept,
|
||||||
|
:requester_name,
|
||||||
|
:requester_ext,
|
||||||
|
:related_request_no,
|
||||||
|
:system_name,
|
||||||
|
:program_name,
|
||||||
|
:change_title,
|
||||||
|
:change_category,
|
||||||
|
:reason_for_change,
|
||||||
|
:description_of_change,
|
||||||
|
:status
|
||||||
|
)";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
|
||||||
|
$stmt->bindValue(':requester_id', $requester_id, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':request_date', !empty($_POST['request_date']) ? $_POST['request_date'] : null);
|
||||||
|
$stmt->bindValue(':requester_dept', $_POST['requester_dept'] ?? null);
|
||||||
|
$stmt->bindValue(':requester_name', $_POST['requester_name'] ?? null);
|
||||||
|
$stmt->bindValue(':requester_ext', $_POST['requester_ext'] ?? null);
|
||||||
|
$stmt->bindValue(':related_request_no', $_POST['related_request_no'] ?? null);
|
||||||
|
$stmt->bindValue(':system_name', $_POST['system_name'] ?? null);
|
||||||
|
$stmt->bindValue(':program_name', $_POST['program_name'] ?? null);
|
||||||
|
$stmt->bindValue(':change_title', $_POST['change_title'] ?? null);
|
||||||
|
$stmt->bindValue(':change_category', $_POST['change_category'] ?? null);
|
||||||
|
$stmt->bindValue(':reason_for_change', $_POST['reason_for_change'] ?? null);
|
||||||
|
$stmt->bindValue(':description_of_change', $_POST['description_of_change'] ?? null);
|
||||||
|
$stmt->bindValue(':status', $status);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$_SESSION['success_message'] = "Request submitted successfully with status: $status.";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$_SESSION['error_message'] = "Error submitting request: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: request_form.php');
|
||||||
|
exit;
|
||||||
92
update_request_status.php
Normal file
92
update_request_status.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'mail/MailService.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: all_requests.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin-only action
|
||||||
|
if ($_SESSION['role'] !== 'admin') {
|
||||||
|
$_SESSION['error_message'] = "You are not authorized to perform this action.";
|
||||||
|
header('Location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestId = filter_input(INPUT_POST, 'request_id', FILTER_VALIDATE_INT);
|
||||||
|
$newStatus = filter_input(INPUT_POST, 'new_status', FILTER_SANITIZE_STRING);
|
||||||
|
$adminComment = filter_input(INPUT_POST, 'admin_comment', FILTER_SANITIZE_STRING);
|
||||||
|
|
||||||
|
if (!$requestId || !$newStatus) {
|
||||||
|
$_SESSION['error_message'] = "Invalid data provided.";
|
||||||
|
header('Location: all_requests.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate status
|
||||||
|
$allowed_statuses = ['Pending', 'Approved', 'In Development', 'Completed', 'Rejected'];
|
||||||
|
if (!in_array($newStatus, $allowed_statuses)) {
|
||||||
|
$_SESSION['error_message'] = "Invalid status value.";
|
||||||
|
header('Location: view_request.php?id=' . $requestId);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdoconn = db();
|
||||||
|
|
||||||
|
// Fetch request details
|
||||||
|
$stmt = $pdoconn->prepare("SELECT cr.status, cr.change_title FROM change_requests cr WHERE cr.id = :id");
|
||||||
|
$stmt->bindParam(':id', $requestId, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$request = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$request) {
|
||||||
|
$_SESSION['error_message'] = "Request not found.";
|
||||||
|
header('Location: all_requests.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the request status and/or comment
|
||||||
|
$sql = "UPDATE change_requests SET status = :status, admin_comment = :comment WHERE id = :id";
|
||||||
|
$stmt = $pdoconn->prepare($sql);
|
||||||
|
$stmt->bindParam(':status', $newStatus, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':comment', $adminComment, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':id', $requestId, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
$_SESSION['success_message'] = "Request status updated successfully.";
|
||||||
|
|
||||||
|
// Send email notification if the status has changed
|
||||||
|
if ($request['status'] !== $newStatus) {
|
||||||
|
// NOTE: Email sending is disabled because requester email is not available in the users table.
|
||||||
|
/*
|
||||||
|
$to = $request['requester_email']; // This column does not exist
|
||||||
|
$subject = "Update on your Change Request #{$requestId}";
|
||||||
|
$body = "<p>The status of your change request '{$request['change_title']}' has been updated to <strong>" . htmlspecialchars(ucfirst($newStatus)) . "</strong>.</p>";
|
||||||
|
if (!empty($adminComment)) {
|
||||||
|
$body .= "<p><strong>Admin Comment:</strong> " . htmlspecialchars($adminComment) . "</p>";
|
||||||
|
}
|
||||||
|
$body .= "<p>You can view the request here: <a href=\"http://{$_SERVER['HTTP_HOST']}/view_request.php?id={$requestId}\">View Request</a></p>";
|
||||||
|
|
||||||
|
MailService::sendMail($to, $subject, $body, strip_tags($body));
|
||||||
|
|
||||||
|
$_SESSION['success_message'] = "Request status updated and notification sent.";
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$_SESSION['info_message'] = "No changes were made to the request.";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$_SESSION['error_message'] = "Database error: " . $e->getMessage();
|
||||||
|
error_log("DB Error: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$_SESSION['error_message'] = "Error: " . $e->getMessage();
|
||||||
|
error_log("General Error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: view_request.php?id=' . $requestId);
|
||||||
|
exit;
|
||||||
87
upload_users_csv.php
Normal file
87
upload_users_csv.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||||
|
$file = $_FILES['csv_file']['tmp_name'];
|
||||||
|
$handle = fopen($file, "r");
|
||||||
|
|
||||||
|
if ($handle !== FALSE) {
|
||||||
|
$pdoconfig = db();
|
||||||
|
$pdo = new PDO($pdoconfig['dsn'], $pdoconfig['user'], $pdoconfig['pass'], $pdoconfig['options']);
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Skip header row
|
||||||
|
fgetcsv($handle, 1000, ",");
|
||||||
|
|
||||||
|
$created_count = 0;
|
||||||
|
$error_count = 0;
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
|
||||||
|
$username = trim($data[0]);
|
||||||
|
$email = trim($data[1]);
|
||||||
|
$password = $data[2];
|
||||||
|
$role = trim($data[3]);
|
||||||
|
|
||||||
|
if (empty($username) || empty($email) || empty($password) || empty($role)) {
|
||||||
|
$errors[] = "Skipping row: required field is empty.";
|
||||||
|
$error_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors[] = "Skipping row for email {$email}: invalid email format.";
|
||||||
|
$error_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = :username OR email = :email');
|
||||||
|
$stmt->execute(['username' => $username, 'email' => $email]);
|
||||||
|
if ($stmt->fetch()) {
|
||||||
|
$errors[] = "Skipping row for user {$username}: username or email already exists.";
|
||||||
|
$error_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO users (username, email, password, role) VALUES (:username, :email, :password, :role)');
|
||||||
|
if ($stmt->execute(['username' => $username, 'email' => $email, 'password' => $hashed_password, 'role' => $role])) {
|
||||||
|
$created_count++;
|
||||||
|
} else {
|
||||||
|
$errors[] = "Failed to create user {$username}.";
|
||||||
|
$error_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
if ($error_count === 0) {
|
||||||
|
$pdo->commit();
|
||||||
|
$success = "{$created_count} users created successfully.";
|
||||||
|
} else {
|
||||||
|
$pdo->rollBack();
|
||||||
|
$error = "There were {$error_count} errors creating users. No users were created. Errors: <br>" . implode("<br>", $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['upload_success'] = $success;
|
||||||
|
$_SESSION['upload_error'] = $error;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$_SESSION['upload_error'] = 'Failed to open CSV file.';
|
||||||
|
}
|
||||||
|
header("Location: manage_users.php");
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
header('Location: manage_users.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
114
view_request.php
Normal file
114
view_request.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth_check.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$pageTitle = 'View Change Request';
|
||||||
|
$requestId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
||||||
|
|
||||||
|
if (!$requestId) {
|
||||||
|
header("Location: all_requests.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the request and requester info
|
||||||
|
try {
|
||||||
|
$pdoconn = db();
|
||||||
|
$stmt = $pdoconn->prepare('SELECT cr.*, u.full_name as requester_full_name, u.username as requester_username FROM change_requests cr JOIN users u ON cr.requester_id = u.id WHERE cr.id = :id');
|
||||||
|
$stmt->bindParam(':id', $requestId, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$request = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$request = null;
|
||||||
|
error_log("DB Error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$request) {
|
||||||
|
$_SESSION['error_message'] = "Request not found.";
|
||||||
|
header("Location: all_requests.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?= htmlspecialchars($pageTitle) ?> - #<?= htmlspecialchars($request['id']) ?></title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<h3>Change Request #<?= htmlspecialchars($request['id']) ?></h3>
|
||||||
|
<span class="badge badge-info" style="font-size: 1rem;"><?= htmlspecialchars(ucfirst($request['status'])) ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title"><?= htmlspecialchars($request['change_title']) ?></h5>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Request Details -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<p><strong>Requester:</strong> <?= htmlspecialchars($request['requester_full_name']) ?></p>
|
||||||
|
<p><strong>Department:</strong> <?= htmlspecialchars($request['requester_dept']) ?></p>
|
||||||
|
<p><strong>System Name:</strong> <?= htmlspecialchars($request['system_name']) ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<p><strong>Submission Date:</strong> <?= date('Y-m-d H:i', strtotime($request['created_at'])) ?></p>
|
||||||
|
<p><strong>Category:</strong> <?= htmlspecialchars($request['change_category']) ?></p>
|
||||||
|
<p><strong>Program Name:</strong> <?= htmlspecialchars($request['program_name']) ?></p>
|
||||||
|
<?php if (!empty($request['related_request_no'])): ?>
|
||||||
|
<p><strong>Related Change Request No:</strong> <a href="view_request.php?id=<?= htmlspecialchars($request['related_request_no']) ?>"><?= htmlspecialchars($request['related_request_no']) ?></a></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<h6><strong>Reason for Change:</strong></h6>
|
||||||
|
<p><?= nl2br(htmlspecialchars($request['reason_for_change'])) ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<h6><strong>Description of Change:</strong></h6>
|
||||||
|
<p><?= nl2br(htmlspecialchars($request['description_of_change'])) ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($_SESSION['role'] === 'admin'): ?>
|
||||||
|
<hr>
|
||||||
|
<div class="mt-4">
|
||||||
|
<h4>Approval Action</h4>
|
||||||
|
<form action="update_request_status.php" method="POST">
|
||||||
|
<input type="hidden" name="request_id" value="<?= $request['id'] ?>">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="new_status">Change Status:</label>
|
||||||
|
<select name="new_status" id="new_status" class="form-control">
|
||||||
|
<option value="Pending" <?= $request['status'] === 'Pending' ? 'selected' : '' ?>>Pending</option>
|
||||||
|
<option value="Approved" <?= $request['status'] === 'Approved' ? 'selected' : '' ?>>Approved</option>
|
||||||
|
<option value="In Development" <?= $request['status'] === 'In Development' ? 'selected' : '' ?>>In Development</option>
|
||||||
|
<option value="Completed" <?= $request['status'] === 'Completed' ? 'selected' : '' ?>>Completed</option>
|
||||||
|
<option value="Rejected" <?= $request['status'] === 'Rejected' ? 'selected' : '' ?>>Rejected</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="admin_comment">Comment:</label>
|
||||||
|
<textarea name="admin_comment" id="admin_comment" class="form-control" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success">Update Status</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user