fix deployment db issue and widthrawal administration page
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 47s
Tests / PHPUnit (push) Failing after 1m19s

This commit is contained in:
root
2026-08-20 20:18:00 -04:00
parent 889c037660
commit d3da699e55
19 changed files with 1170 additions and 194 deletions
+104 -46
View File
@@ -1,15 +1,29 @@
<?php
namespace App\Controllers\View;
use App\Controllers\BaseController;
use Config\SessionTimeout;
use CodeIgniter\Controller;
use CodeIgniter\API\ResponseTrait;
class SessionTimeoutController extends BaseController
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\SessionTimeout;
use Psr\Log\LoggerInterface;
use Throwable;
/**
* Lightweight session heartbeat endpoints.
* Intentionally does not extend BaseController to avoid school-year / API priming.
*/
class SessionTimeoutController extends Controller
{
use ResponseTrait;
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
parent::initController($request, $response, $logger);
session();
}
public function getTimeoutConfig()
{
return $this->response->setJSON([
@@ -17,77 +31,121 @@ class SessionTimeoutController extends BaseController
'timeout' => SessionTimeout::TIMEOUT_DURATION,
'warning_time' => SessionTimeout::TIMEOUT_DURATION - SessionTimeout::WARNING_THRESHOLD,
'check_interval' => SessionTimeout::CLIENT_CHECK_INTERVAL,
'ping_interval' => SessionTimeout::CLIENT_PING_INTERVAL,
'logout_url' => site_url('logout'),
'keep_alive_url' => site_url('session/ping-activity'),
'check_url' => site_url('session/check-timeout')
'check_url' => site_url('session/check-timeout'),
]);
}
public function checkTimeout()
{
$session = session();
try {
$session = session();
// Verify session exists and has last_activity
if (!$session->has('last_activity')) {
return $this->expireSession();
}
if (! $session->has('last_activity')) {
return $this->expireSession();
}
$lastActivity = $session->get('last_activity');
$elapsed = time() - $lastActivity;
$lastActivity = (int) $session->get('last_activity');
$elapsed = time() - $lastActivity;
if ($elapsed >= SessionTimeout::TIMEOUT_DURATION) {
return $this->expireSession();
}
if ($elapsed >= SessionTimeout::WARNING_THRESHOLD) {
return $this->response->setJSON([
'status' => 'warning',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed,
]);
}
if ($elapsed >= SessionTimeout::TIMEOUT_DURATION) {
return $this->expireSession();
} elseif ($elapsed >= SessionTimeout::WARNING_THRESHOLD) {
return $this->response->setJSON([
'status' => 'warning',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed
'status' => 'active',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed,
]);
} catch (Throwable $e) {
$this->logDbFailureOnce('session/check-timeout', $e);
return $this->response
->setStatusCode(503)
->setJSON([
'status' => 'error',
'message' => 'Session check temporarily unavailable.',
]);
}
return $this->response->setJSON([
'status' => 'active',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION - $elapsed
]);
}
public function pingActivity()
{
$session = session();
// Only update if session is still valid
if (!$session->has('last_activity') ||
(time() - $session->get('last_activity') >= SessionTimeout::TIMEOUT_DURATION)) {
return $this->expireSession();
try {
$session = session();
if (! $session->has('last_activity')
|| (time() - (int) $session->get('last_activity') >= SessionTimeout::TIMEOUT_DURATION)
) {
return $this->expireSession();
}
$session->set('last_activity', time());
return $this->response->setJSON([
'status' => 'active',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION,
]);
} catch (Throwable $e) {
$this->logDbFailureOnce('session/ping-activity', $e);
return $this->response
->setStatusCode(503)
->setJSON([
'status' => 'error',
'message' => 'Activity ping temporarily unavailable.',
]);
}
$session->set('last_activity', time());
return $this->response->setJSON([
'status' => 'active',
'time_remaining' => SessionTimeout::TIMEOUT_DURATION
]);
}
private function expireSession()
{
$this->destroySession();
return $this->response->setJSON([
'status' => 'expired',
'redirect' => site_url('login'),
'message' => 'Your session has expired due to inactivity.'
'message' => 'Your session has expired due to inactivity.',
]);
}
private function destroySession()
private function destroySession(): void
{
$session = session();
$session->setFlashdata('error', 'Your session has expired due to inactivity.');
// Clear session data
$session->remove('last_activity');
$session->destroy();
if (session_status() === PHP_SESSION_ACTIVE) {
session_regenerate_id(true);
try {
$session = session();
$session->setFlashdata('error', 'Your session has expired due to inactivity.');
$session->remove('last_activity');
$session->destroy();
if (session_status() === PHP_SESSION_ACTIVE) {
session_regenerate_id(true);
}
} catch (Throwable $e) {
$this->logDbFailureOnce('session/destroy', $e);
}
}
private function logDbFailureOnce(string $endpoint, Throwable $e): void
{
static $logged = [];
$key = $endpoint . '|' . get_class($e);
if (isset($logged[$key])) {
return;
}
$logged[$key] = true;
log_message('error', 'Session endpoint failure on {endpoint}: {message}', [
'endpoint' => $endpoint,
'message' => $e->getMessage(),
]);
}
}