From 2f146ee57fb779693314802405d6024a6560a8dd Mon Sep 17 00:00:00 2001
From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:24:46 -0700
Subject: [PATCH 1/5] Create index.php
---
polls/index.php | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 201 insertions(+)
create mode 100644 polls/index.php
diff --git a/polls/index.php b/polls/index.php
new file mode 100644
index 0000000..c961bac
--- /dev/null
+++ b/polls/index.php
@@ -0,0 +1,201 @@
+prepare("SELECT * FROM poll_questions WHERE id = :id LIMIT 1");
+ $stmt->bindValue(':id', $pollId, PDO::PARAM_INT);
+ $stmt->execute();
+ return $stmt->fetch(PDO::FETCH_ASSOC);
+}
+
+// Helper function: Fetch poll options (and their results) by poll ID
+function getPollOptions($db, $pollId) {
+ $stmt = $db->prepare("
+ SELECT
+ po.id AS option_id,
+ po.option_text,
+ IFNULL(pr.vote_count, 0) AS vote_count
+ FROM poll_options po
+ LEFT JOIN poll_results pr ON po.id = pr.option_id
+ WHERE po.question_id = :question_id
+ ORDER BY po.id ASC
+ ");
+ $stmt->bindValue(':question_id', $pollId, PDO::PARAM_INT);
+ $stmt->execute();
+ return $stmt->fetchAll(PDO::FETCH_ASSOC);
+}
+
+// If a vote is being cast
+if (isset($_POST['vote']) && isset($_POST['option_id']) && isset($_POST['poll_id'])) {
+ $pollId = (int)$_POST['poll_id'];
+ $optionId = (int)$_POST['option_id'];
+
+ // Ensure this user hasn't already voted on this poll in this session
+ if (!in_array($pollId, $_SESSION['voted_polls'], true)) {
+ // Update the vote count
+ $updateStmt = $db->prepare("
+ UPDATE poll_results
+ SET vote_count = vote_count + 1
+ WHERE question_id = :question_id
+ AND option_id = :option_id
+ ");
+ $updateStmt->bindValue(':question_id', $pollId, PDO::PARAM_INT);
+ $updateStmt->bindValue(':option_id', $optionId, PDO::PARAM_INT);
+ $updateStmt->execute();
+
+ // Mark the user as having voted
+ $_SESSION['voted_polls'][] = $pollId;
+ }
+
+ // Redirect back to the same poll to show results
+ header("Location: index.php?poll_id=" . $pollId);
+ exit;
+}
+
+// Check if a specific poll is requested
+$pollId = isset($_GET['poll_id']) ? (int)$_GET['poll_id'] : null;
+?>
+
+
+
+
+ Poll Application
+
+
+
+
+
+
+
Available Polls
+ query("SELECT id, question_text, created_at FROM poll_questions ORDER BY id DESC");
+ $allPolls = $allPollsStmt->fetchAll(PDO::FETCH_ASSOC);
+
+ if ($allPolls) {
+ foreach ($allPolls as $poll) {
+ ?>
+
+
+
No polls available.
+
+
+
+
+ Poll not found.";
+ } else {
+ $options = getPollOptions($db, $pollId);
+ $hasVoted = in_array($pollId, $_SESSION['voted_polls'], true);
+ ?>
+
+
+
+
+ No options available for this poll.";
+ }
+ } else {
+ // Show the results if user has already voted
+ ?>
+
Results
+
+
+ 0) ? ($voteCount / $totalVotes) * 100 : 0;
+ ?>
+ -
+ :
+ votes
+ (%)
+
+
+
+
Total votes:
+
+
+
Back to Poll List
+
+
+
+
+
From 002ea7dfe7358400637cc182e95669311a27a3c7 Mon Sep 17 00:00:00 2001
From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:25:42 -0700
Subject: [PATCH 2/5] Create api.php
---
polls/api.php | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 polls/api.php
diff --git a/polls/api.php b/polls/api.php
new file mode 100644
index 0000000..f4a6b3e
--- /dev/null
+++ b/polls/api.php
@@ -0,0 +1,161 @@
+query("SELECT id, question_text FROM poll_questions ORDER BY id DESC");
+ $polls = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ sendJson(['success' => true, 'polls' => $polls]);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 2) Get a single poll (question + options)
+ // --------------------------------------------------
+ case 'get_poll':
+ $pollId = (int)($_GET['poll_id'] ?? 0);
+ if ($pollId <= 0) {
+ sendJson(['success' => false, 'error' => 'Invalid poll_id'], 400);
+ }
+ try {
+ // Fetch poll question
+ $stmt = $db->prepare("SELECT id, question_text FROM poll_questions WHERE id = :id");
+ $stmt->execute([':id' => $pollId]);
+ $poll = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$poll) {
+ sendJson(['success' => false, 'error' => 'Poll not found'], 404);
+ }
+
+ // Fetch options
+ $optionsStmt = $db->prepare("
+ SELECT po.id AS option_id, po.option_text,
+ IFNULL(pr.vote_count, 0) AS vote_count
+ FROM poll_options po
+ LEFT JOIN poll_results pr ON po.id = pr.option_id
+ WHERE po.question_id = :question_id
+ ORDER BY po.id ASC
+ ");
+ $optionsStmt->execute([':question_id' => $pollId]);
+ $options = $optionsStmt->fetchAll(PDO::FETCH_ASSOC);
+
+ sendJson([
+ 'success' => true,
+ 'poll' => [
+ 'id' => $poll['id'],
+ 'question_text' => $poll['question_text'],
+ 'options' => $options
+ ]
+ ]);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 3) Cast a vote
+ // Expects: poll_id, option_id, username
+ // --------------------------------------------------
+ case 'vote':
+ // This can come from POST or GET. We'll assume POST for clarity.
+ $pollId = (int)($_POST['poll_id'] ?? 0);
+ $optionId = (int)($_POST['option_id'] ?? 0);
+ $username = trim($_POST['username'] ?? '');
+
+ if ($pollId <= 0 || $optionId <= 0 || empty($username)) {
+ sendJson(['success' => false, 'error' => 'Missing or invalid parameters'], 400);
+ }
+
+ // Check if user already voted on this poll
+ try {
+ // 1) Ensure poll & option exist
+ $checkOption = $db->prepare("
+ SELECT COUNT(*)
+ FROM poll_options
+ WHERE id = :option_id
+ AND question_id = :poll_id
+ ");
+ $checkOption->execute([
+ ':option_id' => $optionId,
+ ':poll_id' => $pollId
+ ]);
+ if (!$checkOption->fetchColumn()) {
+ sendJson(['success' => false, 'error' => 'Option does not belong to poll or does not exist'], 400);
+ }
+
+ // 2) Check if user already voted
+ $checkVote = $db->prepare("
+ SELECT COUNT(*)
+ FROM user_votes
+ WHERE question_id = :poll_id
+ AND user_name = :username
+ ");
+ $checkVote->execute([
+ ':poll_id' => $pollId,
+ ':username' => $username
+ ]);
+ if ($checkVote->fetchColumn() > 0) {
+ // Already voted
+ sendJson(['success' => false, 'error' => 'Already voted'], 403);
+ }
+
+ // 3) Cast the vote (increment poll_results)
+ $updateStmt = $db->prepare("
+ UPDATE poll_results
+ SET vote_count = vote_count + 1
+ WHERE question_id = :poll_id
+ AND option_id = :option_id
+ ");
+ $updateStmt->execute([
+ ':poll_id' => $pollId,
+ ':option_id' => $optionId
+ ]);
+
+ // 4) Record the user vote
+ // Ensure user_votes table is created:
+ // CREATE TABLE IF NOT EXISTS user_votes (
+ // id INTEGER PRIMARY KEY AUTOINCREMENT,
+ // question_id INTEGER NOT NULL,
+ // option_id INTEGER NOT NULL,
+ // user_name TEXT NOT NULL,
+ // voted_at DATETIME DEFAULT CURRENT_TIMESTAMP
+ // );
+ $insertVote = $db->prepare("
+ INSERT INTO user_votes (question_id, option_id, user_name)
+ VALUES (:poll_id, :option_id, :username)
+ ");
+ $insertVote->execute([
+ ':poll_id' => $pollId,
+ ':option_id' => $optionId,
+ ':username' => $username
+ ]);
+
+ sendJson(['success' => true, 'message' => 'Vote cast successfully']);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 4) Unknown / default
+ // --------------------------------------------------
+ default:
+ sendJson(['success' => false, 'error' => 'Unknown action'], 400);
+ break;
+}
From 040c0bf64e426aa39d16d6485df4a1fa4869a5a8 Mon Sep 17 00:00:00 2001
From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:26:55 -0700
Subject: [PATCH 3/5] Create admin.php
---
polls/admin.php | 161 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 polls/admin.php
diff --git a/polls/admin.php b/polls/admin.php
new file mode 100644
index 0000000..f4a6b3e
--- /dev/null
+++ b/polls/admin.php
@@ -0,0 +1,161 @@
+query("SELECT id, question_text FROM poll_questions ORDER BY id DESC");
+ $polls = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ sendJson(['success' => true, 'polls' => $polls]);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 2) Get a single poll (question + options)
+ // --------------------------------------------------
+ case 'get_poll':
+ $pollId = (int)($_GET['poll_id'] ?? 0);
+ if ($pollId <= 0) {
+ sendJson(['success' => false, 'error' => 'Invalid poll_id'], 400);
+ }
+ try {
+ // Fetch poll question
+ $stmt = $db->prepare("SELECT id, question_text FROM poll_questions WHERE id = :id");
+ $stmt->execute([':id' => $pollId]);
+ $poll = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$poll) {
+ sendJson(['success' => false, 'error' => 'Poll not found'], 404);
+ }
+
+ // Fetch options
+ $optionsStmt = $db->prepare("
+ SELECT po.id AS option_id, po.option_text,
+ IFNULL(pr.vote_count, 0) AS vote_count
+ FROM poll_options po
+ LEFT JOIN poll_results pr ON po.id = pr.option_id
+ WHERE po.question_id = :question_id
+ ORDER BY po.id ASC
+ ");
+ $optionsStmt->execute([':question_id' => $pollId]);
+ $options = $optionsStmt->fetchAll(PDO::FETCH_ASSOC);
+
+ sendJson([
+ 'success' => true,
+ 'poll' => [
+ 'id' => $poll['id'],
+ 'question_text' => $poll['question_text'],
+ 'options' => $options
+ ]
+ ]);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 3) Cast a vote
+ // Expects: poll_id, option_id, username
+ // --------------------------------------------------
+ case 'vote':
+ // This can come from POST or GET. We'll assume POST for clarity.
+ $pollId = (int)($_POST['poll_id'] ?? 0);
+ $optionId = (int)($_POST['option_id'] ?? 0);
+ $username = trim($_POST['username'] ?? '');
+
+ if ($pollId <= 0 || $optionId <= 0 || empty($username)) {
+ sendJson(['success' => false, 'error' => 'Missing or invalid parameters'], 400);
+ }
+
+ // Check if user already voted on this poll
+ try {
+ // 1) Ensure poll & option exist
+ $checkOption = $db->prepare("
+ SELECT COUNT(*)
+ FROM poll_options
+ WHERE id = :option_id
+ AND question_id = :poll_id
+ ");
+ $checkOption->execute([
+ ':option_id' => $optionId,
+ ':poll_id' => $pollId
+ ]);
+ if (!$checkOption->fetchColumn()) {
+ sendJson(['success' => false, 'error' => 'Option does not belong to poll or does not exist'], 400);
+ }
+
+ // 2) Check if user already voted
+ $checkVote = $db->prepare("
+ SELECT COUNT(*)
+ FROM user_votes
+ WHERE question_id = :poll_id
+ AND user_name = :username
+ ");
+ $checkVote->execute([
+ ':poll_id' => $pollId,
+ ':username' => $username
+ ]);
+ if ($checkVote->fetchColumn() > 0) {
+ // Already voted
+ sendJson(['success' => false, 'error' => 'Already voted'], 403);
+ }
+
+ // 3) Cast the vote (increment poll_results)
+ $updateStmt = $db->prepare("
+ UPDATE poll_results
+ SET vote_count = vote_count + 1
+ WHERE question_id = :poll_id
+ AND option_id = :option_id
+ ");
+ $updateStmt->execute([
+ ':poll_id' => $pollId,
+ ':option_id' => $optionId
+ ]);
+
+ // 4) Record the user vote
+ // Ensure user_votes table is created:
+ // CREATE TABLE IF NOT EXISTS user_votes (
+ // id INTEGER PRIMARY KEY AUTOINCREMENT,
+ // question_id INTEGER NOT NULL,
+ // option_id INTEGER NOT NULL,
+ // user_name TEXT NOT NULL,
+ // voted_at DATETIME DEFAULT CURRENT_TIMESTAMP
+ // );
+ $insertVote = $db->prepare("
+ INSERT INTO user_votes (question_id, option_id, user_name)
+ VALUES (:poll_id, :option_id, :username)
+ ");
+ $insertVote->execute([
+ ':poll_id' => $pollId,
+ ':option_id' => $optionId,
+ ':username' => $username
+ ]);
+
+ sendJson(['success' => true, 'message' => 'Vote cast successfully']);
+ } catch (Exception $e) {
+ sendJson(['success' => false, 'error' => $e->getMessage()], 500);
+ }
+ break;
+
+ // --------------------------------------------------
+ // 4) Unknown / default
+ // --------------------------------------------------
+ default:
+ sendJson(['success' => false, 'error' => 'Unknown action'], 400);
+ break;
+}
From ff4e747196abf64b58fd6693f63a646f9bd8944b Mon Sep 17 00:00:00 2001
From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:31:20 -0700
Subject: [PATCH 4/5] Create setup.php
---
polls/setup.php | 166 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 166 insertions(+)
create mode 100644 polls/setup.php
diff --git a/polls/setup.php b/polls/setup.php
new file mode 100644
index 0000000..c02894e
--- /dev/null
+++ b/polls/setup.php
@@ -0,0 +1,166 @@
+query("SELECT COUNT(*) FROM users")->fetchColumn();
+
+// If at least one user exists, show a message and no form
+if ($checkTotal > 0) {
+ ?>
+
+
+
+
+ Setup Admin User
+
+
+
+
+
Admin User Already Exists
+
+ An admin user has already been created. No additional admins can be set up here.
+
+
+ Go back to the Polls site.
+
+
+
+
+ prepare("
+ INSERT INTO users (username, password)
+ VALUES (:username, :password)
+ ");
+ $insertStmt->bindValue(':username', $username, PDO::PARAM_STR);
+ $insertStmt->bindValue(':password', $hashedPassword, PDO::PARAM_STR);
+ $insertStmt->execute();
+
+ $success = "Admin user '$username' created successfully.";
+ }
+}
+?>
+
+
+
+
+ Setup Admin User
+
+
+
+
+
+
From 6a342bcc7a23ce829f4d4dff6ae8b13a6458b389 Mon Sep 17 00:00:00 2001
From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:32:13 -0700
Subject: [PATCH 5/5] Create db.php
---
polls/db.php | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 166 insertions(+)
create mode 100644 polls/db.php
diff --git a/polls/db.php b/polls/db.php
new file mode 100644
index 0000000..c02894e
--- /dev/null
+++ b/polls/db.php
@@ -0,0 +1,166 @@
+query("SELECT COUNT(*) FROM users")->fetchColumn();
+
+// If at least one user exists, show a message and no form
+if ($checkTotal > 0) {
+ ?>
+
+
+
+
+ Setup Admin User
+
+
+
+
+
Admin User Already Exists
+
+ An admin user has already been created. No additional admins can be set up here.
+
+
+ Go back to the Polls site.
+
+
+
+
+ prepare("
+ INSERT INTO users (username, password)
+ VALUES (:username, :password)
+ ");
+ $insertStmt->bindValue(':username', $username, PDO::PARAM_STR);
+ $insertStmt->bindValue(':password', $hashedPassword, PDO::PARAM_STR);
+ $insertStmt->execute();
+
+ $success = "Admin user '$username' created successfully.";
+ }
+}
+?>
+
+
+
+
+ Setup Admin User
+
+
+
+
+
+