Get setup working again.

This commit is contained in:
Greg Sarjeant 2025-06-04 21:06:29 -04:00
parent 78572bf50b
commit fb69ca4470
12 changed files with 91 additions and 40 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
*.sqlite *.sqlite
*.txt *.txt
init_complete

7
config/init.php Normal file
View File

@ -0,0 +1,7 @@
<?php
// initial configuration. These need to be set on first run so the app loads properly.
// Other settings can be defined in the admin page that loads on first run.
return [
'base_url' => 'http://localhost',
'base_path' => '/tkr/',
];

View File

@ -6,7 +6,7 @@ services:
- "80:80" - "80:80"
volumes: volumes:
- ./public:/var/www/html/tkr/public - ./public:/var/www/html/tkr/public
- ./configs/nginx/folder.conf:/etc/nginx/conf.d/default.conf - ./http_config/nginx/folder.conf:/etc/nginx/conf.d/default.conf
depends_on: depends_on:
- php - php
restart: unless-stopped restart: unless-stopped
@ -15,6 +15,7 @@ services:
image: php:8.2-fpm-alpine image: php:8.2-fpm-alpine
container_name: php-fpm container_name: php-fpm
volumes: volumes:
- ./config:/var/www/html/tkr/config
- ./public:/var/www/html/tkr/public - ./public:/var/www/html/tkr/public
- ./src:/var/www/html/tkr/src - ./src:/var/www/html/tkr/src
- ./storage:/var/www/html/tkr/storage - ./storage:/var/www/html/tkr/storage

View File

@ -11,10 +11,10 @@ if (preg_match('/\.php$/', $path)) {
exit; exit;
} }
// Define all the important paths
define('APP_ROOT', dirname(dirname(__FILE__))); define('APP_ROOT', dirname(dirname(__FILE__)));
define('SRC_DIR', APP_ROOT . '/src');
// Define all the important paths
define('SRC_DIR', APP_ROOT . '/src');
define('STORAGE_DIR', APP_ROOT . '/storage'); define('STORAGE_DIR', APP_ROOT . '/storage');
define('TEMPLATES_DIR', APP_ROOT . '/templates'); define('TEMPLATES_DIR', APP_ROOT . '/templates');
define('TICKS_DIR', STORAGE_DIR . '/ticks'); define('TICKS_DIR', STORAGE_DIR . '/ticks');
@ -42,9 +42,9 @@ loadClasses();
// Everything's loaded. Now we can start ticking. // Everything's loaded. Now we can start ticking.
Util::confirm_setup(); Util::confirm_setup();
$config = Config::load();
Session::start(); Session::start();
Session::generateCsrfToken(); Session::generateCsrfToken();
$config = Config::load();
// Remove the base path from the URL // Remove the base path from the URL
// and strip the trailing slash from the resulting route // and strip the trailing slash from the resulting route
@ -92,7 +92,7 @@ $routeHandlers = [
['', 'HomeController'], ['', 'HomeController'],
['', 'HomeController@handleTick', ['POST']], ['', 'HomeController@handleTick', ['POST']],
['admin', 'AdminController'], ['admin', 'AdminController'],
['admin', 'AdminController@save', ['POST']], ['admin', 'AdminController@handleSave', ['POST']],
['login', 'AuthController@showLogin'], ['login', 'AuthController@showLogin'],
['login', 'AuthController@handleLogin', ['POST']], ['login', 'AuthController@handleLogin', ['POST']],
['logout', 'AuthController@handleLogout', ['GET', 'POST']], ['logout', 'AuthController@handleLogout', ['GET', 'POST']],

View File

@ -4,7 +4,7 @@ class AdminController extends Controller {
// render the admin page // render the admin page
public function index(){ public function index(){
$config = Config::load(); $config = Config::load();
$user = USER::load(); $user = User::load();
$vars = [ $vars = [
'user' => $user, 'user' => $user,
@ -17,13 +17,15 @@ class AdminController extends Controller {
// POST handler // POST handler
// save updated settings // save updated settings
public function handleSave(){ public function handleSave(){
//$isLoggedIn = isset($_SESSION['user_id']); $config = Config::load();
if (!Session::isLoggedIn()){
header('Location: ' . $config->basePath . 'login.php'); if (!Config::isFirstSetup()) {
exit; if (!Session::isLoggedIn()){
header('Location: ' . $config->basePath . '/login');
exit;
}
} }
$config = Config::load();
$user = User::load(); $user = User::load();
// handle form submission // handle form submission
@ -39,11 +41,11 @@ class AdminController extends Controller {
// Site settings // Site settings
$siteTitle = trim($_POST['site_title']) ?? ''; $siteTitle = trim($_POST['site_title']) ?? '';
$siteDescription = trim($_POST['site_description']) ?? ''; $siteDescription = trim($_POST['site_description']) ?? '';
$baseUrl = trim($_POST['base_url'] ?? '');
$basePath = trim($_POST['base_path'] ?? '/'); $basePath = trim($_POST['base_path'] ?? '/');
$itemsPerPage = (int) ($_POST['items_per_page'] ?? 25); $itemsPerPage = (int) ($_POST['items_per_page'] ?? 25);
// Password // Password
// TODO - Make sure I really shouldn't trim these
// (I'm assuming there may be people who end their password with a space character)
$password = $_POST['password'] ?? ''; $password = $_POST['password'] ?? '';
$confirmPassword = $_POST['confirm_password'] ?? ''; $confirmPassword = $_POST['confirm_password'] ?? '';
@ -54,6 +56,9 @@ class AdminController extends Controller {
if (!$displayName) { if (!$displayName) {
$errors[] = "Display name is required."; $errors[] = "Display name is required.";
} }
if (!$baseUrl) {
$errors[] = "Base URL is required.";
}
// Make sure the website looks like a URL and starts with a protocol // Make sure the website looks like a URL and starts with a protocol
if ($website) { if ($website) {
if (!filter_var($website, FILTER_VALIDATE_URL)) { if (!filter_var($website, FILTER_VALIDATE_URL)) {
@ -63,7 +68,6 @@ class AdminController extends Controller {
} }
} }
// Validate site settings // Validate site settings
if (!$siteTitle) { if (!$siteTitle) {
$errors[] = "Site title is required."; $errors[] = "Site title is required.";
@ -85,6 +89,7 @@ class AdminController extends Controller {
// Update site settings // Update site settings
$config->siteTitle = $siteTitle; $config->siteTitle = $siteTitle;
$config->siteDescription = $siteDescription; $config->siteDescription = $siteDescription;
$config->baseUrl = $baseUrl;
$config->basePath = $basePath; $config->basePath = $basePath;
$config->itemsPerPage = $itemsPerPage; $config->itemsPerPage = $itemsPerPage;
@ -104,9 +109,16 @@ class AdminController extends Controller {
if($password){ if($password){
$user->set_password($password); $user->set_password($password);
} }
} else {
echo implode(",", $errors);
exit;
} }
} }
if (Config::isFirstSetup()){
Config::completeSetup();
}
header('Location: ' . $config->basePath . '/admin'); header('Location: ' . $config->basePath . '/admin');
exit; exit;
} }

View File

@ -25,6 +25,8 @@ class Session {
} }
public static function isLoggedIn(): bool { public static function isLoggedIn(): bool {
//echo "User ID set: ". isset($_SESSION['user_id']). "<br/>";
//exit;
return isset($_SESSION['user_id']); return isset($_SESSION['user_id']);
} }

View File

@ -68,10 +68,10 @@ class Util {
// Ensure required tables exist // Ensure required tables exist
$db->exec("CREATE TABLE IF NOT EXISTS user ( $db->exec("CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
username TEXT NOT NULL, username TEXT NOT NULL,
display_name TEXT NOT NULL, display_name TEXT NOT NULL,
password_hash TEXT NOT NULL, password_hash TEXT NULL,
about TEXT NULL, about TEXT NULL,
website TEXT NULL, website TEXT NULL,
mood TEXT NULL mood TEXT NULL
@ -81,6 +81,7 @@ class Util {
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
site_title TEXT NOT NULL, site_title TEXT NOT NULL,
site_description TEXT NULL, site_description TEXT NULL,
base_url TEXT NOT NULL,
base_path TEXT NOT NULL, base_path TEXT NOT NULL,
items_per_page INTEGER NOT NULL items_per_page INTEGER NOT NULL
)"); )");
@ -88,20 +89,24 @@ class Util {
// See if there's any data in the tables // See if there's any data in the tables
$user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn(); $user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn();
$settings_count = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn(); $settings_count = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn();
$config = Config::load();
// If either table has no records and we aren't on setup.php, redirect to setup.php // If either table has no records and we aren't on /admin
if ($user_count === 0 || $settings_count === 0){ if ($user_count === 0 || $settings_count === 0){
if (basename($_SERVER['PHP_SELF']) !== 'setup.php'){ if (basename($_SERVER['PHP_SELF']) !== 'admin'){
header('Location: setup.php'); header('Location: ' . $config->basePath . 'admin');
exit;
}
} else {
// If setup is complete and we are on setup.php, redirect to index.php.
if (basename($_SERVER['PHP_SELF']) === 'setup.php'){
header('Location: index.php');
exit; exit;
} }
}; };
/*
else {
// If setup is complete and we are on setup.php, redirect to index.php.
if (basename($_SERVER['PHP_SELF']) === 'admin'){
header('Location: ' . $config->basePath);
exit;
}
};
*/
} }
public static function tick_time_to_tick_path($tickTime){ public static function tick_time_to_tick_path($tickTime){
@ -115,7 +120,6 @@ class Util {
return "$year/$month/$day/$hour/$minute/$second"; return "$year/$month/$day/$hour/$minute/$second";
} }
// TODO: Move to model base class?
public static function get_db(): PDO { public static function get_db(): PDO {
Util::verify_data_dir(DATA_DIR, true); Util::verify_data_dir(DATA_DIR, true);

View File

@ -3,21 +3,34 @@ class Config {
// properties and default values // properties and default values
public string $siteTitle = 'My tkr'; public string $siteTitle = 'My tkr';
public string $siteDescription = ''; public string $siteDescription = '';
public string $baseUrl = 'http://localhost'; //TODO - make this work public string $baseUrl = '';
public string $basePath = '/'; public string $basePath = '';
public int $itemsPerPage = 25; public int $itemsPerPage = 25;
public string $timezone = 'relative'; public string $timezone = 'relative';
public static function isFirstSetup(): bool {
return !file_exists(STORAGE_DIR . '/init_complete');
}
public static function completeSetup(): void {
touch(STORAGE_DIR . '/init_complete');
}
// load config from sqlite database // load config from sqlite database
public static function load(): self { public static function load(): self {
$db = Util::get_db(); $init = require APP_ROOT . '/config/init.php';
$stmt = $db->query("SELECT site_title, site_description, base_path, items_per_page FROM settings WHERE id=1");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$c = new self(); $c = new self();
$c->baseUrl = ($c->baseUrl === '') ? $init['base_url'] : $c->baseUrl;
$c->basePath = ($c->basePath === '') ? $init['base_path'] : $c->basePath;
$db = Util::get_db();
$stmt = $db->query("SELECT site_title, site_description, base_url, base_path, items_per_page FROM settings WHERE id=1");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) { if ($row) {
$c->siteTitle = $row['site_title']; $c->siteTitle = $row['site_title'];
$c->siteDescription = $row['site_description']; $c->siteDescription = $row['site_description'];
$c->baseUrl = $row['base_url'];
$c->basePath = $row['base_path']; $c->basePath = $row['base_path'];
$c->itemsPerPage = (int) $row['items_per_page']; $c->itemsPerPage = (int) $row['items_per_page'];
} }
@ -28,8 +41,12 @@ class Config {
public function save(): self { public function save(): self {
$db = Util::get_db(); $db = Util::get_db();
$stmt = $db->prepare("UPDATE settings SET site_title=?, site_description=?, base_path=?, items_per_page=? WHERE id=1"); if (!Config::isFirstSetup()){
$stmt->execute([$this->siteTitle, $this->siteDescription, $this->basePath, $this->itemsPerPage]); $stmt = $db->prepare("UPDATE settings SET site_title=?, site_description=?, base_url=?, base_path=?, items_per_page=? WHERE id=1");
} else {
$stmt = $db->prepare("INSERT INTO settings (id, site_title, site_description, base_url, base_path, items_per_page) VALUES (1, ?, ?, ?, ?, ?)");
}
$stmt->execute([$this->siteTitle, $this->siteDescription, $this->baseUrl, $this->basePath, $this->itemsPerPage]);
return self::load(); return self::load();
} }

View File

@ -1,11 +1,11 @@
<?php <?php
class User { class User {
// properties // properties
public string $username; public string $username = '';
public string $displayName; public string $displayName = '';
public string $about; public string $about = '';
public string $website; public string $website = '';
public string $mood; public string $mood = '';
// load user settings from sqlite database // load user settings from sqlite database
public static function load(): self { public static function load(): self {
@ -21,7 +21,7 @@ class User {
$u->displayName = $row['display_name']; $u->displayName = $row['display_name'];
$u->about = $row['about'] ?? ''; $u->about = $row['about'] ?? '';
$u->website = $row['website'] ?? ''; $u->website = $row['website'] ?? '';
$u->mood = $row['mood']; $u->mood = $row['mood'] ?? '';
} }
return $u; return $u;
@ -30,7 +30,12 @@ class User {
public function save(): self { public function save(): self {
$db = Util::get_db(); $db = Util::get_db();
$stmt = $db->prepare("UPDATE user SET username=?, display_name=?, about=?, website=?, mood=? WHERE id=1"); if (!Config::isFirstSetup()){
$stmt = $db->prepare("UPDATE user SET username=?, display_name=?, about=?, website=?, mood=? WHERE id=1");
} else {
$stmt = $db->prepare("INSERT INTO user (id, username, display_name, about, website, mood) VALUES (1, ?, ?, ?, ?, ?)");
}
$stmt->execute([$this->username, $this->displayName, $this->about, $this->website, $this->mood]); $stmt->execute([$this->username, $this->displayName, $this->about, $this->website, $this->mood]);
return self::load(); return self::load();

View File

@ -23,6 +23,7 @@
<legend>Site settings</legend> <legend>Site settings</legend>
<label class="admin-option">Title: <input type="text" name="site_title" value="<?= $config->siteTitle ?>" required></label><br> <label class="admin-option">Title: <input type="text" name="site_title" value="<?= $config->siteTitle ?>" required></label><br>
<label class="admin-option">Description: <input type="text" name="site_description" value="<?= $config->siteDescription ?>"></label><br> <label class="admin-option">Description: <input type="text" name="site_description" value="<?= $config->siteDescription ?>"></label><br>
<label class="admin-option">Base URL: <input type="text" name="base_url" value="<?= $config->baseUrl ?>" required></label><br>
<label class="admin-option">Base path: <input type="text" name="base_path" value="<?= $config->basePath ?>" required></label><br> <label class="admin-option">Base path: <input type="text" name="base_path" value="<?= $config->basePath ?>" required></label><br>
<label class="admin-option">Items per page (max 50): <input type="number" name="items_per_page" value="<?= $config->itemsPerPage ?>" min="1" max="50" required></label><br> <label class="admin-option">Items per page (max 50): <input type="number" name="items_per_page" value="<?= $config->itemsPerPage ?>" min="1" max="50" required></label><br>
</fieldset> </fieldset>