diff --git a/Design/Style.css b/Design/Style.css index 17dc582..b48112e 100644 --- a/Design/Style.css +++ b/Design/Style.css @@ -11,6 +11,7 @@ --Error_Color: #EF4444; --Overlay_Color: rgba(0, 0, 0, 0.65); --Sidebar_Width: 260px; + --Topbar_Height: 70px; } * { @@ -317,8 +318,11 @@ body, html { } .Sidebar_Header { - padding: 24px; + height: var(--Topbar_Height); + padding: 0 24px; border-bottom: 1px solid var(--Border_Color); + display: flex; + align-items: center; } .Sidebar_Nav { @@ -358,7 +362,7 @@ body, html { } .Top_Bar { - height: 70px; + height: var(--Topbar_Height); background: white; border-bottom: 1px solid var(--Border_Color); display: flex; @@ -730,3 +734,14 @@ td { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2); } + +/* Navbar for Voting Screen */ +.Dashboard_Navbar { + height: var(--Topbar_Height); + background: white; + border-bottom: 1px solid var(--Border_Color); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 32px; +} diff --git a/Logic/Backend/Authentication_Handler.php b/Logic/Backend/Authentication_Handler.php index 270bc9b..a30dae0 100644 --- a/Logic/Backend/Authentication_Handler.php +++ b/Logic/Backend/Authentication_Handler.php @@ -12,16 +12,25 @@ class Authentication_Handler { public function Login($User_Type, $Email, $Password, $User_ID) { $Table = ($User_Type === 'Voter') ? 'Voters' : 'Officers'; - $sql = "SELECT * FROM $Table WHERE Email = ? AND User_ID = ?"; + // Try to find user by UID first as it's the primary key + $sql = "SELECT * FROM $Table WHERE User_ID = ?"; $stmt = $this->pdo->prepare($sql); - $stmt->execute([$Email, $User_ID]); + $stmt->execute([$User_ID]); $User = $stmt->fetch(); + // If not found and email is provided, try by Email + if (!$User && !empty($Email)) { + $sql = "SELECT * FROM $Table WHERE Email = ?"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([$Email]); + $User = $stmt->fetch(); + } + if ($User && password_verify($Password, $User['Password'])) { $_SESSION['User_ID'] = $User['User_ID']; $_SESSION['User_Role'] = ($User_Type === 'Voter') ? 'Voter' : $User['Role']; - $_SESSION['Access_Level'] = ($User_Type === 'Voter') ? 0 : $User['Access_Level']; - $_SESSION['User_Name'] = $User['Name'] ?? 'Voter'; + $_SESSION['Access_Level'] = ($User_Type === 'Voter') ? 0 : ($User['Access_Level'] ?? 0); + $_SESSION['User_Name'] = $User['Name'] ?? ($User_Type === 'Voter' ? 'Voter' : 'User'); // Log to Audit_Trail if Access_Level >= 1 if ($_SESSION['Access_Level'] >= 1) { @@ -31,7 +40,7 @@ class Authentication_Handler { return ['success' => true]; } - return ['success' => false, 'error' => 'Invalid credentials']; + return ['success' => false, 'error' => 'Invalid credentials. Please check your UID/Email and Password.']; } public function Log_Action($User_ID, $User_Role, $Action_Type, $Action_Details) { @@ -48,8 +57,34 @@ class Authentication_Handler { } public function Logout() { + if (isset($_SESSION['User_ID']) && isset($_SESSION['Access_Level']) && $_SESSION['Access_Level'] >= 1) { + $this->Log_Action($_SESSION['User_ID'], $_SESSION['User_Role'], 'Logout', 'User logged out of the system'); + } session_destroy(); header('Location: ../../Screens/Login.php'); exit; } } + +// Handle POST request for Login +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['User_ID']) && isset($_POST['Password'])) { + $handler = new Authentication_Handler(); + $userType = $_POST['User_Type'] ?? 'Voter'; + $email = $_POST['Email'] ?? ''; + $uid = $_POST['User_ID']; + $password = $_POST['Password']; + + $result = $handler->Login($userType, $email, $password, $uid); + + if ($result['success']) { + if ($_SESSION['Access_Level'] >= 1) { + header('Location: ../../Screens/Election_Dashboard.php'); + } else { + header('Location: ../../Screens/Voting_Screen.php'); + } + exit; + } else { + header('Location: ../../Screens/Login.php?error=' . urlencode($result['error'])); + exit; + } +} \ No newline at end of file diff --git a/Logic/Backend/Import_Voters_Handler.php b/Logic/Backend/Import_Voters_Handler.php new file mode 100644 index 0000000..fe13d15 --- /dev/null +++ b/Logic/Backend/Import_Voters_Handler.php @@ -0,0 +1,68 @@ +Check_Auth(); + +if ($_SESSION['Access_Level'] < 1) { + header('Location: ../../Screens/Login.php'); + exit; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { + $file = $_FILES['csv_file']['tmp_name']; + + if (!is_uploaded_file($file)) { + header("Location: ../../Screens/Voters.php?error=No file uploaded"); + exit; + } + + $handle = fopen($file, "r"); + if ($handle === false) { + header("Location: ../../Screens/Voters.php?error=Could not open file"); + exit; + } + + $db = db(); + $db->beginTransaction(); + + try { + // Skip header + $header = fgetcsv($handle); + + $importedCount = 0; + while (($data = fgetcsv($handle)) !== false) { + // Mapping: User_ID, Email, Track_Cluster, Grade_Level, Section, Password + $userId = $data[0] ?: 'V-' . bin2hex(random_bytes(4)); + $email = $data[1]; + $track = $data[2]; + $grade = intval($data[3]); + $section = $data[4]; + $password = !empty($data[5]) ? password_hash($data[5], PASSWORD_DEFAULT) : password_hash('Voter123', PASSWORD_DEFAULT); + + if (empty($email)) continue; + + $stmt = $db->prepare("INSERT INTO Voters (User_ID, Email, Password, Track_Cluster, Grade_Level, Section) VALUES (?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE Email = VALUES(Email), Track_Cluster = VALUES(Track_Cluster), Grade_Level = VALUES(Grade_Level), Section = VALUES(Section)"); + $stmt->execute([$userId, $email, $password, $track, $grade, $section]); + $importedCount++; + } + + $db->commit(); + fclose($handle); + + $Auth->Log_Action($_SESSION['User_ID'], $_SESSION['User_Role'], 'Import Voters', "Imported $importedCount voters via CSV"); + header("Location: ../../Screens/Voters.php?success=Successfully imported $importedCount voters"); + exit; + + } catch (Exception $e) { + $db->rollBack(); + fclose($handle); + header("Location: ../../Screens/Voters.php?error=Error importing CSV: " . $e->getMessage()); + exit; + } +} else { + header("Location: ../../Screens/Voters.php"); + exit; +} diff --git a/Screens/Audit_Trail.html b/Screens/Audit_Trail.html deleted file mode 100644 index e69de29..0000000 diff --git a/Screens/Audit_Trail.php b/Screens/Audit_Trail.php new file mode 100644 index 0000000..9100f24 --- /dev/null +++ b/Screens/Audit_Trail.php @@ -0,0 +1,135 @@ +Check_Auth(); + +if ($_SESSION['Access_Level'] < 1) { + header('Location: Voting_Screen.php'); + exit; +} + +$db = db(); + +// Fetch Logs +$query = "SELECT * FROM Audit_Trail ORDER BY Timestamp DESC LIMIT 100"; +$logs = $db->query($query)->fetchAll(); + +?> + + + + + + Audit Trail | Online School Election System + + + + +
+ + + + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + +
+
+

Audit Trail

+

System activity and security logs

+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimestampUser IDRoleActionDetails
+ No activity logs found. +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/Screens/Candidates.php b/Screens/Candidates.php index 11ac910..9bd3763 100644 --- a/Screens/Candidates.php +++ b/Screens/Candidates.php @@ -42,6 +42,9 @@ if ($migrationNeeded && $electionId) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && $electionStatus === 'Preparing') { if (isset($_POST['action'])) { $changed = false; + $logAction = ""; + $logDetails = ""; + if ($_POST['action'] === 'add_position' && !empty($_POST['new_position'])) { $newPosName = trim($_POST['new_position']); $newPosType = $_POST['position_type'] ?? 'Uniform'; @@ -54,26 +57,38 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $electionStatus === 'Preparing') { if (!$exists) { $electionPositions[] = ['name' => $newPosName, 'type' => $newPosType]; $changed = true; + $logAction = "Add Position"; + $logDetails = "Added new position: $newPosName ($newPosType)"; } } elseif ($_POST['action'] === 'remove_position') { $posNameToRemove = $_POST['position']; $electionPositions = array_values(array_filter($electionPositions, fn($p) => $p['name'] !== $posNameToRemove)); $changed = true; + $logAction = "Remove Position"; + $logDetails = "Removed position: $posNameToRemove"; } elseif ($_POST['action'] === 'add_party' && !empty($_POST['new_party'])) { $newParty = trim($_POST['new_party']); if (!in_array($newParty, $electionParties)) { $electionParties[] = $newParty; $changed = true; + $logAction = "Add Party"; + $logDetails = "Added new political party: $newParty"; } } elseif ($_POST['action'] === 'remove_party') { $partyToRemove = $_POST['party']; $electionParties = array_values(array_filter($electionParties, fn($p) => $p !== $partyToRemove)); $changed = true; + $logAction = "Remove Party"; + $logDetails = "Removed political party: $partyToRemove"; } if ($changed) { $stmt = $db->prepare("UPDATE Election_History SET Parties = ?, Positions = ? WHERE Election_ID = ?"); $stmt->execute([json_encode($electionParties), json_encode($electionPositions), $electionId]); + + // Log to Audit Trail + $Auth->Log_Action($_SESSION['User_ID'], $_SESSION['User_Role'], $logAction, $logDetails); + header("Location: Candidates.php"); exit; } @@ -156,8 +171,7 @@ $candidatesList = $stmt->fetchAll(); color: var(--Primary_Color); display: flex; justify-content: center; - align-items: center; - font-weight: 700; + align-items: center; font-weight: 700; overflow: hidden; object-fit: cover; } @@ -229,7 +243,7 @@ $candidatesList = $stmt->fetchAll();