asdas
This commit is contained in:
@@ -515,7 +515,7 @@ $mm->registerFunction($moduleName, 'alpha_vantage_request', static function (
|
|||||||
});
|
});
|
||||||
|
|
||||||
$mm->registerFunction($moduleName, 'display_timezone', static function (): \DateTimeZone {
|
$mm->registerFunction($moduleName, 'display_timezone', static function (): \DateTimeZone {
|
||||||
return new \DateTimeZone('Europe/Berlin');
|
return new \DateTimeZone(nexus_display_timezone_name());
|
||||||
});
|
});
|
||||||
|
|
||||||
$mm->registerFunction($moduleName, 'normalize_market_timestamp_utc', static function (mixed $value): string {
|
$mm->registerFunction($moduleName, 'normalize_market_timestamp_utc', static function (mixed $value): string {
|
||||||
@@ -547,7 +547,7 @@ $mm->registerFunction($moduleName, 'format_datetime_for_display', static functio
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$displayTimezone = new \DateTimeZone('Europe/Berlin');
|
$displayTimezone = new \DateTimeZone(nexus_display_timezone_name());
|
||||||
$source = trim((string) $source);
|
$source = trim((string) $source);
|
||||||
|
|
||||||
if (str_starts_with($source, 'bavest:') || str_starts_with($source, 'alphavantage:')) {
|
if (str_starts_with($source, 'bavest:') || str_starts_with($source, 'alphavantage:')) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ $modules = array_values(array_filter(
|
|||||||
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
<div style="display:flex; gap:10px; flex-wrap:wrap;">
|
||||||
<a class="nav-link" href="/modules">Module verwalten</a>
|
<a class="nav-link" href="/modules">Module verwalten</a>
|
||||||
<?php if (auth_is_admin()): ?>
|
<?php if (auth_is_admin()): ?>
|
||||||
|
<a class="nav-link" href="/settings">Nexus Einstellungen</a>
|
||||||
<a class="nav-link" href="/exports/database.sql">SQL-Export</a>
|
<a class="nav-link" href="/exports/database.sql">SQL-Export</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ foreach ($fields as $field) {
|
|||||||
$generalSetupFields = [];
|
$generalSetupFields = [];
|
||||||
$databaseSetupFields = [];
|
$databaseSetupFields = [];
|
||||||
$cronSetupFields = [];
|
$cronSetupFields = [];
|
||||||
|
$cronTimezoneField = null;
|
||||||
$customSetupFields = [];
|
$customSetupFields = [];
|
||||||
foreach ($generalFields as $field) {
|
foreach ($generalFields as $field) {
|
||||||
$fieldName = (string)($field['name'] ?? '');
|
$fieldName = (string)($field['name'] ?? '');
|
||||||
@@ -177,7 +178,7 @@ foreach ($generalFields as $field) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($fieldName === 'schedule_timezone') {
|
if ($fieldName === 'schedule_timezone') {
|
||||||
$cronSetupFields[] = $field;
|
$cronTimezoneField = $field;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$customSetupFields[] = $field;
|
$customSetupFields[] = $field;
|
||||||
@@ -190,6 +191,10 @@ $driverOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
$timezoneOptions = modules()->timezones();
|
$timezoneOptions = modules()->timezones();
|
||||||
|
$globalCronTimezone = nexus_cron_timezone_name();
|
||||||
|
$globalDisplayTimezone = nexus_display_timezone_name();
|
||||||
|
$moduleCronTimezoneOverride = trim((string) ($current['schedule_timezone'] ?? ''));
|
||||||
|
$effectiveModuleCronTimezone = $moduleCronTimezoneOverride !== '' ? $moduleCronTimezoneOverride : $globalCronTimezone;
|
||||||
|
|
||||||
$describeDbConfig = static function (array $dbConfig): string {
|
$describeDbConfig = static function (array $dbConfig): string {
|
||||||
$driver = (string)($dbConfig['driver'] ?? '');
|
$driver = (string)($dbConfig['driver'] ?? '');
|
||||||
@@ -346,7 +351,7 @@ $formatRunTimestamp = static function (?string $value, ?string $timezone = null)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$dt = new DateTimeImmutable($value, new DateTimeZone('UTC'));
|
$dt = new DateTimeImmutable($value, new DateTimeZone('UTC'));
|
||||||
$targetTz = trim((string) $timezone) !== '' ? new DateTimeZone((string) $timezone) : new DateTimeZone(date_default_timezone_get());
|
$targetTz = trim((string) $timezone) !== '' ? new DateTimeZone((string) $timezone) : new DateTimeZone(nexus_display_timezone_name());
|
||||||
return $dt->setTimezone($targetTz)->format('Y-m-d H:i:s');
|
return $dt->setTimezone($targetTz)->format('Y-m-d H:i:s');
|
||||||
} catch (\Throwable) {
|
} catch (\Throwable) {
|
||||||
$ts = strtotime($value);
|
$ts = strtotime($value);
|
||||||
@@ -376,7 +381,7 @@ $extractSchedulerJobs = static function (array $postedSchedulerJobs, array $cron
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$cronExpression = trim((string) ($entryPayload['cron_expression'] ?? ''));
|
$cronExpression = trim((string) ($entryPayload['cron_expression'] ?? ''));
|
||||||
$timezone = trim((string) ($entryPayload['timezone'] ?? ($current['schedule_timezone'] ?? 'UTC')));
|
$timezone = trim((string) ($entryPayload['timezone'] ?? ($current['schedule_timezone'] ?? $globalCronTimezone)));
|
||||||
if ($cronExpression === '' && $timezone === '') {
|
if ($cronExpression === '' && $timezone === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -523,7 +528,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$payload = [];
|
$payload = [];
|
||||||
$sectionFieldNames = match ($submittedSetupSection) {
|
$sectionFieldNames = match ($submittedSetupSection) {
|
||||||
'general' => array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $generalSetupFields),
|
'general' => array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $generalSetupFields),
|
||||||
'cron' => array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $cronSetupFields),
|
'cron' => array_values(array_filter(array_merge(
|
||||||
|
array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $cronSetupFields),
|
||||||
|
[$cronTimezoneField !== null ? (string) ($cronTimezoneField['name'] ?? '') : '']
|
||||||
|
), static fn (string $name): bool => $name !== '')),
|
||||||
'custom' => array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $customSetupFields),
|
'custom' => array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $customSetupFields),
|
||||||
'database' => array_values(array_filter(array_merge(
|
'database' => array_values(array_filter(array_merge(
|
||||||
array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $databaseSetupFields),
|
array_map(static fn (array $field): string => (string) ($field['name'] ?? ''), $databaseSetupFields),
|
||||||
@@ -583,6 +591,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$postKey = str_replace('.', '_', $name);
|
$postKey = str_replace('.', '_', $name);
|
||||||
$value = $_POST[$postKey] ?? null;
|
$value = $_POST[$postKey] ?? null;
|
||||||
|
|
||||||
|
if ($submittedSetupSection === 'cron' && $name === 'schedule_timezone') {
|
||||||
|
if (!isset($_POST['schedule_timezone_custom'])) {
|
||||||
|
$payload[$name] = '';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($type === 'checkbox') {
|
if ($type === 'checkbox') {
|
||||||
$value = isset($_POST[$postKey]) ? '1' : '0';
|
$value = isset($_POST[$postKey]) ? '1' : '0';
|
||||||
}
|
}
|
||||||
@@ -930,12 +945,31 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
<p class="muted">Hier liegen die zeitbezogenen Modul-Einstellungen, Intervall-Tasks und Cron-Jobs.</p>
|
<p class="muted">Hier liegen die zeitbezogenen Modul-Einstellungen, Intervall-Tasks und Cron-Jobs.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($cronSetupFields !== []): ?>
|
<?php if ($cronTimezoneField !== null || $cronSetupFields !== []): ?>
|
||||||
<div class="setup-grid">
|
<div class="setup-grid">
|
||||||
|
<?php if ($cronTimezoneField !== null): ?>
|
||||||
|
<div class="setup-field muted">
|
||||||
|
<span>Standard-Zeitzone für dieses Modul</span>
|
||||||
|
<label style="display:flex; align-items:center; gap:10px;">
|
||||||
|
<input type="checkbox" name="schedule_timezone_custom" value="1" <?= $moduleCronTimezoneOverride !== '' ? 'checked' : '' ?> data-module-cron-tz-toggle>
|
||||||
|
<span>Custom-Zeitzone verwenden</span>
|
||||||
|
</label>
|
||||||
|
<div class="setup-db-message setup-db-message--hint">Aktiv: <?= e($effectiveModuleCronTimezone) ?></div>
|
||||||
|
<small class="muted">Wenn deaktiviert, wird die globale Nexus-Cron-Zeitzone verwendet: <?= e($globalCronTimezone) ?>.</small>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php foreach ($cronSetupFields as $field): ?>
|
<?php foreach ($cronSetupFields as $field): ?>
|
||||||
<?php $renderField($field); ?>
|
<?php $renderField($field); ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
<?php if ($cronTimezoneField !== null): ?>
|
||||||
|
<div class="setup-grid" data-module-cron-tz-panel <?= $moduleCronTimezoneOverride !== '' ? '' : 'hidden' ?>>
|
||||||
|
<label class="setup-field muted">
|
||||||
|
<span>Custom-Zeitzone für dieses Modul</span>
|
||||||
|
<input type="text" name="schedule_timezone" value="<?= e($moduleCronTimezoneOverride !== '' ? $moduleCronTimezoneOverride : $globalCronTimezone) ?>" list="timezone-options" autocomplete="off">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p class="muted">Dieses Modul hat keine eigenen Zeitzonenfelder. Intervall-Tasks und Cron-Jobs koennen trotzdem weiter unten verwaltet werden.</p>
|
<p class="muted">Dieses Modul hat keine eigenen Zeitzonenfelder. Intervall-Tasks und Cron-Jobs koennen trotzdem weiter unten verwaltet werden.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -987,7 +1021,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
$cronMode = (string) ($cronDefinition['mode'] ?? 'single');
|
$cronMode = (string) ($cronDefinition['mode'] ?? 'single');
|
||||||
$cronEntries = $cronTaskStatusGroups[$cronName] ?? [];
|
$cronEntries = $cronTaskStatusGroups[$cronName] ?? [];
|
||||||
?>
|
?>
|
||||||
<div class="setup-field muted" data-scheduler-job data-job-name="<?= e($cronName) ?>" data-job-mode="<?= e($cronMode) ?>" data-job-label="<?= e((string) ($cronDefinition['label'] ?? $cronName)) ?>" data-job-callback="<?= e((string) ($cronDefinition['callback'] ?? '')) ?>">
|
<div class="setup-field muted" data-scheduler-job data-job-name="<?= e($cronName) ?>" data-job-mode="<?= e($cronMode) ?>" data-job-label="<?= e((string) ($cronDefinition['label'] ?? $cronName)) ?>" data-job-callback="<?= e((string) ($cronDefinition['callback'] ?? '')) ?>" data-default-timezone="<?= e($effectiveModuleCronTimezone) ?>">
|
||||||
<span><?= e((string) ($cronDefinition['label'] ?? $cronName)) ?></span>
|
<span><?= e((string) ($cronDefinition['label'] ?? $cronName)) ?></span>
|
||||||
<?php if (trim((string) ($cronDefinition['help'] ?? '')) !== ''): ?>
|
<?php if (trim((string) ($cronDefinition['help'] ?? '')) !== ''): ?>
|
||||||
<small class="muted"><?= e((string) $cronDefinition['help']) ?></small>
|
<small class="muted"><?= e((string) $cronDefinition['help']) ?></small>
|
||||||
@@ -1002,7 +1036,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
<label><input type="checkbox" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][enabled]" value="1" data-enabled <?= !empty($cronConfig['enabled']) ? 'checked' : '' ?>> Aktiv</label>
|
<label><input type="checkbox" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][enabled]" value="1" data-enabled <?= !empty($cronConfig['enabled']) ? 'checked' : '' ?>> Aktiv</label>
|
||||||
<input type="text" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][cron_expression]" value="<?= e((string) ($cronConfig['cron_expression'] ?? '')) ?>" data-cron-expression>
|
<input type="text" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][cron_expression]" value="<?= e((string) ($cronConfig['cron_expression'] ?? '')) ?>" data-cron-expression>
|
||||||
<small class="muted">Cron-Syntax: Minute Stunde Tag Monat Wochentag</small>
|
<small class="muted">Cron-Syntax: Minute Stunde Tag Monat Wochentag</small>
|
||||||
<input type="text" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][timezone]" value="<?= e((string) ($cronConfig['timezone'] ?? 'UTC')) ?>" data-cron-timezone>
|
<input type="text" name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][timezone]" value="<?= e((string) (($cronConfig['timezone'] ?? '') !== '' ? $cronConfig['timezone'] : '')) ?>" data-cron-timezone>
|
||||||
<select name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][builder][mode]" data-cron-builder-mode>
|
<select name="scheduler_jobs[<?= e($cronName) ?>][entries][<?= e((string) $entryIndex) ?>][builder][mode]" data-cron-builder-mode>
|
||||||
<option value="builder" <?= (string) ($builder['mode'] ?? 'builder') === 'builder' ? 'selected' : '' ?>>Builder</option>
|
<option value="builder" <?= (string) ($builder['mode'] ?? 'builder') === 'builder' ? 'selected' : '' ?>>Builder</option>
|
||||||
<option value="manual" <?= (string) ($builder['mode'] ?? 'builder') === 'manual' ? 'selected' : '' ?>>Cron-Syntax</option>
|
<option value="manual" <?= (string) ($builder['mode'] ?? 'builder') === 'manual' ? 'selected' : '' ?>>Cron-Syntax</option>
|
||||||
@@ -1267,6 +1301,14 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
</label>
|
</label>
|
||||||
<label class="setup-field muted">
|
<label class="setup-field muted">
|
||||||
<span>Zeitzone</span>
|
<span>Zeitzone</span>
|
||||||
|
<label style="display:flex; align-items:center; gap:10px;">
|
||||||
|
<input type="checkbox" value="1" data-modal-timezone-custom>
|
||||||
|
<span>Custom-Zeitzone verwenden</span>
|
||||||
|
</label>
|
||||||
|
<div class="setup-db-message setup-db-message--hint" data-modal-timezone-default>Standard: UTC</div>
|
||||||
|
</label>
|
||||||
|
<label class="setup-field muted" data-modal-timezone-wrap hidden>
|
||||||
|
<span>Custom-Zeitzone</span>
|
||||||
<input type="text" value="UTC" data-modal-timezone list="timezone-options" autocomplete="off">
|
<input type="text" value="UTC" data-modal-timezone list="timezone-options" autocomplete="off">
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -1399,6 +1441,16 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
|
const moduleCronToggle = document.querySelector('[data-module-cron-tz-toggle]');
|
||||||
|
const moduleCronPanel = document.querySelector('[data-module-cron-tz-panel]');
|
||||||
|
if (moduleCronToggle && moduleCronPanel) {
|
||||||
|
const syncModuleCronTimezone = () => {
|
||||||
|
moduleCronPanel.hidden = !moduleCronToggle.checked;
|
||||||
|
};
|
||||||
|
moduleCronToggle.addEventListener('change', syncModuleCronTimezone);
|
||||||
|
syncModuleCronTimezone();
|
||||||
|
}
|
||||||
|
|
||||||
const jobs = document.querySelectorAll('[data-scheduler-job]');
|
const jobs = document.querySelectorAll('[data-scheduler-job]');
|
||||||
const modal = document.querySelector('[data-scheduler-modal]');
|
const modal = document.querySelector('[data-scheduler-modal]');
|
||||||
if (!jobs.length || !modal) return;
|
if (!jobs.length || !modal) return;
|
||||||
@@ -1424,6 +1476,9 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
|
|
||||||
const modalFields = {
|
const modalFields = {
|
||||||
enabled: modal.querySelector('[data-modal-enabled]'),
|
enabled: modal.querySelector('[data-modal-enabled]'),
|
||||||
|
timezoneCustom: modal.querySelector('[data-modal-timezone-custom]'),
|
||||||
|
timezoneDefault: modal.querySelector('[data-modal-timezone-default]'),
|
||||||
|
timezoneWrap: modal.querySelector('[data-modal-timezone-wrap]'),
|
||||||
timezone: modal.querySelector('[data-modal-timezone]'),
|
timezone: modal.querySelector('[data-modal-timezone]'),
|
||||||
intervalHours: modal.querySelector('[data-modal-interval-hours]'),
|
intervalHours: modal.querySelector('[data-modal-interval-hours]'),
|
||||||
monthDay: modal.querySelector('[data-modal-month-day]'),
|
monthDay: modal.querySelector('[data-modal-month-day]'),
|
||||||
@@ -1497,20 +1552,22 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
|
|
||||||
const buildSummary = (tab) => {
|
const buildSummary = (tab) => {
|
||||||
const enabled = modalFields.enabled.value === '1' ? 'Aktiv' : 'Inaktiv';
|
const enabled = modalFields.enabled.value === '1' ? 'Aktiv' : 'Inaktiv';
|
||||||
const timezone = modalFields.timezone.value.trim() || 'UTC';
|
const timezoneLabel = modalFields.timezoneCustom.checked
|
||||||
|
? `Custom ${modalFields.timezone.value.trim() || 'UTC'}`
|
||||||
|
: `Standard ${modalFields.timezoneDefault.dataset.timezone || 'UTC'}`;
|
||||||
const time = formatTime(modalState.hour, modalState.minute);
|
const time = formatTime(modalState.hour, modalState.minute);
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'hourly':
|
case 'hourly':
|
||||||
return `${enabled}, alle ${modalFields.intervalHours.value || '1'} Stunden um Minute ${modalState.minute}, ${timezone}`;
|
return `${enabled}, alle ${modalFields.intervalHours.value || '1'} Stunden um Minute ${modalState.minute}, ${timezoneLabel}`;
|
||||||
case 'weekly':
|
case 'weekly':
|
||||||
return `${enabled}, woechentlich ${weekdayMap[modalState.weekday || '1']} um ${time}, ${timezone}`;
|
return `${enabled}, woechentlich ${weekdayMap[modalState.weekday || '1']} um ${time}, ${timezoneLabel}`;
|
||||||
case 'monthly':
|
case 'monthly':
|
||||||
return `${enabled}, monatlich am ${modalFields.monthDay.value || '1'}. um ${time}, ${timezone}`;
|
return `${enabled}, monatlich am ${modalFields.monthDay.value || '1'}. um ${time}, ${timezoneLabel}`;
|
||||||
case 'custom':
|
case 'custom':
|
||||||
return `${enabled}, benutzerdefinierte Cron-Syntax, ${timezone}`;
|
return `${enabled}, benutzerdefinierte Cron-Syntax, ${timezoneLabel}`;
|
||||||
case 'daily':
|
case 'daily':
|
||||||
default:
|
default:
|
||||||
return `${enabled}, taeglich um ${time}, ${timezone}`;
|
return `${enabled}, taeglich um ${time}, ${timezoneLabel}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1547,6 +1604,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getEntryField = (entry, selector) => entry.querySelector(selector);
|
const getEntryField = (entry, selector) => entry.querySelector(selector);
|
||||||
|
const entryDefaultTimezone = (entry) => entry.closest('[data-scheduler-job]')?.dataset.defaultTimezone || 'UTC';
|
||||||
const findStatusNode = (entry, label) => Array.from(entry.querySelectorAll('small')).find((node) => node.textContent.includes(label));
|
const findStatusNode = (entry, label) => Array.from(entry.querySelectorAll('small')).find((node) => node.textContent.includes(label));
|
||||||
const setStatusText = (entry, label, value) => {
|
const setStatusText = (entry, label, value) => {
|
||||||
const node = findStatusNode(entry, label);
|
const node = findStatusNode(entry, label);
|
||||||
@@ -1696,7 +1754,8 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
const updateEntrySummary = (entry) => {
|
const updateEntrySummary = (entry) => {
|
||||||
const enabled = getEntryField(entry, '[data-enabled]')?.checked ?? false;
|
const enabled = getEntryField(entry, '[data-enabled]')?.checked ?? false;
|
||||||
const expression = getEntryField(entry, '[data-cron-expression]')?.value || '';
|
const expression = getEntryField(entry, '[data-cron-expression]')?.value || '';
|
||||||
const timezone = (getEntryField(entry, '[data-cron-timezone]')?.value || 'UTC').trim() || 'UTC';
|
const timezone = (getEntryField(entry, '[data-cron-timezone]')?.value || '').trim();
|
||||||
|
const timezoneLabel = timezone !== '' ? `Custom ${timezone}` : `Standard ${entryDefaultTimezone(entry)}`;
|
||||||
const builderMode = getEntryField(entry, '[data-cron-builder-mode]')?.value || 'builder';
|
const builderMode = getEntryField(entry, '[data-cron-builder-mode]')?.value || 'builder';
|
||||||
const builderKind = getEntryField(entry, '[data-cron-builder-kind]')?.value || 'daily';
|
const builderKind = getEntryField(entry, '[data-cron-builder-kind]')?.value || 'daily';
|
||||||
const time = getEntryField(entry, '[data-cron-builder-time]')?.value || '18:00';
|
const time = getEntryField(entry, '[data-cron-builder-time]')?.value || '18:00';
|
||||||
@@ -1706,15 +1765,15 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
|
|
||||||
let summary = enabled ? 'Aktiv' : 'Inaktiv';
|
let summary = enabled ? 'Aktiv' : 'Inaktiv';
|
||||||
if (builderMode === 'manual') {
|
if (builderMode === 'manual') {
|
||||||
summary += `, Custom, ${timezone}`;
|
summary += `, Custom, ${timezoneLabel}`;
|
||||||
} else if (builderKind === 'every_x_hours') {
|
} else if (builderKind === 'every_x_hours') {
|
||||||
summary += `, alle ${intervalHours} Stunden, ${timezone}`;
|
summary += `, alle ${intervalHours} Stunden, ${timezoneLabel}`;
|
||||||
} else if (builderKind === 'weekly') {
|
} else if (builderKind === 'weekly') {
|
||||||
summary += `, ${weekdayMap[weekday] || weekday} ${time}, ${timezone}`;
|
summary += `, ${weekdayMap[weekday] || weekday} ${time}, ${timezoneLabel}`;
|
||||||
} else if (builderKind === 'monthly_day') {
|
} else if (builderKind === 'monthly_day') {
|
||||||
summary += `, monatlich am ${monthDay}. ${time}, ${timezone}`;
|
summary += `, monatlich am ${monthDay}. ${time}, ${timezoneLabel}`;
|
||||||
} else {
|
} else {
|
||||||
summary += `, taeglich ${time}, ${timezone}`;
|
summary += `, taeglich ${time}, ${timezoneLabel}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let summaryNode = entry.querySelector('[data-entry-summary]');
|
let summaryNode = entry.querySelector('[data-entry-summary]');
|
||||||
@@ -1784,7 +1843,13 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
const [hour = '18', minute = '00'] = time.split(':');
|
const [hour = '18', minute = '00'] = time.split(':');
|
||||||
|
|
||||||
modalFields.enabled.value = getEntryField(entry, '[data-enabled]')?.checked ? '1' : '0';
|
modalFields.enabled.value = getEntryField(entry, '[data-enabled]')?.checked ? '1' : '0';
|
||||||
modalFields.timezone.value = getEntryField(entry, '[data-cron-timezone]')?.value || 'UTC';
|
const savedTimezone = getEntryField(entry, '[data-cron-timezone]')?.value || '';
|
||||||
|
const defaultTimezone = entryDefaultTimezone(entry);
|
||||||
|
modalFields.timezoneCustom.checked = savedTimezone.trim() !== '';
|
||||||
|
modalFields.timezone.value = savedTimezone || defaultTimezone;
|
||||||
|
modalFields.timezoneDefault.dataset.timezone = defaultTimezone;
|
||||||
|
modalFields.timezoneDefault.textContent = `Standard: ${defaultTimezone}`;
|
||||||
|
modalFields.timezoneWrap.hidden = !modalFields.timezoneCustom.checked;
|
||||||
modalFields.intervalHours.value = getEntryField(entry, '[data-cron-builder-interval-hours]')?.value || '6';
|
modalFields.intervalHours.value = getEntryField(entry, '[data-cron-builder-interval-hours]')?.value || '6';
|
||||||
modalFields.monthDay.value = getEntryField(entry, '[data-cron-builder-month-day]')?.value || '1';
|
modalFields.monthDay.value = getEntryField(entry, '[data-cron-builder-month-day]')?.value || '1';
|
||||||
modalFields.expression.value = getEntryField(entry, '[data-cron-expression]')?.value || '';
|
modalFields.expression.value = getEntryField(entry, '[data-cron-expression]')?.value || '';
|
||||||
@@ -1813,7 +1878,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
tab: modalState.tab,
|
tab: modalState.tab,
|
||||||
entryIndex: entry.dataset.entryIndex || null,
|
entryIndex: entry.dataset.entryIndex || null,
|
||||||
enabled: modalFields.enabled.value,
|
enabled: modalFields.enabled.value,
|
||||||
timezone: modalFields.timezone.value,
|
timezone: modalFields.timezoneCustom.checked ? modalFields.timezone.value : '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const modeNode = getEntryField(entry, '[data-cron-builder-mode]');
|
const modeNode = getEntryField(entry, '[data-cron-builder-mode]');
|
||||||
@@ -1833,7 +1898,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
}
|
}
|
||||||
|
|
||||||
enabledNode.checked = modalFields.enabled.value === '1';
|
enabledNode.checked = modalFields.enabled.value === '1';
|
||||||
timezoneNode.value = modalFields.timezone.value.trim() || 'UTC';
|
timezoneNode.value = modalFields.timezoneCustom.checked ? (modalFields.timezone.value.trim() || entryDefaultTimezone(entry)) : '';
|
||||||
timeNode.value = formatTime(modalState.hour, modalState.minute);
|
timeNode.value = formatTime(modalState.hour, modalState.minute);
|
||||||
weekdayNode.value = modalState.weekday;
|
weekdayNode.value = modalState.weekday;
|
||||||
monthDayNode.value = String(Math.max(1, Math.min(31, Number(modalFields.monthDay.value || 1))));
|
monthDayNode.value = String(Math.max(1, Math.min(31, Number(modalFields.monthDay.value || 1))));
|
||||||
@@ -1913,7 +1978,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
|
|
||||||
getEntryField(entry, '[data-enabled]').checked = Boolean(values.enabled);
|
getEntryField(entry, '[data-enabled]').checked = Boolean(values.enabled);
|
||||||
getEntryField(entry, '[data-cron-expression]').value = values.cron_expression || '0 18 * * *';
|
getEntryField(entry, '[data-cron-expression]').value = values.cron_expression || '0 18 * * *';
|
||||||
getEntryField(entry, '[data-cron-timezone]').value = values.timezone || 'UTC';
|
getEntryField(entry, '[data-cron-timezone]').value = values.timezone || '';
|
||||||
getEntryField(entry, '[data-cron-builder-mode]').value = values.builderMode || 'builder';
|
getEntryField(entry, '[data-cron-builder-mode]').value = values.builderMode || 'builder';
|
||||||
getEntryField(entry, '[data-cron-builder-kind]').value = values.builderKind || 'daily';
|
getEntryField(entry, '[data-cron-builder-kind]').value = values.builderKind || 'daily';
|
||||||
getEntryField(entry, '[data-cron-builder-time]').value = values.time || '18:00';
|
getEntryField(entry, '[data-cron-builder-time]').value = values.time || '18:00';
|
||||||
@@ -2017,11 +2082,16 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
[modalFields.enabled, modalFields.timezone, modalFields.intervalHours, modalFields.monthDay, modalFields.expression].forEach((node) => {
|
[modalFields.enabled, modalFields.timezone, modalFields.intervalHours, modalFields.monthDay, modalFields.expression, modalFields.timezoneCustom].forEach((node) => {
|
||||||
node?.addEventListener('input', refreshPreview);
|
node?.addEventListener('input', refreshPreview);
|
||||||
node?.addEventListener('change', refreshPreview);
|
node?.addEventListener('change', refreshPreview);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modalFields.timezoneCustom?.addEventListener('change', () => {
|
||||||
|
modalFields.timezoneWrap.hidden = !modalFields.timezoneCustom.checked;
|
||||||
|
refreshPreview();
|
||||||
|
});
|
||||||
|
|
||||||
modal.querySelectorAll('[data-scheduler-close]').forEach((button) => {
|
modal.querySelectorAll('[data-scheduler-close]').forEach((button) => {
|
||||||
button.addEventListener('click', closeModal);
|
button.addEventListener('click', closeModal);
|
||||||
});
|
});
|
||||||
@@ -2035,7 +2105,7 @@ $GLOBALS['layout_header_context'] = 'Setup / ' . ($sectionTitles[$currentSection
|
|||||||
addButton?.addEventListener('click', () => {
|
addButton?.addEventListener('click', () => {
|
||||||
const container = job.querySelector('[data-scheduler-entries]');
|
const container = job.querySelector('[data-scheduler-entries]');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
const entry = createEntry(job, { timezone: container.querySelector('[data-cron-timezone]')?.value || 'UTC' });
|
const entry = createEntry(job, { timezone: '' });
|
||||||
container.appendChild(entry);
|
container.appendChild(entry);
|
||||||
bindEntry(job, entry);
|
bindEntry(job, entry);
|
||||||
reindexJob(job);
|
reindexJob(job);
|
||||||
|
|||||||
@@ -8,40 +8,155 @@ $themes = [
|
|||||||
require_auth();
|
require_auth();
|
||||||
|
|
||||||
$current = user_theme();
|
$current = user_theme();
|
||||||
|
$timezoneOptions = modules()->timezones();
|
||||||
|
$nexusSettings = nexus_settings();
|
||||||
|
$isAdmin = auth_is_admin();
|
||||||
$notice = null;
|
$notice = null;
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$theme = (string)($_POST['theme'] ?? 'light');
|
$settingsSection = trim((string) ($_POST['settings_section'] ?? 'theme'));
|
||||||
if (!isset($themes[$theme])) {
|
if ($settingsSection === 'nexus' && $isAdmin) {
|
||||||
$theme = 'light';
|
$displayTimezoneCustom = isset($_POST['display_timezone_custom']) ? '1' : '0';
|
||||||
|
$displayTimezone = trim((string) ($_POST['display_timezone'] ?? ''));
|
||||||
|
$cronTimezone = trim((string) ($_POST['cron_timezone'] ?? ''));
|
||||||
|
|
||||||
|
foreach (['displayTimezone' => $displayTimezone, 'cronTimezone' => $cronTimezone] as $key => $value) {
|
||||||
|
if ($value !== '') {
|
||||||
|
try {
|
||||||
|
new DateTimeZone($value);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
$$key = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nexusSettings['display_timezone_custom'] = $displayTimezoneCustom;
|
||||||
|
$nexusSettings['display_timezone'] = $displayTimezoneCustom === '1' ? $displayTimezone : '';
|
||||||
|
$nexusSettings['cron_timezone'] = $cronTimezone;
|
||||||
|
nexus_save_settings($nexusSettings);
|
||||||
|
$nexusSettings = nexus_settings();
|
||||||
|
$notice = 'Nexus-Einstellungen gespeichert.';
|
||||||
|
} else {
|
||||||
|
$theme = (string)($_POST['theme'] ?? 'light');
|
||||||
|
if (!isset($themes[$theme])) {
|
||||||
|
$theme = 'light';
|
||||||
|
}
|
||||||
|
set_user_theme($theme);
|
||||||
|
$current = $theme;
|
||||||
|
$notice = 'Theme gespeichert.';
|
||||||
}
|
}
|
||||||
set_user_theme($theme);
|
|
||||||
$current = $theme;
|
|
||||||
$notice = 'Theme gespeichert.';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$systemTimezone = nexus_system_timezone_name();
|
||||||
|
$effectiveDisplayTimezone = nexus_display_timezone_name();
|
||||||
|
$effectiveCronTimezone = nexus_cron_timezone_name();
|
||||||
|
$displayTimezoneCustom = !empty($nexusSettings['display_timezone_custom']);
|
||||||
|
$savedDisplayTimezone = trim((string) ($nexusSettings['display_timezone'] ?? ''));
|
||||||
|
$savedCronTimezone = trim((string) ($nexusSettings['cron_timezone'] ?? ''));
|
||||||
?>
|
?>
|
||||||
<div class="card">
|
<div class="module-shell"><div class="module-page-bg"><div class="module-page-stack">
|
||||||
<div class="pill">Einstellungen</div>
|
<section class="section-box">
|
||||||
<h1 style="margin-top:.75rem;">User-Design</h1>
|
<h1>Nexus Einstellungen</h1>
|
||||||
<p class="muted">Wähle deine persönliche Farbpalette.</p>
|
<p class="muted">Persönliche Anzeige und systemweite Standardwerte.</p>
|
||||||
|
|
||||||
<?php if ($notice): ?>
|
<?php if ($notice): ?>
|
||||||
<div class="card" style="margin-top:1rem; border-color:var(--accent-2);">
|
<div class="section-box" style="margin-top:1rem; border-color:var(--accent-2);">
|
||||||
<?= e($notice) ?>
|
<?= e($notice) ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="setup-form" style="margin-top:1rem;">
|
||||||
|
<section class="section-box setup-panel">
|
||||||
|
<div class="setup-panel__head">
|
||||||
|
<div>
|
||||||
|
<span class="pill">Benutzer</span>
|
||||||
|
<h2>Persönliches Design</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="post" class="setup-form">
|
||||||
|
<input type="hidden" name="settings_section" value="theme">
|
||||||
|
<div class="setup-grid">
|
||||||
|
<label class="setup-field muted">
|
||||||
|
<span>Farbpalette</span>
|
||||||
|
<select name="theme">
|
||||||
|
<?php foreach ($themes as $key => $label): ?>
|
||||||
|
<option value="<?= e($key) ?>" <?= $current === $key ? 'selected' : '' ?>>
|
||||||
|
<?= e($label) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="setup-actions setup-actions--footer">
|
||||||
|
<button class="cta-button" type="submit">Design speichern</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?php if ($isAdmin): ?>
|
||||||
|
<section class="section-box setup-panel">
|
||||||
|
<div class="setup-panel__head">
|
||||||
|
<div>
|
||||||
|
<span class="pill">Nexus</span>
|
||||||
|
<h2>Standard-Zeitzonen</h2>
|
||||||
|
<p class="muted">Diese Werte werden von Modulen als Default übernommen, sofern dort kein eigener Override gesetzt ist.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="post" class="setup-form">
|
||||||
|
<input type="hidden" name="settings_section" value="nexus">
|
||||||
|
<datalist id="nexus-timezone-options">
|
||||||
|
<?php foreach ($timezoneOptions as $timezoneOption): ?>
|
||||||
|
<option value="<?= e((string) $timezoneOption['value']) ?>"><?= e((string) $timezoneOption['label']) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</datalist>
|
||||||
|
<div class="setup-grid">
|
||||||
|
<div class="setup-field muted">
|
||||||
|
<span>System-Zeitzone</span>
|
||||||
|
<div><?= e($systemTimezone) ?></div>
|
||||||
|
<small class="muted">Diese Zeitzone wird genutzt, wenn keine globale Anzeige-Zeitzone gesetzt ist.</small>
|
||||||
|
</div>
|
||||||
|
<div class="setup-field muted">
|
||||||
|
<span>Anzeige-Zeitzone</span>
|
||||||
|
<label style="display:flex; align-items:center; gap:10px;">
|
||||||
|
<input type="checkbox" name="display_timezone_custom" value="1" <?= $displayTimezoneCustom ? 'checked' : '' ?> data-global-display-tz-toggle>
|
||||||
|
<span>Custom-Zeitzone verwenden</span>
|
||||||
|
</label>
|
||||||
|
<div class="setup-db-message setup-db-message--hint">Aktiv: <?= e($effectiveDisplayTimezone) ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setup-grid" data-global-display-tz-panel <?= $displayTimezoneCustom ? '' : 'hidden' ?>>
|
||||||
|
<label class="setup-field muted">
|
||||||
|
<span>Custom Anzeige-Zeitzone</span>
|
||||||
|
<input type="text" name="display_timezone" value="<?= e($savedDisplayTimezone !== '' ? $savedDisplayTimezone : $effectiveDisplayTimezone) ?>" list="nexus-timezone-options" autocomplete="off">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="setup-grid">
|
||||||
|
<label class="setup-field muted">
|
||||||
|
<span>Standard-Zeitzone für Crons</span>
|
||||||
|
<input type="text" name="cron_timezone" value="<?= e($savedCronTimezone !== '' ? $savedCronTimezone : $effectiveCronTimezone) ?>" list="nexus-timezone-options" autocomplete="off">
|
||||||
|
<small class="muted">Wird in Modul-Crons als Standard verwendet. Einzelne Module oder Einträge können das übersteuern.</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="setup-actions setup-actions--footer">
|
||||||
|
<button class="cta-button" type="submit">Nexus-Einstellungen speichern</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
</section>
|
||||||
|
</div></div></div>
|
||||||
<form method="post" style="margin-top:1rem; display:grid; gap:12px; max-width:360px;">
|
<?php if ($isAdmin): ?>
|
||||||
<label class="muted" style="display:grid; gap:6px;">
|
<script>
|
||||||
<span>Farbpalette</span>
|
(() => {
|
||||||
<select name="theme">
|
const toggle = document.querySelector('[data-global-display-tz-toggle]');
|
||||||
<?php foreach ($themes as $key => $label): ?>
|
const panel = document.querySelector('[data-global-display-tz-panel]');
|
||||||
<option value="<?= e($key) ?>" <?= $current === $key ? 'selected' : '' ?>>
|
if (!toggle || !panel) return;
|
||||||
<?= e($label) ?>
|
const sync = () => {
|
||||||
</option>
|
panel.hidden = !toggle.checked;
|
||||||
<?php endforeach; ?>
|
};
|
||||||
</select>
|
toggle.addEventListener('change', sync);
|
||||||
</label>
|
sync();
|
||||||
<button class="cta-button" type="submit">Speichern</button>
|
})();
|
||||||
</form>
|
</script>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -306,6 +306,9 @@ final class ModuleCronScheduler
|
|||||||
$job = $jobExists ? $jobs[$definition['name']] : [];
|
$job = $jobExists ? $jobs[$definition['name']] : [];
|
||||||
$timezoneSetting = trim((string) ($definition['timezone_setting'] ?? ''));
|
$timezoneSetting = trim((string) ($definition['timezone_setting'] ?? ''));
|
||||||
$fallbackTimezone = $timezoneSetting !== '' ? trim((string) ($settings[$timezoneSetting] ?? '')) : '';
|
$fallbackTimezone = $timezoneSetting !== '' ? trim((string) ($settings[$timezoneSetting] ?? '')) : '';
|
||||||
|
if ($fallbackTimezone === '' && function_exists('nexus_cron_timezone_name')) {
|
||||||
|
$fallbackTimezone = trim((string) nexus_cron_timezone_name());
|
||||||
|
}
|
||||||
$defaultEntry = [
|
$defaultEntry = [
|
||||||
'enabled' => (bool) $definition['default_enabled'],
|
'enabled' => (bool) $definition['default_enabled'],
|
||||||
'cron_expression' => trim((string) ($definition['default_cron'] ?? '0 * * * *')),
|
'cron_expression' => trim((string) ($definition['default_cron'] ?? '0 * * * *')),
|
||||||
@@ -336,7 +339,7 @@ final class ModuleCronScheduler
|
|||||||
$result[] = [
|
$result[] = [
|
||||||
'enabled' => array_key_exists('enabled', $entry) ? $this->settingBool($entry['enabled'], (bool) $defaultEntry['enabled']) : (bool) $defaultEntry['enabled'],
|
'enabled' => array_key_exists('enabled', $entry) ? $this->settingBool($entry['enabled'], (bool) $defaultEntry['enabled']) : (bool) $defaultEntry['enabled'],
|
||||||
'cron_expression' => trim((string) ($entry['cron_expression'] ?? $defaultEntry['cron_expression'])),
|
'cron_expression' => trim((string) ($entry['cron_expression'] ?? $defaultEntry['cron_expression'])),
|
||||||
'timezone' => trim((string) ($entry['timezone'] ?? $defaultEntry['timezone'])),
|
'timezone' => (($entryTimezone = trim((string) ($entry['timezone'] ?? ''))) !== '' ? $entryTimezone : $defaultEntry['timezone']),
|
||||||
'builder' => is_array($entry['builder'] ?? null) ? $entry['builder'] : [],
|
'builder' => is_array($entry['builder'] ?? null) ? $entry['builder'] : [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,6 +336,66 @@ function nexus_debug_clear(?string $source = null): void
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nexus_settings(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return modules()->settings('_nexus');
|
||||||
|
} catch (\Throwable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nexus_save_settings(array $settings): void
|
||||||
|
{
|
||||||
|
modules()->saveSettings('_nexus', $settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nexus_system_timezone_name(): string
|
||||||
|
{
|
||||||
|
$timezone = trim((string) date_default_timezone_get());
|
||||||
|
if ($timezone === '') {
|
||||||
|
return 'UTC';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new \DateTimeZone($timezone);
|
||||||
|
return $timezone;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
return 'UTC';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nexus_display_timezone_name(): string
|
||||||
|
{
|
||||||
|
$settings = nexus_settings();
|
||||||
|
$useCustom = !empty($settings['display_timezone_custom']);
|
||||||
|
$timezone = trim((string) ($settings['display_timezone'] ?? ''));
|
||||||
|
if ($useCustom && $timezone !== '') {
|
||||||
|
try {
|
||||||
|
new \DateTimeZone($timezone);
|
||||||
|
return $timezone;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nexus_system_timezone_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
function nexus_cron_timezone_name(): string
|
||||||
|
{
|
||||||
|
$settings = nexus_settings();
|
||||||
|
$timezone = trim((string) ($settings['cron_timezone'] ?? ''));
|
||||||
|
if ($timezone !== '') {
|
||||||
|
try {
|
||||||
|
new \DateTimeZone($timezone);
|
||||||
|
return $timezone;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nexus_display_timezone_name();
|
||||||
|
}
|
||||||
|
|
||||||
function module_debug_enabled(string $module): bool
|
function module_debug_enabled(string $module): bool
|
||||||
{
|
{
|
||||||
if (preg_match('/[^a-zA-Z0-9_\-]/', $module)) {
|
if (preg_match('/[^a-zA-Z0-9_\-]/', $module)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user