candidate_id (string or array) $user = get_user(); if (!$election_id) { die("Invalid submission."); } try { $pdo = db(); $pdo->beginTransaction(); // 1. Verify election is ongoing $eStmt = $pdo->prepare("SELECT status FROM elections WHERE id = ?"); $eStmt->execute([$election_id]); $election = $eStmt->fetch(); if (!$election || $election["status"] !== "Ongoing") { throw new Exception("Election is not currently ongoing."); } // 2. Verify user hasn't voted yet $vCheck = $pdo->prepare("SELECT COUNT(*) FROM votes WHERE election_id = ? AND voter_id = ?"); $vCheck->execute([$election_id, $user["id"]]); if ($vCheck->fetchColumn() > 0) { throw new Exception("You have already cast your vote for this election."); } // 3. Prepare statement for inserting votes $stmt = $pdo->prepare("INSERT INTO votes (id, election_id, position_id, candidate_id, voter_id, ip_address, user_agent) VALUES (?, ?, ?, ?, ?, ?, ?)"); // 4. Validate each position's votes foreach ($raw_votes as $position_id => $candidate_id) { if (empty($candidate_id)) continue; // Fetch position details $pStmt = $pdo->prepare("SELECT * FROM positions WHERE id = ? AND election_id = ?"); $pStmt->execute([$position_id, $election_id]); $pos = $pStmt->fetch(); if (!$pos) { throw new Exception("Invalid position detected."); } // Validate candidate $cStmt = $pdo->prepare("SELECT c.*, u.track FROM candidates c JOIN users u ON c.user_id = u.id WHERE c.id = ? AND c.position_id = ? AND c.approved = TRUE"); $cStmt->execute([$candidate_id, $position_id]); $cand = $cStmt->fetch(); if (!$cand) { throw new Exception("Invalid or unapproved candidate selected."); } // Check Track Specific logic if ($pos["type"] === "Track Specific" && $cand["track"] !== $user["track"]) { throw new Exception("Candidate track mismatch for position: " . $pos["name"]); } // Insert vote $stmt->execute([ uuid(), $election_id, $position_id, $candidate_id, $user["id"], $_SERVER["REMOTE_ADDR"] ?? "unknown", $_SERVER["HTTP_USER_AGENT"] ?? "unknown" ]); } audit_log("Cast ballot", "elections", $election_id); $pdo->commit(); header("Location: ../index.php?success=voted"); exit; } catch (Exception $e) { if (isset($pdo) && $pdo->inTransaction()) $pdo->rollBack(); die("Error casting vote: " . $e->getMessage()); } }