mirror of https://github.com/tildeclub/site.git
Merge pull request #69 from tildeclub/deepend-tildeclub-patch-2
add poll system.
This commit is contained in:
commit
f106cbecb9
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once 'db.php';
|
||||
|
||||
// Quick helper to send JSON responses and exit
|
||||
function sendJson($data, $statusCode = 200) {
|
||||
http_response_code($statusCode);
|
||||
echo json_encode($data);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $_GET['action'] ?? ($_POST['action'] ?? null);
|
||||
|
||||
switch ($action) {
|
||||
// --------------------------------------------------
|
||||
// 1) List all polls (IDs + questions)
|
||||
// --------------------------------------------------
|
||||
case 'list_polls':
|
||||
try {
|
||||
$stmt = $db->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;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once 'db.php';
|
||||
|
||||
// Quick helper to send JSON responses and exit
|
||||
function sendJson($data, $statusCode = 200) {
|
||||
http_response_code($statusCode);
|
||||
echo json_encode($data);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $_GET['action'] ?? ($_POST['action'] ?? null);
|
||||
|
||||
switch ($action) {
|
||||
// --------------------------------------------------
|
||||
// 1) List all polls (IDs + questions)
|
||||
// --------------------------------------------------
|
||||
case 'list_polls':
|
||||
try {
|
||||
$stmt = $db->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;
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
session_start();
|
||||
|
||||
// Include the database setup/connection
|
||||
require_once 'db.php';
|
||||
|
||||
// Initialize variables
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// Count how many users already exist in the database
|
||||
$checkTotal = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
|
||||
// If at least one user exists, show a message and no form
|
||||
if ($checkTotal > 0) {
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Setup Admin User</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.info {
|
||||
color: #333;
|
||||
}
|
||||
a {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Admin User Already Exists</h2>
|
||||
<p class="info">
|
||||
An admin user has already been created. No additional admins can be set up here.
|
||||
</p>
|
||||
<p>
|
||||
Go back to the <a href="index.php">Polls site</a>.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
// If we are here, no user exists yet, so show the form
|
||||
if (isset($_POST['setup'])) {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = trim($_POST['password'] ?? '');
|
||||
$confirmPassword = trim($_POST['confirm_password'] ?? '');
|
||||
|
||||
// Basic validation
|
||||
if ($username === '' || $password === '' || $confirmPassword === '') {
|
||||
$error = 'All fields are required.';
|
||||
} elseif ($password !== $confirmPassword) {
|
||||
$error = 'Passwords do not match.';
|
||||
} else {
|
||||
// Create the first (and only) admin user
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
$insertStmt = $db->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.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Setup Admin User</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
}
|
||||
input[type=text],
|
||||
input[type=password] {
|
||||
width: 250px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Setup Admin User</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="success"><?php echo htmlspecialchars($success); ?></div>
|
||||
<p>You can now <a href="admin.php">go to the Admin page</a> to log in.</p>
|
||||
<?php else: ?>
|
||||
<form action="setup.php" method="post">
|
||||
<div>
|
||||
<label for="username">Admin Username:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
value="<?php echo isset($_POST['username']) ? htmlspecialchars($_POST['username']) : ''; ?>"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="confirm_password">Confirm Password:</label>
|
||||
<input
|
||||
type="password"
|
||||
name="confirm_password"
|
||||
id="confirm_password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" name="setup">Save Admin User</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
session_start();
|
||||
require_once 'db.php'; // Ensures $db is available and the database is set up
|
||||
|
||||
// Array to store poll IDs that the user has voted on in this session
|
||||
if (!isset($_SESSION['voted_polls'])) {
|
||||
$_SESSION['voted_polls'] = [];
|
||||
}
|
||||
|
||||
// Helper function: Fetch poll details by ID
|
||||
function getPollById($db, $pollId) {
|
||||
$stmt = $db->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;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Poll Application</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
.poll-list, .poll-detail {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h2, h3 { margin-bottom: 10px; }
|
||||
.poll-item {
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.poll-options ul { list-style-type: none; padding: 0; }
|
||||
.poll-options li { margin-bottom: 8px; }
|
||||
.vote-button { margin-top: 10px; }
|
||||
.results { margin-top: 10px; }
|
||||
.results li { margin-bottom: 5px; }
|
||||
.back-link { margin-top: 20px; display: inline-block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
// If no poll_id given, show all polls
|
||||
if ($pollId === null) {
|
||||
?>
|
||||
<div class="poll-list">
|
||||
<h2>Available Polls</h2>
|
||||
<?php
|
||||
// Fetch all polls
|
||||
$allPollsStmt = $db->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) {
|
||||
?>
|
||||
<div class="poll-item">
|
||||
<strong>Question:</strong> <?php echo htmlspecialchars($poll['question_text']); ?><br>
|
||||
<em>Created at: <?php echo htmlspecialchars($poll['created_at']); ?></em><br>
|
||||
<a href="index.php?poll_id=<?php echo $poll['id']; ?>">View Poll</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
<p>No polls available.</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
// Display a single poll
|
||||
$poll = getPollById($db, $pollId);
|
||||
|
||||
?>
|
||||
<div class="poll-detail">
|
||||
<?php
|
||||
if (!$poll) {
|
||||
echo "<p>Poll not found.</p>";
|
||||
} else {
|
||||
$options = getPollOptions($db, $pollId);
|
||||
$hasVoted = in_array($pollId, $_SESSION['voted_polls'], true);
|
||||
?>
|
||||
<h2><?php echo htmlspecialchars($poll['question_text']); ?></h2>
|
||||
|
||||
<?php
|
||||
// If not voted yet, show the vote form
|
||||
if (!$hasVoted) {
|
||||
if (!empty($options)) {
|
||||
?>
|
||||
<form method="post" action="index.php">
|
||||
<div class="poll-options">
|
||||
<ul>
|
||||
<?php foreach ($options as $option) { ?>
|
||||
<li>
|
||||
<label>
|
||||
<input type="radio" name="option_id"
|
||||
value="<?php echo $option['option_id']; ?>"
|
||||
required>
|
||||
<?php echo htmlspecialchars($option['option_text']); ?>
|
||||
</label>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="hidden" name="poll_id" value="<?php echo $poll['id']; ?>">
|
||||
<button type="submit" name="vote" class="vote-button">Vote</button>
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
echo "<p>No options available for this poll.</p>";
|
||||
}
|
||||
} else {
|
||||
// Show the results if user has already voted
|
||||
?>
|
||||
<h3>Results</h3>
|
||||
<div class="results">
|
||||
<ul>
|
||||
<?php
|
||||
$totalVotes = 0;
|
||||
foreach ($options as $opt) {
|
||||
$totalVotes += $opt['vote_count'];
|
||||
}
|
||||
|
||||
foreach ($options as $opt) {
|
||||
$voteCount = (int) $opt['vote_count'];
|
||||
$percentage = ($totalVotes > 0) ? ($voteCount / $totalVotes) * 100 : 0;
|
||||
?>
|
||||
<li>
|
||||
<?php echo htmlspecialchars($opt['option_text']); ?>:
|
||||
<?php echo $voteCount; ?> votes
|
||||
(<?php echo round($percentage, 1); ?>%)
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<p>Total votes: <?php echo $totalVotes; ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<a href="index.php" class="back-link">Back to Poll List</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
session_start();
|
||||
|
||||
// Include the database setup/connection
|
||||
require_once 'db.php';
|
||||
|
||||
// Initialize variables
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// Count how many users already exist in the database
|
||||
$checkTotal = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
|
||||
// If at least one user exists, show a message and no form
|
||||
if ($checkTotal > 0) {
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Setup Admin User</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.info {
|
||||
color: #333;
|
||||
}
|
||||
a {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Admin User Already Exists</h2>
|
||||
<p class="info">
|
||||
An admin user has already been created. No additional admins can be set up here.
|
||||
</p>
|
||||
<p>
|
||||
Go back to the <a href="index.php">Polls site</a>.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
// If we are here, no user exists yet, so show the form
|
||||
if (isset($_POST['setup'])) {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = trim($_POST['password'] ?? '');
|
||||
$confirmPassword = trim($_POST['confirm_password'] ?? '');
|
||||
|
||||
// Basic validation
|
||||
if ($username === '' || $password === '' || $confirmPassword === '') {
|
||||
$error = 'All fields are required.';
|
||||
} elseif ($password !== $confirmPassword) {
|
||||
$error = 'Passwords do not match.';
|
||||
} else {
|
||||
// Create the first (and only) admin user
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
$insertStmt = $db->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.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Setup Admin User</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
}
|
||||
input[type=text],
|
||||
input[type=password] {
|
||||
width: 250px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Setup Admin User</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="success"><?php echo htmlspecialchars($success); ?></div>
|
||||
<p>You can now <a href="admin.php">go to the Admin page</a> to log in.</p>
|
||||
<?php else: ?>
|
||||
<form action="setup.php" method="post">
|
||||
<div>
|
||||
<label for="username">Admin Username:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
value="<?php echo isset($_POST['username']) ? htmlspecialchars($_POST['username']) : ''; ?>"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="confirm_password">Confirm Password:</label>
|
||||
<input
|
||||
type="password"
|
||||
name="confirm_password"
|
||||
id="confirm_password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" name="setup">Save Admin User</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue