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
*.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"
volumes:
- ./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:
- php
restart: unless-stopped
@ -15,6 +15,7 @@ services:
image: php:8.2-fpm-alpine
container_name: php-fpm
volumes:
- ./config:/var/www/html/tkr/config
- ./public:/var/www/html/tkr/public
- ./src:/var/www/html/tkr/src
- ./storage:/var/www/html/tkr/storage

View File

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

View File

@ -4,7 +4,7 @@ class AdminController extends Controller {
// render the admin page
public function index(){
$config = Config::load();
$user = USER::load();
$user = User::load();
$vars = [
'user' => $user,
@ -17,13 +17,15 @@ class AdminController extends Controller {
// POST handler
// save updated settings
public function handleSave(){
//$isLoggedIn = isset($_SESSION['user_id']);
if (!Session::isLoggedIn()){
header('Location: ' . $config->basePath . 'login.php');
exit;
$config = Config::load();
if (!Config::isFirstSetup()) {
if (!Session::isLoggedIn()){
header('Location: ' . $config->basePath . '/login');
exit;
}
}
$config = Config::load();
$user = User::load();
// handle form submission
@ -39,11 +41,11 @@ class AdminController extends Controller {
// Site settings
$siteTitle = trim($_POST['site_title']) ?? '';
$siteDescription = trim($_POST['site_description']) ?? '';
$baseUrl = trim($_POST['base_url'] ?? '');
$basePath = trim($_POST['base_path'] ?? '/');
$itemsPerPage = (int) ($_POST['items_per_page'] ?? 25);
// 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'] ?? '';
$confirmPassword = $_POST['confirm_password'] ?? '';
@ -54,6 +56,9 @@ class AdminController extends Controller {
if (!$displayName) {
$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
if ($website) {
if (!filter_var($website, FILTER_VALIDATE_URL)) {
@ -63,7 +68,6 @@ class AdminController extends Controller {
}
}
// Validate site settings
if (!$siteTitle) {
$errors[] = "Site title is required.";
@ -85,6 +89,7 @@ class AdminController extends Controller {
// Update site settings
$config->siteTitle = $siteTitle;
$config->siteDescription = $siteDescription;
$config->baseUrl = $baseUrl;
$config->basePath = $basePath;
$config->itemsPerPage = $itemsPerPage;
@ -104,9 +109,16 @@ class AdminController extends Controller {
if($password){
$user->set_password($password);
}
} else {
echo implode(",", $errors);
exit;
}
}
if (Config::isFirstSetup()){
Config::completeSetup();
}
header('Location: ' . $config->basePath . '/admin');
exit;
}

View File

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

View File

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

View File

@ -3,21 +3,34 @@ class Config {
// properties and default values
public string $siteTitle = 'My tkr';
public string $siteDescription = '';
public string $baseUrl = 'http://localhost'; //TODO - make this work
public string $basePath = '/';
public string $baseUrl = '';
public string $basePath = '';
public int $itemsPerPage = 25;
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
public static function load(): self {
$db = Util::get_db();
$stmt = $db->query("SELECT site_title, site_description, base_path, items_per_page FROM settings WHERE id=1");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$init = require APP_ROOT . '/config/init.php';
$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) {
$c->siteTitle = $row['site_title'];
$c->siteDescription = $row['site_description'];
$c->baseUrl = $row['base_url'];
$c->basePath = $row['base_path'];
$c->itemsPerPage = (int) $row['items_per_page'];
}
@ -28,8 +41,12 @@ class Config {
public function save(): self {
$db = Util::get_db();
$stmt = $db->prepare("UPDATE settings SET site_title=?, site_description=?, base_path=?, items_per_page=? WHERE id=1");
$stmt->execute([$this->siteTitle, $this->siteDescription, $this->basePath, $this->itemsPerPage]);
if (!Config::isFirstSetup()){
$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();
}

View File

@ -1,11 +1,11 @@
<?php
class User {
// properties
public string $username;
public string $displayName;
public string $about;
public string $website;
public string $mood;
public string $username = '';
public string $displayName = '';
public string $about = '';
public string $website = '';
public string $mood = '';
// load user settings from sqlite database
public static function load(): self {
@ -21,7 +21,7 @@ class User {
$u->displayName = $row['display_name'];
$u->about = $row['about'] ?? '';
$u->website = $row['website'] ?? '';
$u->mood = $row['mood'];
$u->mood = $row['mood'] ?? '';
}
return $u;
@ -30,7 +30,12 @@ class User {
public function save(): self {
$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]);
return self::load();

View File

@ -23,6 +23,7 @@
<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">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">Items per page (max 50): <input type="number" name="items_per_page" value="<?= $config->itemsPerPage ?>" min="1" max="50" required></label><br>
</fieldset>