parent
a8e7aedadf
commit
529979f078
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class AuthenticatedMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (!Auth::check()) {
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return response()->json(['message' => 'Unauthenticated'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class GuestOnlyMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::check()) {
|
||||||
|
// Eingeloggt → z. B. Dashboard weiterleiten
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -44,6 +44,7 @@ class HealthCard extends Component
|
||||||
public ?int $ramPercent = null;
|
public ?int $ramPercent = null;
|
||||||
public ?string $updatedAtHuman = null;
|
public ?string $updatedAtHuman = null;
|
||||||
|
|
||||||
|
public $guardOk = [];
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->loadData();
|
$this->loadData();
|
||||||
|
|
@ -179,19 +180,52 @@ class HealthCard extends Component
|
||||||
'127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket'],
|
'127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket'],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->servicesCompact = collect($this->services)
|
// $nameMap = [
|
||||||
->map(function ($srv) use ($nameMap) {
|
// // --- Mail ---
|
||||||
$key = (string)($srv['name'] ?? '');
|
// 'postfix' => ['label' => 'Postfix', 'hint' => 'MTA / Versand'],
|
||||||
$ok = (bool) ($srv['ok'] ?? false);
|
// 'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP / POP3'],
|
||||||
$label = $nameMap[$key]['label'] ?? ucfirst($key);
|
// 'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'],
|
||||||
$hint = $nameMap[$key]['hint'] ?? (str_contains($key, ':') ? $key : '');
|
// 'clamav' => ['label' => 'ClamAV', 'hint' => 'Virenscanner'],
|
||||||
|
//
|
||||||
|
// // --- Daten & Cache ---
|
||||||
|
// 'db' => ['label' => 'Datenbank', 'hint' => 'MySQL / MariaDB'],
|
||||||
|
// '127.0.0.1:6379' => ['label' => 'Redis', 'hint' => 'Cache / Queue'],
|
||||||
|
//
|
||||||
|
// // --- Web / PHP ---
|
||||||
|
// 'php8.2-fpm' => ['label' => 'PHP-FPM', 'hint' => 'PHP Runtime'],
|
||||||
|
// 'nginx' => ['label' => 'Nginx', 'hint' => 'Webserver'],
|
||||||
|
//
|
||||||
|
// // --- MailWolt spezifisch ---
|
||||||
|
// 'mailwolt-queue' => ['label' => 'MailWolt Queue', 'hint' => 'Job Worker'],
|
||||||
|
// 'mailwolt-schedule'=> ['label' => 'MailWolt Schedule','hint' => 'Task Scheduler'],
|
||||||
|
//
|
||||||
|
// // --- Sonstige Infrastruktur ---
|
||||||
|
// 'fail2ban' => ['label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection'],
|
||||||
|
// 'systemd-journald'=> ['label' => 'System Logs', 'hint' => 'Logging / Journal'],
|
||||||
|
//
|
||||||
|
// // --- WebSocket & Echtzeit ---
|
||||||
|
// '127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket Server'],
|
||||||
|
// ];
|
||||||
|
|
||||||
|
$existing = collect($this->services)->keyBy('name');
|
||||||
|
|
||||||
|
$this->servicesCompact = collect($nameMap)
|
||||||
|
->map(function ($meta, $key) use ($existing) {
|
||||||
|
$srv = $existing->get($key, []);
|
||||||
|
$ok = (bool)($srv['ok'] ?? false);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'label' => $label,
|
'label' => $meta['label'],
|
||||||
'hint' => $hint,
|
'hint' => $meta['hint'],
|
||||||
'ok' => $ok,
|
'ok' => $ok,
|
||||||
|
|
||||||
|
// Punktfarbe
|
||||||
'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||||||
'pillText' => $ok ? 'ok' : 'down',
|
|
||||||
|
// ✅ Bessere Status-Texte
|
||||||
|
'pillText' => $ok ? 'Aktiv' : 'Offline',
|
||||||
|
|
||||||
|
// Farbe für Pill
|
||||||
'pillClass' => $ok
|
'pillClass' => $ok
|
||||||
? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||||||
: 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
: 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||||||
|
|
@ -199,6 +233,31 @@ class HealthCard extends Component
|
||||||
})
|
})
|
||||||
->values()
|
->values()
|
||||||
->all();
|
->all();
|
||||||
|
|
||||||
|
$this->guardOk = collect($this->services)->every(
|
||||||
|
fn($s) => (bool)($s['ok'] ?? false)
|
||||||
|
);
|
||||||
|
// $this->servicesCompact = collect($this->services)
|
||||||
|
// ->map(function ($srv) use ($nameMap) {
|
||||||
|
// $key = (string)($srv['name'] ?? '');
|
||||||
|
// $ok = (bool) ($srv['ok'] ?? false);
|
||||||
|
// $label = $nameMap[$key]['label'] ?? ucfirst($key);
|
||||||
|
// $hint = $nameMap[$key]['hint'] ?? (str_contains($key, ':') ? $key : '');
|
||||||
|
//
|
||||||
|
// var_dump($srv);
|
||||||
|
// return [
|
||||||
|
// 'label' => $label,
|
||||||
|
// 'hint' => $hint,
|
||||||
|
// 'ok' => $ok,
|
||||||
|
// 'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||||||
|
// 'pillText' => $ok ? 'Läuft' : 'Down',
|
||||||
|
// 'pillClass' => $ok
|
||||||
|
// ? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||||||
|
// : 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||||||
|
// ];
|
||||||
|
// })
|
||||||
|
// ->values()
|
||||||
|
// ->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function decorateDisk(): void
|
protected function decorateDisk(): void
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class TopBar extends Component
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
// Domains + Zertifikate (passe an deinen Storage an)
|
// Domains + Zertifikate (passe an deinen Storage an)
|
||||||
$this->domainsCount = Domain::count(); // oder aus Cache/Repo
|
$this->domainsCount = Domain::where('is_server', false)->where('is_system', false)->count(); // oder aus Cache/Repo
|
||||||
|
|
||||||
// Beispiel: Domain::select('cert_expires_at','cert_issuer')...
|
// Beispiel: Domain::select('cert_expires_at','cert_issuer')...
|
||||||
// -> hier simple Annahme: im Cache 'domains:certs' liegt [{domain, days_left, type}]
|
// -> hier simple Annahme: im Cache 'domains:certs' liegt [{domain, days_left, type}]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,324 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Livewire\Ui\System;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class UpdateCard extends Component
|
||||||
|
{
|
||||||
|
public ?string $current = null; // installierte Version
|
||||||
|
public ?string $latest = null; // verfügbare Version (oder null)
|
||||||
|
public string $state = 'idle'; // idle | running
|
||||||
|
|
||||||
|
// UI-Textausgabe nach einer Prüfung / Aktion
|
||||||
|
public ?string $message = null; // z.B. "Du bist auf dem neuesten Stand (v1.0.16)"
|
||||||
|
public ?bool $messagePositive = null; // true = grün, false = neutral/weiß
|
||||||
|
|
||||||
|
// low-level (falls du sie später brauchst)
|
||||||
|
public bool $running = false; // aus /var/lib/mailwolt/update/state
|
||||||
|
public ?int $rc = null;
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->current = $this->readCurrentVersion();
|
||||||
|
$this->latest = Cache::get('mailwolt.update_available');
|
||||||
|
$this->refreshLowLevelState();
|
||||||
|
|
||||||
|
// Starttext, falls nichts geprüft wurde
|
||||||
|
if ($this->message === null) {
|
||||||
|
$this->message = $this->latest && $this->hasUpdate()
|
||||||
|
? "Neue Version verfügbar: {$this->latest}"
|
||||||
|
: ($this->current ? "Du bist auf dem neuesten Stand ({$this->current})" : "Status unbekannt");
|
||||||
|
$this->messagePositive = !$this->hasUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.ui.system.update-card');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* „Erneut prüfen“ – ohne Toast:
|
||||||
|
* - Progress anzeigen
|
||||||
|
* - Check-Command laufen lassen
|
||||||
|
* - Message in der Box aktualisieren
|
||||||
|
*/
|
||||||
|
public function refreshState(): void
|
||||||
|
{
|
||||||
|
$this->state = 'running';
|
||||||
|
$this->message = 'Prüfe auf Updates …';
|
||||||
|
$this->messagePositive = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Passe den Namen hier an dein tatsächliches Command an:
|
||||||
|
Artisan::call('mailwolt:check-updates');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// weich fallen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Daten neu einlesen
|
||||||
|
$this->current = $this->readCurrentVersion();
|
||||||
|
$this->latest = Cache::get('mailwolt.update_available');
|
||||||
|
|
||||||
|
if ($this->hasUpdate()) {
|
||||||
|
$this->message = "Neue Version verfügbar: {$this->latest}";
|
||||||
|
$this->messagePositive = false; // neutral
|
||||||
|
} else {
|
||||||
|
$cur = $this->current ?: '–';
|
||||||
|
$this->message = "Du bist auf dem neuesten Stand ({$cur})";
|
||||||
|
$this->messagePositive = true; // grün
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->refreshLowLevelState();
|
||||||
|
$this->state = 'idle';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* „Jetzt aktualisieren“ – ohne Toast:
|
||||||
|
* - Hinweis sofort aus Cache entfernen (Badge weg)
|
||||||
|
* - Update-Wrapper starten
|
||||||
|
* - Running + Text in der Box anzeigen
|
||||||
|
*/
|
||||||
|
public function runUpdate(): void
|
||||||
|
{
|
||||||
|
Cache::forget('mailwolt.update_available');
|
||||||
|
|
||||||
|
@shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
|
||||||
|
|
||||||
|
$this->latest = null;
|
||||||
|
$this->state = 'running';
|
||||||
|
$this->running = true;
|
||||||
|
$this->message = 'Update läuft …';
|
||||||
|
$this->messagePositive = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** --------------------- helpers --------------------- */
|
||||||
|
|
||||||
|
protected function hasUpdate(): bool
|
||||||
|
{
|
||||||
|
if (!$this->latest) return false;
|
||||||
|
$cur = $this->current ?: '0.0.0';
|
||||||
|
return version_compare($this->latest, $cur, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function refreshLowLevelState(): void
|
||||||
|
{
|
||||||
|
$state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
|
||||||
|
$this->running = ($state === 'running');
|
||||||
|
|
||||||
|
$rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
|
||||||
|
$this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function readCurrentVersion(): ?string
|
||||||
|
{
|
||||||
|
// bevorzugt /etc/mailwolt/build.info (wird im Installer/Updater gepflegt)
|
||||||
|
$build = @file_get_contents('/etc/mailwolt/build.info');
|
||||||
|
if ($build) {
|
||||||
|
foreach (preg_split('/\R+/', $build) as $line) {
|
||||||
|
if (str_starts_with($line, 'version=')) {
|
||||||
|
$v = trim(substr($line, 8));
|
||||||
|
if ($v !== '') return $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$v = config('app.version');
|
||||||
|
return $v !== '' ? $v : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//namespace App\Livewire\Ui\System;
|
||||||
|
//
|
||||||
|
//use Livewire\Component;
|
||||||
|
//use Illuminate\Support\Facades\Artisan;
|
||||||
|
//use Illuminate\Support\Facades\Cache;
|
||||||
|
//
|
||||||
|
//class UpdateCard extends Component
|
||||||
|
//{
|
||||||
|
// public ?string $current = null; // z.B. v1.0.16 (aktuell installiert)
|
||||||
|
// public ?string $latest = null; // z.B. v1.0.17 (verfügbar) oder null
|
||||||
|
// public string $state = 'idle'; // idle | running
|
||||||
|
//
|
||||||
|
// // optional: Low-level-Infos, falls du sie irgendwo anders brauchst
|
||||||
|
// public bool $running = false; // Wrapper-/Updater läuft gerade (aus State-Datei)
|
||||||
|
// public string $log = '';
|
||||||
|
// public ?int $rc = null;
|
||||||
|
//
|
||||||
|
// public function mount(): void
|
||||||
|
// {
|
||||||
|
// $this->current = $this->readCurrentVersion();
|
||||||
|
// $this->latest = Cache::get('mailwolt.update_available');
|
||||||
|
// $this->refreshLowLevelState(); // liest /var/lib/mailwolt/update/*
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function render()
|
||||||
|
// {
|
||||||
|
// return view('livewire.ui.system.update-card');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * „Erneut prüfen“:
|
||||||
|
// * - zeigt Running-Progress
|
||||||
|
// * - ruft den Checker (dein bestehendes Artisan-Command)
|
||||||
|
// * - aktualisiert $latest / $current
|
||||||
|
// * - dispatcht passenden Toast
|
||||||
|
// */
|
||||||
|
// public function refreshState(): void
|
||||||
|
// {
|
||||||
|
// $this->state = 'running';
|
||||||
|
//
|
||||||
|
// // Falls vorhanden: dein Command, der cache('mailwolt.update_available') setzt
|
||||||
|
// // -> Namen ggf. anpassen (du hattest z.B. mailwolt:check-updates erwähnt)
|
||||||
|
// try {
|
||||||
|
// Artisan::call('mailwolt:check-updates');
|
||||||
|
// } catch (\Throwable $e) {
|
||||||
|
// // Wenn das Command (noch) nicht existiert, nicht crashen – state einfach zurücksetzen
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // App-Status neu einlesen
|
||||||
|
// $this->current = $this->readCurrentVersion();
|
||||||
|
// $this->latest = Cache::get('mailwolt.update_available');
|
||||||
|
//
|
||||||
|
// $hasUpdate = $this->hasUpdate();
|
||||||
|
//
|
||||||
|
// // Toast ausspielen
|
||||||
|
// $this->dispatch('toast',
|
||||||
|
// type: $hasUpdate ? 'info' : 'done',
|
||||||
|
// badge: 'Update',
|
||||||
|
// title: $hasUpdate ? 'Neue Version verfügbar' : 'Alles aktuell',
|
||||||
|
// text: $hasUpdate
|
||||||
|
// ? "Verfügbar: {$this->latest} – installiert: {$this->current}"
|
||||||
|
// : "Du bist auf dem neuesten Stand ({$this->current}).",
|
||||||
|
// duration: 6000
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // Low-level-State (optional) und UI-State zurücksetzen
|
||||||
|
// $this->refreshLowLevelState();
|
||||||
|
// $this->state = 'idle';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * „Jetzt aktualisieren“:
|
||||||
|
// * - blendet die verfügbare-Version sofort aus
|
||||||
|
// * - startet den Root-Wrapper im Hintergrund
|
||||||
|
// * - zeigt einen Toast „Update gestartet“
|
||||||
|
// */
|
||||||
|
// public function runUpdate(): void
|
||||||
|
// {
|
||||||
|
// Cache::forget('mailwolt.update_available'); // Badge sofort weg
|
||||||
|
// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
|
||||||
|
//
|
||||||
|
// $this->state = 'running';
|
||||||
|
// $this->running = true;
|
||||||
|
//
|
||||||
|
// $this->dispatch('toast',
|
||||||
|
// type: 'info',
|
||||||
|
// badge: 'Update',
|
||||||
|
// title: 'Update gestartet',
|
||||||
|
// text: 'Das System wird aktualisiert …',
|
||||||
|
// duration: 6000
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** ---- Helpers ------------------------------------------------------- */
|
||||||
|
//
|
||||||
|
// protected function hasUpdate(): bool
|
||||||
|
// {
|
||||||
|
// if (!$this->latest) return false;
|
||||||
|
// $cur = $this->current ?: '0.0.0';
|
||||||
|
// return version_compare($this->latest, $cur, '>');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected function refreshLowLevelState(): void
|
||||||
|
// {
|
||||||
|
// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
|
||||||
|
// $this->running = ($state === 'running');
|
||||||
|
//
|
||||||
|
// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
|
||||||
|
// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
|
||||||
|
//
|
||||||
|
// // Log bewusst NICHT angezeigt, aber verfügbar, falls du es später brauchst
|
||||||
|
// $this->log = @shell_exec('tail -n 200 /var/log/mailwolt-update.log 2>/dev/null') ?? '';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected function readCurrentVersion(): ?string
|
||||||
|
// {
|
||||||
|
// // bevorzugt build.info, sonst config('app.version')
|
||||||
|
// $build = @file_get_contents('/etc/mailwolt/build.info');
|
||||||
|
// if ($build) {
|
||||||
|
// foreach (preg_split('/\R+/', $build) as $line) {
|
||||||
|
// if (str_starts_with($line, 'version=')) {
|
||||||
|
// $v = trim(substr($line, 8));
|
||||||
|
// if ($v !== '') return $v;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// $v = config('app.version');
|
||||||
|
// return $v !== '' ? $v : null;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
////
|
||||||
|
////namespace App\Livewire\Ui\System;
|
||||||
|
////
|
||||||
|
////use Livewire\Component;
|
||||||
|
////use Illuminate\Support\Facades\Artisan;
|
||||||
|
////use Illuminate\Support\Facades\Cache;
|
||||||
|
////
|
||||||
|
////class UpdateCard extends Component
|
||||||
|
////{
|
||||||
|
//// public ?string $current = null;
|
||||||
|
//// public ?string $latest = null;
|
||||||
|
//// public string $state = 'idle'; // idle|running
|
||||||
|
////
|
||||||
|
//// public bool $running = false;
|
||||||
|
//// public string $log = '';
|
||||||
|
//// public ?int $rc = null;
|
||||||
|
////
|
||||||
|
//// public function mount(): void
|
||||||
|
//// {
|
||||||
|
////// $this->refreshState();
|
||||||
|
//// $this->latest = cache('mailwolt.update_available');
|
||||||
|
////
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// public function render()
|
||||||
|
//// {
|
||||||
|
//// return view('livewire.ui.system.update-card');
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// public function refreshState(): void
|
||||||
|
//// {
|
||||||
|
//// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
|
||||||
|
//// $this->running = ($state === 'running');
|
||||||
|
////
|
||||||
|
//// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
|
||||||
|
//// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
|
||||||
|
////
|
||||||
|
//// // letzte 200 Zeilen Log
|
||||||
|
//// $this->log = @shell_exec('tail -n 200 /var/log/mailwolt-update.log 2>/dev/null') ?? '';
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// public function runUpdate(): void
|
||||||
|
//// {
|
||||||
|
//// // Hinweis „Update verfügbar“ ausblenden
|
||||||
|
//// cache()->forget('mailwolt.update_available');
|
||||||
|
////
|
||||||
|
//// // Update im Hintergrund starten
|
||||||
|
//// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
|
||||||
|
////
|
||||||
|
//// $this->running = true;
|
||||||
|
//// $this->dispatch('toast',
|
||||||
|
//// type: 'info',
|
||||||
|
//// badge: 'Update',
|
||||||
|
//// title: 'Update gestartet',
|
||||||
|
//// text: 'Das System wird aktualisiert …',
|
||||||
|
//// duration: 6000
|
||||||
|
//// );
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
|
@ -23,13 +23,8 @@ class AppServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function boot(\App\Support\SettingsRepository $settings): void
|
public function boot(\App\Support\SettingsRepository $settings): void
|
||||||
{
|
{
|
||||||
|
|
||||||
Domain::observe(DomainObserver::class);
|
Domain::observe(DomainObserver::class);
|
||||||
|
|
||||||
// $ver = trim(@file_get_contents(base_path('VERSION'))) ?: 'dev';
|
|
||||||
// config(['app.version' => $ver]);
|
|
||||||
|
|
||||||
|
|
||||||
config(['app.version' => trim(@file_get_contents('/var/lib/mailwolt/version')) ?: 'dev']);
|
config(['app.version' => trim(@file_get_contents('/var/lib/mailwolt/version')) ?: 'dev']);
|
||||||
if (file_exists(base_path('.git/HEAD'))) {
|
if (file_exists(base_path('.git/HEAD'))) {
|
||||||
$ref = trim(file_get_contents(base_path('.git/HEAD')));
|
$ref = trim(file_get_contents(base_path('.git/HEAD')));
|
||||||
|
|
@ -39,6 +34,7 @@ class AppServiceProvider extends ServiceProvider
|
||||||
} else {
|
} else {
|
||||||
$commit = $ref;
|
$commit = $ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
config(['app.git_commit' => substr($commit ?? '', 0, 7)]);
|
config(['app.git_commit' => substr($commit ?? '', 0, 7)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Support\BuildMeta;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class BuildMetaServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->singleton(BuildMeta::class, fn () => BuildMeta::detect());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
$meta = $this->app->make(BuildMeta::class);
|
||||||
|
|
||||||
|
// zentral verfügbar
|
||||||
|
config([
|
||||||
|
'app.version' => $meta->version,
|
||||||
|
'app.git_rev' => $meta->rev,
|
||||||
|
'app.git_short' => $meta->short,
|
||||||
|
'app.build_time' => $meta->updated,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// optional: in allen Views als $build
|
||||||
|
View::share('build', $meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
final class BuildMeta
|
||||||
|
{
|
||||||
|
public string $version = 'dev';
|
||||||
|
public string $rev = '';
|
||||||
|
public string $short = '';
|
||||||
|
public ?string $updated = null;
|
||||||
|
|
||||||
|
public static function detect(
|
||||||
|
string $buildFile = '/etc/mailwolt/build.info',
|
||||||
|
string $basePath = null
|
||||||
|
): self {
|
||||||
|
$m = new self();
|
||||||
|
$basePath ??= base_path();
|
||||||
|
|
||||||
|
// 1) /etc/mailwolt/build.info (vom Updater)
|
||||||
|
if (is_file($buildFile) && is_readable($buildFile)) {
|
||||||
|
$lines = @file($buildFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
if (!str_contains($line, '=')) continue;
|
||||||
|
[$k, $v] = explode('=', $line, 2);
|
||||||
|
$k = trim($k); $v = trim($v);
|
||||||
|
if ($k === 'version') $m->version = $v;
|
||||||
|
if ($k === 'rev') $m->rev = $v;
|
||||||
|
if ($k === 'updated') $m->updated = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Fallback: .env APP_VERSION
|
||||||
|
if ($m->version === 'dev' && ($envVer = env('APP_VERSION'))) {
|
||||||
|
$m->version = trim($envVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Fallback: Git (ohne "-dirty")
|
||||||
|
if ($m->rev === '' || $m->version === 'dev') {
|
||||||
|
$head = $basePath.'/.git/HEAD';
|
||||||
|
if (is_file($head)) {
|
||||||
|
$ref = trim((string)@file_get_contents($head));
|
||||||
|
if (Str::startsWith($ref, 'ref:')) {
|
||||||
|
$refFile = $basePath.'/.git/'.substr($ref, 5);
|
||||||
|
$commit = @file_get_contents($refFile);
|
||||||
|
} else {
|
||||||
|
$commit = $ref;
|
||||||
|
}
|
||||||
|
$m->rev = $m->rev ?: trim((string)$commit);
|
||||||
|
|
||||||
|
if ($m->version === 'dev') {
|
||||||
|
$tag = @shell_exec('git -C '.escapeshellarg($basePath).' describe --tags --abbrev=0 2>/dev/null');
|
||||||
|
$m->version = $tag ? trim($tag) : 'dev';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sauber: "-dirty" entfernen
|
||||||
|
$m->version = preg_replace('/-dirty$/', '', $m->version);
|
||||||
|
|
||||||
|
// Kurz-Commit
|
||||||
|
$m->short = $m->rev ? substr($m->rev, 0, 7) : '';
|
||||||
|
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'version' => $this->version,
|
||||||
|
'rev' => $this->rev,
|
||||||
|
'short' => $this->short,
|
||||||
|
'updated' => $this->updated,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,8 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||||
$middleware->alias([
|
$middleware->alias([
|
||||||
'ensure.setup' => \App\Http\Middleware\EnsureSetupCompleted::class,
|
'ensure.setup' => \App\Http\Middleware\EnsureSetupCompleted::class,
|
||||||
'signup.open' => \App\Http\Middleware\SignupOpen::class,
|
'signup.open' => \App\Http\Middleware\SignupOpen::class,
|
||||||
|
'auth.user' => \App\Http\Middleware\AuthenticatedMiddleware::class,
|
||||||
|
'guest.only' => \App\Http\Middleware\GuestOnlyMiddleware::class,
|
||||||
|
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
|
|
||||||
return [
|
return [
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\BuildMetaServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'name' => env('APP_NAME', 'Laravel'),
|
'name' => env('APP_NAME', 'MailWolt'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -123,6 +123,8 @@ return [
|
||||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
],
|
],
|
||||||
|
|
||||||
'version' => env('APP_VERSION', '1.0.0'),
|
'version' => env('APP_VERSION', 'dev'),
|
||||||
'git_commit' => env('APP_GIT_COMMIT', ''),
|
'git_rev' => null,
|
||||||
|
'git_short' => null,
|
||||||
|
'build_time' => null,
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -18,25 +18,25 @@ return [
|
||||||
[
|
[
|
||||||
'title' => 'Security',
|
'title' => 'Security',
|
||||||
'icon' => 'icons.icon-security',
|
'icon' => 'icons.icon-security',
|
||||||
'route' => 'logout',
|
'route' => 'ui.logout',
|
||||||
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Team',
|
'title' => 'Team',
|
||||||
'icon' => 'icons.icon-team',
|
'icon' => 'icons.icon-team',
|
||||||
'route' => 'logout',
|
'route' => 'ui.logout',
|
||||||
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Settings',
|
'title' => 'Settings',
|
||||||
'icon' => 'icons.icon-settings',
|
'icon' => 'icons.icon-settings',
|
||||||
'route' => 'logout',
|
'route' => 'ui.logout',
|
||||||
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Logout',
|
'title' => 'Logout',
|
||||||
'icon' => 'icons.icon-logout',
|
'icon' => 'icons.icon-logout',
|
||||||
'route' => 'logout',
|
'route' => 'ui.logout',
|
||||||
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
'roles' => ['super_admin', 'admin', 'employee', 'user'],
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,14 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-slow {
|
||||||
|
0%, 100% { opacity: 0.4; }
|
||||||
|
50% { opacity: 0.8; }
|
||||||
|
}
|
||||||
|
.animate-pulse-slow {
|
||||||
|
animation: pulse-slow 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.safe-pads {
|
.safe-pads {
|
||||||
padding-top: env(safe-area-inset-top);
|
padding-top: env(safe-area-inset-top);
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,13 @@
|
||||||
{{--resources/views/components/partials/header.blade.php--}}
|
{{--resources/views/components/partials/header.blade.php--}}
|
||||||
<div
|
<div
|
||||||
class="#sticky top-0 w-full border-b hr rounded-lg">
|
class="#sticky top-0 w-full border-b hr #rounded-lg max-w-9xl mx-auto">
|
||||||
|
|
||||||
<header id="header" class="header w-full rounded-r-2xl rounded-l-none">
|
<header id="header" class="header w-full rounded-r-2xl rounded-l-none">
|
||||||
<nav class="flex h-[71px] #h-[74px] items-center justify-between #p-3">
|
<nav class="flex h-[71px] #h-[74px] items-center justify-between #p-3">
|
||||||
<div class="#flex-1 md:w-3/5 w-full">
|
<div class="#flex-1 md:w-3/5 w-full">
|
||||||
<div class="relative flex items-center gap-5">
|
<div class="relative flex items-center gap-5">
|
||||||
<button class="sidebar-toggle translate-0 right-5 block sm:hidden text-white/60 hover:text-white text-2xl">
|
<button class="sidebar-toggle translate-0 right-5 block s#m:hidden text-white/60 hover:text-white text-2xl">
|
||||||
<i class="ph ph-list"></i>
|
<i class="ph ph-list"></i>
|
||||||
</button>
|
</button>
|
||||||
{{-- @if ($latest = cache('mailwolt.update_available'))--}}
|
|
||||||
{{-- <div class="bg-blue-900/40 text-blue-100 p-4 rounded-xl border border-blue-800">--}}
|
|
||||||
{{-- <div class="flex justify-between items-center">--}}
|
|
||||||
{{-- <div>--}}
|
|
||||||
{{-- <strong>Neue Version verfügbar:</strong> {{ $latest }}--}}
|
|
||||||
{{-- </div>--}}
|
|
||||||
{{-- <button wire:click="runUpdate"--}}
|
|
||||||
{{-- class="bg-blue-600 hover:bg-blue-500 text-white px-3 py-1 rounded">--}}
|
|
||||||
{{-- Jetzt aktualisieren--}}
|
|
||||||
{{-- </button>--}}
|
|
||||||
{{-- </div>--}}
|
|
||||||
{{-- </div>--}}
|
|
||||||
{{-- @endif--}}
|
|
||||||
{{-- <button id="sidebar-toggle-btn"--}}
|
|
||||||
{{-- class="action-button sidebar-toggle flex items-center justify-center p-1.5 shadow-2xl rounded">--}}
|
|
||||||
{{-- <svg class="size-5 group-[.expanded]/side:rotate-180"--}}
|
|
||||||
{{-- fill="none" stroke="currentColor" stroke-width="1.5"--}}
|
|
||||||
{{-- viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">--}}
|
|
||||||
{{-- <path stroke-linecap="round" stroke-linejoin="round"--}}
|
|
||||||
{{-- d="M9 5l7 7-7 7"></path>--}}
|
|
||||||
{{-- </svg>--}}
|
|
||||||
{{-- </button>--}}
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<h1 class="font-bold text-2xl">@yield('header_title')</h1>
|
<h1 class="font-bold text-2xl">@yield('header_title')</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -83,20 +83,19 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{-- Footer Toggle (Desktop/Tablet) --}}
|
{{-- Footer Toggle (Desktop/Tablet) --}}
|
||||||
<div class="p-3 border-t hr flex justify-between items-center">
|
<div class="p-5 border-t hr flex justify-center items-center">
|
||||||
{{-- Version (z.B. aus config/app.php 'version' oder env) --}}
|
<div class="sidebar-label text-[10px] text-slate-300/70 whitespace-nowrap">
|
||||||
<div class="sidebar-label text-[10px] text-slate-300/70">
|
<span class="text-xs text-white/40">{{ config('app.name') }} | v{{ config('app.version') }}</span>
|
||||||
<span class="text-xs text-white/40">v{{ config('app.version') }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button"
|
{{-- <button type="button"--}}
|
||||||
class="action-button sidebar-toggle flex items-center justify-center p-2 shadow-2xl rounded"
|
{{-- class="action-button sidebar-toggle flex items-center justify-center p-2 shadow-2xl rounded"--}}
|
||||||
aria-label="Sidebar ein/ausklappen">
|
{{-- aria-label="Sidebar ein/ausklappen">--}}
|
||||||
<svg class="size-6" fill="none" stroke="currentColor" stroke-width="1.5"
|
{{-- <svg class="size-6" fill="none" stroke="currentColor" stroke-width="1.5"--}}
|
||||||
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
{{-- viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">--}}
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"></path>
|
{{-- <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"></path>--}}
|
||||||
</svg>
|
{{-- </svg>--}}
|
||||||
</button>
|
{{-- </button>--}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@
|
||||||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
<i class="ph ph-cpu text-white/70 text-[13px]"></i>
|
<i class="ph ph-cpu text-white/70 text-[13px]"></i>
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">CPU</span>
|
<span class="text-[11px] tracking-wide uppercase text-white/70">CPU</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -31,7 +32,8 @@
|
||||||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
<i class="ph ph-memory text-white/70 text-[13px]"></i>
|
<i class="ph ph-memory text-white/70 text-[13px]"></i>
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">RAM</span>
|
<span class="text-[11px] tracking-wide uppercase text-white/70">RAM</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -54,7 +56,8 @@
|
||||||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
<i class="ph ph-activity text-white/70 text-[13px]"></i>
|
<i class="ph ph-activity text-white/70 text-[13px]"></i>
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">Load</span>
|
<span class="text-[11px] tracking-wide uppercase text-white/70">Load</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -78,7 +81,8 @@
|
||||||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
<i class="{{ $uptimeIcon }} text-white/70 text-[13px]"></i>
|
<i class="{{ $uptimeIcon }} text-white/70 text-[13px]"></i>
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">Uptime</span>
|
<span class="text-[11px] tracking-wide uppercase text-white/70">Uptime</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -96,68 +100,90 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Dienste & Storage: kompakt & bündig --}}
|
<div class="grid grid-cols-2 #items-center justify-between gap-3">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
{{-- MailGuard Status Card --}}
|
||||||
{{-- Dienste kompakt --}}
|
<div
|
||||||
<div class="glass-card p-4">
|
class="glass-card p-4 flex flex-row items-start justify-between gap-4 relative overflow-hidden mb-4">
|
||||||
<div class="flex items-center justify-between mb-3">
|
{{-- Linke Seite: Icon + Titel --}}
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
<div class="flex #items-start gap-3 relative z-10">
|
||||||
<i class="ph ph-gear-six text-white/70 text-[13px]"></i>
|
<div class="shrink-0">
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">Dienste</span>
|
{{-- Modernes Shield-Icon --}}
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="shieldGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#4ade80"/>
|
||||||
|
<stop offset="1" stop-color="#15803d"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="shine" cx="30%" cy="20%" r="70%">
|
||||||
|
<stop offset="0%" stop-color="rgba(255,255,255,0.4)"/>
|
||||||
|
<stop offset="100%" stop-color="rgba(255,255,255,0)"/>
|
||||||
|
</radialGradient>
|
||||||
|
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feDropShadow dx="0" dy="0" stdDeviation="3" flood-color="#22c55e"
|
||||||
|
flood-opacity="0.6"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z"
|
||||||
|
fill="url(#shieldGradient)" filter="url(#glow)"/>
|
||||||
|
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z"
|
||||||
|
fill="url(#shine)"/>
|
||||||
|
<path d="M23 33l7 7 11-14" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-white/90">WoltGuard</h3>
|
||||||
|
<p class="text-sm text-white/50">System-Wächter aktiv und fehlerfrei</p>
|
||||||
</div>
|
</div>
|
||||||
<span class="inline-flex items-center gap-1 rounded-full bg-white/5 border border-white/10 px-2 py-0.5 text-[10px] text-white/60">
|
|
||||||
systemctl / TCP
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<ul class="overflow-auto divide-y divide-white/5">
|
|
||||||
@forelse($servicesCompact as $s)
|
{{-- Rechte Seite: Status & Avatar --}}
|
||||||
<li class="grid grid-cols-[auto,1fr,auto] items-center gap-3 py-2">
|
<div class="flex items-start gap-3 relative z-10">
|
||||||
<div class="flex items-center justify-between">
|
{{-- Status Badge --}}
|
||||||
<div>
|
@if($guardOk ?? false)
|
||||||
<div class="flex items-center gap-2">
|
<span
|
||||||
<span class="h-2 w-2 rounded-full {{ $s['dotClass'] }}"></span>
|
class="inline-flex #items-center gap-1 px-3 py-1 rounded-full text-sm border border-emerald-400/30 text-emerald-300 bg-emerald-500/10">
|
||||||
<div class="min-w-0">
|
<i class="ph ph-check-circle text-[14px]"></i>
|
||||||
<div class="text-white/90 truncate">{{ $s['label'] }}</div>
|
<span class="text-[11px]">alle Dienste OK</span>
|
||||||
</div>
|
</span>
|
||||||
</div>
|
@else
|
||||||
@if($s['hint'])
|
<span
|
||||||
<div class="text-[11px] text-white/45 truncate">{{ $s['hint'] }}</div>
|
class="inline-flex #items-center gap-1 px-3 py-1 rounded-full text-sm border border-rose-400/30 text-rose-300 bg-rose-500/10">
|
||||||
@endif
|
<i class="ph ph-warning-circle text-[11px]"></i>
|
||||||
</div>
|
Störung erkannt
|
||||||
<span
|
</span>
|
||||||
class="justify-self-end inline-flex items-center px-2.5 py-0.5 rounded-full text-xs border {{ $s['pillClass'] }}">
|
@endif
|
||||||
{{ $s['pillText'] }}
|
</div>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
@empty
|
|
||||||
<li class="py-2 text-white/50 text-sm">Keine Daten.</li>
|
|
||||||
@endforelse
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<livewire:ui.system.update-card/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- 2-Spalten Abschnitt: links Dienste, rechts Storage --}}
|
{{-- Dienste & Storage: kompakt & bündig --}}
|
||||||
<div class="glass-card relative p-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{{-- Kopf: Titel + Link oben links --}}
|
<div class="glass-card relative p-4 max-h-fit">
|
||||||
<div class="flex items-center justify-between mb-3">
|
|
||||||
<div class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
|
||||||
<i class="ph ph-hard-drives text-white/70 text-[13px]"></i>
|
|
||||||
<span class="text-[11px] tracking-wide uppercase text-white/70">Storage</span>
|
|
||||||
</div>
|
|
||||||
<a href="#"
|
|
||||||
class="inline-flex items-center gap-1 rounded-full border border-white/10 bg-white/5 px-2 py-0.5 text-[10px] text-white/70 hover:text-white hover:border-white/20 transition">
|
|
||||||
Details <i class="ph ph-caret-right text-[12px]"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{-- Inhalt: Donut links, Zahlen rechts – stacked auf kleineren Screens --}}
|
{{-- Inhalt: Donut links, Zahlen rechts – stacked auf kleineren Screens --}}
|
||||||
<div class="grid grid-cols-1 #md:grid-cols-[minmax(220px,1fr)_minmax(220px,1fr)] #gap-6 items-center">
|
<div class="grid grid-cols-1 items-center">
|
||||||
{{-- Donut --}}
|
{{-- Donut --}}
|
||||||
|
<div class="flex items-center justify-between -mb-3">
|
||||||
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
|
<i class="ph ph-hard-drives text-white/70 text-[13px]"></i>
|
||||||
|
<span class="text-[11px] tracking-wide uppercase text-white/70">Storage</span>
|
||||||
|
</div>
|
||||||
|
<a href="#"
|
||||||
|
class="inline-flex items-center gap-1 rounded-full border border-white/10 bg-white/5 px-2 py-0.5 text-[10px] text-white/70 hover:text-white hover:border-white/20 transition">
|
||||||
|
Details <i class="ph ph-caret-right text-[12px]"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-center">
|
<div class="flex items-center justify-center">
|
||||||
<div class="relative"
|
<div class="relative"
|
||||||
style="width: {{ $diskInnerSize + 80 }}px; height: {{ $diskInnerSize + 80 }}px;">
|
style="width: {{ $diskInnerSize + 80 }}px; height: {{ $diskInnerSize + 80 }}px;">
|
||||||
{{-- Innerer grauer Kreis --}}
|
{{-- Innerer grauer Kreis --}}
|
||||||
<div class="absolute inset-[36px] rounded-full bg-white/[0.04] backdrop-blur-sm ring-1 ring-white/10"></div>
|
<div
|
||||||
|
class="absolute inset-[36px] rounded-full bg-white/[0.04] backdrop-blur-sm ring-1 ring-white/10"></div>
|
||||||
|
|
||||||
{{-- Prozentanzeige im Zentrum – leicht kleiner & feiner --}}
|
{{-- Prozentanzeige im Zentrum – leicht kleiner & feiner --}}
|
||||||
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
||||||
|
|
@ -206,5 +232,47 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="glass-card p-4">
|
||||||
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
<div
|
||||||
|
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||||||
|
<i class="ph ph-gear-six text-white/70 text-[13px]"></i>
|
||||||
|
<span class="text-[11px] tracking-wide uppercase text-white/70">Dienste</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-1 rounded-full bg-white/5 border border-white/10 px-2 py-0.5 text-[10px] text-white/60">
|
||||||
|
systemctl / TCP
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul class="overflow-auto divide-y divide-white/5">
|
||||||
|
@forelse($servicesCompact as $s)
|
||||||
|
<li class="grid grid-cols-[auto,1fr,auto] items-center gap-3 py-2">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="h-2 w-2 rounded-full {{ $s['dotClass'] }}"></span>
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div class="text-white/90 truncate">{{ $s['label'] }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if($s['hint'])
|
||||||
|
<div class="text-[11px] text-white/45 truncate">{{ $s['hint'] }}</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="justify-self-end inline-flex items-center px-2.5 py-0.5 rounded-full text-xs border {{ $s['pillClass'] }}">
|
||||||
|
{{ $s['pillText'] }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@empty
|
||||||
|
<li class="py-2 text-white/50 text-sm">Keine Daten.</li>
|
||||||
|
@endforelse
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
@php
|
||||||
|
$hasUpdate = $latest && $current && version_compare($latest, $current, '>');
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="glass-card rounded-2xl p-4 border border-white/10 bg-white/5 max-h-fit">
|
||||||
|
<div class="flex items-start gap-2">
|
||||||
|
{{-- Shield-Bot --}}
|
||||||
|
<div class="relative shrink-0">
|
||||||
|
<div class="shrink-0 relative">
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="shieldGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#4ade80"></stop>
|
||||||
|
<stop offset="1" stop-color="#15803d"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="shine" cx="30%" cy="20%" r="70%">
|
||||||
|
<stop offset="0%" stop-color="rgba(255,255,255,0.4)"></stop>
|
||||||
|
<stop offset="100%" stop-color="rgba(255,255,255,0)"></stop>
|
||||||
|
</radialGradient>
|
||||||
|
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feDropShadow dx="0" dy="0" stdDeviation="3" flood-color="#22c55e" flood-opacity="0.6"></feDropShadow>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z" fill="url(#shieldGradient)" filter="url(#glow)"></path>
|
||||||
|
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z" fill="url(#shine)"></path>
|
||||||
|
<i class="ph-bold ph-arrows-clockwise absolute top-1/2 left-1/2 -translate-1/2 text-2xl {{ $state === 'running' ? 'animate-spin' : '' }}"></i>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<div class="flex items-center justify-between gap-3">
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div class="text-white/90 font-semibold">MailWolt Update</div>
|
||||||
|
{{-- kleine Statuszeile mit Versionen, wenn vorhanden --}}
|
||||||
|
<div class="text-xs text-white/70">
|
||||||
|
@if($current)
|
||||||
|
aktuell: <span class="text-white/90">v{{ $current }}</span>
|
||||||
|
@else
|
||||||
|
aktuell: <span class="text-white/60">–</span>
|
||||||
|
@endif
|
||||||
|
@if($latest)
|
||||||
|
<span class="mx-1 text-white/30">•</span>
|
||||||
|
verfügbar: <span class="text-emerald-200">v{{ $latest }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{-- Badge rechts --}}
|
||||||
|
<span class="shrink-0 inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[11px] border px-3 py-1
|
||||||
|
{{ $hasUpdate
|
||||||
|
? 'text-yellow-200 bg-yellow-500/10 border-yellow-400/30'
|
||||||
|
: 'text-emerald-200 bg-emerald-500/10 border-emerald-400/30' }}">
|
||||||
|
<i class="ph {{ $hasUpdate ? 'ph-arrow-fat-line-up' : 'ph-check-circle' }} text-[12px]"></i>
|
||||||
|
{{ $hasUpdate ? 'Update verfügbar' : 'Aktuell' }}
|
||||||
|
</span>
|
||||||
|
{{-- <button wire:click="refreshState"--}}
|
||||||
|
{{-- @disabled($state==='running')--}}
|
||||||
|
{{-- class="inline-flex items-center gap-2 rounded p-1.5--}}
|
||||||
|
{{-- text-white/75 bg-white/5 border border-white/10 hover:border-white/20--}}
|
||||||
|
{{-- disabled:opacity-60">--}}
|
||||||
|
{{-- <i class="ph ph-arrow-clockwise text-[11px]"></i>--}}
|
||||||
|
{{-- </button>--}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex items-center gap-2">
|
||||||
|
@if($hasUpdate)
|
||||||
|
<button wire:click="runUpdate"
|
||||||
|
@disabled($state==='running')
|
||||||
|
class="inline-flex items-center gap-2 rounded-lg px-3 py-1.5
|
||||||
|
text-emerald-200 bg-emerald-500/10 border border-emerald-400/30
|
||||||
|
hover:bg-emerald-500/15 hover:border-emerald-300/50
|
||||||
|
disabled:opacity-60">
|
||||||
|
<i class="ph ph-arrow-fat-lines-up text-[14px]"></i> Jetzt aktualisieren
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Progress-Bar, wenn running --}}
|
||||||
|
@if($state === 'running')
|
||||||
|
<div class="mt-3 h-1.5 rounded bg-white/10 overflow-hidden">
|
||||||
|
<div class="h-full bg-emerald-400/70 animate-[progress_1.4s_infinite]" style="width:40%"></div>
|
||||||
|
</div>
|
||||||
|
<style>@keyframes progress {
|
||||||
|
0% {
|
||||||
|
transform: translateX(-100%)
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(260%)
|
||||||
|
}
|
||||||
|
}</style>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
@section('header_title', 'Dashboard')
|
@section('header_title', 'Dashboard')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="max-w-7xl mx-auto space-y-6 px-2 md:px-4">
|
<div class="max-w-9xl mx-auto space-y-6 px-2 md:px-4">
|
||||||
<div class="max-w-fit col-span-4 #lg:col-span-6">
|
{{-- <div class="max-w-fit col-span-4 #lg:col-span-6">--}}
|
||||||
<livewire:ui.system.update-manager />
|
{{-- <livewire:ui.system.update-manager />--}}
|
||||||
</div>
|
{{-- </div>--}}
|
||||||
|
|
||||||
<div class="col-span-12 lg:col-span-6">
|
<div class="col-span-12 lg:col-span-6">
|
||||||
<livewire:ui.dashboard.top-bar />
|
<livewire:ui.dashboard.top-bar />
|
||||||
|
|
@ -18,20 +18,9 @@
|
||||||
<livewire:ui.dashboard.health-card />
|
<livewire:ui.dashboard.health-card />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">--}}
|
|
||||||
{{-- @livewire('ui.dashboard.services-health') --}}{{----}}{{-- NEU --}}
|
|
||||||
{{-- @livewire('ui.dashboard.mail-kpis-card', ['key'=>'outgoing_queue'])--}}
|
|
||||||
{{-- @livewire('ui.dashboard.app-updates') --}}{{-- NEU --}}
|
|
||||||
{{-- </div>--}}
|
|
||||||
|
|
||||||
{{-- <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">--}}
|
|
||||||
{{-- @livewire('ui.dashboard.mail-trend-chart')--}}
|
|
||||||
{{-- @livewire('ui.dashboard.alerts-feed') --}}{{-- NEU --}}
|
|
||||||
{{-- </div>--}}
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||||
@livewire('ui.dashboard.domains-panel')
|
<livewire:ui.dashboard.domains-panel />
|
||||||
@livewire('ui.dashboard.recent-logins-table')
|
<livewire:ui.dashboard.recent-logins-table />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,57 +2,55 @@
|
||||||
|
|
||||||
use App\Http\Controllers\Api\TaskFeedController;
|
use App\Http\Controllers\Api\TaskFeedController;
|
||||||
use App\Http\Controllers\Auth\LoginController;
|
use App\Http\Controllers\Auth\LoginController;
|
||||||
use App\Http\Controllers\Setup\SetupWizard;
|
use App\Http\Controllers\Auth\SignUpController;
|
||||||
use App\Http\Controllers\UI\Domain\DomainDnsController;
|
use App\Http\Controllers\UI\Domain\DomainDnsController;
|
||||||
use App\Http\Controllers\UI\Mail\AliasController;
|
use App\Http\Controllers\UI\Mail\AliasController;
|
||||||
use App\Http\Controllers\UI\Mail\MailboxController;
|
use App\Http\Controllers\UI\Mail\MailboxController;
|
||||||
use App\Http\Controllers\UI\Security\RecoveryCodeDownloadController;
|
|
||||||
use App\Http\Controllers\UI\Security\SecurityController;
|
use App\Http\Controllers\UI\Security\SecurityController;
|
||||||
use App\Http\Controllers\UI\System\SettingsController;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use App\Livewire\PingButton;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return Auth::check()
|
||||||
|
? redirect()->route('ui.dashboard')
|
||||||
|
: redirect()->route('login');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::middleware('auth.user')->name('ui.')->group(function () {
|
||||||
|
#DASHBOARD ROUTE
|
||||||
|
Route::get('/dashboard', [\App\Http\Controllers\UI\DashboardController::class, 'index'])->name('dashboard');
|
||||||
|
|
||||||
Route::get('/dashboard', [\App\Http\Controllers\UI\DashboardController::class, 'index'])
|
|
||||||
->middleware(['auth']) // falls gewünscht
|
|
||||||
->name('ui.dashboard');
|
|
||||||
|
|
||||||
//Route::middleware(['auth']) // falls du auth nutzt
|
#SYSTEM ROUTES
|
||||||
//->get('/system/settings', [SettingsController::class, 'index'])
|
Route::prefix('system')->name('system.')->group(function () {
|
||||||
// ->name('ui.system.settings');
|
Route::get('/settings', [\App\Http\Controllers\UI\System\SettingsController::class, 'index'])->name('settings');
|
||||||
|
|
||||||
Route::middleware(['auth'])
|
|
||||||
->prefix('system')
|
|
||||||
->name('ui.system.')
|
|
||||||
->group(function () {
|
|
||||||
Route::get('/settings', [\App\Http\Controllers\UI\System\SettingsController::class, 'index'])
|
|
||||||
->name('settings');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])
|
#SECURITY ROUTES
|
||||||
->prefix('security')
|
Route::prefix('security')->name('security.')->group(function () {
|
||||||
->name('ui.security.')
|
|
||||||
->group(function () {
|
|
||||||
Route::get('/', [SecurityController::class, 'index'])->name('index');
|
Route::get('/', [SecurityController::class, 'index'])->name('index');
|
||||||
Route::get('/ssl', [SecurityController::class, 'ssl'])->name('ssl');
|
Route::get('/ssl', [SecurityController::class, 'ssl'])->name('ssl');
|
||||||
Route::get('/fail2ban', [SecurityController::class, 'fail2ban'])->name('fail2ban');
|
Route::get('/fail2ban', [SecurityController::class, 'fail2ban'])->name('fail2ban');
|
||||||
Route::get('/rspamd', [SecurityController::class, 'rspamd'])->name('rspamd');
|
Route::get('/rspamd', [SecurityController::class, 'rspamd'])->name('rspamd');
|
||||||
Route::get('/tls-ciphers', [SecurityController::class, 'tlsCiphers'])->name('tls');
|
Route::get('/tls-ciphers', [SecurityController::class, 'tlsCiphers'])->name('tls');
|
||||||
Route::get('/audit-logs', [SecurityController::class, 'auditLogs'])->name('audit');
|
Route::get('/audit-logs', [SecurityController::class, 'auditLogs'])->name('audit');
|
||||||
|
});
|
||||||
|
|
||||||
|
#DOMAIN ROUTES
|
||||||
|
Route::name('domain.')->group(function () {
|
||||||
|
Route::get('/domains', [DomainDnsController::class, 'index'])->name('index');
|
||||||
|
});
|
||||||
|
|
||||||
|
#MAIL ROUTES
|
||||||
|
Route::name('mail.')->group(function () {
|
||||||
|
Route::get('/mailboxes', [MailboxController::class, 'index'])->name('mailbox.index');
|
||||||
|
Route::get('/aliases', [AliasController::class, 'index'])->name('aliases.index');
|
||||||
|
});
|
||||||
|
|
||||||
|
#LOGOUT ROUTE
|
||||||
|
Route::post('/logout', [LoginController::class, 'logout'])->name('logout');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])->name('ui.domain.')->group(function () {
|
|
||||||
Route::get('/domains', [DomainDnsController::class, 'index'])->name('index');
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(['auth'])->name('ui.mail.')->group(function () {
|
|
||||||
Route::get('/mailboxes', [MailboxController::class, 'index'])->name('mailbox.index');
|
|
||||||
Route::get('/aliases', [AliasController::class, 'index'])->name('aliases.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//Route::middleware(['auth'])
|
//Route::middleware(['auth'])
|
||||||
|
|
@ -61,32 +59,12 @@ Route::middleware(['auth'])->name('ui.mail.')->group(function () {
|
||||||
// ->middleware('signed'); // wichtig: signierte URL
|
// ->middleware('signed'); // wichtig: signierte URL
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(['web','auth']) // nutzt Session, kein Token nötig
|
Route::middleware(['web', 'auth']) // nutzt Session, kein Token nötig
|
||||||
->get('/ui/tasks/active', [TaskFeedController::class, 'active'])
|
->get('/ui/tasks/active', [TaskFeedController::class, 'active'])
|
||||||
->name('ui.tasks.active');
|
->name('ui.tasks.active');
|
||||||
|
|
||||||
//Route::middleware(['auth'])->group(function () {
|
Route::middleware('guest.only')->group(function () {
|
||||||
// Route::get('/tasks/active', [TaskFeedController::class, 'active'])
|
Route::get('/login', [LoginController::class, 'show'])->name('login');
|
||||||
// ->name('tasks.active');
|
Route::get('/signup', [SignUpController::class, 'show'])->middleware('signup.open')->name('signup');
|
||||||
// Route::post('/tasks/ack', [TaskFeedController::class, 'ack'])
|
});
|
||||||
// ->name('tasks.ack');
|
|
||||||
//});
|
|
||||||
//Route::middleware(['web','auth']) // gleiche Session wie im Dashboard
|
|
||||||
//->get('/ui/tasks/active', [\App\Http\Controllers\Api\TaskStatusController::class, 'index'])
|
|
||||||
// ->name('ui.tasks.active');
|
|
||||||
|
|
||||||
//Route::get('/dashboard', [DashboardController::class, 'show'])->name('dashboard');
|
|
||||||
Route::get('/login', [LoginController::class, 'show'])->name('login');
|
|
||||||
Route::get('/signup', [\App\Http\Controllers\Auth\SignUpController::class, 'show' ])->middleware('signup.open')->name('signup');
|
|
||||||
Route::post('/logout', [\App\Http\Controllers\Auth\LoginController::class, 'logout'])->name('logout');
|
|
||||||
|
|
||||||
//Route::middleware(['auth', 'ensure.setup'])->group(function () {
|
|
||||||
//// Route::get('/dashboard', Dashboard::class)->name('dashboard');
|
|
||||||
// Route::get('/setup', [SetupWizard::class, 'show'])->name('setup.wizard');
|
|
||||||
//});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Route::middleware(['auth', 'ensure.setup'])->group(function () {
|
|
||||||
// Route::get('/dashboard', fn() => view('dashboard'))->name('dashboard');
|
|
||||||
//});
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue