Skip to content

Commit

Permalink
Authentication: User session: Add expiration notification system - refs
Browse files Browse the repository at this point in the history
  • Loading branch information
juancp-contidosdixitais authored and ywarnier committed Oct 18, 2024
1 parent 0f96eac commit 14e699f
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 0 deletions.
75 changes: 75 additions & 0 deletions main/inc/ajax/session_clock.ajax.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

require_once __DIR__.'/../../../vendor/autoload.php';
require_once __DIR__.'/../../../app/AppKernel.php';

$kernel = new AppKernel('', '');

// Check for 'action' parameter in the GET request
if (isset($_GET['action'])) {
$action = $_GET['action'];

if ($action == 'time') {
// Load the Chamilo configuration
$alreadyInstalled = false;
if (file_exists($kernel->getConfigurationFile())) {
require_once $kernel->getConfigurationFile();
$alreadyInstalled = true;
}

// Load the API library BEFORE loading the Chamilo configuration
require_once $_configuration['root_sys'].'main/inc/lib/api.lib.php';

if (api_get_configuration_value('session_lifetime_controller')) {
// Get the session
session_name('ch_sid');
session_start();

$session = new ChamiloSession();

$endTime = 0;
$isExpired = false;
$timeLeft = -1;

$currentTime = time();

// Existing code for time action
if ($alreadyInstalled && api_get_user_id()) {
$endTime = $session->end_time();
$isExpired = $session->is_expired();
} else {
// Chamilo not installed or user not logged in
$endTime = $currentTime + 315360000; // This sets a default end time far in the future
$isExpired = false;
}

$timeLeft = $endTime - $currentTime;
}
else {
$endTime = 999999;
$isExpired = false;
$timeLeft = 999999;
}

if ($endTime > 0) {
echo json_encode(['sessionEndDate' => $endTime, 'sessionTimeLeft' => $timeLeft, 'sessionExpired' => $isExpired]);
} else {
http_response_code(500);
echo json_encode(['error' => 'Error retrieving data from the current session']);
}
} elseif ($action == 'logout') {
require_once __DIR__.'/../../../main/inc/global-min.inc.php';

$userId = api_get_user_id();
online_logout($userId, false);
echo json_encode(['message' => 'Logged out successfully']);
} else {
// Handle unexpected action value
http_response_code(400);
echo json_encode(['error' => 'Invalid action parameter']);
}
} else {
// No action provided
http_response_code(400);
echo json_encode(['error' => 'No action parameter provided']);
}
3 changes: 3 additions & 0 deletions main/install/configuration.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -2580,3 +2580,6 @@
// is '$1EdTech-CC-FILEBASE$' (the latest), but previous versions of the standard
// recommended '$IMS-CC-FILEBASE$', so you might want to use that for greater compatibility.
//$_configuration['commoncartridge_path_token'] = '$IMS-CC-FILEBASE$';

// Set the following parameter to true to enable a session lifetime controller that notifies users that their session is about to expire
//$_configuration['session_lifetime_controller'] = false;
4 changes: 4 additions & 0 deletions main/lang/english/trad4all.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -9073,4 +9073,8 @@
$CreateExport = "Create export file";
$MoodleExportAdminIDComment = "Moodle requires a user identification to be stored inside some XML files of the .mbz format. Please provide an internal (integer) ID of the user exporting this course or Moodle's internal user ID of the user that will be the owner of the imported resources. If you're in doubt, just write '1' and some fake data ton continue.";
$DropboxVulnerabilityWarning = "Remember to only download files sent by people you trust. If in doubt, please use a anti-virus tool on your computer to mitigate the risk of harm to your data.";
$SessionExpiredAt = "Session expired at";
$DueToInactivityTheSessionIsGoingToClose = "Due to your inactivity, this session is going to close in";
$KeepGoing = "Keep going";
$SessionIsClosing = "Your session is closing";
?>
4 changes: 4 additions & 0 deletions main/lang/french/trad4all.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -9008,4 +9008,8 @@
$MoodleExportAdminIDComment = "Moodle requiert une identification de l'utilisateur pour la stocker au sein de fichiers XML qui font partie du format .mbz.
Merci de bien vouloir fournir un numéro interne (nombre entier) de l'utilisateur qui exporte le cours, ou d'un utilisateur de notre système, qui sera désigné (s'il y a correspondance) comme le propriétaire des ressources importées sur l'autre système. Si vous avez encore des doutes, indiquez simplement '1' et donnez des données fictives.";
$DropboxVulnerabilityWarning = "Ne téléchargez que des fichiers envoyés par des personnes en qui vous avez confiance. Dans le doute, merci d'utiliser un programme anti-virus sur votre ordinateur pour réduire les risques pour vos données.";
$SessionExpiredAt = "Session expirée à";
$DueToInactivityTheSessionIsGoingToClose = "Dû à votre inactivité, la session se fermera dans";
$KeepGoing = "Rester connecté";
$SessionIsClosing = "Votre session est en cours de fermeture";
?>
4 changes: 4 additions & 0 deletions main/lang/spanish/trad4all.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -9098,4 +9098,8 @@
$CreateExport = "Crear archivo de exporte";
$MoodleExportAdminIDComment = "Moodle requiere la indentificación de algún usuario para almacenarla dentro de los archivos XML del formato .mbz. Por favor indique un número de ID interno (entero) del usuario quien está exportando este curso, o el ID interno del usuario en Moodle para el usuario quien será propietario de los recursos importados. Si tiene duda, puede simplemente marcar '1' y algunos datos falsos para seguir.";
$DropboxVulnerabilityWarning = "Recuerde únicamente descargar archivos enviados por personas conocidas. Si tiene dudas, use un anti-virus en su computadora para reducir el riesgo de daños a sus datos.";
$SessionExpiredAt = "Sesión expirada el";
$DueToInactivityTheSessionIsGoingToClose = "Debido a su inactividad, esta sesión se cerrará en";
$KeepGoing = "Seguir conectado";
$SessionIsClosing = "Su sesión se está cerrando";
?>
197 changes: 197 additions & 0 deletions main/template/default/layout/main.js.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ var offline_button = '<img src="' + _p.web_img + 'statusoffline.png">';
var connect_lang = '{{ "ChatConnected"|get_lang | escape('js')}}';
var disconnect_lang = '{{ "ChatDisconnected"|get_lang | escape('js')}}';
var chatLang = '{{ "GlobalChat"|get_lang | escape('js')}}';
var sessionRemainingSeconds = 0;
var sessionCounterInterval;
var sessionClosing = false;

{% if 'hide_chat_video'|api_get_configuration_value %}
var hide_chat_video = true;
Expand Down Expand Up @@ -443,6 +446,10 @@ $(function() {
});
});
{% endif %}

if (window.self === window.top) {
checkSessionTime();
}
});

$(window).resize(function() {
Expand Down Expand Up @@ -731,3 +738,193 @@ function copyTextToClipBoard(elementId)
/* Copy the text inside the text field */
document.execCommand("copy");
}

function checkSessionTime()
{
fetch('/main/inc/ajax/session_clock.ajax.php?action=time')
.then(response => {
if (!response.ok) {
throw new Error('Server error: ' + response.statusText);
}
return response.json();
})
.then(data => {
if (data.sessionTimeLeft <= 0) {
if (!document.getElementById('session-checker-overlay')) {
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}

var now = new Date();
var day = String(now.getDate()).padStart(2, '0');
var month = String(now.getMonth() + 1).padStart(2, '0');
var year = now.getFullYear();
var hour = String(now.getHours()).padStart(2, '0');
var minutes = String(now.getMinutes()).padStart(2, '0');

var dateTimeSessionExpired = day + '/' + month + '/' + year + ' ' + hour + ':' + minutes;

document.body.insertAdjacentHTML('afterbegin', '<div id="session-checker-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,1);display:flex;justify-content:center;align-items:center;z-index:1000;"><div id="session-checker-modal" style="background:white;padding:20px;border-radius:5px;box-shadow:0010pxrgba(0,0,0,0.5);width:35%;text-align:center;"><p style="margin-bottom:20px;">{{ 'SessionExpiredAt' | get_lang | escape('js')}} ' + dateTimeSessionExpired + '.</p><button class="btn btn-primary" onclick="window.location.pathname = \'/\';">OK</button></div></div>');
}
} else if (data.sessionTimeLeft <= 110) {
sessionRemainingSeconds = data.sessionTimeLeft - 5;
if (sessionRemainingSeconds < 0) {
sessionRemainingSeconds = 0;
}

if (!document.getElementById('session-count-overlay')) {
document.body.insertAdjacentHTML('afterbegin', '<div id="session-count-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);display:flex;justify-content:center;align-items:center;z-index:1000;"><div id="session-checker-modal" style="background:white;padding:20px;border-radius:5px;box-shadow:0010pxrgba(0,0,0,0.5);width:35%;text-align:center;"><p id="session-counter" style="margin-bottom:20px;">{{ 'DueToInactivityTheSessionIsGoingToClose' | get_lang | escape('js')}} ' + sessionRemainingSeconds + ' {{ 'Seconds' | get_lang | escape('js')}}</p><button class="btn btn-primary" id="btn-session-extend" onclick="extendSession();">{{ 'KeepGoing' | get_lang | escape('js')}}</button></div></div>');
sessionCounterInterval = setInterval(updateSessionTimeCounter, 1000);
}
setTimeout(checkSessionTime, 60000);
} else {
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}

setTimeout(checkSessionTime, 60000);
}
})
.catch(error => console.error('Error:', error));
}

function extendSession() {
fetch('/main/inc/ajax/online.ajax.php')
.then(response => {
if (!response.ok) {
throw new Error('Server error: ' + response.statusText);
}
return response;
})
.then(data => {
console.log('Session extended');
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}
})
.catch(error => console.error('Error:', error));
}

function updateSessionTimeCounter() {
var sessionCounter = document.getElementById('session-counter');
if (sessionRemainingSeconds > 3) {
sessionCounter.innerHTML = '{{ 'DueToInactivityTheSessionIsGoingToClose' | get_lang | escape('js')}} ' + sessionRemainingSeconds + ' {{ 'Seconds' | get_lang | escape('js')}}';
sessionRemainingSeconds--;
} else if (sessionRemainingSeconds <= 3 && sessionRemainingSeconds > 1) {
var currentUrl = window.location.href;
if (currentUrl.includes('lp_controller.php') && currentUrl.includes('lp_id=') && currentUrl.includes('action=view')) {
if (!sessionClosing) {
var btnSessionExtend = document.getElementById('btn-session-extend');
if (btnSessionExtend) {
btnSessionExtend.remove();
}

document.getElementById('session-counter').innerHTML = '{{ 'SessionIsClosing' | get_lang | escape('js')}}';

setTimeout(function() {
fetch('/main/inc/ajax/session_clock.ajax.php?action=logout')
.then(response => response.json())
.then(data => {
if (!document.getElementById('session-checker-overlay')) {
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}

var now = new Date();
var day = String(now.getDate()).padStart(2, '0');
var month = String(now.getMonth() + 1).padStart(2, '0');
var year = now.getFullYear();
var hour = String(now.getHours()).padStart(2, '0');
var minutes = String(now.getMinutes()).padStart(2, '0');

var dateTimeSessionExpired = day + '/' + month + '/' + year + ' ' + hour + ':' + minutes;

document.body.insertAdjacentHTML('afterbegin', '<div id="session-checker-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,1);display:flex;justify-content:center;align-items:center;z-index:1000;"><div id="session-checker-modal" style="background:white;padding:20px;border-radius:5px;box-shadow:0010pxrgba(0,0,0,0.5);width:35%;text-align:center;"><p style="margin-bottom:20px;">{{ 'SessionExpiredAt' | get_lang | escape('js')}} ' + dateTimeSessionExpired + '.</p><button class="btn btn-primary" onclick="window.location.pathname = \'/\';">OK</button></div></div>');
}
})
.catch((error) => {
console.error('Error:', error);
});
}, 1000);

lastCall();
}
sessionClosing = true;
}
else {
if (!sessionClosing) {
var btnSessionExtend = document.getElementById('btn-session-extend');
if (btnSessionExtend) {
btnSessionExtend.remove();
}

document.getElementById('session-counter').innerHTML = '{{ 'SessionIsClosing' | get_lang | escape('js')}}';

setTimeout(function() {
fetch('/main/inc/ajax/session_clock.ajax.php?action=logout')
.then(response => response.json())
.then(data => {
if (!document.getElementById('session-checker-overlay')) {
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}

var now = new Date();
var day = String(now.getDate()).padStart(2, '0');
var month = String(now.getMonth() + 1).padStart(2, '0');
var year = now.getFullYear();
var hour = String(now.getHours()).padStart(2, '0');
var minutes = String(now.getMinutes()).padStart(2, '0');

var dateTimeSessionExpired = day + '/' + month + '/' + year + ' ' + hour + ':' + minutes;

document.body.insertAdjacentHTML('afterbegin', '<div id="session-checker-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,1);display:flex;justify-content:center;align-items:center;z-index:1000;"><div id="session-checker-modal" style="background:white;padding:20px;border-radius:5px;box-shadow:0010pxrgba(0,0,0,0.5);width:35%;text-align:center;"><p style="margin-bottom:20px;">{{ 'SessionExpiredAt' | get_lang | escape('js')}} ' + dateTimeSessionExpired + '.</p><button class="btn btn-primary" onclick="window.location.pathname = \'/\';">OK</button></div></div>');
}
})
.catch((error) => {
console.error('Error:', error);
});
}, 1000);
}
sessionClosing = true;
}
}
else {
clearInterval(sessionCounterInterval);
var counterOverlay = document.getElementById('session-count-overlay');
if (counterOverlay) {
counterOverlay.remove();
}

var now = new Date();
var day = String(now.getDate()).padStart(2, '0');
var month = String(now.getMonth() + 1).padStart(2, '0');
var year = now.getFullYear();
var hour = String(now.getHours()).padStart(2, '0');
var minutes = String(now.getMinutes()).padStart(2, '0');

var dateTimeSessionExpired = day + '/' + month + '/' + year + ' ' + hour + ':' + minutes;

document.body.insertAdjacentHTML('afterbegin', '<div id="session-checker-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,1);display:flex;justify-content:center;align-items:center;z-index:1000;"><div id="session-checker-modal" style="background:white;padding:20px;border-radius:5px;box-shadow:0010pxrgba(0,0,0,0.5);width:35%;text-align:center;"><p style="margin-bottom:20px;">{{ 'SessionExpiredAt' | get_lang | escape('js')}} ' + dateTimeSessionExpired + '.</p><button class="btn btn-primary" onclick="window.location.pathname = \'/\';">OK</button></div></div>');
}
}

0 comments on commit 14e699f

Please sign in to comment.