dolibarr.globalnotify/admin/setup.php
data c65d15a86b feat: GlobalNotify v1.1.0 - Schwebendes Benachrichtigungs-Widget
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>
2026-02-23 11:04:43 +01:00

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();