get($moduleName); $error = null; $notice = null; $testGroup = null; $dbTestMessages = []; $currentSection = trim((string) ($_GET['section'] ?? 'general')); require_admin(); if (!$module) { http_response_code(404); echo '
Modul nicht gefunden.
'; return; } $allowedSetupSections = ['general', 'access', 'cron', 'custom']; if (!in_array($currentSection, $allowedSetupSections, true)) { $currentSection = 'general'; } $fields = (array)($module['setup']['fields'] ?? []); $hasGlobalDebugField = false; foreach ($fields as $field) { if ((string)($field['name'] ?? '') === 'debug_enabled') { $hasGlobalDebugField = true; break; } } if (!$hasGlobalDebugField) { $fields[] = [ 'name' => 'debug_enabled', 'label' => 'Modul-Debug aktivieren', 'type' => 'checkbox', 'help' => 'Wenn aktiv, darf dieses Modul Debug-Daten in den globalen Nexus-Debugstream schreiben.', ]; } $fieldTypes = []; $fieldMeta = []; foreach ($fields as $field) { $fname = (string)($field['name'] ?? ''); if ($fname === '') { continue; } $fieldTypes[$fname] = (string)($field['type'] ?? 'text'); $fieldMeta[$fname] = $field; } $isFxRatesSetup = $moduleName === 'fx-rates'; $current = modules()->settings($moduleName); $intervalTaskStatuses = []; $cronTaskDefinitions = modules()->cronTasks($moduleName); $cronTaskStatuses = []; $cronTaskStatusGroups = []; $refreshSchedulerState = static function () use ($moduleName, &$intervalTaskStatuses, &$cronTaskStatuses, &$cronTaskStatusGroups): void { $intervalTaskStatuses = modules()->intervalTaskStatuses($moduleName); $cronTaskStatuses = modules()->cronTaskStatuses($moduleName); $cronTaskStatusGroups = []; foreach ($cronTaskStatuses as $cronTaskStatus) { $cronGroupName = trim((string) ($cronTaskStatus['job_name'] ?? $cronTaskStatus['name'] ?? '')); if ($cronGroupName === '') { continue; } $cronTaskStatusGroups[$cronGroupName][] = $cronTaskStatus; } }; $refreshSchedulerState(); $setupActions = modules()->hasFunction($moduleName, 'setup_actions') ? (array) module_fn($moduleName, 'setup_actions') : []; $defaults = $module['db_defaults'] ?? []; if (empty($current['db']) && is_array($defaults)) { $current['db'] = $defaults; } $metadataDefaults = $module['metadata_db_defaults'] ?? []; if (empty($current['metadata_db']) && is_array($metadataDefaults)) { $current['metadata_db'] = $metadataDefaults; } $dbDefaultsByGroup = [ 'db' => is_array($defaults) ? $defaults : [], 'metadata_db' => is_array($metadataDefaults) ? $metadataDefaults : [], ]; $authConfig = is_array($module['auth'] ?? null) ? $module['auth'] : ['required' => false, 'users' => [], 'groups' => []]; $allowedUsers = []; $allowedGroups = []; $knownUsers = []; $knownGroups = []; $manualUsers = []; $manualGroups = []; $setNested = function (array &$target, string $path, mixed $value): void { $parts = explode('.', $path); $last = array_pop($parts); $node = &$target; foreach ($parts as $part) { if (!isset($node[$part]) || !is_array($node[$part])) { $node[$part] = []; } $node = &$node[$part]; } if ($last !== null && $last !== '') { $node[$last] = $value; } }; $getNested = function (array $source, string $path): mixed { $node = $source; foreach (explode('.', $path) as $part) { if (!is_array($node) || !array_key_exists($part, $node)) { return null; } $node = $node[$part]; } return $node; }; $dbGroups = []; $fieldsByDbGroup = []; $generalFields = []; foreach ($fields as $field) { $name = (string)($field['name'] ?? ''); if (!str_contains($name, '.')) { continue; } [$group, $key] = explode('.', $name, 2); if ($key !== 'driver') { continue; } $label = (string)($field['label'] ?? $group); $label = trim(preg_replace('/\s+DB\s+Driver$/i', ' DB', $label) ?? $label); $label = $label !== '' ? $label : $group; $dbGroups[$group] = $label; } foreach ($fields as $field) { $name = (string)($field['name'] ?? ''); if (str_contains($name, '.')) { [$group] = explode('.', $name, 2); if (array_key_exists($group, $dbGroups)) { $fieldsByDbGroup[$group][] = $field; continue; } } $generalFields[] = $field; } $generalSetupFields = []; $cronSetupFields = []; $customSetupFields = []; foreach ($generalFields as $field) { $fieldName = (string)($field['name'] ?? ''); if ($fieldName === 'debug_enabled') { $generalSetupFields[] = $field; continue; } if ($fieldName === 'schedule_timezone') { $cronSetupFields[] = $field; continue; } $customSetupFields[] = $field; } $driverOptions = [ 'pgsql' => 'PostgreSQL', 'mysql' => 'MySQL / MariaDB', 'sqlite' => 'SQLite', ]; $timezoneOptions = modules()->timezones(); $describeDbConfig = static function (array $dbConfig): string { $driver = (string)($dbConfig['driver'] ?? ''); $host = (string)($dbConfig['host'] ?? ''); $port = (string)($dbConfig['port'] ?? ''); return 'Aktive Einstellung: Treiber ' . ($driver !== '' ? $driver : 'nicht gesetzt') . ', Host ' . ($host !== '' ? $host : 'nicht gesetzt') . ', Port ' . ($port !== '' ? $port : 'nicht gesetzt') . '.'; }; $describeDbDefaults = static function (array $dbDefaults): string { $driver = (string)($dbDefaults['driver'] ?? ''); $host = (string)($dbDefaults['host'] ?? ''); $port = (string)($dbDefaults['port'] ?? ''); if ($driver === '' && $host === '' && $port === '') { return ''; } return 'Standard: Treiber ' . ($driver !== '' ? $driver : 'nicht gesetzt') . ', Host ' . ($host !== '' ? $host : 'nicht gesetzt') . ', Port ' . ($port !== '' ? $port : 'nicht gesetzt') . '.'; }; $dbConfigWarning = static function (array $dbConfig): ?string { $driver = (string)($dbConfig['driver'] ?? ''); $port = (string)($dbConfig['port'] ?? ''); if ($driver === 'pgsql' && $port === '3306') { return 'Port 3306 ist typisch fuer MySQL/MariaDB, aber als Treiber ist PostgreSQL ausgewaehlt. Bitte den Treiber auf MySQL / MariaDB stellen.'; } if ($driver === 'mysql' && $port === '5432') { return 'Port 5432 ist typisch fuer PostgreSQL, aber als Treiber ist MySQL / MariaDB ausgewaehlt. Bitte Port oder Treiber pruefen.'; } return null; }; $dbConfigHint = static function (string $group, array $dbConfig, array $dbDefaults): ?string { if ($group !== 'metadata_db') { return null; } $driver = (string)($dbConfig['driver'] ?? ''); $host = (string)($dbConfig['host'] ?? ''); $port = (string)($dbConfig['port'] ?? ''); $defaultDriver = (string)($dbDefaults['driver'] ?? ''); $defaultHost = (string)($dbDefaults['host'] ?? ''); $defaultPort = (string)($dbDefaults['port'] ?? ''); if ($driver !== $defaultDriver || $host !== $defaultHost || $port !== $defaultPort) { return 'Diese Verbindung ist fuer Nexus-eigene DHCP-Zusatzinfos gedacht, nicht fuer die Nexus-App/Base-DB. Erwartet wird normalerweise: ' . ($defaultDriver !== '' ? $defaultDriver : 'Treiber offen') . ' auf ' . ($defaultHost !== '' ? $defaultHost : 'Host offen') . ':' . ($defaultPort !== '' ? $defaultPort : 'Port offen') . '.'; } return null; }; $fetchJsonWithApiKey = static function (string $url, string $apiKey, int $timeout = 10): array { $headers = [ 'Accept: application/json', 'x-api-key: ' . $apiKey, ]; $responseBody = null; $httpCode = 0; $curlError = ''; if (function_exists('curl_init')) { $ch = curl_init($url); if ($ch !== false) { curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_CONNECTTIMEOUT => min(5, $timeout), CURLOPT_HTTPHEADER => $headers, ]); $responseBody = curl_exec($ch); $curlError = curl_error($ch); $httpCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE); curl_close($ch); } } if (!is_string($responseBody) || $responseBody === '') { $context = stream_context_create([ 'http' => [ 'method' => 'GET', 'timeout' => $timeout, 'header' => implode("\r\n", $headers) . "\r\n", ], ]); $responseBody = @file_get_contents($url, false, $context); } if (!is_string($responseBody) || $responseBody === '') { return [ 'ok' => false, 'message' => 'Abruf fehlgeschlagen.' . ($curlError !== '' ? ' ' . $curlError : '') . ($httpCode > 0 ? ' HTTP ' . $httpCode : ''), ]; } $decoded = json_decode($responseBody, true); if (!is_array($decoded)) { return [ 'ok' => false, 'message' => 'Antwort ist kein gueltiges JSON.', ]; } foreach (['error', 'message', 'detail'] as $errorKey) { if (isset($decoded[$errorKey]) && is_string($decoded[$errorKey]) && trim($decoded[$errorKey]) !== '') { return [ 'ok' => false, 'message' => trim((string) $decoded[$errorKey]), ]; } } return [ 'ok' => true, 'data' => $decoded, ]; }; $normalizeDriver = static function (mixed $value): mixed { if (!is_string($value)) { return $value; } $normalized = strtolower(trim($value)); return match ($normalized) { 'postgres', 'postgresql' => 'pgsql', 'mariadb', 'mysql/mariadb', 'mysql / mariadb' => 'mysql', default => $normalized, }; }; $formatRunTimestamp = static function (?string $value, ?string $timezone = null): string { $value = trim((string) $value); if ($value === '') { return '-'; } try { $dt = new DateTimeImmutable($value, new DateTimeZone('UTC')); $targetTz = trim((string) $timezone) !== '' ? new DateTimeZone((string) $timezone) : new DateTimeZone(date_default_timezone_get()); return $dt->setTimezone($targetTz)->format('Y-m-d H:i:s'); } catch (\Throwable) { $ts = strtotime($value); if ($ts === false) { return $value; } return date('Y-m-d H:i:s', $ts); } }; $extractSchedulerJobs = static function (array $postedSchedulerJobs, array $cronTaskDefinitions, array $current): array { $schedulerJobs = []; foreach ($cronTaskDefinitions as $cronTask) { if (!is_array($cronTask)) { continue; } $cronName = trim((string) ($cronTask['name'] ?? '')); if ($cronName === '') { continue; } $jobPayload = is_array($postedSchedulerJobs[$cronName] ?? null) ? $postedSchedulerJobs[$cronName] : []; $entriesPayload = is_array($jobPayload['entries'] ?? null) ? $jobPayload['entries'] : []; $entries = []; foreach (array_values($entriesPayload) as $entryPayload) { if (!is_array($entryPayload)) { continue; } $cronExpression = trim((string) ($entryPayload['cron_expression'] ?? '')); $timezone = trim((string) ($entryPayload['timezone'] ?? ($current['schedule_timezone'] ?? 'UTC'))); if ($cronExpression === '' && $timezone === '') { continue; } $entries[] = [ 'enabled' => !empty($entryPayload['enabled']), 'cron_expression' => $cronExpression, 'timezone' => $timezone !== '' ? $timezone : 'UTC', 'builder' => [ 'mode' => trim((string) ($entryPayload['builder']['mode'] ?? 'builder')), 'kind' => trim((string) ($entryPayload['builder']['kind'] ?? 'daily')), 'time' => trim((string) ($entryPayload['builder']['time'] ?? '18:00')), 'interval_days' => max(1, (int) ($entryPayload['builder']['interval_days'] ?? 2)), 'weekday' => trim((string) ($entryPayload['builder']['weekday'] ?? '1')), 'month_day' => max(1, min(31, (int) ($entryPayload['builder']['month_day'] ?? 1))), 'interval_hours' => max(1, min(23, (int) ($entryPayload['builder']['interval_hours'] ?? 6))), ], ]; } if ((string) ($cronTask['mode'] ?? 'single') !== 'multi' && $entries !== []) { $entries = [array_values($entries)[0]]; } $schedulerJobs[$cronName] = ['entries' => $entries]; } return $schedulerJobs; }; $cronWeekdays = [ '0' => 'Sonntag', '1' => 'Montag', '2' => 'Dienstag', '3' => 'Mittwoch', '4' => 'Donnerstag', '5' => 'Freitag', '6' => 'Samstag', ]; $renderField = function (array $field) use (&$current, $getNested, $driverOptions): void { $name = (string)($field['name'] ?? ''); if ($name === '') { return; } $label = (string)($field['label'] ?? $name); $type = (string)($field['type'] ?? 'text'); $required = !empty($field['required']); $help = (string)($field['help'] ?? $field['description'] ?? ''); $postKey = str_replace('.', '_', $name); $value = ''; if ($name === 'kea_auto_init') { $value = !empty($current[$name]) ? '1' : '0'; } elseif (str_contains($name, '.')) { $value = (string)($getNested($current, $name) ?? ''); } else { $value = (string)($current[$name] ?? ''); } ?> saveSettings($moduleName, $current); $current = modules()->settings($moduleName); $refreshSchedulerState(); $testResult = null; if ($isSchedulerTest) { $jobName = trim((string) ($_POST['scheduler_job_name'] ?? '')); $entryIndex = max(0, (int) ($_POST['scheduler_entry_index'] ?? 0)); $testResult = modules()->runCronTaskNow($moduleName, $jobName, $entryIndex); $refreshSchedulerState(); } while (ob_get_level() > 0) { ob_end_clean(); } header('Content-Type: application/json; charset=utf-8'); echo json_encode([ 'ok' => true, 'message' => $isSchedulerTest ? (string) ($testResult['message'] ?? 'Cron-Test ausgefuehrt.') : 'Scheduler gespeichert.', 'scheduler_jobs' => $current['scheduler_jobs'] ?? [], 'statuses' => $cronTaskStatuses, 'test_result' => $testResult, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } foreach ($fields as $field) { $name = (string)($field['name'] ?? ''); if ($name === '') { continue; } $type = (string)($field['type'] ?? 'text'); $postKey = str_replace('.', '_', $name); $value = $_POST[$postKey] ?? null; if ($type === 'checkbox') { $value = isset($_POST[$postKey]) ? '1' : '0'; } if (is_array($value) && $type === 'multiselect') { $value = array_values(array_filter(array_map( static fn (mixed $item): string => trim((string) $item), $value ), static fn (string $item): bool => $item !== '')); } elseif (is_array($value)) { continue; } $value = is_string($value) ? trim($value) : $value; if (str_ends_with($name, '.driver')) { $value = $normalizeDriver($value); } if ($name === 'kea_auto_init') { $payload[$name] = $value === '1'; continue; } if (str_contains($name, '.')) { $setNested($payload, $name, $value); continue; } $payload[$name] = $value; } $current = array_replace_recursive($current, $payload); if ($cronTaskDefinitions !== []) { $postedSchedulerJobs = is_array($_POST['scheduler_jobs'] ?? null) ? $_POST['scheduler_jobs'] : []; $schedulerJobs = $extractSchedulerJobs($postedSchedulerJobs, $cronTaskDefinitions, $current); $current['scheduler_jobs'] = $schedulerJobs; } $postedTestGroup = (string)($_POST['test_db'] ?? ''); $postedResetGroup = (string)($_POST['reset_db'] ?? ''); $postedSetupAction = trim((string)($_POST['module_setup_action'] ?? '')); if ($postedSetupAction !== '') { if (!modules()->hasFunction($moduleName, 'run_setup_action')) { $error = 'Diese Setup-Aktion wird vom Modul nicht unterstuetzt.'; } else { try { $actionResult = module_fn($moduleName, 'run_setup_action', $postedSetupAction); $current = modules()->settings($moduleName); $notice = 'Setup-Aktion ausgefuehrt.'; if (is_array($actionResult)) { if (isset($actionResult['message']) && is_string($actionResult['message']) && trim($actionResult['message']) !== '') { $notice = trim((string) $actionResult['message']); } elseif (isset($actionResult['synced_count'])) { $notice = 'Waehrungskatalog synchronisiert. ' . (int) $actionResult['synced_count'] . ' Waehrungen verarbeitet.'; } } } catch (\Throwable $e) { $error = $e->getMessage(); } } } elseif ($postedResetGroup !== '') { $testGroup = $postedResetGroup; if (!array_key_exists($postedResetGroup, $dbGroups)) { $error = 'Unbekannte Datenbank-Konfiguration.'; } elseif (($dbDefaultsByGroup[$postedResetGroup] ?? []) === []) { $dbTestMessages[$postedResetGroup] = [ 'type' => 'error', 'text' => 'Fuer diese Datenbank sind keine Standardwerte hinterlegt.', ]; } else { $current[$postedResetGroup] = $dbDefaultsByGroup[$postedResetGroup]; $dbTestMessages[$postedResetGroup] = [ 'type' => 'success', 'text' => 'Standardwerte geladen. Bitte pruefen und speichern.', ]; } } elseif ($postedTestGroup !== '') { $testGroup = $postedTestGroup; if (!array_key_exists($postedTestGroup, $dbGroups)) { $error = 'Unbekannte Datenbank-Konfiguration.'; } else { $dbConfig = $getNested($current, $postedTestGroup); if (!is_array($dbConfig)) { $dbTestMessages[$postedTestGroup] = [ 'type' => 'error', 'text' => 'Datenbank-Konfiguration ist unvollstaendig.', ]; } else { $warning = $dbConfigWarning($dbConfig); if ($warning !== null) { $dbTestMessages[$postedTestGroup] = [ 'type' => 'error', 'text' => $warning . ' ' . $describeDbConfig($dbConfig), ]; } else { try { $dbConfig['options'] = array_replace([ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, ], (array)($dbConfig['options'] ?? [])); $testPdo = \App\Database::createFromArray($dbConfig); $testPdo->query('SELECT 1')->fetchColumn(); $dbTestMessages[$postedTestGroup] = [ 'type' => 'success', 'text' => 'Verbindung erfolgreich. ' . $describeDbConfig($dbConfig), ]; } catch (\Throwable $e) { $dbTestMessages[$postedTestGroup] = [ 'type' => 'error', 'text' => 'Verbindung fehlgeschlagen. ' . $describeDbConfig($dbConfig) . ' ' . $e->getMessage(), ]; } } } } } else { modules()->saveSettings($moduleName, $current); if ($submittedSetupSection === 'access') { $selectedUsers = is_array($_POST['auth_user_values'] ?? null) ? $_POST['auth_user_values'] : []; $selectedGroups = is_array($_POST['auth_group_values'] ?? null) ? $_POST['auth_group_values'] : []; $manualUserValues = preg_split('/[,\\n]+/', (string) ($_POST['auth_users'] ?? '')) ?: []; $manualGroupValues = preg_split('/[,\\n]+/', (string) ($_POST['auth_groups'] ?? '')) ?: []; modules()->saveAuth($moduleName, [ 'required' => isset($_POST['auth_required']), 'users' => array_merge($selectedUsers, $manualUserValues), 'groups' => array_merge($selectedGroups, $manualGroupValues), ]); } if ($isFxRatesSetup && modules()->hasFunction($moduleName, 'save_runtime_settings')) { module_fn($moduleName, 'save_runtime_settings', $payload); $current = modules()->settings($moduleName); } $refreshSchedulerState(); if ($submittedSetupSection === 'general' && array_key_exists('debug_enabled', $payload) && empty($payload['debug_enabled'])) { module_debug_clear($moduleName); } $notice = 'Setup gespeichert.'; $module = modules()->get($moduleName) ?: $module; $authConfig = is_array($module['auth'] ?? null) ? $module['auth'] : $authConfig; } } $moduleStatusPanel = null; $activeDbGroup = $testGroup !== null && array_key_exists($testGroup, $dbGroups) ? $testGroup : (array_key_first($dbGroups) ?? ''); $authConfig = is_array($module['auth'] ?? null) ? $module['auth'] : ['required' => false, 'users' => [], 'groups' => []]; $allowedUsers = is_array($authConfig['users'] ?? null) ? array_values(array_filter(array_map('strval', $authConfig['users']))) : []; $allowedGroups = is_array($authConfig['groups'] ?? null) ? array_values(array_filter(array_map('strval', $authConfig['groups']))) : []; $knownUsers = modules()->knownAuthUsers(); $knownGroups = modules()->knownAuthGroups(); $currentUser = auth_user(); if (is_array($currentUser) && trim((string)($currentUser['sub'] ?? '')) !== '') { $currentSub = (string) $currentUser['sub']; $hasCurrentUser = false; foreach ($knownUsers as $knownUser) { if ((string) ($knownUser['sub'] ?? '') === $currentSub) { $hasCurrentUser = true; break; } } if (!$hasCurrentUser) { $knownUsers[] = [ 'sub' => $currentSub, 'username' => (string) ($currentUser['username'] ?? ''), 'email' => (string) ($currentUser['email'] ?? ''), 'name' => (string) ($currentUser['name'] ?? ''), 'groups' => is_array($currentUser['groups'] ?? null) ? $currentUser['groups'] : [], ]; } } $knownGroups = array_values(array_unique(array_merge($knownGroups, auth_groups()))); sort($knownGroups, SORT_NATURAL | SORT_FLAG_CASE); $knownUserValues = array_column($knownUsers, 'sub'); $manualUsers = array_values(array_filter($allowedUsers, fn (string $value): bool => !in_array($value, $knownUserValues, true))); $manualGroups = array_values(array_filter($allowedGroups, fn (string $value): bool => !in_array($value, $knownGroups, true))); $hasCustomSection = $customSetupFields !== [] || $setupActions !== [] || $isFxRatesSetup; $sectionUrls = [ 'general' => '/modules/setup/' . rawurlencode($moduleName) . '/general', 'access' => '/modules/setup/' . rawurlencode($moduleName) . '/access', 'cron' => '/modules/setup/' . rawurlencode($moduleName) . '/cron', 'custom' => '/modules/setup/' . rawurlencode($moduleName) . '/custom', ]; $sectionTitles = [ 'general' => 'Allgemein', 'access' => 'Zugriffsrechte', 'cron' => 'Cron Einstellungen', 'custom' => 'Custom Settings', ]; if ($currentSection === 'custom' && !$hasCustomSection) { $currentSection = 'general'; } $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection] ?? 'Allgemein'); ?>
Setup

Trage die benötigten Informationen für das Modul ein.

['code' => $code, 'name' => $name], array_values($fxCatalogOptions), array_keys($fxCatalogOptions) ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>
Custom Settings

Provider und Abruf

Allgemein

Datenbank und Debug

>
Aktionen

Modulaktionen

Waehrungssynch Laedt die verfuegbaren Waehrungen einmalig aus dem konfigurierten FX-Provider.
Letzter Sync:
Zugriffsrechte

Zugriff verwalten

Steuert, ob Login erforderlich ist und welche Benutzer oder Gruppen das Modul oeffnen duerfen.

Login erforderlich
Erlaubte Benutzer Noch keine bekannten Benutzer vorhanden. Nutzer erscheinen hier, sobald sie sich einmal angemeldet haben.
Erlaubte Gruppen Noch keine bekannten Gruppen vorhanden.
Wenn Login aktiv ist und Benutzer sowie Gruppen leer bleiben, darf jeder eingeloggte Benutzer das Modul oeffnen.
Cron Einstellungen

Scheduler und Zeitsteuerung

Hier liegen die zeitbezogenen Modul-Einstellungen, Intervall-Tasks und Cron-Jobs.

Automationen

Intervall-Aufgaben

Diese Aufgaben werden beim ersten gueltigen Modulaufruf nach Ablauf des Intervalls automatisch ausgefuehrt.

Intervall: Stunden Letzter Start: Letzter Erfolg: Naechster Lauf:
Automationen

Cron-Jobs

Diese Jobs werden ueber den zentralen Nexus-Scheduler ausgefuehrt. Der System-Cron sollte den CLI-Runner jede Minute starten.

$task): ?>
Cron-Syntax: Minute Stunde Tag Monat Wochentag
Letzter Start: Letzter Erfolg: Naechster Lauf lokal: Aktion: () Status: Meldung: Cron-Fehler:
Allgemein

Datenbank und Debug

Zugriffsrechte

Zugriff verwalten

Steuert, ob Login erforderlich ist und welche Benutzer oder Gruppen das Modul oeffnen duerfen.

Login erforderlich
Erlaubte Benutzer Noch keine bekannten Benutzer vorhanden. Nutzer erscheinen hier, sobald sie sich einmal angemeldet haben.
Erlaubte Gruppen Noch keine bekannten Gruppen vorhanden.
Wenn Login aktiv ist und Benutzer sowie Gruppen leer bleiben, darf jeder eingeloggte Benutzer das Modul oeffnen.
Cron Einstellungen

Scheduler und Zeitsteuerung

Hier liegen die zeitbezogenen Modul-Einstellungen, Intervall-Tasks und Cron-Jobs.

Dieses Modul hat keine eigenen Zeitzonenfelder. Intervall-Tasks und Cron-Jobs koennen trotzdem weiter unten verwaltet werden.

Automationen

Intervall-Aufgaben

Diese Aufgaben werden beim ersten gueltigen Modulaufruf nach Ablauf des Intervalls automatisch ausgefuehrt.

Intervall: Stunden Letzter Start: Letzter Erfolg: Naechster Lauf: Status: Meldung:
Automationen

Cron-Jobs

Diese Jobs werden ueber den zentralen Nexus-Scheduler ausgefuehrt. Der System-Cron sollte den CLI-Runner jede Minute starten.

$task): ?>
Cron-Syntax: Minute Stunde Tag Monat Wochentag
Letzter Start: Letzter Erfolg: Naechster Lauf lokal: Aktion: () Status: Meldung: Cron-Fehler:
>
Aktionen

Modulaktionen

Seltene Wartungsaktionen koennen direkt hier aus dem Setup ausgefuehrt werden.

Status

Der Status wird beim Aufruf der Setup-Seite automatisch geprueft.

>
Datenbanken

Verbindungen

Jede Verbindung kann getrennt konfiguriert und getestet werden.

$label): ?>
$label): ?>
>

konfigurieren

Custom Settings

Modulspezifische Einstellungen