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";
// 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 = pg_connect($db_info);
// default schema
// 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_section_name = "New Section";
$default_row_name = "New Row";
$default_schema = array(
"general" => array(
"name" => "General",
"show_subtitle" => false,
"items" => array(
"general" => array(
"name" => "",
"display_format" => "For %C<b>%t</b>%c - %d"
"name" => $default_row_name,
"display_format" => $default_format
)
)
)

View file

@ -33,7 +33,7 @@ body {
font-size: 18px;
}
h3 {
h3, h4 {
margin-bottom: 0;
}
@ -87,6 +87,12 @@ details:not([open]) summary {
color: var(--subtext);
}
blockquote {
margin: 10px 0;
padding-left: 10px;
border-left: 4px solid var(--subtext);
}
code {
font-family: monospace;
padding: 1px 3px;
@ -138,3 +144,11 @@ code {
flex-wrap: wrap;
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") {
$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"];
$date = strtotime($_POST["date"]);
$description = $_POST["description"];
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) {
$err = lang["add"]["errors"]["date"];
$err = $lang["add"]["errors"]["date"];
} else if (strlen($description) === 0 || strlen($description) > 256) {
$err = lang["add"]["errors"]["description_length"];
$err = $lang["add"]["errors"]["description_length"];
} else {
$repopulate = array(
"row_id" => $row_id,
@ -75,25 +111,47 @@ if ($user === false) {
$err = $lang["account"]["errors"]["incorrect_password"];
}
}
} else if ($_GET["del"] && strlen($_GET["del"]) === 64 && preg_match("/[a-f0-9]{64}/", $_GET["del"])) {
pg_query($db, "DELETE FROM item WHERE id='{$_GET['del']}';");
} else if ($_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";
$select_options = "";
$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));
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";
$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;
$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) {
$select_options .= "<optgroup label=\"" . htmlspecialchars($section["name"]) . "\">";
@ -114,7 +172,21 @@ foreach ($sections as $section) {
$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));
$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;
}
$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) {
$select_options .= "</optgroup>";
}
@ -185,6 +263,37 @@ foreach ($sections as $section) {
<div id="settings-container">
<div>
<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>

View file

@ -43,7 +43,39 @@
"settings": {
"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": {

View file

@ -33,7 +33,7 @@
$token = get_token($u, $user["password_hash"]);
setcookie(
"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");
exit();

View file

@ -70,7 +70,7 @@
$token = get_token($u, $pw_hash);
setcookie(
"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");
exit();