Complete Phase 1: MVC, DB migrations, Auth, RBAC, Security, and Views

This commit is contained in:
Hamza-Ayed
2026-06-05 00:56:41 +03:00
parent 7ffbc8bafa
commit bed7624ae9
51 changed files with 3295 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Controllers\Admin;
use App\Controllers\Controller;
use App\Core\Request;
use App\Core\Response;
class DashboardController extends Controller
{
/**
* Display admin dashboard.
*/
public function index(Request $request, Response $response): string
{
$user = $request->routeParam('_authenticated_user');
return $this->render('admin/dashboard', [
'user' => $user,
'title' => 'Dashboard',
], 'admin');
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace App\Controllers;
use App\Core\Request;
use App\Core\Response;
use App\Services\Auth\AuthService;
use App\Services\Database\ActivityLogger;
use Throwable;
class AuthController extends Controller
{
private AuthService $authService;
private ActivityLogger $logger;
public function __construct(AuthService $authService, ActivityLogger $logger)
{
parent::__construct();
$this->authService = $authService;
$this->logger = $logger;
}
/**
* Render the login page.
*/
public function showLogin(Request $request, Response $response): string
{
if ($this->session->get('user_id')) {
$response->redirect('/admin/dashboard');
}
return $this->render('auth/login', [], 'auth');
}
/**
* Handle login requests.
*/
public function login(Request $request, Response $response): void
{
$email = $request->post('email', '');
$password = $request->post('password', '');
try {
$user = $this->authService->login($email, $password);
$this->session->set('user_id', $user['id']);
$this->session->set('user_name', $user['name']);
$this->session->set('user_email', $user['email']);
// Security log
$this->logger->log($user['id'], 'user_login', 'User logged in successfully via Web.');
$this->session->setFlash('success', 'Welcome back, ' . $user['name'] . '!');
$response->redirect('/admin/dashboard');
} catch (Throwable $e) {
$this->session->setFlash('error', $e->getMessage());
$response->redirect('/login');
}
}
/**
* Render registration page.
*/
public function showRegister(Request $request, Response $response): string
{
if ($this->session->get('user_id')) {
$response->redirect('/admin/dashboard');
}
return $this->render('auth/register', [], 'auth');
}
/**
* Handle registration requests.
*/
public function register(Request $request, Response $response): void
{
$name = $request->post('name', '');
$email = $request->post('email', '');
$password = $request->post('password', '');
try {
if (empty($name) || empty($email) || empty($password)) {
throw new \Exception("All fields are required.");
}
$user = $this->authService->register($name, $email, $password);
$this->session->set('user_id', $user['id']);
$this->session->set('user_name', $user['name']);
$this->session->set('user_email', $user['email']);
// Security log
$this->logger->log($user['id'], 'user_register', 'User registered and logged in.');
$this->session->setFlash('success', 'Registration successful! Welcome to ScoutIQ.');
$response->redirect('/admin/dashboard');
} catch (Throwable $e) {
$this->session->setFlash('error', $e->getMessage());
$response->redirect('/register');
}
}
/**
* Destroy user sessions and logout.
*/
public function logout(Request $request, Response $response): void
{
$userId = $this->session->get('user_id');
if ($userId) {
$this->logger->log($userId, 'user_logout', 'User logged out.');
}
$this->session->destroy();
$response->redirect('/login');
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Controllers;
use App\Core\App;
use App\Core\Session;
abstract class Controller
{
protected Session $session;
public function __construct()
{
$this->session = App::$app->session;
}
/**
* Render a view within a layout.
*/
protected function render(string $view, array $data = [], string $layout = 'app'): string
{
$viewFile = __DIR__ . "/../../resources/views/{$view}.php";
if (!file_exists($viewFile)) {
throw new \Exception("View template {$view} not found.");
}
// Extract variables to local scope
extract($data);
// Capture inner view content
ob_start();
include $viewFile;
$content = ob_get_clean();
// Capture layout content wrapping the inner view
$layoutFile = __DIR__ . "/../../resources/views/layouts/{$layout}.php";
if (!file_exists($layoutFile)) {
return $content;
}
ob_start();
include $layoutFile;
return ob_get_clean();
}
/**
* Escape string values for rendering safely.
*/
protected function escape(mixed $data): string
{
return htmlspecialchars((string)$data, ENT_QUOTES, 'UTF-8');
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Controllers;
use App\Core\Request;
use App\Core\Response;
class HomeController extends Controller
{
/**
* Handle root url routing.
*/
public function index(Request $request, Response $response): void
{
if ($this->session->get('user_id')) {
$response->redirect('/admin/dashboard');
return;
}
$response->redirect('/login');
}
}