Merge pull request 'Add user registration page' (#4) from feat/user-registration into master

Reviewed-on: #4
Reviewed-by: rafaga21 <rafaelminaya20@hotmail.com>
This commit was merged in pull request #4.
This commit is contained in:
2026-06-06 19:41:32 -04:00
5 changed files with 128 additions and 0 deletions

View File

@@ -2112,6 +2112,24 @@ textarea.form-input {
margin-bottom: 1.25rem; margin-bottom: 1.25rem;
} }
.auth-footer {
text-align: center;
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid var(--border-color);
color: var(--text-muted);
font-size: 0.85rem;
}
.auth-footer a {
color: var(--accent);
text-decoration: none;
}
.auth-footer a:hover {
text-decoration: underline;
}
/* ========================================================================== /* ==========================================================================
Error Pages Error Pages
========================================================================== */ ========================================================================== */

View File

@@ -23,6 +23,8 @@ $router->get('/dashboard/refresh-metrics', [DashboardController::class, 'refresh
$router->get('/login', [AuthController::class, 'loginForm']); $router->get('/login', [AuthController::class, 'loginForm']);
$router->post('/login', [AuthController::class, 'login'], [CSRFMiddleware::class, RateLimitMiddleware::class]); $router->post('/login', [AuthController::class, 'login'], [CSRFMiddleware::class, RateLimitMiddleware::class]);
$router->get('/register', [AuthController::class, 'registerForm']);
$router->post('/register', [AuthController::class, 'register'], [CSRFMiddleware::class]);
$router->get('/logout', [AuthController::class, 'logout']); $router->get('/logout', [AuthController::class, 'logout']);
$router->get('/profile', [AuthController::class, 'profile'], [AuthMiddleware::class]); $router->get('/profile', [AuthController::class, 'profile'], [AuthMiddleware::class]);

View File

@@ -80,6 +80,65 @@ class AuthController
$this->view->redirect($intended); $this->view->redirect($intended);
} }
public function registerForm(): void
{
if (Session::has('user_id')) {
$this->view->redirect('/dashboard');
}
$this->view->setLayout('auth');
$this->view->display('auth.register', [
'title' => 'Register - ServerManager',
]);
}
public function register(): void
{
$validator = new Validator();
$rules = [
'username' => 'required|min:3|max:50',
'email' => 'required|email',
'password' => 'required|min:8',
'confirm_password' => 'required|match:password',
];
if (!$validator->validate($_POST, $rules)) {
Session::setFlash('error', $validator->getFirstError());
$this->view->redirect('/register');
}
$username = $_POST['username'];
$email = $_POST['email'];
$existing = $this->userModel->findByUsername($username);
if ($existing) {
Session::setFlash('error', 'Username already exists.');
$this->view->redirect('/register');
}
$existingEmail = $this->userModel->findByEmail($email);
if ($existingEmail) {
Session::setFlash('error', 'Email already registered.');
$this->view->redirect('/register');
}
$id = $this->userModel->create([
'username' => $username,
'email' => $email,
'password' => $_POST['password'],
'role' => 'operator',
'is_active' => 1,
]);
$this->auditService->log('user_registered', 'user', $id, [
'username' => $username,
'role' => 'operator',
]);
Session::setFlash('success', 'Account created. You can now log in.');
$this->view->redirect('/login');
}
public function logout(): void public function logout(): void
{ {
$this->auditService->log( $this->auditService->log(

View File

@@ -43,5 +43,8 @@
<i class="fas fa-sign-in-alt"></i> Sign In <i class="fas fa-sign-in-alt"></i> Sign In
</button> </button>
</div> </div>
<div class="auth-footer">
<p>Don't have an account? <a href="/register">Register</a></p>
</div>
</form> </form>
</div> </div>

46
views/auth/register.php Normal file
View File

@@ -0,0 +1,46 @@
<div class="auth-card">
<div class="auth-header">
<i class="fas fa-server auth-logo"></i>
<h1>ServerManager</h1>
<p>Create your account</p>
</div>
<?php if ($flash = \ServerManager\Core\Session::getFlash('error')): ?>
<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> <?= htmlspecialchars($flash[0]) ?></div>
<?php endif; ?>
<form method="POST" action="/register" class="auth-form" id="registerForm">
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
<div class="form-group">
<label for="username"><i class="fas fa-user"></i> Username</label>
<input type="text" id="username" name="username" class="form-input" placeholder="Choose a username" required autofocus autocomplete="username">
</div>
<div class="form-group">
<label for="email"><i class="fas fa-envelope"></i> Email</label>
<input type="email" id="email" name="email" class="form-input" placeholder="your@email.com" required autocomplete="email">
</div>
<div class="form-group">
<label for="password"><i class="fas fa-lock"></i> Password</label>
<div class="input-group">
<input type="password" id="password" name="password" class="form-input" placeholder="At least 8 characters" required autocomplete="new-password">
<button type="button" class="input-toggle-password" tabindex="-1"><i class="fas fa-eye"></i></button>
</div>
</div>
<div class="form-group">
<label for="confirm_password"><i class="fas fa-lock"></i> Confirm Password</label>
<input type="password" id="confirm_password" name="confirm_password" class="form-input" placeholder="Repeat password" required autocomplete="new-password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block"><i class="fas fa-user-plus"></i> Create Account</button>
</div>
<div class="auth-footer">
<p>Already have an account? <a href="/login">Sign in</a></p>
</div>
</form>
</div>