Initial commit - signing up + boilerplate/schema

This commit is contained in:
trinkey 2025-03-21 23:43:07 -04:00
commit d8f1874ebb
10 changed files with 393 additions and 0 deletions

BIN
assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

2
boilerplate/foot.php Normal file
View file

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

34
boilerplate/head.php Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title><?php
if ($title) {
echo "$title | ";
}
echo $site_name;
?></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#190b14">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="/assets/favicon.png">
<link rel="icon" href="/assets/favicon.png">
<link rel="stylesheet" href="/css/base.css">
</head>
<body>
<?php
if ($title) {
echo "<h1>$title</h1><h2>$site_name</h2>";
} else {
echo "<h1>$site_name</h1>";
}
if ($err) {
echo "<div class=\"err\">$err<div></div></div>";
}
?>

36
config.php Normal file
View file

@ -0,0 +1,36 @@
<?php
// 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
$admin_users = array(
// "username1", "username2", ...
);
// database config
$db_host = "localhost";
$db_name = "todo";
$db_username = "postgres";
$db_password = "postgres";
// DO NOT CHANGE THIS!!!
$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!!!
$default_schema = array(
"general" => array(
"name" => "General",
"show_subtitle" => false,
"items" => array(
"general" => array(
"name" => "",
"display_format" => "For <b>%d</b> - %c"
)
)
)
);
?>

79
css/base.css Normal file
View file

@ -0,0 +1,79 @@
:root {
--background: #190b14;
--text: #c5b8ca;
--subtext: #c5a8ca80;
--border: #d8a4c62a;
--input-background: #2e1425;
--button-background: #3c1a30;
--button-hover-background: #5e2a4e;
--accent: #d8a4c6;
--red: #d67677;
--yellow: #d3d381;
color-scheme: dark;
}
::selection {
background-color: var(--accent);
color: var(--background);
}
body {
position: absolute;
top: 0;
left: 0;
background-color: var(--background);
color: var(--text);
min-height: calc(100vh - 16px);
width: calc(100vw - 16px);
overflow-x: hidden;
margin: 8px;
text-align: center;
font-family: sans-serif;
font-size: 18px;
}
input {
background-color: var(--input-background);
color: var(--color);
border: 1px solid var(--border);
padding: 3px 5px;
border-radius: 7.5px;
margin: 2px;
}
input:focus {
outline: 2px solid var(--subtext);
}
input::placeholder {
color: var(--subtext);
}
a {
color: var(--accent);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
i {
color: var(--subtext);
}
.err {
color: var(--red);
border: 2px dashed var(--red);
padding: 20px;
border-radius: 20px;
max-width: 400px;
margin: 0 auto;
margin-bottom: 20px;
}
#container {
text-align: left;
margin: 0 10vw;
}

37
helper.php Normal file
View file

@ -0,0 +1,37 @@
<?php
function generate_id(): string {
return hash("sha256", uniqid("", true));
}
function get_token(string $username, string $password_hash): string {
return $username . "-" . hash("sha256", $password_hash . $username);
}
function validate_token(string $token): bool {
}
function is_logged_in(): false | array {
$token = $_COOKIE["token"];
if (!$token) {
return false;
}
global $db;
$u = explode("-", $token, 2)[0];
$user_object = pg_select(
$db, "users", array(
"username" => $u
)
);
if ($user_object && get_token($user_object[0]["username"], $user_object[0]["password_hash"]) === $token) {
return $user_object;
}
return false;
}
?>

16
index.php Normal file
View file

@ -0,0 +1,16 @@
<?php
include "config.php";
include "boilerplate/head.php";
?>
<a href="login.php">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>";
}
include "boilerplate/foot.php";
?>

46
login.php Normal file
View file

@ -0,0 +1,46 @@
<?php
include "config.php";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$u = $_POST["username"];
$p = $_POST["password"];
if ($u && $p) {
$response = pg_select(
$db,
"users",
array("username" => $u)
);
if (sizeof($response) === 0) {
$err = "User '" . htmlspecialchars($u) . "' not found";
} else {
echo json_encode($response);
}
} else {
$err = "Bad request, missing username or password parameter";
}
} else {
$u = "";
$p = "";
}
$title = "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>
</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>";
}
include "boilerplate/foot.php";
?>

43
setup.php Normal file
View file

@ -0,0 +1,43 @@
<?php
include "config.php";
$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
);",
"CREATE TABLE IF NOT EXISTS section (
id VARCHAR(64) PRIMARY KEY,
users VARCHAR(64) NOT NULL REFERENCES users(id),
name VARCHAR(128),
show_subtitle BOOLEAN NOT NULL -- whether or not to separately show the name of the first item
);",
"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
);",
"CREATE TABLE IF NOT EXISTS item (
id VARCHAR(64) PRIMARY KEY,
row VARCHAR(64) NOT NULL REFERENCES row(id),
description VARCHAR(256) NOT NULL,
date DATE NOT NULL
);",
"CREATE TABLE IF NOT EXISTS invites (
id VARCHAR(64) PRIMARY KEY
);"
);
foreach($queries as $q) {
if (!pg_query($db, $q)) {
echo "uh oh" . pg_last_error($db);
exit();
}
}
echo "ok :verygood:";
?>

100
signup.php Normal file
View file

@ -0,0 +1,100 @@
<?php
include "config.php";
include "helper.php";
if (is_logged_in()) {
header("Location: index.php");
exit();
}
$u = "";
$p = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$u = strtolower(str_replace(" ", "", $_POST["username"]));
$p = $_POST["password"];
$v = $_POST["verify"];
if ($v != $p) {
$err = "Passwords don't match";
} else if (!($u && $p && $v)) {
$err = "Bad request, missing username, password, or verify parameter";
} else if (strlen($u) > 64 || strlen($u) === 0) {
$err = "Username must be 1-64 chars";
} else if (!preg_match("/^[a-z0-9_-]{1,64}$/", $u)) {
$err = "Username can only include a-z, 0-9, _, and -";
} else {
$query = "SELECT count(*) FROM users WHERE username='$u' LIMIT 1;";
$response = pg_query($db, $query);
$c = pg_fetch_array($response)["count"];
if ($c === "0") {
$user_id = generate_id();
$pw_hash = password_hash($p, PASSWORD_DEFAULT);
$user_parameters = array(
"id" => $user_id,
"username" => $u,
"password_hash" => $pw_hash
);
pg_insert($db, "users", $user_parameters);
foreach ($default_schema as $section_id => $section_data) {
$section_id = generate_id();
$section_parameters = array(
"id" => $section_id,
"users" => $user_id,
"name" => $section_data["name"],
"show_subtitle" => $section_data["show_subtitle"]
);
pg_insert($db, "section", $section_parameters);
foreach ($section_data["items"] as $row_id => $row_data) {
$row_id = generate_id();
$row_parameters = array(
"id" => $row_id,
"section" => $section_id,
"name" => $row_data["name"],
"display_format" => $row_data["display_format"]
);
pg_insert($db, "row", $row_parameters);
}
}
$token = get_token($u, $pw_hash);
setcookie(
"token",
$token,
time() + 60 * 60 * 24 * 30 * 265 // 1 year from now
);
header("Location: index.php");
exit();
} else {
$err = "User '" . htmlspecialchars($u) . "' already exists";
}
}
}
$title = "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 placeholder="Verify Password" name="verify" type="password" required></div>
<div><input type="submit" value="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>";
}
include "boilerplate/foot.php";
?>