From 2aecc934f2485280c425d43cc99941a8770f9b73 Mon Sep 17 00:00:00 2001 From: Greg Sarjeant <1686767+gsarjeant@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:54:18 -0400 Subject: [PATCH] Clean up setup validation. --- config/bootstrap.php | 27 ++++++++++++++++++ .../AdminController/AdminController.php | 28 ++++++++++--------- src/Framework/Router/Router.php | 2 ++ src/Model/ConfigModel/ConfigModel.php | 15 +++------- src/Model/UserModel/UserModel.php | 7 +++-- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/config/bootstrap.php b/config/bootstrap.php index 3c27742..c769b4b 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -29,6 +29,33 @@ class SetupException extends Exception { } } +function handle_setup_exception(SetupException $e){ + switch ($e->getSetupIssue()){ + case 'storage_missing': + case 'storage_permissions': + case 'directory_creation': + case 'directory_permissions': + case 'database_connection': + case 'table_creation': + // Unrecoverable errors. + // Show error message and exit + http_response_code(500); + echo "
" . htmlspecialchars($setupError['message']) . "
"; + exit; + case 'table_contents': + // Recoverable error. + // Redirect to setup if we aren't already headed there. + $config = ConfigModel::load(); + $currentPath = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'); + + if (strpos($currentPath, 'setup') === false) { + header("Location: {$config->basePath}/setup"); + exit; + } + } +} + // Main validation function // Any failures will throw a SetupException function confirm_setup(): void { diff --git a/src/Controller/AdminController/AdminController.php b/src/Controller/AdminController/AdminController.php index 580a2f1..3b5bc4f 100644 --- a/src/Controller/AdminController/AdminController.php +++ b/src/Controller/AdminController/AdminController.php @@ -14,18 +14,24 @@ class AdminController extends Controller { $this->render("admin.php", $vars); } - // POST handler - // save updated settings public function handleSave(){ - $config = ConfigModel::load(); - - if (!ConfigModel::isFirstSetup()) { - if (!Session::isLoggedIn()){ - header('Location: ' . $config->basePath . '/login'); - exit; - } + if (!Session::isLoggedIn()){ + header('Location: ' . $config->basePath . '/login'); + exit; } + $this->save(); + } + + public function handleSetup(){ + // for setup, we don't care if they're logged in + // (because they can't be until setup is complete) + $this->save(); + } + + // save updated settings + private function save(){ + $config = ConfigModel::load(); $user = UserModel::load(); // handle form submission @@ -115,10 +121,6 @@ class AdminController extends Controller { } } - if (ConfigModel::isFirstSetup()){ - ConfigModel::completeSetup(); - } - header('Location: ' . $config->basePath . 'admin'); exit; } diff --git a/src/Framework/Router/Router.php b/src/Framework/Router/Router.php index e0ea793..4365197 100644 --- a/src/Framework/Router/Router.php +++ b/src/Framework/Router/Router.php @@ -17,6 +17,8 @@ class Router { ['logout', 'AuthController@handleLogout', ['GET', 'POST']], ['mood', 'MoodController'], ['mood', 'MoodController@handleMood', ['POST']], + ['setup', 'AdminController@showSetup'], + ['setup', 'AdminController@handleSetup', ['POST']], ['tick/{y}/{m}/{d}/{h}/{i}/{s}', 'TickController'], ['css/custom/{filename}.css', 'CssController@serveCustomCss'], ]; diff --git a/src/Model/ConfigModel/ConfigModel.php b/src/Model/ConfigModel/ConfigModel.php index 8d08457..f111c39 100644 --- a/src/Model/ConfigModel/ConfigModel.php +++ b/src/Model/ConfigModel/ConfigModel.php @@ -9,14 +9,6 @@ class ConfigModel { public string $timezone = 'relative'; public ?int $cssId = null; - 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 { $init = require APP_ROOT . '/config/init.php'; @@ -54,11 +46,12 @@ class ConfigModel { public function save(): self { global $db; + $settingsCount = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn(); - if (!ConfigModel::isFirstSetup()){ - $stmt = $db->prepare("UPDATE settings SET site_title=?, site_description=?, base_url=?, base_path=?, items_per_page=?, css_id=? WHERE id=1"); - } else { + if ($settingsCount === 0){ $stmt = $db->prepare("INSERT INTO settings (id, site_title, site_description, base_url, base_path, items_per_page, css_id) VALUES (1, ?, ?, ?, ?, ?, ?)"); + } else { + $stmt = $db->prepare("UPDATE settings SET site_title=?, site_description=?, base_url=?, base_path=?, items_per_page=?, css_id=? WHERE id=1"); } $stmt->execute([$this->siteTitle, $this->siteDescription, $this->baseUrl, $this->basePath, $this->itemsPerPage, $this->cssId]); diff --git a/src/Model/UserModel/UserModel.php b/src/Model/UserModel/UserModel.php index d5bdf29..ca07c76 100644 --- a/src/Model/UserModel/UserModel.php +++ b/src/Model/UserModel/UserModel.php @@ -29,11 +29,12 @@ class UserModel { public function save(): self { global $db; + $userCount = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn(); - if (!ConfigModel::isFirstSetup()){ - $stmt = $db->prepare("UPDATE user SET username=?, display_name=?, about=?, website=?, mood=? WHERE id=1"); - } else { + if ($userCount === 0){ $stmt = $db->prepare("INSERT INTO user (id, username, display_name, about, website, mood) VALUES (1, ?, ?, ?, ?, ?)"); + } else { + $stmt = $db->prepare("UPDATE user SET username=?, display_name=?, about=?, website=?, mood=? WHERE id=1"); } $stmt->execute([$this->username, $this->displayName, $this->about, $this->website, $this->mood]);