locales and start on logged in page

This commit is contained in:
trinkey 2025-03-22 12:11:59 -04:00
parent 664020ff37
commit 18e4d29063
9 changed files with 191 additions and 43 deletions

View file

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<title><?php
if ($title) {
@ -8,7 +8,7 @@
}
echo $site_name;
?></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#190b14">
@ -31,4 +31,3 @@
echo "<div class=\"err\">$err<div></div></div>";
}
?>

View file

@ -3,6 +3,7 @@
// site config
$site_name = "Todo List Manager";
$signups = "invite"; // true, false, "invite" - treats it as true if no users currently exist, invite requires an admin to invite the user
$language = "en-US"; // an item from the lang folder. exclude the ".json"
$admin_users = array(
// "username1", "username2", ...
@ -20,6 +21,8 @@ $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_schema = array(
"general" => array(
"name" => "General",
@ -27,7 +30,7 @@ $default_schema = array(
"items" => array(
"general" => array(
"name" => "",
"display_format" => "For <b>%d</b> - %c"
"display_format" => "For %C<b>%t</b>%c - %d"
)
)
)

View file

@ -33,7 +33,12 @@ body {
font-size: 18px;
}
input {
h3 {
margin-bottom: 0;
}
input,
select {
background-color: var(--input-background);
color: var(--color);
border: 1px solid var(--border);
@ -42,7 +47,8 @@ input {
margin: 2px;
}
input:focus {
input:focus,
select:focus {
outline: 2px solid var(--subtext);
}
@ -63,6 +69,15 @@ i {
color: var(--subtext);
}
ul {
margin: 0;
padding-left: 25px;
}
.right {
text-align: right;
}
.err {
color: var(--red);
border: 2px dashed var(--red);

View file

@ -28,7 +28,7 @@ function is_logged_in(): false | array {
);
if ($user_object && get_token($user_object[0]["username"], $user_object[0]["password_hash"]) === $token) {
return $user_object;
return $user_object[0];
}
return false;

106
index.php
View file

@ -1,19 +1,109 @@
<?php
include "config.php";
include "helper.php";
include "boilerplate/head.php";
echo(is_logged_in());
?>
include "config.php";
include "helper.php";
include "boilerplate/head.php";
<a href="login.php">Log In</a>
$user = is_logged_in();
if ($user === false) {
echo "<a href=\"login.php\">{$lang['account']['log_in']}</a>";
<?php
$q = "SELECT count(*) FROM users LIMIT 1;";
if ($signups !== false || ($signups === false && pg_fetch_array(pg_query($db, $q))["count"] !== 0)) {
echo "- <a href=\"signup.php\">Sign Up</a>";
echo " - <a href=\"signup.php\">{$lang['account']['sign_up']}</a>";
}
include "boilerplate/foot.php";
exit();
}
$select_options = "";
$todo_list = "";
$q = "SELECT * FROM section WHERE users='{$user['id']}' ORDER BY LOWER(name) 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";
$enable_optgroup = $show_subtitle || count($rows) !== 1;
$todo_list .= "<h3>" . htmlspecialchars($section["name"]) . "</h3>";
if ($enable_optgroup) {
$select_options .= "<optgroup label=\"" . htmlspecialchars($section["name"]) . "\">";
}
$first = true;
foreach ($rows as $row) {
$select_options .= "<option value=\"{$section['id']}-{$row['id']}\">";
if ($first && !$show_subtitle) {
$select_options .= htmlspecialchars($section["name"]);
} else {
$select_options .= htmlspecialchars($row["name"]);
$todo_list .= "<strong>" . htmlspecialchars($row["name"]) . "</strong>";
}
$q = "SELECT * FROM item WHERE row='{$row['id']}' ORDER BY date ASC, LOWER(description) ASC;";
$items = pg_fetch_all(pg_query($db, $q));
$todo_list .= "<ul>";
if (count($items) === 0) {
$todo_list .= "<li><i>{$lang['list']['none']}</i></li>";
} else {
foreach ($items as $item) {
$todo_list .= "<li>" . str_replace("%d", htmlspecialchars($item["description"]), $row["display_format"]) . "</li>";
}
}
$todo_list .= "</ul>";
$select_options .= "</option>";
$first = false;
}
if ($enable_optgroup) {
$select_options .= "</optgroup>";
}
}
?>
<div id="container">
<h2><?php echo $lang["add"]["title"]; ?></h2>
<form method="POST">
<table>
<tr>
<td class="right"><label for="section"><?php echo $lang["add"]["section"]; ?></label></td>
<td>
<select required id="section" name="section">
<?php echo $select_options; ?>
</select>
</td>
</tr>
<tr>
<td class="right"><label for="date"><?php echo $lang["add"]["date"]; ?></label></td>
<td><input type="date" name="date" id="date" required></td>
</tr>
<tr>
<td class="right"><label for="description"><?php echo $lang["add"]["description"]; ?></label></td>
<td><input autofocus maxlength="256" placeholder="<?php echo $lang["add"]["description_placeholder"]; ?>" name="description" id="description" required></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="<?php echo $lang["add"]["button"]; ?>"></td>
</tr>
</table>
</form>
<h2><?php echo $lang["list"]["title"]; ?></h2>
<?php echo $todo_list; ?>
</div>
<?php
include "boilerplate/foot.php";
?>

36
lang/en-US.json Normal file
View file

@ -0,0 +1,36 @@
{
"account": {
"errors": {
"bad_request": "Bad request",
"username_length": "Username must be between 1 and 64 characters",
"username_characters": "Username can only include a-z, 0-9, _, and -",
"user_not_found": "User '%u' not found",
"user_exists": "User '%u' already exists",
"incorrect_password": "Incorrect password",
"password_match": "Passwords don't match"
},
"log_in": "Log In",
"log_in_instead": "Log in instead?",
"sign_up": "Sign Up",
"sign_up_instead": "Sign up instead?",
"username": "Username",
"password": "Password",
"verify": "Verify password"
},
"add": {
"title": "Add Item",
"section": "Section:",
"date": "Date:",
"description": "Description:",
"description_placeholder": "Important thing",
"button": "Add"
},
"list": {
"title": "Current Todo List",
"remove": "Completed",
"none": "None"
}
}

View file

@ -15,18 +15,18 @@
$p = $_POST["password"];
if (!($u && $p)) {
$err = "Bad request, missing username or password parameter";
$err = $lang["account"]["errors"]["bad_request"];
} else if (strlen($u) > 64 || strlen($u) === 0) {
$err = "Username must be 1-64 chars";
$err = $lang["account"]["errors"]["username_length"];
} else if (!preg_match("/^[a-z0-9_-]{1,64}$/", $u)) {
$err = "Username can only include a-z, 0-9, _, and -";
$err = $lang["account"]["errors"]["username_characters"];
} else {
$query = "SELECT password_hash FROM users WHERE username='$u' LIMIT 1;";
$response = pg_query($db, $query);
if (pg_num_rows($response) === 0) {
$err = "User '" . htmlspecialchars($u) . "' not found";
$err = str_replace("%u", htmlspecialchars($u), $lang["account"]["errors"]["user_not_found"]);
} else {
$user = pg_fetch_array($response);
if (password_verify($p, $user["password_hash"])) {
@ -38,27 +38,27 @@
header("Location: index.php");
exit();
} else {
$err = "Incorrect password";
$err = $lang["account"]["errors"]["incorrect_password"];
}
}
}
}
$title = "Log In";
$title = $lang["account"]["log_in"];
include "boilerplate/head.php";
?>
<form method="POST">
<div><input placeholder="Username" name="username" value="<?php echo htmlspecialchars($u); ?>" maxlength="64" required></div>
<div><input placeholder="Password" name="password" type="password" value="<?php echo htmlspecialchars($p); ?>" required></div>
<div><input type="submit" value="Log in"></div>
<div><input placeholder="<?php echo $lang["account"]["username"]; ?>" name="username" value="<?php echo htmlspecialchars($u); ?>" maxlength="64" required></div>
<div><input placeholder="<?php echo $lang["account"]["password"]; ?>" name="password" type="password" value="<?php echo htmlspecialchars($p); ?>" required></div>
<div><input type="submit" value="<?php echo $lang["account"]["log_in"]; ?>"></div>
</form>
<?php
$q = "SELECT count(*) FROM users LIMIT 1;";
if ($signups !== false || ($signups === false && pg_fetch_array(pg_query($db, $q))["count"] !== 0)) {
echo "<p><a href=\"signup.php\">Sign up instead?</a></p>";
echo "<p><a href=\"signup.php\">{$lang['account']['sign_up_instead']}</a></p>";
}
include "boilerplate/foot.php";

View file

@ -6,7 +6,10 @@ $queries = array(
"CREATE TABLE IF NOT EXISTS users (
id VARCHAR(64) PRIMARY KEY,
username VARCHAR(64) UNIQUE NOT NULL,
password_hash VARCHAR(256) NOT NULL
password_hash VARCHAR(256) NOT NULL,
enable_colors BOOLEAN NOT NULL,
yellow_threshold INT NOT NULL,
gray_threshold INT NOT NULL
);",
"CREATE TABLE IF NOT EXISTS section (
id VARCHAR(64) PRIMARY KEY,
@ -17,8 +20,8 @@ $queries = array(
"CREATE TABLE IF NOT EXISTS row (
id VARCHAR(64) PRIMARY KEY,
section VARCHAR(64) NOT NULL REFERENCES section(id),
name VARCHAR(128),
display_format VARCHAR(128) NOT NULL -- %d - date, %c - description
name VARCHAR(128), -- ignored if first item and show_subtitle is enabled
display_format VARCHAR(128) NOT NULL -- %t - date, %d - description, %C - start color, %c - end color
);",
"CREATE TABLE IF NOT EXISTS item (
id VARCHAR(64) PRIMARY KEY,

View file

@ -16,13 +16,13 @@
$v = $_POST["verify"];
if ($v != $p) {
$err = "Passwords don't match";
$err = $lang["account"]["errors"]["password_match"];
} else if (!($u && $p && $v)) {
$err = "Bad request, missing username, password, or verify parameter";
$err = $lang["account"]["errors"]["bad_request"];
} else if (strlen($u) > 64 || strlen($u) === 0) {
$err = "Username must be 1-64 chars";
$err = $lang["account"]["errors"]["username_length"];
} else if (!preg_match("/^[a-z0-9_-]{1,64}$/", $u)) {
$err = "Username can only include a-z, 0-9, _, and -";
$err = $lang["account"]["errors"]["username_characters"];
} else {
$query = "SELECT count(*) FROM users WHERE username='$u' LIMIT 1;";
@ -35,11 +35,14 @@
$user_parameters = array(
"id" => $user_id,
"username" => $u,
"password_hash" => $pw_hash
"password_hash" => $pw_hash,
"enable_colors" => true,
"yellow_threshold" => 2,
"gray_threshold" => 60
);
pg_insert($db, "users", $user_parameters);
foreach ($default_schema as $section_id => $section_data) {
$section_id = generate_id();
$section_parameters = array(
@ -66,28 +69,27 @@
$token = get_token($u, $pw_hash);
setcookie(
"token",
$token,
"token", $token,
time() + 60 * 60 * 24 * 30 * 265 // 1 year from now
);
header("Location: index.php");
exit();
} else {
$err = "User '" . htmlspecialchars($u) . "' already exists";
$err = str_replace("%u", htmlspecialchars($u), $lang["account"]["errors"]["user_exists"]);
}
}
}
$title = "Sign Up";
$title = $lang["account"]["sign_up"];
include "boilerplate/head.php";
?>
<form method="POST">
<div><input placeholder="Username" name="username" value="<?php echo htmlspecialchars($u); ?>" maxlength="64" required></div>
<div><input placeholder="Password" name="password" type="password" value="<?php echo htmlspecialchars($p); ?>" required></div>
<div><input placeholder="Verify Password" name="verify" type="password" required></div>
<div><input type="submit" value="Sign Up"></div>
<p><a href="login.php">Log in instead?</a></p>
<div><input placeholder="<?php echo $lang["account"]["username"]; ?>" name="username" value="<?php echo htmlspecialchars($u); ?>" maxlength="64" required></div>
<div><input placeholder="<?php echo $lang["account"]["password"]; ?>" name="password" type="password" value="<?php echo htmlspecialchars($p); ?>" required></div>
<div><input placeholder="<?php echo $lang["account"]["verify"]; ?>" name="verify" type="password" required></div>
<div><input type="submit" value="<?php echo $lang["account"]["sign_up"]; ?>"></div>
<p><a href="login.php"><?php echo $lang["account"]["log_in_instead"]; ?></a></p>
</form>
<?php