diff --git a/assets/pasted-20260215-205745-40292c52.png b/assets/pasted-20260215-205745-40292c52.png new file mode 100644 index 0000000..7cca604 Binary files /dev/null and b/assets/pasted-20260215-205745-40292c52.png differ diff --git a/ballot.php b/ballot.php index d29b0dd..9a4e50c 100644 --- a/ballot.php +++ b/ballot.php @@ -30,121 +30,273 @@ if ($check->fetchColumn() > 0) { $positions = $pdo->prepare("SELECT * FROM positions WHERE election_id = ? ORDER BY sort_order ASC"); $positions->execute([$id]); $positions = $positions->fetchAll(); + +$endTime = strtotime($election['end_date_and_time']) * 1000; ?> - Vote: <?= htmlspecialchars($election['title']) ?> - - + + Ballot: <?= htmlspecialchars($election['title']) ?> +
-
-
- OFFICIAL BALLOT +
+
+ + TIME REMAINING: + 00:00:00
-

-

Your vote is secure and anonymous. Choose your representatives below.

-
+
+

+

Your choice matters. Review the candidates carefully and cast your secure vote below.

+
+ + $pos): ?> -
+
- +
@@ -163,8 +315,8 @@ $positions = $positions->fetchAll(); ?> -
-

No candidates for this position.

+
+

No candidates available for your track.

@@ -180,7 +332,7 @@ $positions = $positions->fetchAll();

- +
@@ -190,21 +342,51 @@ $positions = $positions->fetchAll();
-
-

Ready to submit?

-

Please review your selections before casting your vote.

+
+
+

READY TO SUBMIT?

+

Review your selections

+
-
- Verified Secure Election -
+ - diff --git a/db/config.php b/db/config.php index d13f431..2c44b7b 100644 --- a/db/config.php +++ b/db/config.php @@ -6,16 +6,39 @@ define('DB_USER', 'app_38458'); define('DB_PASS', 'c217529c-a428-4a97-8f31-773c420377a7'); // Supabase Configuration - Provide your project URL and Service Role Key -define('SUPABASE_URL', getenv('SUPABASE_URL') ?: 'https://your-project.supabase.co'); -define('SUPABASE_SERVICE_ROLE_KEY', getenv('SUPABASE_SERVICE_ROLE_KEY') ?: 'your-service-role-key'); +define('SUPABASE_URL', getenv('SUPABASE_URL') ?: 'https://siqeqnizegizxemrfgkf.supabase.co'); +define('SUPABASE_SERVICE_ROLE_KEY', getenv('SUPABASE_SERVICE_ROLE_KEY') ?: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InNpcWVxbml6ZWdpenhlbXJmZ2tmIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3MDEyMjgzMywiZXhwIjoyMDg1Njk4ODMzfQ.8K66Y3hSfSq5mRDeU8YT6pH9tqPVngxA9dEwCgQUCl0'); +define('SUPABASE_DB_PASS', getenv('SUPABASE_DB_PASS') ?: 'gA82h8K80T5QUAwi'); // Set your DB password here for PostgreSQL migration function db() { 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, - ]); + if (defined('SUPABASE_DB_PASS') && !empty(SUPABASE_DB_PASS)) { + // Use Supabase PostgreSQL + $host = 'aws-1-ap-southeast-1.pooler.supabase.com'; + $port = '6543'; + $dbname = 'postgres'; + $user = 'postgres.siqeqnizegizxemrfgkf'; + $pass = SUPABASE_DB_PASS; + try { + $pdo = new PDO("pgsql:host=$host;port=$port;dbname=$dbname", $user, $pass, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]); + } catch (PDOException $e) { + // Fallback to local MariaDB if PostgreSQL fails + $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, + ]); + } + } else { + // Use local MariaDB + $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; } diff --git a/find_region.php b/find_region.php new file mode 100644 index 0000000..dd56123 --- /dev/null +++ b/find_region.php @@ -0,0 +1,29 @@ +getMessage(), 'Tenant or user not found') !== false) { + echo "Not here.\n"; + } else { + echo "Error: " . $e->getMessage() . "\n"; + } + } +} diff --git a/index.php b/index.php index b509f02..413acf1 100644 --- a/index.php +++ b/index.php @@ -13,7 +13,41 @@ if (in_array($user['role'], ['Admin', 'Adviser', 'Officer'])) { } $pdo = db(); -$elections = $pdo->query("SELECT * FROM elections WHERE archived = FALSE ORDER BY created_at DESC")->fetchAll(); + +// Voter redirection logic +if ($user['role'] === 'Voter') { + // Find ongoing elections that this voter is assigned to + $stmt = $pdo->prepare(" + SELECT e.* FROM elections e + JOIN election_assignments ea ON e.id = ea.election_id + WHERE ea.user_id = ? + AND e.status = 'Ongoing' + AND e.archived = FALSE + AND e.end_date_and_time > CURRENT_TIMESTAMP + "); + $stmt->execute([$user['id']]); + $activeElections = $stmt->fetchAll(); + + // Filter out elections where the user has already voted + $votedElectionsStmt = $pdo->prepare("SELECT election_id FROM votes WHERE voter_id = ?"); + $votedElectionsStmt->execute([$user['id']]); + $votedIds = $votedElectionsStmt->fetchAll(PDO::FETCH_COLUMN); + + $eligibleElections = array_filter($activeElections, function($e) use ($votedIds) { + return !in_array($e['id'], $votedIds); + }); + + if (count($eligibleElections) === 1) { + $singleElection = reset($eligibleElections); + header("Location: ballot.php?id=" . $singleElection['id']); + exit; + } + + // For voters, only show their assigned elections in the list + $elections = $activeElections; +} else { + $elections = $pdo->query("SELECT * FROM elections WHERE archived = FALSE ORDER BY created_at DESC")->fetchAll(); +} $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System for Senior High School'; ?> diff --git a/supabase_migration.php b/supabase_migration.php new file mode 100644 index 0000000..aa8350e --- /dev/null +++ b/supabase_migration.php @@ -0,0 +1,163 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]); + + echo "Connecting to Supabase PostgreSQL...\n"; + $dsn = "pgsql:host=$supabaseHost;port=$supabasePort;dbname=$supabaseDb"; + $supabasePdo = new PDO($dsn, $supabaseUser, $dbPassword, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION + ]); + + echo "Converting and creating tables in Supabase...\n"; + + // Define tables and their PostgreSQL schemas + $schemas = [ + "users" => "CREATE TABLE IF NOT EXISTS users ( + id VARCHAR(255) PRIMARY KEY, + supabase_uid VARCHAR(255), + student_id VARCHAR(10) UNIQUE NOT NULL, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255), + grade_level INTEGER, + track VARCHAR(100), + section VARCHAR(100), + role VARCHAR(50) DEFAULT 'Voter', + access_level INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP + )", + "elections" => "CREATE TABLE IF NOT EXISTS elections ( + id VARCHAR(255) PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + status VARCHAR(50) DEFAULT 'Preparing', + start_date_and_time TIMESTAMP NOT NULL, + end_date_and_time TIMESTAMP NOT NULL, + created_by VARCHAR(255) REFERENCES users(id), + archived BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )", + "positions" => "CREATE TABLE IF NOT EXISTS positions ( + id VARCHAR(255) PRIMARY KEY, + election_id VARCHAR(255) REFERENCES elections(id) ON DELETE CASCADE, + name VARCHAR(255) NOT NULL, + type VARCHAR(50) DEFAULT 'Uniform', + max_votes INTEGER DEFAULT 1, + sort_order INTEGER DEFAULT 0 + )", + "candidates" => "CREATE TABLE IF NOT EXISTS candidates ( + id VARCHAR(255) PRIMARY KEY, + election_id VARCHAR(255) REFERENCES elections(id) ON DELETE CASCADE, + position_id VARCHAR(255) REFERENCES positions(id) ON DELETE CASCADE, + user_id VARCHAR(255) REFERENCES users(id) ON DELETE CASCADE, + party_name VARCHAR(255), + manifesto TEXT, + approved BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )", + "votes" => "CREATE TABLE IF NOT EXISTS votes ( + id VARCHAR(255) PRIMARY KEY, + election_id VARCHAR(255) REFERENCES elections(id), + position_id VARCHAR(255) REFERENCES positions(id), + candidate_id VARCHAR(255) REFERENCES candidates(id), + voter_id VARCHAR(255) REFERENCES users(id), + casted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + ip_address VARCHAR(45), + user_agent TEXT, + UNIQUE (election_id, position_id, voter_id) + )", + "election_assignments" => "CREATE TABLE IF NOT EXISTS election_assignments ( + id VARCHAR(255) PRIMARY KEY, + election_id VARCHAR(255) REFERENCES elections(id) ON DELETE CASCADE, + user_id VARCHAR(255) REFERENCES users(id) ON DELETE CASCADE, + role_in_election VARCHAR(50) DEFAULT 'Voter', + assigned_by VARCHAR(255) REFERENCES users(id), + assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )", + "parties" => "CREATE TABLE IF NOT EXISTS parties ( + id VARCHAR(255) PRIMARY KEY, + election_id VARCHAR(255) REFERENCES elections(id) ON DELETE CASCADE, + name VARCHAR(255) NOT NULL, + description TEXT, + logo_url TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )", + "audit_logs" => "CREATE TABLE IF NOT EXISTS audit_logs ( + id VARCHAR(255) PRIMARY KEY, + user_id VARCHAR(255) REFERENCES users(id), + action VARCHAR(255) NOT NULL, + details TEXT, + table_name VARCHAR(100), + record_id VARCHAR(255), + old_values TEXT, + new_values TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + election_id VARCHAR(255) REFERENCES elections(id) ON DELETE CASCADE + )" + ]; + + foreach ($schemas as $tableName => $sql) { + echo "Creating table: $tableName...\n"; + $supabasePdo->exec($sql); + } + + echo "Migrating data...\n"; + + $tables = array_keys($schemas); + // Order matters for foreign keys: users, elections, positions, candidates, assignments, votes, audit_logs + $orderedTables = ["users", "elections", "positions", "election_assignments", "parties", "candidates", "votes", "audit_logs"]; + + foreach ($orderedTables as $table) { + echo "Migrating data for $table...\n"; + $stmt = $localPdo->query("SELECT * FROM $table"); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (empty($rows)) { + echo "No data for $table.\n"; + continue; + } + + $columns = array_keys($rows[0]); + $placeholders = implode(',', array_fill(0, count($columns), '?')); + $insertSql = "INSERT INTO $table (" . implode(',', $columns) . ") VALUES ($placeholders) ON CONFLICT (id) DO NOTHING"; + + $insertStmt = $supabasePdo->prepare($insertSql); + $count = 0; + foreach ($rows as $row) { + $insertStmt->execute(array_values($row)); + $count++; + } + echo "Migrated $count rows for $table.\n"; + } + + echo "Migration completed successfully!\n"; + +} catch (Exception $e) { + echo "Error: " . $e->getMessage() . "\n"; + exit(1); +}