Add admin panel

This commit is contained in:
scoliono 2021-12-27 07:01:20 +00:00
parent 107f599f27
commit 3a42952593
10 changed files with 312 additions and 70 deletions

71
admin/index.php Normal file
View File

@ -0,0 +1,71 @@
<?php
session_start();
if (!isset($_SESSION['uid'])) {
header('Location: /admin/login.php');
die;
}
$conn = new mysqli("localhost", "mileslinden", "Daiso@6969", "mileslinden");
$result = $conn->query("SELECT * FROM subscribers");
if (!$result) {
http_response_code(500);
die("Error: {$conn->error}");
}
$subscribers = [];
while ($row = $result->fetch_assoc()) {
$subscribers[] = $row;
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Miles Linden for San Jose City Council</title>
</head>
<body>
<h1>Admin Panel</h1>
<div>
<p><a href="logout.php">Logout</a></p>
<p><a href="mail.php">Mail All</a></p>
</div>
<h2>Subscribers</h2>
<table cellpadding="5">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<!--<th>Gender</th>-->
<th>Join Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach ($subscribers as $row) {
?>
<tr>
<td><?= htmlspecialchars($row['full_name']) ?></td>
<td>
<a href="mailto:<?= htmlspecialchars($row['email']) ?>"><?= htmlspecialchars($row['email']) ?></a></td>
<td><?= htmlspecialchars($row['phone']) ?></td>
<!--<td><?= htmlspecialchars($row['gender']) ?></td>-->
<td><?= htmlspecialchars($row['join_date']) ?></td>
<td>
<form action="/admin/unsubscribe.php" method="POST">
<input type="hidden" name="email" value="<?= htmlspecialchars($row['email']) ?>">
<button type="submit">Delete</button>
</form>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</body>
</html>

34
admin/login.php Normal file
View File

@ -0,0 +1,34 @@
<?php
session_start();
$token = $_POST['token'];
if (!isset($_SESSION['uid'])) {
if (!isset($token)) {
?>
<!DOCTYPE HTML>
<html>
<body>
<form action="/admin/login.php" method="POST">
<div>
<p>Enter passcode:</p>
<input type="password" name="token">
</div>
<div>
<button type="submit">Login</button>
</div>
</form>
</body>
</html>
<?php
die;
} else if ($token !== '1445') {
http_response_code(403);
die("Error: incorrect token");
} else {
$_SESSION['uid'] = 1;
}
}
header('Location: /admin');

16
admin/logout.php Normal file
View File

@ -0,0 +1,16 @@
<?php
session_start();
unset($_SESSION['uid']);
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="refresh" content="3; /">
</head>
<body>
<p>Signed out.</p>
</body>
</html>

53
admin/mail.php Normal file
View File

@ -0,0 +1,53 @@
<?php
session_start();
if (!isset($_SESSION['uid'])) {
header('Location: /admin/login.php');
die;
}
$message = $_POST['message'];
if (!isset($message)) {
?>
<!DOCTYPE HTML>
<html>
<body>
<form action="/admin/mail.php" method="POST">
<div>
<textarea name="message" placeholder="Message..."></textarea>
</div>
<div>
<button type="submit">Send</button>
</div>
</form>
</body>
</html>
<?php
die;
}
$conn = new mysqli("localhost", "mileslinden", "Daiso@6969", "mileslinden");
$result = $conn->query("SELECT email, full_name FROM subscribers");
if (!$result) {
http_response_code(500);
die(json_encode(['message' => $conn->error]));
}
$to_emails = [];
while ($row = $result->fetch_row()) {
$to_emails[] = "$row[1] <$row[0]>";
}
$to = implode(", ", $to_emails);
$headers = [
'From: Miles Linden <no-reply@mileslinden.com>',
'X-Mailer: PHP/' . phpversion()
];
$message = wordwrap($message, 80, "\r\n");
if (!mail($to, "MILES LINDEN CAMPAIGN ALERT", $message, implode("\r\n", $headers), '-fno-reply@mileslinden.com')) {
http_response_code(500);
die("Error: failed to send email message.");
}
die("Sent email successfully.");

32
admin/unsubscribe.php Normal file
View File

@ -0,0 +1,32 @@
<?php
session_start();
if (!isset($_SESSION['uid'])) {
header('Location: /admin/login.php');
die;
}
$email = $_POST['email'];
if (!isset($email)) {
http_response_code(400);
die("Error: no email provided to unsubscribe");
}
$conn = new mysqli("localhost", "mileslinden", "Daiso@6969", "mileslinden");
$query = $conn->prepare("DELETE FROM subscribers WHERE email = ?");
if (!$query) {
http_response_code(500);
die("Error: {$conn->error}");
}
$query->bind_param("s", $email);
$query->execute();
if ($query->affected_rows === 0) {
http_response_code(400);
die("Error: that email address does not exist");
} else {
header('Location: /admin');
die;
}

View File

@ -98,6 +98,10 @@ nav a:hover {
min-width: 250px;
}
.banner form input.invalid {
border-bottom-color: red;
}
.banner input {
border: none;
font-size: 32px;

View File

@ -3,8 +3,10 @@
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" integrity="sha512-NhSC1YmyruXifcj/KFRWoC561YpHpc5Jtzgvbuzx5VozKpWvQ+4nXhPdFgmx8xqexRcpAglTj9sIBWINXa8x5w==" crossorigin="anonymous">
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<link rel="fav icon" href="assets/favicon.png">
<script src="https://unpkg.com/vue@latest"></script>
<script src="js/app.js"></script>
<title>Miles Linden for San Jose City Council</title>
</head>
<body>

74
js/app.js Normal file
View File

@ -0,0 +1,74 @@
document.addEventListener('DOMContentLoaded', function () {
var fullName = document.querySelector('input[name="full_name"]');
var email = document.querySelector('input[name="email"]');
var phone = document.querySelector('input[name="phone"]');
var submit = document.querySelector('button[type="submit"]');
const emailRegex = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
const phoneRegex = /^(\+?0?1\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/;
const fullNameRegex = /[^\s.]{2,} [^\s.]{2,}/;
fullName.addEventListener('input', function (e) {
if (! fullName.value.toLowerCase().match(fullNameRegex)) {
fullName.classList.add('invalid');
} else {
fullName.classList.remove('invalid');
}
});
email.addEventListener('input', function (e) {
if (! email.value.toLowerCase().match(emailRegex)) {
email.classList.add('invalid');
} else {
email.classList.remove('invalid');
}
});
phone.addEventListener('input', function (e) {
if (! phone.value.match(phoneRegex)) {
phone.classList.add('invalid');
} else {
phone.classList.remove('invalid');
}
});
submit.addEventListener('click', function (e) {
e.preventDefault();
if (! fullName.value.toLowerCase().match(fullNameRegex)) {
alert("Your full name appears invalid.");
return;
}
if (! email.value.toLowerCase().match(emailRegex)) {
alert("Your email address is invalid.");
return;
}
if (! phone.value.match(phoneRegex)) {
alert("Your phone number is invalid.");
return;
}
var fd = new FormData();
fd.append('full_name', fullName.value);
fd.append('email', email.value);
fd.append('phone', phone.value);
var req = fetch('/subscribe.php', {
method: 'POST',
body: fd
}).then(function (res) {
if (!res.ok) {
res.json().then(function (err) {
document.querySelector('input[name="'+ err.field + '"]').classList.add('invalid');
alert(err.message);
});
} else {
alert("You have subscribed successfully.");
fullName.value = "";
email.value = "";
phone.value = "";
}
});
});
});

View File

@ -1,46 +0,0 @@
<?php
$token = $_POST['token'];
$message = $_POST['message'];
if ($token !== '1445') {
die("Error: invalid token.");
}
if (!$message) {
die("Error: invalid message (or lack thereof)");
}
$conn = mysql_connect(":/tmp/mysql.sock", "root", "");
if (!$conn) {
die("MySQL connection error: " . mysql_error());
}
mysql_select_db("mileslinden", $conn);
$result = mysql_query("SELECT * FROM subscribers");
$to_emails = array();
while ($row = mysql_fetch_assoc($result)) {
$to_emails[] = $row["email"];
}
$to = implode(", ", $to_emails);
$headers = array(
'From: no-reply@mileslinden.com',
'Reply-To: no-reply@mileslinden.com',
'X-Mailer: PHP/' . phpversion()
);
if (!mail($to, "MILES LINDEN CAMPAIGN ALERT", $message, implode("\r\n", $headers))) {
die("Error: failed to send email message.");
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Miles Linden for San Jose City Council</title>
</head>
<body>
<h1>Great success!</h1>
</body>
</html>

View File

@ -1,9 +1,10 @@
<?php
#ini_set('display_errors', 1);
$email = $_POST['email'];
$fname = $_POST['full_name'];
$phone = $_POST['phone'];
$gender = $_POST['gender'];
$gender = isset($_POST['gender']) && $_POST['gender'];
$pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';
@ -15,34 +16,35 @@ if (strlen($phone_num) == 11)
$phone_num = preg_replace("/^1/", '', $phone_num);
if (!$email || preg_match($pattern, $email) !== 1 || !$fname || strlen($phone_num) != 10) {
die("Error: An email address, first name, and last name are required.");
http_response_code(400);
die(json_encode([
'field' => 'email',
'message' => 'Error: An email address, first name, and last name are required.'
]));
}
if ($gender && $gender !== 'm' && $gender !== 'f') {
die("Error: An invalid gender was given.");
http_response_code(400);
die(json_encode([
'field' => 'full_name',
'message' => 'Error: An invalid gender was given.'
]));
}
$conn = mysql_connect(":/tmp/mysql.sock", "root", "");
if (!$conn) {
die("MySQL connection error: " . mysql_error());
}
mysql_select_db("mileslinden", $conn);
$conn = new mysqli("localhost", "mileslinden", "Daiso@6969", "mileslinden");
$query = sprintf(
"INSERT INTO subscribers (`email`, `full_name`, `phone`, `gender`, `join_date`) ".
"VALUES ('%s', '%s', '%s', '%s', '%s')",
mysql_real_escape_string($email),
mysql_real_escape_string($fname),
mysql_real_escape_string($phone),
mysql_real_escape_string($gender),
$query = $conn->prepare(
"INSERT INTO subscribers (`email`, `full_name`, `phone`, `gender`, `join_date`) VALUES (?, ?, ?, ?, ?)"
);
if (!$query) {
http_response_code(500);
die(json_encode(['message' => $conn->error]));
}
$query->bind_param(
"sssss",
$email, $fname, $phone_num, $gender,
date("Y-m-d H:i:s")
);
$res = mysql_query($query);
if (!$res) {
die("MySQL query error: " . mysql_error());
}
mysql_close($conn);
$query->execute();
?>
<!DOCTYPE HTML>
@ -52,6 +54,6 @@ mysql_close($conn);
<title>Miles Linden for San Jose City Council</title>
</head>
<body>
<h1>You have subscribed successfully!</h1>
<h1>You have subscribed successfully.</h1>
</body>
</html>