Finish install module rewrite

This commit is contained in:
Sky Johnson 2024-07-13 23:15:25 -05:00
parent e8c3320429
commit 6835d6832c
13 changed files with 130 additions and 64 deletions

View File

@ -38,7 +38,23 @@ body {
margin-bottom: 2rem;
}
.my-1 {
margin-top: 1rem;
margin-bottom: 1rem;
}
.my-2 {
margin-top: 2rem;
margin-bottom: 2rem;
}
div.alert {
font-size: 0.9rem;
padding: 0.5rem;
background-color: gray;
&.is-danger {
color: hsl(359deg, 68%, 11%);
background-color: hsl(359deg, 68%, 71%);
}
}

View File

@ -1,38 +0,0 @@
<?php // install.php :: creates/populates database tables on a new installation.
// Admin account; create it from the provided info
if ($step == 'third') {
$errors = [];
// Make sure our info is at least mostly valid
if (!required(['username', 'password', 'email'])) {
$errors[] = 'All fields are required.';
} else {
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email address format.';
}
if (strlen($_POST['password']) < 6) {
$errors[] = 'Password must be at least 6 characters long.';
}
}
// Make sure the class selection is valid
$class = isset($_POST['class']) && in_array($_POST['class'], [1, 2, 3]) ? $_POST['class'] : 1;
// If we have any errors, bail to the form and let the user know
if (!empty($errors)) {
echo render('install/layout', ['title' => 'Admin Account', 'step' => 'third', 'errors' => $errors, 'complete' => $_POST['complete'] ?? false]);
exit;
}
// Create the .installed file in the server folder
file_put_contents(SERVER.'/.installed', 'Installed on '.date('Y-m-d H:i:s'));
// Create the admin account
createUser($_POST['username'], $_POST['password'], $_POST['email'], $class, ['role' => 5, 'verified' => 1]);
// Render the finished page!
echo render('install/layout', ['title' => 'Finished!', 'step' => 'done', 'name' => $_POST['username'], 'complete' => $_POST['complete'] ?? false]);
exit;
}

View File

@ -7,11 +7,21 @@
class App
{
public static Database $db;
private static string $dbPath;
public static Request $req;
public function __construct(string $dbPath)
{
self::$req = new Request(); // the current request
self::$db = new Database($dbPath); // the database
self::$dbPath = $dbPath; // the database path
}
public static function performDatabaseReset(): void
{
if (file_exists(self::$dbPath)) {
unlink(self::$dbPath);
self::$db = new Database(self::$dbPath);
}
}
}

View File

@ -82,6 +82,11 @@ class Database
return $this->time;
}
public function lastInsertID(): int
{
return $this->c->lastInsertId();
}
public function insertFromCSV(string $table, string $path): PDOStatement|false
{
// open the file

View File

@ -30,6 +30,10 @@ const MAP = [
// modules
'HomeModule' => SERVER.'/modules/HomeModule.php',
'InstallModule' => SERVER.'/modules/InstallModule.php',
// models
'Classes' => SERVER.'/models/Classes.php',
'Player' => SERVER.'/models/Player.php',
];
// autoloader

View File

@ -57,25 +57,6 @@ function dd(mixed $var, bool $r = false)
exit;
}
/**
* Creates a new user. Optionally pass an array of additional fields to add. Returns the user ID, or 0 if failed.
*/
function createUser(string $username, string $password, string $email, int $class = 1, array $addtl = []): int
{
// @BAD Yes, this is bad, but it works.
global $db;
$data = [
'username' => trim($username),
'password' => password_hash($password, PASSWORD_ARGON2ID),
'email' => trim($email),
'class_id' => $class
];
$db->table('players')->insert(array_merge($data, $addtl));
return $db->lastInsertId();
}
function getmicrotime() { // Used for timing script operations.
list($usec, $sec) = explode(" ",microtime());

10
server/models/Classes.php Normal file
View File

@ -0,0 +1,10 @@
<?php
class Classes
{
public static function all(): array|false
{
$res = App::$db->q("SELECT * FROM classes");
return $res->fetchAll() ?: false;
}
}

13
server/models/Player.php Normal file
View File

@ -0,0 +1,13 @@
<?php
class Player
{
public static function create(array $data): int
{
$keys = implode(', ', array_keys($data));
$placeholders = implode(', ', array_fill(0, count($data), '?'));
App::$db->do("INSERT INTO 'players' ($keys) VALUES ($placeholders);", array_values($data));
return App::$db->lastInsertID();
}
}

View File

@ -13,6 +13,8 @@ class InstallModule
if ($s == '' || $s == 'intro') return self::intro();
if ($s == 'database' && $m == 'POST') return self::database();
if ($s == 'finish' && $m == 'POST') return self::finish();
return self::fourOhFour();
}
private static function intro()
@ -27,6 +29,9 @@ class InstallModule
$complete = $_POST['mode'] == 'complete'; // complete or partial setup
$defaults = SERVER.'/database/packs/Default/';
// if the database already exists, have the app remake it
App::performDatabaseReset();
// @Settings
App::$db->q("CREATE TABLE IF NOT EXISTS 'settings' (
'id' INTEGER PRIMARY KEY,
@ -232,4 +237,52 @@ class InstallModule
echo render('install/layout', ['title' => 'Database Setup', 'step' => 'second', 'complete' => $complete, 'start' => $istart]);
}
private static function finish()
{
$errors = [];
// Make sure our info is at least mostly valid
if (!required(['username', 'password', 'email'])) {
$errors[] = 'All fields are required.';
} else {
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email address format.';
}
if (strlen($_POST['password']) < 6) {
$errors[] = 'Password must be at least 6 characters long.';
}
}
// Make sure the class selection is valid
$class = isset($_POST['class']) && in_array($_POST['class'], [1, 2, 3]) ? $_POST['class'] : 1;
// If we have any errors, bail to the form and let the user know
if (!empty($errors)) {
echo render('install/layout', ['title' => 'Admin Account', 'step' => 'third', 'errors' => $errors, 'complete' => $_POST['complete'] ?? false]);
exit;
}
// Create the .installed file in the server folder
file_put_contents(SERVER.'/.installed', 'Installed on '.date('Y-m-d H:i:s'));
// Create the admin account
Player::create([
'username' => trim($_POST['username']),
'password' => password_hash($_POST['password'], PASSWORD_ARGON2ID),
'email' => trim($_POST['email']),
'class_id' => $class,
'verified' => 1,
'role' => 5
]);
// Render the finished page!
echo render('install/layout', ['title' => 'Finished!', 'step' => 'done', 'name' => $_POST['username'], 'complete' => $_POST['complete'] ?? false]);
}
private static function fourOhFour()
{
echo render('install/layout', ['title' => 'Four Oh Four', 'step' => 'four']);
}
}

View File

@ -6,7 +6,7 @@
</p>
<p class="mb-1">
<a href="/">Click here to log in.</a>
<a href="/gate/login">Click here to log in.</a>
</p>
<p>

View File

@ -23,7 +23,7 @@
</ul>
</p>
<p>
<p class="mb-1">
Click the appropriate button below for your preferred installation method.
<form action="/install/database" method="post">
<button type="submit" name="mode" value="complete">Complete Setup</button><br>
@ -31,3 +31,8 @@
<button type="submit" name="mode" value="partial">Partial Setup</button>
</form>
</p>
<div class="alert is-danger my-2">
<b>WARNING:</b> if the database already exists, clicking either
option will delete all existing data. This is not reversible.
</div>

View File

@ -0,0 +1,7 @@
<p class="mb-1">
That's weird... you're not supposed to be here.
</p>
<p class="mb-1">
<a href="/">Go back.</a>
</p>

View File

@ -1,9 +1,9 @@
<form action="/install/?step=third" method="post" style="max-width: 300px;">
<form action="/install/finish" method="post" style="max-width: 300px;">
<input type="hidden" name="complete" value="<?= $complete ? "true" : "false" ?>">
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" id="username">
<input type="text" name="username" id="username" required>
</div>
<div class="form-group">
@ -20,9 +20,9 @@
<div class="form-group">
<label for="class">Class</label>
<select name="class" id="class">
<option value="1">Mage</option>
<option value="2">Paladin</option>
<option value="3">Warrior</option>
<?php foreach (Classes::all() as $class): ?>
<option value="<?= $class['id'] ?>"><?= $class['name'] ?></option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>