Messenger-artiges Benachrichtigungssystem für Dolibarr: - Schwebendes FAB (Floating Action Button) unten links - Ausklappbares Panel mit allen Benachrichtigungen - Historie der gelesenen Nachrichten - Direktes Abhaken per Checkbox - Click-to-Navigate für Aktionen - Pulsierender Button bei dringenden Nachrichten - Draggable Panel-Header - Automatische Erkennung hängender Cron-Jobs - API für andere Module: GlobalNotify::error(), ::warning(), etc. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
183 lines
5.4 KiB
PHP
183 lines
5.4 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* GlobalNotify Admin Setup Page
|
|
*/
|
|
|
|
// Load Dolibarr environment
|
|
$res = 0;
|
|
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
|
|
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
|
|
}
|
|
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
|
|
$tmp2 = realpath(__FILE__);
|
|
$i = strlen($tmp) - 1;
|
|
$j = strlen($tmp2) - 1;
|
|
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
|
|
$i--;
|
|
$j--;
|
|
}
|
|
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
|
|
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
|
|
}
|
|
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
|
|
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
|
|
}
|
|
if (!$res && file_exists("../../main.inc.php")) {
|
|
$res = @include "../../main.inc.php";
|
|
}
|
|
if (!$res && file_exists("../../../main.inc.php")) {
|
|
$res = @include "../../../main.inc.php";
|
|
}
|
|
if (!$res) {
|
|
die("Include of main fails");
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
|
|
dol_include_once('/globalnotify/class/globalnotify.class.php');
|
|
|
|
/**
|
|
* @var Conf $conf
|
|
* @var DoliDB $db
|
|
* @var Translate $langs
|
|
* @var User $user
|
|
*/
|
|
|
|
$langs->loadLangs(array("admin", "globalnotify@globalnotify"));
|
|
|
|
// Access control
|
|
if (!$user->admin) {
|
|
accessforbidden();
|
|
}
|
|
|
|
$action = GETPOST('action', 'aZ09');
|
|
|
|
/*
|
|
* Actions
|
|
*/
|
|
|
|
if ($action == 'clearall') {
|
|
// Clear all notifications
|
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name LIKE 'GLOBALNOTIFY_%'";
|
|
$db->query($sql);
|
|
setEventMessages("Alle Benachrichtigungen gelöscht", null, 'mesgs');
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'resetcronjobs') {
|
|
// Reset all stuck cron jobs
|
|
$sql = "UPDATE ".MAIN_DB_PREFIX."cronjob SET processing = 0 WHERE processing = 1";
|
|
$resql = $db->query($sql);
|
|
$affected = $db->affected_rows($resql);
|
|
setEventMessages("{$affected} Cron-Jobs zurückgesetzt", null, 'mesgs');
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
$page_name = "GlobalNotify - ".$langs->trans("Settings");
|
|
llxHeader('', $page_name);
|
|
|
|
print load_fiche_titre($page_name, '', 'title_setup');
|
|
|
|
// Get all notifications
|
|
$notify = new GlobalNotify($db);
|
|
$allNotifications = $notify->getAllNotifications(0, false); // All, including read
|
|
|
|
// Get stuck cron jobs
|
|
$sql = "SELECT rowid, label, module_name, datelastrun, processing, status
|
|
FROM ".MAIN_DB_PREFIX."cronjob
|
|
WHERE status = 1
|
|
ORDER BY processing DESC, label";
|
|
$resql = $db->query($sql);
|
|
|
|
print '<div class="div-table-responsive">';
|
|
|
|
// Actions
|
|
print '<div class="tabsAction">';
|
|
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=clearall" onclick="return confirm(\'Alle Benachrichtigungen löschen?\')">Alle Benachrichtigungen löschen</a>';
|
|
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=resetcronjobs" onclick="return confirm(\'Alle hängenden Cron-Jobs zurücksetzen?\')">Hängende Cron-Jobs zurücksetzen</a>';
|
|
print '</div>';
|
|
|
|
// Cron Jobs Overview
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th>Cron-Job</th>';
|
|
print '<th>Modul</th>';
|
|
print '<th>Status</th>';
|
|
print '<th>Letzter Lauf</th>';
|
|
print '</tr>';
|
|
|
|
if ($resql) {
|
|
while ($obj = $db->fetch_object($resql)) {
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$obj->label.'</td>';
|
|
print '<td>'.($obj->module_name ?: '-').'</td>';
|
|
print '<td>';
|
|
if ($obj->processing) {
|
|
print '<span class="badge badge-status1" style="background-color:#ff9800">HÄNGT</span>';
|
|
} else {
|
|
print '<span class="badge badge-status4">OK</span>';
|
|
}
|
|
print '</td>';
|
|
print '<td>'.dol_print_date($db->jdate($obj->datelastrun), 'dayhour').'</td>';
|
|
print '</tr>';
|
|
}
|
|
}
|
|
print '</table>';
|
|
|
|
// All Notifications
|
|
print '<br>';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th>Benachrichtigungen ('.count($allNotifications).')</th>';
|
|
print '<th>Modul</th>';
|
|
print '<th>Typ</th>';
|
|
print '<th>Datum</th>';
|
|
print '<th>Status</th>';
|
|
print '</tr>';
|
|
|
|
if (empty($allNotifications)) {
|
|
print '<tr class="oddeven"><td colspan="5" class="center opacitymedium">Keine Benachrichtigungen</td></tr>';
|
|
} else {
|
|
foreach ($allNotifications as $notif) {
|
|
print '<tr class="oddeven">';
|
|
print '<td>';
|
|
print '<strong>'.dol_escape_htmltag($notif['title']).'</strong><br>';
|
|
print '<small>'.dol_escape_htmltag($notif['message']).'</small>';
|
|
if (!empty($notif['action_url'])) {
|
|
print '<br><a href="'.dol_escape_htmltag($notif['action_url']).'">'.$notif['action_label'].'</a>';
|
|
}
|
|
print '</td>';
|
|
print '<td>'.$notif['module'].'</td>';
|
|
print '<td>';
|
|
$typeLabels = array(
|
|
'error' => '<span class="badge badge-status8">Fehler</span>',
|
|
'warning' => '<span class="badge badge-status1" style="background:#ff9800">Warnung</span>',
|
|
'info' => '<span class="badge badge-status4">Info</span>',
|
|
'success' => '<span class="badge badge-status4">Erfolg</span>',
|
|
'action' => '<span class="badge badge-status6">Aktion</span>',
|
|
);
|
|
print $typeLabels[$notif['type']] ?? $notif['type'];
|
|
print '</td>';
|
|
print '<td>'.dol_print_date($notif['created'], 'dayhour').'</td>';
|
|
print '<td>';
|
|
if (!empty($notif['read'])) {
|
|
print '<span class="opacitymedium">Gelesen</span>';
|
|
} else {
|
|
print '<strong>Ungelesen</strong>';
|
|
}
|
|
print '</td>';
|
|
print '</tr>';
|
|
}
|
|
}
|
|
print '</table>';
|
|
|
|
print '</div>';
|
|
|
|
llxFooter();
|
|
$db->close();
|