Compare commits

...

10 commits

25 changed files with 582 additions and 426 deletions

View file

@ -1,3 +1,9 @@
trinkey's fork of [notfire's qna](https://git.notfire.cc/notfire/qna)
has the same functionality but i added custom css support and made the code less messy
---
to set up, generally: to set up, generally:
- make a database in postgres - make a database in postgres
- set up config.php based off of the example - set up config.php based off of the example

View file

@ -4,74 +4,76 @@ $query = "
SELECT * FROM data; SELECT * FROM data;
"; ";
$qresp = pg_query($db, $query); $queryResponse = pg_query($db, $query);
$questions = pg_fetch_all($queryResponse);
asort($questions);
$rows = pg_fetch_all($qresp); $properTitle = "{$pageTitle} — admin";
$CSSdownDirectory = 1;
include "../boilerplate/pageStart.php";
include "../boilerplate/question.php";
$totalUnresponded = 0; echo("<h2 class=\"title\"> {$pageTitle} &mdash; admin</h2>");
$totalPriv = 0;
$totalRespondedPub = 0;
foreach (array_reverse($rows) as $i) {
if ($i["isrespondedto"] === "f" && $i["ispublic"] === "t") {
$totalUnresponded++;
} else if ($i["ispublic"] === "f") {
$totalPriv++;
} else {
$totalRespondedPub++;
}
}
echo("<h2 class=\"title\">" . $pageTitle . " admin</h2>");
if ($_GET["deleted"] == 1) { if ($_GET["deleted"] == 1) {
echo("<span class=\"sentconf\">deleted!</span>"); echo("<div class=\"sentconf\">deleted!</div>");
} }
if ($_GET["responded"] == 1) { if ($_GET["responded"] == 1) {
echo("<span class=\"sentconf\">response sent!</span>"); echo("<div class=\"sentconf\">response sent!</div>");
} }
asort($rows); if ($_GET["read"] == 1) {
echo("<div class=\"sentconf\">marked as read!</div>");
}
echo("<h3 class=\"sect\">not responded to ({$totalUnresponded})</h3>"); if ($_GET["unread"] == 1) {
foreach (array_reverse($rows) as $i){ echo("<div class=\"sentconf\">marked as unread!</div>");
if ($i["isrespondedto"] === "f" && $i["ispublic"] == "t") { }
echo("<div class=\"question\">");
if ($i["iscwed"] === "t") { if ($_GET["migrated"] == 1) {
echo("<details><summary>cw: " . $i["cw"] . "</summary><span class=\"cwfiller\"></span>"); echo("<div class=\"sentconf\">migrations have been run!</div>");
} }
echo(htmlspecialchars($i["text"]));
echo("<div class=\"time\">" . $i["time"] . "</div>"); $totalUnresponded = 0;
echo("<a class=\"permalink\" href=\"index.php?page=respond&id=" . $i["id"] . "&pw={$adminPassword}\">respond</a> / <a class=\"permalink\" href=\"index.php?page=delete&id=" . $i["id"] . "&pw={$adminPassword}\">delete</a></div>"); $totalPriv = 0;
$totalPrivRead = 0;
$totalRespondedPub = 0;
$unresponded = "";
$private = "";
$privateRead = "";
$responded = "";
foreach (array_reverse($questions) as $question) {
if ($question["isrespondedto"] === "f" && $question["ispublic"] === "t") {
$totalUnresponded++;
$unresponded .= getQuestion($question, 0, 1, 0, $adminPassword);
} else if ($question["ispublic"] === "f") {
if ($question["isprivread"] === "t") {
$totalPrivRead++;
$privateRead .= getQuestion($question, 0, 1, 0, $adminPassword);
} else {
$totalPriv++;
$private .= getQuestion($question, 0, 1, 0, $adminPassword);
} }
} else {
$totalRespondedPub++;
$responded .= getQuestion($question, 0, 1, 0, $adminPassword);
}
} }
echo("<h3 class=\"sect\">private ({$totalPriv})</h3>"); echo("
foreach (array_reverse($rows) as $i){ <h3 class=\"sect\">not responded to ({$totalUnresponded})</h3>
if ($i["ispublic"] === "f") { {$unresponded}
echo("<div class=\"question\">"); <h3 class=\"sect\">unread private ({$totalPriv})</h3>
if ($i["iscwed"] === "t") { {$private}
echo("<details><summary>cw: " . $i["cw"] . "</summary><span class=\"cwfiller\"></span>"); <h3 class=\"sect\">public ({$totalRespondedPub})</h3>
} {$responded}
echo(htmlspecialchars($i["text"])); <h3 class=\"sect\">read private ({$totalPrivRead})</h3>
echo("<div class=\"time\">" . $i["time"] . "</div>"); {$privateRead}
echo("<a class=\"permalink\" href=\"index.php?page=delete&id=" . $i["id"] . "&pw={$adminPassword}\">delete</a></div>"); ");
}
}
echo("<h3 class=\"sect\">public ({$totalRespondedPub})</h3>"); include '../boilerplate/pageEnd.php';
foreach (array_reverse($rows) as $i){
if ($i["ispublic"] === "t" && $i["isrespondedto"] === "t") {
echo("<div class=\"question\">");
if ($i["iscwed"] === "t") {
echo("<details><summary>cw: " . $i["cw"] . "</summary><span class=\"cwfiller\"></span>");
}
echo(htmlspecialchars($i["text"]));
echo("<div class=\"time\">" . $i["time"] . "</div>");
echo("<div class=\"response\">" . htmlspecialchars($i["responsetext"]) . "");
echo("<div class=\"time\">" . $i["responsetime"] . "</div></div>");
echo("<a class=\"permalink\" href=\"index.php?page=respond&responded=1&id=" . $i["id"] . "&pw={$adminPassword}\">edit response</a> / <a class=\"permalink\" href=\"index.php?page=delete&id=" . $i["id"] . "&pw={$adminPassword}\">delete</a></div>");
}
}
?> ?>

View file

@ -1,9 +1,9 @@
<?php <?php
$id = $_GET["id"]; $id = (int)$_GET["id"];
if ($id === null) { if ($id === null) {
exit(); exit();
} }
$query = " $query = "
@ -13,8 +13,6 @@ WHERE id = {$id};
pg_query($db, $query); pg_query($db, $query);
echo("done");
header("Location: index.php?deleted=1&pw={$adminPassword}"); header("Location: index.php?deleted=1&pw={$adminPassword}");
?> ?>

View file

@ -5,31 +5,43 @@ SELECT * FROM data
WHERE id = {$id}; WHERE id = {$id};
"; ";
$qresp = pg_query($db, $query); $queryResponse = pg_query($db, $query);
$arr = pg_fetch_array($qresp); $question = pg_fetch_array($queryResponse);
$url = "{$pageProto}://" . $_SERVER["HTTP_HOST"] . $pagePath . "/fetch.php?id={$id}";
if (strlen($question["fedipostid"]) == 0) {
$method = "POST";
$route = $fediAPIRoute;
} else {
$method = "PUT";
$route = $fediAPIRoute . "/" . $question["fedipostid"];
}
$cw = "anonymous question response (automated)";
if ($question["iscwed"] == "t") {
$cw .= "; cw: {$question['cw']}";
}
$ch = curl_init(); $ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$fediAPIRoute); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: {$fediAPIToken}"));
curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, curl_setopt($ch, CURLOPT_URL, $route);
array("Authorization: {$fediAPIToken}")); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
"status" => "question: {$question['text']}\n\nresponse: {$question['responsetext']}\n\nlink: {$url}",
"visibility" => $fediVisibility,
"spoiler_text" => $cw
)));
$contentO = $arr["text"]; $resp = curl_exec($ch);
$contentR = $arr["responsetext"]; if (strlen($question["fedipostid"]) == 0) {
$url = "{$pageProto}://" . $_SERVER["HTTP_HOST"] . $pagePath . "/fetch.php?id={$id}"; $jsonResp = json_decode($resp, true);
$fediID = $jsonResp["id"];
if ($arr["iscwed"] == "t") { pg_update($db, "data", array("fedipostid" => $fediID), array("id" => $id));
$contentCW = $arr["cw"];
curl_setopt($ch, CURLOPT_POSTFIELDS,
http_build_query(array('status' => "question: {$contentO}\n\nresponse: {$contentR}\n\nlink: {$url}", 'visibility' => "{$fediVisibility}", 'spoiler_text' => "anonymous question response (automated); cw: {$contentCW}")));
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS,
http_build_query(array('status' => "question: {$contentO}\n\nresponse: {$contentR}\n\nlink: {$url}", 'visibility' => "{$fediVisibility}", 'spoiler_text' => "anonymous question response (automated)")));
} }
curl_exec($ch);
curl_close($ch); curl_close($ch);
?> ?>

View file

@ -2,19 +2,25 @@
include '../config.php'; include '../config.php';
echo("<link rel=\"stylesheet\" href=\"../css/admin.css\">");
if ($_GET["pw"] === $adminPassword) { if ($_GET["pw"] === $adminPassword) {
if ($_GET["page"] === "delete") { switch ($_GET["page"]) {
include 'delete.php'; case "delete": include "delete.php"; break;
} elseif ($_GET["page"] === "respond") { case "respond": include "respond.php"; break;
include 'respond.php'; case "mark": include "mark.php"; break;
} else { case "migrate": include "migrate.php"; break;
include 'all.php'; default: include "all.php";
} }
} else { } else {
echo("<h2 class=\"sect\">enter password</h2>"); $properTitle = $pageTitle . " &mdash; sign in";
echo("<form class=\"frm\" action=\"index.php\"><input id=\"passinput\" name=\"pw\" required=\"\"><br><button class=\"submitbutton\" type=\"submit\">login</button></form>"); $CSSdownDirectory = 1;
include "../boilerplate/pageStart.php";
echo("
<h2 class=\"sect\">enter password</h2>
<form class=\"frm\" action=\"index.php\"><input id=\"passinput\" name=\"pw\" required=\"\"><br><button class=\"submitbutton\" type=\"submit\">login</button></form>
");
include "../boilerplate/pageEnd.php";
} }
?> ?>

29
admin/mark.php Normal file
View file

@ -0,0 +1,29 @@
<?php
$id = (int)$_GET["id"];
if ($id === null) {
exit();
}
if ($_GET["action"] === "unread") {
$query = "
UPDATE data
SET isprivread = False
WHERE id = {$id};
";
$headerinfo = "Location: index.php?unread=1&pw={$adminPassword}";
} else if ($_GET["action"] === "read") {
$query = "
UPDATE data
SET isprivread = True
WHERE id = {$id};
";
$headerinfo = "Location: index.php?read=1&pw={$adminPassword}";
}
pg_query($db, $query);
header($headerinfo);
?>

26
admin/migrate.php Normal file
View file

@ -0,0 +1,26 @@
<?php
$query = "
SELECT * FROM migrations;
";
$queryResponse = pg_query($db, $query);
$rows = pg_fetch_all($queryResponse);
$migrations = array(
"20240218-AddMigrationsTable-40641e8d",
"20240218-AddMarkReadOption-a7e43358",
"20240218-AddFalsesToPrivRead-67d82b18",
"20250310-AddFediIDColumn-64520350"
);
foreach ($migrations as $mig) {
if (!in_array($mig, array_column($rows, 'id'))) {
include "../migrations/{$mig}.php";
}
}
header("Location: index.php?migrated=1&pw={$adminPassword}");
?>

View file

@ -1,29 +1,30 @@
<?php <?php
$id = $_GET["id"]; $id = (int)$_GET["id"];
if ($id === null) { if ($id === null) {
exit(); exit();
} }
if ($_GET["text"] !== null) { if ($_GET["text"] !== null) {
$text = $_GET["text"]; $text = $_GET["text"];
$cdate = date("Y-m-d H:i:sP"); $cdate = date("Y-m-d H:i:sP");
$query = "
UPDATE data
SET \"responsetime\" = timestamptz'{$cdate}', isrespondedto = True
WHERE id = {$id};
";
pg_query($db, $query); $query = "
UPDATE data
SET \"responsetime\" = timestamptz'{$cdate}', isrespondedto = True
WHERE id = {$id};
";
pg_update($db, "data", array("responsetext" => $text), array("id" => $id)); pg_query($db, $query);
pg_update($db, "data", array("responsetext" => $text), array("id" => $id));
if ($fediEnabled) { if ($fediEnabled) {
include 'fedi.php'; include "fedi.php";
} }
header("Location: index.php?responded=1&pw={$adminPassword}"); header("Location: index.php?responded=1&pw={$adminPassword}");
exit();
} }
$query = " $query = "
@ -31,33 +32,27 @@ SELECT * FROM data
WHERE id = {$id}; WHERE id = {$id};
"; ";
$qresp = pg_query($db, $query); $queryResponse = pg_query($db, $query);
$arr = pg_fetch_array($qresp); $question = pg_fetch_array($queryResponse);
echo("<link rel=\"stylesheet\" href=\"css/indiv.css\">"); $properTitle = $pageTitle . " &mdash; respond to question #" . $id;
$CSSdownDirectory = 1;
include "../boilerplate/pageStart.php";
include "../boilerplate/question.php";
if ($arr["ispublic"] === "f") { if ($question["ispublic"] === "f") {
echo("<h2 class=\"title\">{$pageTitle} no such question exists</h2>"); echo("
echo("<a class=\"goback\" href=\"index.php\">(go back?)</a>"); <h2 class=\"title\">{$pageTitle} &mdash; no such question exists</h2>
http_response_code(404); <a class=\"go-back\" href=\"index.php\">(go back?)</a>
");
http_response_code(404);
} else { } else {
echo("<h2 class=\"title\">{$pageTitle} question number " . $arr["id"] . "</h2>"); echo("
<h2 class=\"title\">{$pageTitle} &mdash; question number {$question['id']}</h2>
<a class=\"go-back\" href=\"index.php?pw={$adminPassword}\">(go back?)</a>
");
echo("<a class=\"goback\" href=\"index.php?pw={$adminPassword}\">(go back?)</a>"); echo(getQuestion($question, 0, 0, 1, $adminPassword));
echo("<div class=\"question\">");
if ($arr["iscwed"] === "t") {
echo("<h3>cw: " . $arr["cw"] . "</h3>");
}
echo(htmlspecialchars($arr["text"]));
echo("<div class=\"time\">" . $arr["time"] . "</div>");
if ($_GET["responded"] == 1) {
echo("<div class=\"response\">" . htmlspecialchars($arr["responsetext"]) . "");
echo("<div class=\"time\">" . $arr["responsetime"] . "</div></div>");
echo("<h3>enter your edits</h3>");
} else {
echo("<h3>enter a response</h3>");
}
echo("<form class=\"frm\" action=\"index.php\"><input hidden name=\"id\" value=\"{$id}\"><input hidden name=\"page\" value=\"respond\"><input hidden name=\"pw\" value=\"{$adminPassword}\"><input id=\"passinput\" name=\"text\" required=\"\"><br><button class=\"submitbutton\" type=\"submit\">send</button></form>");
} }
?> ?>

2
boilerplate/pageEnd.php Normal file
View file

@ -0,0 +1,2 @@
</body>
</html>

14
boilerplate/pageStart.php Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title><?php echo($properTitle) ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="<?php if ($CSSdownDirectory) { echo("../"); } ?>css/base.css">
<?php
if ($customCSSurl) {
echo("<link rel=\"stylesheet\" href=\"" . $customCSSurl . "\">");
}
?>
</head>
<body>

87
boilerplate/question.php Normal file
View file

@ -0,0 +1,87 @@
<?php
function getQuestion(
$question,
$includePermalink=1,
$isAdmin=0,
$isResponding=0,
$adminPassword=""
) {
$q = htmlspecialchars($question["text"]);
$q .= "<div class=\"time\">{$question['time']}</div>";
if ($question["responsetext"]) {
$q .= "<div class=\"response\">" . htmlspecialchars($question['responsetext']);
$q .= "<div class=\"time\">{$question['responsetime']}</div></div>";
}
if ($isResponding) {
if ($question["responsetext"]) {
$q .= "<h3>enter your edits</h3>";
} else {
$q .= "<h3>enter a response</h3>";
}
$q .= "
<form class=\"frm\" action=\"index.php\">
<input hidden name=\"id\" value=\"{$question['id']}\">
<input hidden name=\"page\" value=\"respond\">
<input hidden name=\"pw\" value=\"{$adminPassword}\">
<input id=\"passinput\" name=\"text\" value=\"{$question['responsetext']}\" autofocus required><br>
<button class=\"submitbutton\" type=\"submit\">send</button>
</form>
";
}
if ($includePermalink === 1) {
$q .= "<a class=\"permalink\" href=\"fetch.php?id={$question['id']}\">permalink</a>";
}
if ($isAdmin === 1) {
if ($question["ispublic"] === "t") {
$q .= "<a class=\"permalink\" href=\"index.php?page=respond&id={$question['id']}&pw={$adminPassword}\">";
if ($question["isrespondedto"] === "t") {
$q .= "edit response";
} else {
$q .= "respond";
}
$q .= "</a>";
} else {
$q .= "<a class=\"permalink\" href=\"index.php?page=mark&action=";
if ($question["isprivread"] === "t") {
$q .= "unread";
} else {
$q .= "read";
}
$q .= "&id={$question['id']}&pw={$adminPassword}\">mark ";
if ($question["isprivread"] === "t") {
$q .= "unread";
} else {
$q .= "read";
}
$q .= "</a>";
}
$q .= " / <a class=\"permalink\" href=\"index.php?page=delete&id={$question['id']}&pw={$adminPassword}\">delete</a>";
}
if ($question["iscwed"] === "t") {
$open = "";
if ($isResponding) {
$open = " open";
}
$q = "<details{$open}><summary>cw: " . htmlspecialchars($question["cw"]) . "</summary>{$q}</details>";
}
return "<div class=\"question\">{$q}</div>";
}
?>

View file

@ -1,7 +1,7 @@
<?php <?php
// timezone (valid ones: https://www.php.net/manual/en/timezones.php) // timezone (valid ones: https://www.php.net/manual/en/timezones.php)
date_default_timezone_set('America/New_York'); date_default_timezone_set("America/New_York");
// admin // admin
$adminPassword = "setAPasswordHere!123"; $adminPassword = "setAPasswordHere!123";
@ -11,16 +11,20 @@ $pageTitle = "the cool qna";
$pageDomainEnabled = True; $pageDomainEnabled = True;
$pageProto = "https"; $pageProto = "https";
$pagePath = "/qna";
$pageDomain = "example.com"; $pageDomain = "example.com";
$pageDomainOther = $pageDomain; // you can comment out and change this to a subdomain you want to "go back to". eg your site is me.example.org but you want it to say example.org $pageDomainOther = $pageDomain; // you can comment out and change this to a subdomain you want to "go back to". eg your site is me.example.org but you want it to say example.org
//$pageDomainOther = "me.example.com"; //$pageDomainOther = "me.example.com";
$pageRoot = "/"; // path to go to $pageRoot = "/"; // path to go to
// set this to the url of any custom css
$customCSSurl = NULL;
// post to fedi? // post to fedi?
$fediEnabled = False; $fediEnabled = False;
$fediAPIRoute = "https://example.com/api/v1/statuses"; $fediAPIRoute = "https://example.com/api/v1/statuses";
$fediAPIToken = "Bearer AUTHTOKENGOESHERE"; $fediAPIToken = "Bearer AUTHTOKENGOESHERE";
$fediVisibility = "private"; $fediVisibility = "private"; // "direct", "private", "unlisted", "public"
// database setup // database setup
$dbHost = "localhost"; $dbHost = "localhost";
@ -28,7 +32,6 @@ $dbName = "postgres";
$dbUsername = "postgres"; $dbUsername = "postgres";
$dbPassword = "postgres"; $dbPassword = "postgres";
// !!! DON'T CHANGE ANYTHING AFTER THIS UNLESS YOU KNOW WHAT YOU'RE DOING !!! // !!! DON'T CHANGE ANYTHING AFTER THIS UNLESS YOU KNOW WHAT YOU'RE DOING !!!
$dbInfo = "host={$dbHost} dbname={$dbName} user={$dbUsername} password={$dbPassword}"; $dbInfo = "host={$dbHost} dbname={$dbName} user={$dbUsername} password={$dbPassword}";
$db = pg_connect($dbInfo); $db = pg_connect($dbInfo);

View file

@ -1,82 +0,0 @@
body {
background-image: url(https://notfire.cc/design/images/groundback.gif);
background-color: black;
color: white;
font-family: Arial, Helvetica, sans-serif;
}
.permalink {
color: #ff0000;
font-size: .9em;
}
.goback {
color: #ff0000;
}
.title {
margin-bottom: .1em;
}
.question {
margin-top: .7em;
background-color: #2c2c2c;
border-radius: 5px;
max-width: fit-content;
padding: .5em;
}
.response {
background-color: #505050;
border-radius: 5px;
margin-top: .3em;
padding: .4em;
margin-bottom: .25em;
}
.time {
font-size: .8em;
}
.cwfiller {
height: 1.3em;
display: inline-block;
}
.sect {
margin-top: .2em;
margin-bottom: .2em;
}
.sentconf {
color: lime;
margin-bottom: .3em;
}
.sendsum {
font-size: 1.17em;
font-weight: bold;
}
.sendmsg {
margin-top: 1em;
border-radius: 5px;
background-color: #2c2c2c;
max-width: fit-content;
padding: .7em;
}
#passinput, .submitbutton {
background-color: black;
color: white;
margin-bottom: .3em;
}
.submitbutton {
font-size: 1.17em;
margin-top: .3em;
}
.frm {
margin-bottom: 0px;
}

99
css/base.css Normal file
View file

@ -0,0 +1,99 @@
:root {
--background-color: #000000;
--text-color: #ffffff;
--hr-color: #808080;
--link-color: #ff0000;
--confirmation-color: #00ff00;
--question-background: #2c2c2c;
--response-background: #505050;
/* set to "none" to disable the background image */
--background-image: url("https://notfire.cc/design/images/groundback.gif");
--font-family: Arial, Helvetica, sans-serif;
}
body {
background-image: var(--background-image);
background-color: var(--background-color);
color: var(--text-color);
font-family: var(--font-family);
}
hr {
border: none;
height: 1.5px;
background-color: var(--hr-color);
}
.permalink {
color: var(--link-color);
font-size: .9em;
}
.go-back {
color: var(--link-color);
}
.title {
margin-bottom: .1em;
}
.question {
margin-top: .7em;
background-color: var(--question-background);
border-radius: 5px;
max-width: fit-content;
padding: .5em;
}
.response {
background-color: var(--response-background);
border-radius: 5px;
margin-top: .3em;
padding: .4em;
}
.time {
font-size: .8em;
}
.sect {
margin-top: .2em;
margin-bottom: .2em;
}
.sentconf {
color: var(--confirmation-color);
margin-bottom: .3em;
}
.sendsum {
font-size: 1.17em;
font-weight: bold;
}
.sendmsg {
margin-top: 1em;
border-radius: 5px;
background-color: var(--question-background);
max-width: fit-content;
padding: .7em;
}
#passinput,
#questioninput,
#cwinput,
.submitbutton {
background-color: var(--background-color);
color: var(--text-color);
margin-bottom: .3em;
}
.submitbutton {
font-size: 1.17em;
margin-top: .3em;
}
.frm {
margin-bottom: 0px;
}

View file

@ -1,38 +0,0 @@
body {
background-image: url(https://notfire.cc/design/images/groundback.gif);
background-color: black;
color: white;
font-family: Arial, Helvetica, sans-serif;
}
.goback {
color: #ff0000;
}
.title {
margin-bottom: .1em;
}
.question {
margin-top: .7em;
background-color: #2c2c2c;
border-radius: 5px;
max-width: fit-content;
padding: .5em;
}
.response {
background-color: #505050;
border-radius: 5px;
margin-top: .3em;
padding: .4em;
}
.time {
font-size: .8em;
}
.cwfiller {
height: 1.3em;
display: inline-block;
}

View file

@ -1,83 +0,0 @@
body {
background-image: url(https://notfire.cc/design/images/groundback.gif);
background-color: black;
color: white;
font-family: Arial, Helvetica, sans-serif;
}
.permalink {
color: #ff0000;
font-size: .9em;
}
.goback {
color: #ff0000;
}
.title {
margin-bottom: .1em;
}
.question {
margin-top: .7em;
background-color: #2c2c2c;
border-radius: 5px;
max-width: fit-content;
padding: .5em;
}
.response {
background-color: #505050;
border-radius: 5px;
margin-top: .3em;
padding: .4em;
margin-bottom: .25em;
}
.time {
font-size: .8em;
}
.cwfiller {
height: 1.3em;
display: inline-block;
}
.sect {
margin-bottom: .2em;
margin-top: .2em;
}
.sentconf {
color: lime;
margin-top: .3em;
margin-bottom: .3em;
}
.sendsum {
font-size: 1.17em;
font-weight: bold;
}
.sendmsg {
margin-top: 1em;
border-radius: 5px;
background-color: #2c2c2c;
max-width: fit-content;
padding: .7em;
}
#questioninput, #cwinput, .submitbutton {
background-color: black;
color: white;
margin-bottom: .3em;
}
.submitbutton {
font-size: 1.17em;
margin-top: .3em;
}
.frm {
margin-bottom: 0px;
}

View file

@ -1,11 +1,12 @@
<?php <?php
include 'config.php'; include "config.php";
include "boilerplate/question.php";
$id = $_GET["id"]; $id = (int)$_GET["id"];
if ($id === null) { if ($id === null) {
exit(); exit();
} }
$query = " $query = "
@ -13,27 +14,28 @@ SELECT * FROM data
WHERE id = {$id}; WHERE id = {$id};
"; ";
$qresp = pg_query($db, $query); $queryResponse = pg_query($db, $query);
$arr = pg_fetch_array($qresp); $question = pg_fetch_array($queryResponse);
echo("<link rel=\"stylesheet\" href=\"css/indiv.css\">"); $properTitle = "{$pageTitle} &mdash; question #{$id}";
include "boilerplate/pageStart.php";
if (pg_num_rows($qresp) === 0 || $arr["ispublic"] === "f" || $arr["isrespondedto"] === "f") { if (pg_num_rows($queryResponse) === 0 || $question["ispublic"] === "f" || $question["isrespondedto"] === "f") {
echo("<h2 class=\"title\">{$pageTitle} no such question exists</h2>"); echo("
echo("<a class=\"goback\" href=\"index.php\">(go back?)</a>"); <h2 class=\"title\">{$pageTitle} &mdash; no such question exists</h2>
http_response_code(404); <a class=\"go-back\" href=\"index.php\">(go back?)</a>
");
http_response_code(404);
} else { } else {
echo("<h2 class=\"title\">{$pageTitle} question number " . $arr["id"] . "</h2>"); echo("
<h2 class=\"title\">{$pageTitle} &mdash; question number {$question['id']}</h2>
<a class=\"go-back\" href=\"index.php\">(go back?)</a>
");
echo("<a class=\"goback\" href=\"index.php\">(go back?)</a>"); echo(getQuestion($question));
echo("<div class=\"question\">");
if ($arr["iscwed"] === "t") {
echo("<details><summary>cw: " . $arr["cw"] . "</summary><span class=\"cwfiller\"></span>");
}
echo(htmlspecialchars($arr["text"]));
echo("<div class=\"time\">" . $arr["time"] . "</div>");
echo("<div class=\"response\">" . $arr["responsetext"] . "");
echo("<div class=\"time\">" . $arr["responsetime"] . "</div></div></div>");
} }
include "boilerplate/pageEnd.php";
?> ?>

View file

@ -1,49 +1,56 @@
<?php <?php
include 'config.php'; include "config.php";
include "boilerplate/question.php";
$query = " $query = "
SELECT * FROM data; SELECT * FROM data
WHERE ispublic=true
AND isrespondedto=true;
"; ";
$qresp = pg_query($db, $query); $queryResponse = pg_query($db, $query);
$questions = pg_fetch_all($queryResponse);
asort($questions);
$rows = pg_fetch_all($qresp); $properTitle = "{$pageTitle} &mdash; all messages";
include "boilerplate/pageStart.php";
echo("<link rel=\"stylesheet\" href=\"css/main.css\">");
echo("<h2 class=\"title\">" . $pageTitle . "</h2>"); echo("<h2 class=\"title\">" . $pageTitle . "</h2>");
if ($pageDomainEnabled) { if ($pageDomainEnabled) {
echo("<a class=\"goback\" href=\"https://{$pageDomainOther}{$pageRoot}\">(go back to " . $pageDomain . "?)</a>"); echo("<a class=\"go-back\" href=\"https://{$pageDomainOther}{$pageRoot}\">(go back to " . $pageDomain . "?)</a>");
} }
if ($_GET["sent"] == 1) { if ($_GET["sent"] == 1) {
echo("<span class=\"sentconf\"><br>message sent!</span>"); echo("<span class=\"sentconf\"><br>message sent!</span>");
}
echo("<div class=\"sendmsg\"><details open=\"\"><summary class=\"sendsum\">send a message!</summary>");
echo("<form class=\"frm\" action=\"send.php\"><label for=\"questioninput\">enter your message: </label><input id=\"questioninput\" name=\"text\" required=\"\"><br><label for=\"cwinput\">cw if applicable: </label><input id=\"cwinput\" name=\"cw\"><br><input type=\"checkbox\" id=\"pubbox\" name=\"public\" value=\"1\" checked> <label for=\"pubbox\">if this is checked, your message will be available publicly</label><br><button class=\"submitbutton\" type=\"submit\">send!</button></form></details></div>");
echo("<hr>");
echo("<h3 class=\"sect\">all past messages</h3>");
asort($rows);
foreach (array_reverse($rows) as $i){
if ($i["ispublic"] === "t" && $i["isrespondedto"] === "t") {
echo("<div class=\"question\">");
if ($i["iscwed"] === "t") {
echo("<details><summary>cw: " . $i["cw"] . "</summary><span class=\"cwfiller\"></span>");
}
echo(htmlspecialchars($i["text"]));
echo("<div class=\"time\">" . $i["time"] . "</div>");
echo("<div class=\"response\">" . htmlspecialchars($i["responsetext"]) . "");
echo("<div class=\"time\">" . $i["responsetime"] . "</div></div>");
echo("<a class=\"permalink\" href=\"fetch.php?id=" . $i["id"] . "\">permalink</a></div>");
}
} }
?> ?>
<div class="sendmsg">
<details open>
<summary class="sendsum">send a message!</summary>
<form class="frm" action="send.php">
<label for="questioninput">enter your message: </label>
<input id="questioninput" name="text" required><br>
<label for="cwinput">cw if applicable: </label>
<input id="cwinput" name="cw"><br>
<input type="checkbox" id="pubbox" name="public" value="1" checked>
<label for="pubbox">if this is checked, your message will be available publicly</label><br>
<button class="submitbutton" type="submit">send!</button>
</form>
</details>
</div>
<hr>
<h3 class="sect">all past messages</h3>
<?php
foreach (array_reverse($questions) as $question){
echo(getQuestion($question));
}
include "boilerplate/pageEnd.php";
?>

View file

@ -0,0 +1,19 @@
<?php
// ensure already private messages still get shown
$query = "
UPDATE data
SET isprivread = False
WHERE ispublic IS FALSE;
";
pg_query($db, $query);
$dataArray = array(
"id" => "20240218-AddFalsesToPrivRead-67d82b18"
);
pg_insert($db, "migrations", $dataArray);
?>

View file

@ -0,0 +1,18 @@
<?php
// add "isprivread" to data columns
$query = "
ALTER TABLE data
ADD COLUMN isprivread BOOLEAN;
";
pg_query($db, $query);
$dataArray = array(
"id" => "20240218-AddMarkReadOption-a7e43358"
);
pg_insert($db, "migrations", $dataArray);
?>

View file

@ -0,0 +1,19 @@
<?php
// add migrations table to track migrations that have been run
$query = "
CREATE TABLE migrations (
id TEXT NOT NULL
);
";
pg_query($db, $query);
$dataArray = array(
"id" => "20240218-AddMigrationsTable-40641e8d"
);
pg_insert($db, "migrations", $dataArray);
?>

View file

@ -0,0 +1,18 @@
<?php
// add "fedipostid" column to data
$query = "
ALTER TABLE data
ADD COLUMN fedipostid TEXT;
";
pg_query($db, $query);
$dataArray = array(
"id" => "20250310-AddFediIDColumn-64520350"
);
pg_insert($db, "migrations", $dataArray);
?>

View file

@ -1,32 +1,18 @@
<?php <?php
include 'config.php'; include "config.php";
if ($_GET["text"] === null) { if ($_GET["text"] === null) {
exit(); exit();
} }
if ($_GET["cw"] === null || $_GET["cw"] === "") {
$iscw = False;
} else {
$iscw = True;
}
if ($_GET["public"] == 1) {
$isPublic = True;
} else {
$isPublic = False;
}
$curTime = date("Y-m-d H:i:sP");
$dataArray = array( $dataArray = array(
"text" => $_GET["text"], "text" => $_GET["text"],
"cw" => $_GET["cw"], "cw" => $_GET["cw"],
"iscwed" => $iscw, "iscwed" => !($_GET["cw"] === null || $_GET["cw"] === ""),
"time" => $curTime, "time" => date("Y-m-d H:i:sP"),
"ispublic" => $isPublic, "ispublic" => $_GET["public"] == 1,
"isrespondedto" => False "isrespondedto" => False
); );
pg_insert($db, "data", $dataArray); pg_insert($db, "data", $dataArray);

View file

@ -1,23 +1,34 @@
<?php <?php
include 'config.php'; include "config.php";
$query = " $query = "
CREATE TABLE data ( CREATE TABLE data (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
text TEXT NOT NULL, text TEXT NOT NULL,
cw TEXT, cw TEXT,
iscwed BOOLEAN NOT NULL, iscwed BOOLEAN NOT NULL,
time TIMESTAMPTZ NOT NULL, time TIMESTAMPTZ NOT NULL,
ispublic BOOLEAN NOT NULL, ispublic BOOLEAN NOT NULL,
isrespondedto BOOLEAN NOT NULL, isrespondedto BOOLEAN NOT NULL,
responsetext TEXT, responsetext TEXT,
responsetime TIMESTAMPTZ responsetime TIMESTAMPTZ,
isprivread BOOLEAN
); );
"; ";
pg_query($db, $query); pg_query($db, $query);
$query = "
CREATE TABLE migrations (
id TEXT NOT NULL
);
";
pg_query($db, $query);
include "admin/migrate.php";
echo "database set up"; echo "database set up";
?> ?>