Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

## 1.1

- FIX : COMPAT V23 - 1.1.2 *22/12/2025*
- FIX : COMPAT V22 - 1.1.1 *08/07/2025*
- NEW : configuration for redirection on login page to new URL - 1.1.0 *17/05/2024*

Expand Down
184 changes: 90 additions & 94 deletions admin/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,13 @@
* Actions
*/

if($action == 'setMaintenanceModeOn'){
if ($action == 'setMaintenanceModeOn') {
dolibarr_del_const($db, 'MAIN_ONLY_LOGIN_ALLOWED', 0);
dolibarr_del_const($db, 'MAIN_ONLY_LOGIN_ALLOWED', $conf->entity);
dolibarr_set_const($db, 'MAIN_ONLY_LOGIN_ALLOWED', $user->login, 'chaine', 1, 'Maintenance mode add by '.$user->login, 0);
}

if($action == 'setMaintenanceModeOff'){
if ($action == 'setMaintenanceModeOff') {
dolibarr_del_const($db, 'MAIN_ONLY_LOGIN_ALLOWED', 0);
dolibarr_del_const($db, 'MAIN_ONLY_LOGIN_ALLOWED', $conf->entity);
}
Expand Down Expand Up @@ -210,135 +210,131 @@
// Récupération de la date de mise en maintenance
$maintTime = 0;
$maintObj = $db->getRow('SELECT MAX(tms) tms FROM '.$db->prefix().'const WHERE name = \'MAIN_ONLY_LOGIN_ALLOWED\' ');
if($maintObj){
if ($maintObj) {
$maintTime = $db->jdate($maintObj->tms);
}

$mainOnlyLoginAllowed = getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED');

print '<fieldset>';
print '<legend>'.$langs->trans('MaintenanceStatus') . ' ';
if(!empty($mainOnlyLoginAllowed)){
print dolGetBadge($langs->trans('MaintenanceOn'), '', 'success');

print dolGetButtonAction(
$langs->trans('DisableMaintenanceMode'),
'',
'danger',
dol_buildpath('maintenanceatm/admin/setup.php', 1).'?action=setMaintenanceModeOff',
'',
1,
[
'confirm' => [
//'url' => 'http://', // Overide Url to go when user click on action btn, if empty default url is $url.?confirm=yes, for no js compatibility use $url for fallback confirm.
'title' => '', // Overide title of modal, if empty default title use "ConfirmBtnCommonTitle" lang key
'action-btn-label' => $langs->trans('DisableMaintenanceMode'), // Overide label of action button, if empty default label use "Confirm" lang key
'cancel-btn-label' => '', // Overide label of cancel button, if empty default label use "CloseDialog" lang key
'content' => $langs->trans('ActivateMaintenanceModeOffConfirm'), // Overide text of content, if empty default content use "ConfirmBtnCommonContent" lang key
],
]
);
}else{
print dolGetBadge($langs->trans('MaintenanceOff'), '', 'info');
// --- Préparation des variables factorisées ---
$ajaxUrl = dol_buildpath('/maintenanceatm/admin/setup.php', 1);
$cleanToken = newToken();
$isMaintOn = !empty($mainOnlyLoginAllowed);

print dolGetButtonAction(
$langs->trans('ActivateMaintenanceMode'),
'',
'danger',
dol_buildpath('maintenanceatm/admin/setup.php', 1).'?action=setMaintenanceModeOn',
'',
1,
[
'confirm' => [
//'url' => 'http://', // Overide Url to go when user click on action btn, if empty default url is $url.?confirm=yes, for no js compatibility use $url for fallback confirm.
'title' => '', // Overide title of modal, if empty default title use "ConfirmBtnCommonTitle" lang key
'action-btn-label' => $langs->trans('ActivateMaintenanceMode'), // Overide label of action button, if empty default label use "Confirm" lang key
'cancel-btn-label' => '', // Overide label of cancel button, if empty default label use "CloseDialog" lang key
'content' => $langs->trans('ActivateMaintenanceModeConfirm', $user->login), // Overide text of content, if empty default content use "ConfirmBtnCommonContent" lang key
],
]
);
// 1. Titre et Badge d'état dans la légende
print '<legend>' . $langs->trans('MaintenanceStatus') . ' ';
if ($isMaintOn) {
print dolGetBadge($langs->trans('MaintenanceOn'), '', 'success');
} else {
print dolGetBadge($langs->trans('MaintenanceOff'), '', 'info');
}


print '</legend>';

print '<div id="maintenance-check-table">';


// Security warning if install.lock file is missing or if conf file is writable
// 2. Bouton d'action dynamique
$btnLabel = $isMaintOn ? 'DisableMaintenanceMode' : 'ActivateMaintenanceMode';
$confirmMsg = $isMaintOn ? $langs->trans('ActivateMaintenanceModeOffConfirm') : $langs->trans('ActivateMaintenanceModeConfirm', $user->login);

print dolGetButtonAction(
$langs->trans($btnLabel),
'',
'danger',
'#',
'btn-trigger-maint',
1,
array(
'confirm' => array(
'title' => $langs->trans($btnLabel),
'content' => $confirmMsg,
'action-btn-label' => $langs->trans('Confirm'),
)
)
);

// 3. Conteneur pour le tableau (auto-refresh)
print '<div id="maintenance-check-table" class="marginbottomonly">';

// Avertissements de sécurité (install.lock et conf.php)
if (getDolGlobalString('MAIN_REMOVE_INSTALL_WARNING') || true) {

// TODO : check for maint.lock (je me rappel plus du nom de fichier

// Check if install lock file is present
$lockfile = DOL_DATA_ROOT.'/install.lock';
if (!empty($lockfile) && !file_exists($lockfile) && is_dir(DOL_DOCUMENT_ROOT."/install")) {
if (!file_exists($lockfile) && is_dir(DOL_DOCUMENT_ROOT."/install")) {
$langs->load("errors");
print info_admin($langs->trans("WarningLockFileDoesNotExists", DOL_DATA_ROOT).' '.$langs->trans("WarningUntilDirRemoved", DOL_DOCUMENT_ROOT."/install"), 0, 0, '1', 'clearboth');
}

// Conf files must be in read only mode
if (is_writable(DOL_DOCUMENT_ROOT.'/'.$conffile)) { // $conffile is defined into filefunc.inc.php
if (is_writable(DOL_DOCUMENT_ROOT.'/'.$conffile)) {
$langs->load("errors");
print info_admin($langs->transnoentities("WarningConfFileMustBeReadOnly").' '.$langs->trans("WarningUntilDirRemoved", DOL_DOCUMENT_ROOT."/install"), 0, 0, '1', 'clearboth');
}
}

print '<table class="tagtable nobottomiftotal liste" >';

print '<tr class="oddeven" >';
print '<table class="tagtable nobottomiftotal liste">';

print '<td>'.$langs->trans('LastBackupSql').' <a target="_blank" href="'.dol_buildpath('admin/tools/dolibarr_export.php',1).'" title="'.$langs->trans('NewBackupBdd').'" ><span class="fa fa-link"></span></a></td>';
// Ligne : Dernier Backup SQL
print '<tr class="oddeven">';
print '<td>'.$langs->trans('LastBackupSql').' <a target="_blank" href="'.dol_buildpath('admin/tools/dolibarr_export.php', 1).'" title="'.$langs->trans('NewBackupBdd').'" ><span class="fa fa-link"></span></a></td>';
print '<td>';

$fileArray = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', "date", SORT_DESC, 1);
if(!empty($fileArray) && is_array($fileArray)){

$fileArray = reset($fileArray);
$class = $maintTime > (int) $fileArray['date'] ? 'warning' : 'success';
if($maintTime < (int) $fileArray['date']){
print dol_print_date($fileArray['date'], '%d/%m/%Y %H:%M:%S');
}else{
print dolGetBadge(dol_print_date($fileArray['date'], '%d/%m/%Y %H:%M:%S'), '' , 'warning');
if (!empty($fileArray) && is_array($fileArray)) {
$latestFile = reset($fileArray);
$formattedDate = dol_print_date($latestFile['date'], '%d/%m/%Y %H:%M:%S');

// Alerte si la maintenance a été lancée APRES le dernier backup
if (isset($maintTime) && $maintTime > (int) $latestFile['date']) {
print dolGetBadge($formattedDate, '', 'warning');
} else {
print $formattedDate;
}

if(0 >= (int) $fileArray['size']){
print ' '.dolGetBadge(dol_print_size($fileArray['size'], 0, 0), '' , 'danger');
if (0 >= (int) $latestFile['size']) {
print ' '.dolGetBadge(dol_print_size($latestFile['size'], 0, 0), '', 'danger');
}

print ' '.$fileArray['name'];


}else{
dolGetBadge('NoBackupFound', '', 'danger');
print ' <span class="opacitymedium">'.$latestFile['name'].'</span>';
} else {
print dolGetBadge($langs->trans('NoBackupFound'), '', 'danger');
}
print '</td></tr>';

print '</td>';
print '</tr>';


if(empty($dolibarr_main_prod)){
print '<tr class="oddeven" >';
// Ligne : Mode Production
if (empty($dolibarr_main_prod)) {
print '<tr class="oddeven">';
print '<td>'.$langs->trans('ModeMainProd').'</td>';
print '<td>'.dolGetBadge($langs->trans('Disabled'), '', 'danger').'</td>';
print '</tr>';
}


print '</table>';
print '</div>';

print '
<script>
$(function() {
setInterval(function(){
$("#maintenance-check-table").load("'.dol_buildpath('maintenanceatm/admin/setup.php',1).' #maintenance-check-table");
}, 5000);
});
</script>
';

print '</div>'; // Fin de maintenance-check-table

// 4. SCRIPT UNIQUE : Gestion Redirection + Auto-refresh
print '<script>
$(document).ready(function() {
// Gestion de la redirection forcée pour éviter le bug des &amp; et du #
$(document).on("click", ".ui-dialog-buttonset .ui-button", function() {
var btnText = $(this).text().trim();
var confirmLabel = "'.dol_escape_js($langs->trans("Confirm")).'";

if (btnText === confirmLabel && $("#btn-trigger-maint").hasClass("butActionConfirm")) {
var actionStr = "'.($isMaintOn ? 'setMaintenanceModeOff' : 'setMaintenanceModeOn').'";
window.location.href = "'.$ajaxUrl.'?action=" + actionStr + "&token='.$cleanToken.'&confirm=yes";
return false;
}
});

// Auto-refresh du tableau toutes les 5 secondes
var refreshTimer = setInterval(function() {
var $container = $("#maintenance-check-table");
if ($container.length) {
// Le " > *" permet de ne rafraîchir que l intérieur du div
$container.load("'.dol_buildpath('maintenanceatm/admin/setup.php', 1).' #maintenance-check-table > *");
} else {
clearInterval(refreshTimer);
}
}, 5000);
});
</script>';

print '</fieldset>';

Expand Down
46 changes: 20 additions & 26 deletions class/actions_maintenanceatm.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class ActionsMaintenanceATM extends maintenanceatm\RetroCompatCommonHookActions


/**
* Constructor
* Constructor for ActionsMaintenanceATM
*
* @param DoliDB $db Database handler
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
Expand All @@ -75,14 +75,12 @@ public function __construct($db)


/**
* Execute action
* Execute action during login page display (Hook mainloginpage)
*
* @param array $parameters Array of parameters
* @param CommonObject $object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...)
* @param string $action 'add', 'update', 'view'
* @return int Return integer <0 if KO,
* =0 if OK but we want to process standard actions too,
* >0 if OK and we want to replace standard actions.
* @param array $parameters Array of parameters from hook context
* @param CommonObject $object The object to process
* @param string $action Current action
* @return int 0 if OK, <0 if KO, >0 to replace standard actions
*/
public function getLoginPageOptions($parameters, &$object, &$action)
{
Expand All @@ -92,7 +90,7 @@ public function getLoginPageOptions($parameters, &$object, &$action)
$mainOnlyLoginAllowed = getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED');
$newUrl = getDolGlobalString('MAINTENANCEATM_REDIRECT_NEW_URL');

if(!empty($mainOnlyLoginAllowed)){
if (!empty($mainOnlyLoginAllowed)) {
$langs->load('maintenanceatm@maintenanceatm');

$this->resprints = '
Expand All @@ -106,31 +104,29 @@ public function getLoginPageOptions($parameters, &$object, &$action)
}
</style>
';

// Ajout de la redirection JS
if(filter_var($newUrl, FILTER_VALIDATE_URL)){

if (filter_var($newUrl, FILTER_VALIDATE_URL)) {
$redirectSeconds = 9;
$this->resprints.= '
<div class="maintenance-bloc">
<h1>'.$langs->trans('ModeMaintenanceActivatedNewUrlTitle').'</h1>
<p>
'.$langs->trans('ModeMaintenanceActivatedNewUrl', $newUrl).' : <a href="'.$newUrl.'">'.$newUrl.'</a><br/><br/>

'.$langs->trans('ModeMaintenanceActivatedNewUrlDescPart1', $newUrl).'
<strong id="maint-redirect-timer">'.$redirectSeconds.'</strong>
<strong id="maint-redirect-timer">'.$redirectSeconds.'</strong>
'.$langs->trans('ModeMaintenanceActivatedNewUrlDescPart2').'
<button id="maint-redirect-timer-stop" title="'.dol_htmlentities($langs->trans('ModeMaintenanceStopTimer')).'">x</button>
<button id="maint-redirect-timer-stop" title="'.dol_htmlentities($langs->trans('ModeMaintenanceStopTimer')).'">x</button>
</p>
</div>
<script>
var seconds = '.$redirectSeconds.'; // seconds for HTML
var maintRedirectClearInterval; // variable for clearInterval() function

function redirect() {
document.location.href = '.json_encode($newUrl).';
}

function updateSecs() {
document.getElementById("maint-redirect-timer").innerHTML = seconds;
seconds--;
Expand All @@ -139,26 +135,25 @@ function updateSecs() {
redirect();
}
}

function countdownTimer() {
maintRedirectClearInterval = setInterval(function () {
updateSecs()
}, 1000);
}

countdownTimer();


document.getElementById("maint-redirect-timer-stop").addEventListener("click", function (e){
e.preventDefault();
clearInterval(maintRedirectClearInterval);
});


</script>
';

}else{
} else {
$this->resprints.= '
<div class="maintenance-bloc">
<h1>'.$langs->trans('ModeMaintenanceActivatedLoginTitle').'</h1>
Expand All @@ -184,5 +179,4 @@ function countdownTimer() {
$this->resprints = '';
return 0;
}

}
Loading