diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 9a27ab3..2120aaa 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -539,7 +539,7 @@ $routes->post('administrator/event-charges/remove/(:num)', 'View\EventController $routes->post('administrator/event-charges/payment/(:num)', 'View\EventController::toggleEventPayment/$1'); $routes->get('administrator/get-students-with-charges', 'View\EventController::getStudentsWithCharges'); -$routes->get('parent/events', 'View\ParentController::parentEventPage'); +$routes->get('parent/events', 'View\ParentController::parentEventPage', ['filter' => 'auth:parent']); // parent event participation page $routes->post('parent/updateParticipation', 'View\ParentController::updateParticipation'); // handle parent participation updates diff --git a/app/Controllers/AuthController.php b/app/Controllers/AuthController.php index aee212d..df2a879 100644 --- a/app/Controllers/AuthController.php +++ b/app/Controllers/AuthController.php @@ -56,13 +56,32 @@ class AuthController extends Controller public function loginMask() { - // Serve the login view directly here - return view('user/login'); // Adjust the view path as needed + $redirectTo = $this->sanitizeRedirectTarget((string) ($this->request->getGet('redirect_to') ?? '')); + + if (session()->get('is_logged_in')) { + if ($redirectTo !== null) { + return redirect()->to($redirectTo); + } + + $roles = session()->get('roles') ?? []; + if (empty($roles) && session()->get('role')) { + $roles = [session()->get('role')]; + } + + if (!empty($roles)) { + return $this->redirectToDashboard($roles); + } + } + + return view('user/login', [ + 'redirect_to' => $redirectTo ?? '', + ]); } public function login() { log_message('info', 'Processing login form submission.'); + $redirectTo = $this->sanitizeRedirectTarget((string) ($this->request->getPost('redirect_to') ?? $this->request->getGet('redirect_to') ?? '')); // Step 1: Get email, password, and IP from the request $email = $this->request->getPost('email'); @@ -98,7 +117,7 @@ class AuthController extends Controller $this->logLoginAttempt($user['id'], $user['email'], $ip, $this->request->getUserAgent()); // ✅ Step 7: Call loginUser() to set session and redirect - return $this->loginUser($user); + return $this->loginUser($user, $redirectTo); } else { // Step 8: Password mismatch — log failed attempt $this->handleFailedLogin($user['id'], $user['email'], $ip); @@ -491,7 +510,7 @@ class AuthController extends Controller return true; } - private function loginUser($user) + private function loginUser($user, ?string $redirectTo = null) { $userRoleModel = new UserRoleModel(); $roles = $userRoleModel->select('roles.name') @@ -525,9 +544,17 @@ class AuthController extends Controller if (count($roleNames) === 1) { // One role → set and redirect directly session()->set('role', $roleNames[0]); + if ($redirectTo !== null) { + return redirect()->to($redirectTo); + } return $this->redirectToDashboard([$roleNames[0]]); } else { // Multiple roles → redirect to role selection view + if ($redirectTo !== null) { + session()->set('post_login_redirect', $redirectTo); + } else { + session()->remove('post_login_redirect'); + } return redirect()->to('/select-role'); } @@ -592,12 +619,17 @@ private function redirectToDashboard(array $roles) { $selectedRole = $this->request->getPost('selected_role'); $availableRoles = session()->get('roles'); + $redirectTo = $this->sanitizeRedirectTarget((string) ($this->request->getPost('redirect_to') ?? session()->get('post_login_redirect') ?? '')); if (!$selectedRole || !in_array($selectedRole, $availableRoles)) { return redirect()->to('/select-role')->with('error', 'Invalid role selected.'); } session()->set('role', $selectedRole); + session()->remove('post_login_redirect'); + if ($redirectTo !== null) { + return redirect()->to($redirectTo); + } return $this->redirectToDashboard([$selectedRole]); } @@ -609,7 +641,44 @@ private function redirectToDashboard(array $roles) return redirect()->to('/login')->with('error', 'No roles available.'); } - return view('auth/select_role', ['roles' => $roles]); + return view('auth/select_role', [ + 'roles' => $roles, + 'redirect_to' => (string) (session()->get('post_login_redirect') ?? ''), + ]); + } + + private function sanitizeRedirectTarget(string $redirectTo): ?string + { + $redirectTo = trim($redirectTo); + if ($redirectTo === '') { + return null; + } + + if (preg_match('#^https?://#i', $redirectTo)) { + $appHost = (string) parse_url(base_url('/'), PHP_URL_HOST); + $targetHost = (string) parse_url($redirectTo, PHP_URL_HOST); + $targetPath = (string) parse_url($redirectTo, PHP_URL_PATH); + $targetQuery = (string) parse_url($redirectTo, PHP_URL_QUERY); + + if ($appHost === '' || $targetHost === '' || strcasecmp($appHost, $targetHost) !== 0) { + return null; + } + + $redirectTo = $targetPath !== '' ? $targetPath : '/'; + if ($targetQuery !== '') { + $redirectTo .= '?' . $targetQuery; + } + } + + if (!str_starts_with($redirectTo, '/')) { + $redirectTo = '/' . ltrim($redirectTo, '/'); + } + + if (str_starts_with($redirectTo, '//')) { + return null; + } + + return $redirectTo; } } diff --git a/app/Filters/AuthFilter.php b/app/Filters/AuthFilter.php index f3fcae6..0bc85f3 100644 --- a/app/Filters/AuthFilter.php +++ b/app/Filters/AuthFilter.php @@ -41,7 +41,13 @@ class AuthFilter implements FilterInterface // Must be logged in if (empty($userRoles) || empty($userId)) { - return redirect()->to('/login'); + $target = ltrim($request->getUri()->getPath(), '/'); + $query = $request->getUri()->getQuery(); + if ($query !== '') { + $target .= '?' . $query; + } + + return redirect()->to('/login?redirect_to=' . rawurlencode('/' . ltrim($target, '/'))); } // Enforce 12-hour session lifetime @@ -110,7 +116,14 @@ class AuthFilter implements FilterInterface ]); } - return redirect()->to('/login')->with('error', 'Your session has expired. Please log in again.'); + $target = ltrim($request->getUri()->getPath(), '/'); + $query = $request->getUri()->getQuery(); + if ($query !== '') { + $target .= '?' . $query; + } + + return redirect()->to('/login?redirect_to=' . rawurlencode('/' . ltrim($target, '/'))) + ->with('error', 'Your session has expired. Please log in again.'); } public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) diff --git a/app/Views/auth/select_role.php b/app/Views/auth/select_role.php index fc89aec..3d7b95a 100644 --- a/app/Views/auth/select_role.php +++ b/app/Views/auth/select_role.php @@ -25,6 +25,7 @@
+
@@ -68,4 +69,4 @@ tooltipTriggerList.forEach(el => new bootstrap.Tooltip(el)); }); -endSection() ?> \ No newline at end of file +endSection() ?> diff --git a/app/Views/user/login.php b/app/Views/user/login.php index 3b45f8d..5818426 100644 --- a/app/Views/user/login.php +++ b/app/Views/user/login.php @@ -1,25 +1,10 @@ -get('isLoggedIn')) { - header('Location: ' . base_url('/dashboard')); - exit(); -} -?> - extend('layout/register_layout') ?> section('content') ?>
+ - getFlashdata('error')): ?> + getFlashdata('error')): ?> @@ -125,4 +110,4 @@ if ($session->get('isLoggedIn')) { } }); -endSection() ?> \ No newline at end of file +endSection() ?>