Fixed admin panel user registration.

Now including start.sh to start a php server using the router.php so no webserver is needed.
This commit is contained in:
2025-12-03 08:10:38 +01:00
parent 3a99bd6683
commit 1a30c45d62
9 changed files with 49 additions and 94 deletions

12
.gitignore vendored
View File

@@ -6,3 +6,15 @@
./.idea ./.idea
./.idea/* ./.idea/*
./.crush
/AGENTS.md
/composer.lock
/.idea/copilot.data.migration.agent.xml
/.idea/copilot.data.migration.ask.xml
/.idea/copilot.data.migration.ask2agent.xml
/.idea/copilot.data.migration.edit.xml
/.idea/php.xml
/.idea/phpunit.xml
/PROFILES_README.md
/.idea/vcs.xml
/.idea/workspace.xml

View File

@@ -32,25 +32,4 @@ class AdminController extends Controller
Redirect::to("admin"); Redirect::to("admin");
} }
public function registerUser()
{
// Ensure the user is logged in and is an admin
if (!LoginModel::isUserLoggedIn() || !LoginModel::isAdmin()) {
Session::add('feedback_negative', Text::get('FEEDBACK_ADMIN_ONLY'));
Redirect::to('admin/index');
return;
}
// Validate and register the new user
$registration_successful = RegistrationModel::registerNewUser(true);
if ($registration_successful) {
Session::add('feedback_positive', Text::get('FEEDBACK_USER_REGISTERED_SUCCESSFULLY'));
} else {
Session::add('feedback_negative', Text::get('FEEDBACK_USER_REGISTRATION_FAILED'));
}
Redirect::to('admin/index');
}
} }

View File

@@ -22,12 +22,8 @@ class RegisterController extends Controller
*/ */
public function index() public function index()
{ {
// Redirect non-logged-in users to the login page // only admins can access registration; reuse existing admin auth check
if (!LoginModel::isUserLoggedIn()) { Auth::checkAdminAuthentication();
Redirect::to('login/index');
return;
}
$this->View->render('register/index'); $this->View->render('register/index');
} }
@@ -37,20 +33,12 @@ class RegisterController extends Controller
*/ */
public function register_action() public function register_action()
{ {
// Restrict registration to admins only // enforce admin-only for registration
if (!LoginModel::isAdmin()) { Auth::checkAdminAuthentication();
Session::add('feedback_negative', Text::get('FEEDBACK_ADMIN_ONLY'));
Redirect::to('login/index');
return;
}
$registration_successful = RegistrationModel::registerNewUser(); RegistrationModel::registerNewUser();
if ($registration_successful) { Redirect::to('admin/index');
Redirect::to('login/index');
} else {
Redirect::to('register/index');
}
} }
/** /**
@@ -76,7 +64,7 @@ class RegisterController extends Controller
*/ */
public function showCaptcha() public function showCaptcha()
{ {
Session::add('feedback_negative', Text::get('FEEDBACK_CAPTCHA_NOT_USED')); // Captcha no longer used
Redirect::to('register/index'); Redirect::to('register/index');
} }
} }

View File

@@ -2,29 +2,16 @@
class Text class Text
{ {
private static $texts; public static $texts;
public static function get($key, $data = null) public static function get($key)
{ {
// if not $key
if (!$key) {
return null;
}
if ($data) {
foreach ($data as $var => $value) {
${$var} = $value;
}
}
// load config file (this is only done once per application lifecycle)
if (!self::$texts) { if (!self::$texts) {
self::$texts = require(__DIR__ . '/../config/texts.php'); self::$texts = require(__DIR__ . '/../config/texts.php');
} }
// check if array key exists
if (!array_key_exists($key, self::$texts)) { if (!array_key_exists($key, self::$texts)) {
return null; return "TEXT NOT FOUND";
} }
return self::$texts[$key]; return self::$texts[$key];

View File

@@ -379,15 +379,4 @@ class LoginModel
{ {
return Session::userIsLoggedIn(); return Session::userIsLoggedIn();
} }
/**
* Check if the logged-in user is an admin
*
* @return bool True if the user is an admin, false otherwise
*/
public static function isAdmin()
{
$user_role = Session::get('user_role'); // Assuming user role is stored in session
return $user_role === 'admin';
}
} }

View File

@@ -19,28 +19,35 @@ class RegistrationModel
$user_name = strip_tags(Request::post('user_name')); $user_name = strip_tags(Request::post('user_name'));
$user_email = strip_tags(Request::post('user_email')); $user_email = strip_tags(Request::post('user_email'));
// Use 'user_password' if provided (admin registration), otherwise 'user_password_new' // Use 'user_password' if provided (admin registration), otherwise 'user_password_new'
$user_password_new = $isAdmin ? Request::post('user_password') : Request::post('user_password_new'); $user_password_new = $isAdmin ? Request::post('user_password_new') : Request::post('user_password_new');
$user_password_repeat = $user_password_new; // no repeat field
// validate input (skip captcha validation) // validate using existing validators and messages
$validation_result = self::registrationInputValidation($user_name, $user_password_new, $user_email); $valid = true;
if (!$validation_result) { if (!self::validateUserName($user_name)) { $valid = false; }
return false; if (!self::validateUserEmail($user_email, $user_email)) { $valid = false; }
} if (!self::validateUserPassword($user_password_new, $user_password_repeat)) { $valid = false; }
if (!$valid) { return false; }
// hash the password // hash the password
$user_password_hash = password_hash($user_password_new, PASSWORD_DEFAULT); $user_password_hash = password_hash($user_password_new, PASSWORD_DEFAULT);
// check if username or email already exists $return = true;
if (UserModel::doesUsernameAlreadyExist($user_name) || UserModel::doesEmailAlreadyExist($user_email)) { if (UserModel::doesUsernameAlreadyExist($user_name)) {
Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_OR_EMAIL_TAKEN')); Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_ALREADY_TAKEN'));
return false; $return = false;
} }
if (UserModel::doesEmailAlreadyExist($user_email)) {
Session::add('feedback_negative', Text::get('FEEDBACK_USER_EMAIL_ALREADY_TAKEN'));
$return = false;
}
if (!$return) return false;
// directly activate user (skip email verification) // directly activate user: set empty activation hash
$user_active = 1; $user_activation_hash = null;
// write user data to database // write user data to database
if (!self::writeNewUserToDatabase($user_name, $user_password_hash, $user_email, time(), $user_active)) { if (!self::writeNewUserToDatabase($user_name, $user_password_hash, $user_email, time(), $user_activation_hash)) {
Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_CREATION_FAILED')); Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_CREATION_FAILED'));
return false; return false;
} }
@@ -141,11 +148,7 @@ class RegistrationModel
return false; return false;
} }
if (strlen($user_password_new) < 6) { // no minimum length restriction
Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_TOO_SHORT'));
return false;
}
return true; return true;
} }
@@ -164,9 +167,9 @@ class RegistrationModel
{ {
$database = DatabaseFactory::getFactory()->getConnection(); $database = DatabaseFactory::getFactory()->getConnection();
// write new users data into database // write new users data into database; set user_active=1 and user_activation_hash to provided value (can be null)
$sql = "INSERT INTO users (user_name, user_password_hash, user_email, user_creation_timestamp, user_activation_hash, user_provider_type) $sql = "INSERT INTO users (user_name, user_password_hash, user_email, user_creation_timestamp, user_activation_hash, user_provider_type, user_active)
VALUES (:user_name, :user_password_hash, :user_email, :user_creation_timestamp, :user_activation_hash, :user_provider_type)"; VALUES (:user_name, :user_password_hash, :user_email, :user_creation_timestamp, :user_activation_hash, :user_provider_type, 1)";
$query = $database->prepare($sql); $query = $database->prepare($sql);
try { try {
$query->execute(array( $query->execute(array(
@@ -178,8 +181,7 @@ class RegistrationModel
':user_provider_type' => 'DEFAULT' ':user_provider_type' => 'DEFAULT'
)); ));
} catch (PDOException $e) { } catch (PDOException $e) {
error_log("Database error during user creation: " . $e->getMessage()); // only one feedback message on failure
Session::add('feedback_negative', "Database error: " . $e->getMessage());
return false; return false;
} }
$count = $query->rowCount(); $count = $query->rowCount();

View File

@@ -56,10 +56,10 @@
<h3>Register a new user</h3> <h3>Register a new user</h3>
<form method="post" action="<?php echo Config::get('URL'); ?>admin/registerUser"> <form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
<input type="text" name="user_name" placeholder="Username" required /> <input type="text" name="user_name" placeholder="Username" required />
<input type="email" name="user_email" placeholder="Email address" required /> <input type="email" name="user_email" placeholder="Email address" required />
<input type="password" name="user_password" placeholder="Password" required /> <input type="password" name="user_password_new" placeholder="Password" required autocomplete="off" />
<input type="submit" value="Register User" /> <input type="submit" value="Register User" />
</form> </form>

View File

@@ -11,9 +11,7 @@
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action"> <form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
<input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required /> <input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required />
<input type="text" name="user_email" placeholder="email address (a real address)" required /> <input type="text" name="user_email" placeholder="email address (a real address)" required />
<input type="text" name="user_email_repeat" placeholder="repeat email address (to prevent typos)" required />
<input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" /> <input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" />
<input type="password" name="user_password_repeat" pattern=".{6,}" required placeholder="Repeat your password" autocomplete="off" />
<input type="submit" value="Register" /> <input type="submit" value="Register" />
</form> </form>
</div> </div>

0
start.sh Normal file → Executable file
View File