creating/deleting rows and sections

This commit is contained in:
trinkey 2025-03-27 08:31:55 -04:00
parent 89efc1ccc0
commit 34256263ac
7 changed files with 180 additions and 18 deletions

4
TODO.md Normal file
View file

@ -0,0 +1,4 @@
- saving section info
- account deletion
- admin page
- invite codes

View file

@ -16,21 +16,24 @@ $db_username = "postgres";
$db_password = "postgres"; $db_password = "postgres";
// DO NOT CHANGE THIS!!! // DO NOT CHANGE THIS!!!
$lang = json_decode(file_get_contents("lang/$language.json"), true);
$db_info = "host=$db_host dbname=$db_name user=$db_username password=$db_password"; $db_info = "host=$db_host dbname=$db_name user=$db_username password=$db_password";
$db = pg_connect($db_info); $db = pg_connect($db_info);
// default schema // default schema
// DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!!! // DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!!!
$lang = json_decode(file_get_contents("lang/$language.json"), true);
$default_format = "For %C<b>%t</b>%c - %d"; $default_format = "For %C<b>%t</b>%c - %d";
$default_section_name = "New Section";
$default_row_name = "New Row";
$default_schema = array( $default_schema = array(
"general" => array( "general" => array(
"name" => "General", "name" => "General",
"show_subtitle" => false, "show_subtitle" => false,
"items" => array( "items" => array(
"general" => array( "general" => array(
"name" => "", "name" => $default_row_name,
"display_format" => "For %C<b>%t</b>%c - %d" "display_format" => $default_format
) )
) )
) )

View file

@ -33,7 +33,7 @@ body {
font-size: 18px; font-size: 18px;
} }
h3 { h3, h4 {
margin-bottom: 0; margin-bottom: 0;
} }
@ -87,6 +87,12 @@ details:not([open]) summary {
color: var(--subtext); color: var(--subtext);
} }
blockquote {
margin: 10px 0;
padding-left: 10px;
border-left: 4px solid var(--subtext);
}
code { code {
font-family: monospace; font-family: monospace;
padding: 1px 3px; padding: 1px 3px;
@ -138,3 +144,11 @@ code {
flex-wrap: wrap; flex-wrap: wrap;
gap: 3px 30px; gap: 3px 30px;
} }
#section-config {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
gap: 10px;
margin-bottom: 10px;
}

131
index.php
View file

@ -20,17 +20,53 @@ if ($user === false) {
} else if ($_SERVER["REQUEST_METHOD"] === "POST") { } else if ($_SERVER["REQUEST_METHOD"] === "POST") {
$intent = $_POST["intent"]; $intent = $_POST["intent"];
if ($intent === "create-item") { // TODO: update-texts
if ($intent === "create-section") {
$section_id = generate_id();
pg_insert(
$db, "section", array(
"id" => $section_id,
"users" => $user["id"],
"name" => $default_section_name,
"show_subtitle" => false
)
);
pg_insert(
$db, "row", array(
"id" => generate_id(),
"section" => $section_id,
"name" => $default_row_name,
"display_format" => $default_format
)
);
} else if ($intent === "create-row") {
$section_id = $_POST["section"];
if (strlen($section_id) !== 64 || !preg_match("/[a-f0-9]{64}/", $section_id)) {
$err = $lang["add"]["errors"]["invalid_id"];
} else {
pg_insert(
$db, "row", array(
"id" => generate_id(),
"section" => $section_id,
"name" => $default_row_name,
"display_format" => $default_format
)
);
}
} else if ($intent === "create-item") {
$row_id = $_POST["row"]; $row_id = $_POST["row"];
$date = strtotime($_POST["date"]); $date = strtotime($_POST["date"]);
$description = $_POST["description"]; $description = $_POST["description"];
if (strlen($row_id) !== 64 || !preg_match("/[a-f0-9]{64}/", $row_id)) { if (strlen($row_id) !== 64 || !preg_match("/[a-f0-9]{64}/", $row_id)) {
$err = lang["add"]["errors"]["invalid_id"]; $err = $lang["add"]["errors"]["invalid_id"];
} else if ($date === false) { } else if ($date === false) {
$err = lang["add"]["errors"]["date"]; $err = $lang["add"]["errors"]["date"];
} else if (strlen($description) === 0 || strlen($description) > 256) { } else if (strlen($description) === 0 || strlen($description) > 256) {
$err = lang["add"]["errors"]["description_length"]; $err = $lang["add"]["errors"]["description_length"];
} else { } else {
$repopulate = array( $repopulate = array(
"row_id" => $row_id, "row_id" => $row_id,
@ -75,25 +111,47 @@ if ($user === false) {
$err = $lang["account"]["errors"]["incorrect_password"]; $err = $lang["account"]["errors"]["incorrect_password"];
} }
} }
} else if ($_GET["del"] && strlen($_GET["del"]) === 64 && preg_match("/[a-f0-9]{64}/", $_GET["del"])) { } else if ($_GET["del"]) {
pg_query($db, "DELETE FROM item WHERE id='{$_GET['del']}';"); $del_type = explode("-", $_GET["del"])[0];
$del_id = explode("-", $_GET["del"])[1];
if (strlen($del_id) === 64 && preg_match("/[a-f0-9]{64}/", $del_id) && ($del_type === "item" || $del_type === "row" || $del_type === "section")) {
pg_query($db, "DELETE FROM $del_type WHERE id='$del_id';");
}
} }
include "boilerplate/head.php"; include "boilerplate/head.php";
$select_options = ""; $select_options = "";
$todo_list = ""; $todo_list = "";
$section_conf = "";
$section_forms = "";
$q = "SELECT * FROM section WHERE users='{$user['id']}' ORDER BY LOWER(name) ASC;"; $q = "SELECT * FROM section WHERE users='{$user['id']}' ORDER BY LOWER(name) ASC, id ASC;";
$sections = pg_fetch_all(pg_query($db, $q)); $sections = pg_fetch_all(pg_query($db, $q));
foreach ($sections as $section) { foreach ($sections as $section) {
$q = "SELECT * FROM row WHERE section='{$section['id']}' ORDER BY LOWER(name) ASC;";
$rows = pg_fetch_all(pg_query($db, $q));
$show_subtitle = $section["show_subtitle"] === "t"; $show_subtitle = $section["show_subtitle"] === "t";
$q = "SELECT * FROM row WHERE section='{$section['id']}' ORDER BY LOWER(name) ASC, id ASC;";
$rows = pg_fetch_all(pg_query($db, $q));
$enable_optgroup = $show_subtitle || count($rows) !== 1; $enable_optgroup = $show_subtitle || count($rows) !== 1;
$todo_list .= "<h3>" . htmlspecialchars($section["name"]) . "</h3>"; $todo_list .= "<h3>" . htmlspecialchars($section["name"]) . "</h3>";
$section_conf .= "<blockquote>
<div><label>
{$lang['settings']['sections']['section']['title']}
<input maxlength=\"128\" placeholder='{$lang['settings']['sections']['section']['placeholder']}' value=\"" . htmlspecialchars($section["name"]) . "\" required name=\"section-{$section['id']}-name\">
</label></div>
<div><label>
{$lang['settings']['sections']['section']['show_subtitle']}
<input type=\"checkbox\" name=\"section-{$section['id']}-subtitle\"" . ($show_subtitle ? " checked" : "") . ">
</label></div>
<div>
<a class=\"plain\" href=\"index.php?del=section-{$section['id']}\">
<button type=\"button\" tabindex=\"-1\">{$lang['settings']['sections']['section']['delete']}</button>
</a>
</div>
";
if ($enable_optgroup) { if ($enable_optgroup) {
$select_options .= "<optgroup label=\"" . htmlspecialchars($section["name"]) . "\">"; $select_options .= "<optgroup label=\"" . htmlspecialchars($section["name"]) . "\">";
@ -114,7 +172,21 @@ foreach ($sections as $section) {
$todo_list .= "<strong>" . htmlspecialchars($row["name"]) . "</strong>"; $todo_list .= "<strong>" . htmlspecialchars($row["name"]) . "</strong>";
} }
$q = "SELECT * FROM item WHERE row='{$row['id']}' ORDER BY date ASC, LOWER(description) ASC;"; $section_conf .= "<blockquote><div><label>
{$lang['settings']['sections']['row']['title']}
<input required placeholder=\"{$lang['settings']['sections']['row']['placeholder']}\" maxlength=\"128\" name=\"row-{$row['id']}-name\" value=\"" . htmlspecialchars($row["name"]) . "\">
</label></div>
<div><label>
{$lang['settings']['sections']['row']['format']}
<input placeholder=\"{$lang['settings']['sections']['row']['format_placeholder']}\" maxlength=\"128\" name=\"row-{$row['id']}-format\" value=\"" . htmlspecialchars($row["display_format"]) . "\">
</label></div>
<div><a class=\"plain\" href=\"index.php?del=row-{$row['id']}\">
<button tabindex=\"-1\" type=\"button\">
{$lang['settings']['sections']['row']['delete']}
</button>
</a></div></blockquote>";
$q = "SELECT * FROM item WHERE row='{$row['id']}' ORDER BY date ASC, LOWER(description) ASC, id ASC;";
$items = pg_fetch_all(pg_query($db, $q)); $items = pg_fetch_all(pg_query($db, $q));
$todo_list .= "<ul>"; $todo_list .= "<ul>";
@ -132,7 +204,7 @@ foreach ($sections as $section) {
) )
) )
) )
) . " <a class=\"plain\" href=\"index.php?del={$item['id']}\"><button tabindex=\"-1\">{$lang['list']['remove']}</button></a></li>"; ) . " <a class=\"plain\" href=\"index.php?del=item-{$item['id']}\"><button tabindex=\"-1\">{$lang['list']['remove']}</button></a></li>";
} }
} }
@ -141,6 +213,12 @@ foreach ($sections as $section) {
$first = false; $first = false;
} }
$section_forms .= "<form method=\"POST\" id=\"section-{$section['id']}-new\">
<input type=\"hidden\" name=\"intent\" value=\"create-row\">
<input type=\"hidden\" name=\"section\" value=\"{$section['id']}\">
</form>";
$section_conf .= "<input type=\"submit\" form=\"section-{$section['id']}-new\" value=\"{$lang['settings']['sections']['row']['new']}\"></blockquote>";
if ($enable_optgroup) { if ($enable_optgroup) {
$select_options .= "</optgroup>"; $select_options .= "</optgroup>";
} }
@ -185,6 +263,37 @@ foreach ($sections as $section) {
<div id="settings-container"> <div id="settings-container">
<div> <div>
<h3><?php echo $lang["settings"]["sections"]["title"]; ?></h3> <h3><?php echo $lang["settings"]["sections"]["title"]; ?></h3>
<?php echo $section_forms; ?>
<form method="POST" id="create-section">
<input type="hidden" name="intent" value="create-section">
</form>
<form method="POST">
<div id="section-config">
<?php echo $section_conf; ?>
</div>
<input type="hidden" name="intent" value="update-texts">
<input type="submit" value="<?php echo $lang["settings"]["sections"]["save"]; ?>">
<input type="submit" form="create-section" value="<?php echo $lang["settings"]["sections"]["section"]["new"]; ?>">
</form>
<h4><?php echo $lang["settings"]["sections"]["format"]["title"]; ?></h4>
<ul>
<li><?php echo $lang["settings"]["sections"]["format"]["alphabetical"]; ?></li>
<li><?php echo $lang["settings"]["sections"]["format"]["html"]; ?></li>
<li>
<?php echo $lang["settings"]["sections"]["format"]["replacements"]["title"] ?>
<ul>
<li><code>%t</code> - <?php echo $lang["settings"]["sections"]["format"]["replacements"]["%t"]; ?></li>
<li><code>%d</code> - <?php echo $lang["settings"]["sections"]["format"]["replacements"]["%d"]; ?></li>
<li><code>%C</code> - <?php echo $lang["settings"]["sections"]["format"]["replacements"]["%C"]; ?></li>
<li><code>%c</code> - <?php echo $lang["settings"]["sections"]["format"]["replacements"]["%c"]; ?></li>
</ul>
</li>
</ul>
</div> </div>
<div> <div>

View file

@ -43,7 +43,39 @@
"settings": { "settings": {
"sections": { "sections": {
"title": "Configure Sections" "section": {
"title": "Title:",
"placeholder": "Section title",
"delete": "Delete section",
"new": "New section",
"show_subtitle": "Show separate title for first item?"
},
"row": {
"title": "Title:",
"placeholder": "Row title",
"delete": "Delete row",
"new": "New row",
"format": "Item display format:",
"format_placeholder": "For %C<b>%t</b>%c - %d"
},
"format": {
"replacements": {
"title": "Item display format replacements:",
"%t": "date",
"%d": "item description",
"%C": "start color",
"%c": "end color"
},
"title": "Formatting Information",
"alphabetical": "Sorted alphabetically by row/section title",
"html": "Displayed as raw HTML"
},
"title": "Configure Sections",
"save": "Save"
}, },
"account": { "account": {

View file

@ -33,7 +33,7 @@
$token = get_token($u, $user["password_hash"]); $token = get_token($u, $user["password_hash"]);
setcookie( setcookie(
"token", $token, "token", $token,
time() + 60 * 60 * 24 * 30 * 265 // 1 year from now time() + 60 * 60 * 24 * 265 // 1 year from now
); );
header("Location: index.php"); header("Location: index.php");
exit(); exit();

View file

@ -70,7 +70,7 @@
$token = get_token($u, $pw_hash); $token = get_token($u, $pw_hash);
setcookie( setcookie(
"token", $token, "token", $token,
time() + 60 * 60 * 24 * 30 * 265 // 1 year from now time() + 60 * 60 * 24 * 365 // 1 year from now
); );
header("Location: index.php"); header("Location: index.php");
exit(); exit();