Fix database migrations for first-time setup. (#29)
Some checks failed
Run unit tests / run-unit-tests (push) Has been cancelled
Some checks failed
Run unit tests / run-unit-tests (push) Has been cancelled
The database initialization had a number of bugs for the first-time setup. This PR fixes them. Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/29 Co-authored-by: Greg Sarjeant <greg@subcultureofone.org> Co-committed-by: Greg Sarjeant <greg@subcultureofone.org>
This commit is contained in:
parent
edd7f6effe
commit
4255f46fc7
@ -1,2 +0,0 @@
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN strict_accessibility BOOLEAN DEFAULT TRUE;
|
@ -15,7 +15,8 @@ CREATE TABLE IF NOT EXISTS settings (
|
||||
base_url TEXT NOT NULL,
|
||||
base_path TEXT NOT NULL,
|
||||
items_per_page INTEGER NOT NULL,
|
||||
css_id INTEGER NULL
|
||||
css_id INTEGER NULL,
|
||||
strict_accessibility BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS css (
|
0
config/migrations/002_add_show_tick_mood_setting.sql
Executable file → Normal file
0
config/migrations/002_add_show_tick_mood_setting.sql
Executable file → Normal file
@ -14,16 +14,19 @@ if (preg_match('/\.php$/', $path)) {
|
||||
// Define base paths and load classes
|
||||
include_once(dirname(dirname(__FILE__)) . "/config/bootstrap.php");
|
||||
|
||||
// validate that necessary directories exist and are writable
|
||||
$fsMgr = new Filesystem();
|
||||
$fsMgr->validate();
|
||||
|
||||
// do any necessary database migrations
|
||||
$dbMgr = new Database();
|
||||
$dbMgr->migrate();
|
||||
|
||||
// Make sure the initial setup is complete
|
||||
// unless we're already heading to setup
|
||||
if (!(preg_match('/setup$/', $path))) {
|
||||
try {
|
||||
// filesystem validation
|
||||
$fsMgr = new Filesystem();
|
||||
$fsMgr->validate();
|
||||
|
||||
// database validation
|
||||
$dbMgr = new Database();
|
||||
$dbMgr->validate();
|
||||
} catch (SetupException $e) {
|
||||
$e->handle();
|
||||
@ -31,7 +34,8 @@ if (!(preg_match('/setup$/', $path))) {
|
||||
}
|
||||
}
|
||||
|
||||
// initialize the database
|
||||
// Get a database connection
|
||||
// TODO: Change from static function.
|
||||
global $db;
|
||||
$db = Database::get();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
class Database{
|
||||
// TODO = Make this not static
|
||||
public static function get(): PDO {
|
||||
try {
|
||||
// SQLite will just create this if it doesn't exist.
|
||||
@ -19,20 +20,16 @@ class Database{
|
||||
}
|
||||
|
||||
public function validate(): void{
|
||||
$this->validateTables();
|
||||
$this->validateTableContents();
|
||||
$this->migrate();
|
||||
}
|
||||
|
||||
// The database version will just be an int
|
||||
// stored as PRAGMA user_version. It will
|
||||
// correspond to the most recent migration file applied to the db.
|
||||
//
|
||||
// I'm starting from 0, so if the user_version is NULL, I'll return -1.
|
||||
private function getVersion(): int {
|
||||
$db = self::get();
|
||||
|
||||
return $db->query("PRAGMA user_version")->fetchColumn() ?? -1;
|
||||
return $db->query("PRAGMA user_version")->fetchColumn() ?? 0;
|
||||
}
|
||||
|
||||
private function migrationNumberFromFile(string $filename): int {
|
||||
@ -71,7 +68,7 @@ class Database{
|
||||
return $pending;
|
||||
}
|
||||
|
||||
private function migrate(): void {
|
||||
public function migrate(): void {
|
||||
$migrations = $this->getPendingMigrations();
|
||||
|
||||
if (empty($migrations)) {
|
||||
@ -121,78 +118,6 @@ class Database{
|
||||
}
|
||||
}
|
||||
|
||||
private function createTables(): void {
|
||||
$db = self::get();
|
||||
|
||||
try {
|
||||
// user table
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS user (
|
||||
id INTEGER PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
password_hash TEXT NULL,
|
||||
about TEXT NULL,
|
||||
website TEXT NULL,
|
||||
mood TEXT NULL
|
||||
)");
|
||||
|
||||
// settings table
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS settings (
|
||||
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,
|
||||
css_id INTEGER NULL
|
||||
)");
|
||||
|
||||
// css table
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS css (
|
||||
id INTEGER PRIMARY KEY,
|
||||
filename TEXT UNIQUE NOT NULL,
|
||||
description TEXT NULL
|
||||
)");
|
||||
|
||||
// mood table
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS emoji(
|
||||
id INTEGER PRIMARY KEY,
|
||||
emoji TEXT UNIQUE NOT NULL,
|
||||
description TEXT NOT NULL
|
||||
)");
|
||||
} catch (PDOException $e) {
|
||||
throw new SetupException(
|
||||
"Table creation failed: " . $e->getMessage(),
|
||||
'table_creation',
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure all tables exist
|
||||
// attempt to create them if they don't
|
||||
private function validateTables(): void {
|
||||
$appTables = array();
|
||||
$appTables[] = "settings";
|
||||
$appTables[] = "user";
|
||||
$appTables[] = "css";
|
||||
$appTables[] = "emoji";
|
||||
|
||||
$db = self::get();
|
||||
|
||||
foreach ($appTables as $appTable){
|
||||
$stmt = $db->prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?");
|
||||
$stmt->execute([$appTable]);
|
||||
if (!$stmt->fetch()){
|
||||
// At least one table doesn't exist.
|
||||
// Try creating tables (hacky, but I have 4 total tables)
|
||||
// Will throw an exception if it fails
|
||||
$this->createTables();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure tables that need to be seeded have been
|
||||
private function validateTableContents(): void {
|
||||
$db = self::get();
|
||||
@ -201,8 +126,8 @@ class Database{
|
||||
$user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn();
|
||||
$settings_count = (int) $db->query("SELECT COUNT(*) FROM settings")->fetchColumn();
|
||||
|
||||
// If either required table has no records and we aren't on /admin,
|
||||
// redirect to /admin to complete setup
|
||||
// If either required table has no records, throw an exception.
|
||||
// This will be caught and redirect to setup.
|
||||
if ($user_count === 0 || $settings_count === 0){
|
||||
throw new SetupException(
|
||||
"Required tables aren't populated. Please complete setup",
|
||||
|
@ -67,7 +67,7 @@ class ConfigModel {
|
||||
base_path,
|
||||
items_per_page,
|
||||
css_id,
|
||||
strict_accessibility,
|
||||
strict_accessibility
|
||||
)
|
||||
VALUES (1, ?, ?, ?, ?, ?, ?, ?)");
|
||||
} else {
|
||||
|
@ -30,7 +30,7 @@ class UserModel {
|
||||
$userCount = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn();
|
||||
|
||||
if ($userCount === 0){
|
||||
$stmt = $db->prepare("INSERT INTO user (id, username, display_name, website, mood) VALUES (1, ?, ?, ?, ?, ?)");
|
||||
$stmt = $db->prepare("INSERT INTO user (id, username, display_name, website, mood) VALUES (1, ?, ?, ?, ?)");
|
||||
} else {
|
||||
$stmt = $db->prepare("UPDATE user SET username=?, display_name=?, website=?, mood=? WHERE id=1");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user