Domain Create Modal anpassen Fehler auf Null
parent
c85dc952d6
commit
d99913df06
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\MailUser;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class UpdateMailboxStats extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'mail:update-stats {--user=}';
|
||||||
|
protected $description = 'Aktualisiert Mailquota und Nachrichtenzahl für alle Mailboxen (oder einen spezifischen Benutzer)';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$query = MailUser::query()->where('is_active', true);
|
||||||
|
|
||||||
|
if ($email = $this->option('user')) {
|
||||||
|
$query->where('email', $email);
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = $query->get();
|
||||||
|
|
||||||
|
foreach ($users as $u) {
|
||||||
|
$email = $u->email;
|
||||||
|
$domain = explode('@', $email)[1];
|
||||||
|
$local = explode('@', $email)[0];
|
||||||
|
$path = "/var/mail/vhosts/{$domain}/{$local}";
|
||||||
|
|
||||||
|
$usedBytes = 0;
|
||||||
|
$messageCount = 0;
|
||||||
|
|
||||||
|
if (is_dir($path)) {
|
||||||
|
$usedBytes = (int) trim(shell_exec('du -sb '.escapeshellarg($path).' 2>/dev/null | cut -f1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = trim(shell_exec('doveadm mailbox status -u '.escapeshellarg($email).' messages INBOX 2>/dev/null'));
|
||||||
|
if (preg_match('/messages=(\d+)/', $out, $m)) {
|
||||||
|
$messageCount = (int) $m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$u->update([
|
||||||
|
'used_bytes' => $usedBytes,
|
||||||
|
'message_count' => $messageCount,
|
||||||
|
'stats_refreshed_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->info(sprintf("%-35s %6.1f MiB %4d Nachrichten", $email, $usedBytes / 1024 / 1024, $messageCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -78,7 +78,7 @@ class DomainDnsModal extends ModalComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Domain-spezifisch ---
|
// --- Domain-spezifisch ---
|
||||||
$spf = 'v=spf1 mx a -all';
|
$spf = "v=spf1 a mx ip4:{$ipv4} ip6:{$ipv6} ~all";
|
||||||
$dmarc = "v=DMARC1; p=none; rua=mailto:dmarc@{$this->domainName}; pct=100";
|
$dmarc = "v=DMARC1; p=none; rua=mailto:dmarc@{$this->domainName}; pct=100";
|
||||||
|
|
||||||
$dkim = DB::table('dkim_keys')
|
$dkim = DB::table('dkim_keys')
|
||||||
|
|
@ -90,14 +90,14 @@ class DomainDnsModal extends ModalComponent
|
||||||
: ($dkim->public_key_txt ?? 'v=DKIM1; k=rsa; p=');
|
: ($dkim->public_key_txt ?? 'v=DKIM1; k=rsa; p=');
|
||||||
|
|
||||||
$this->dynamic = [
|
$this->dynamic = [
|
||||||
['type' => 'CNAME', 'name' => "autoconfig.$this->domainName", 'value' => "$this->domainName."],
|
['type' => 'CNAME', 'name' => "autoconfig.$this->domainName", 'value' => "$mailServerFqdn."],
|
||||||
['type' => 'CNAME', 'name' => "autodiscover.$this->domainName", 'value' => "$this->domainName."],
|
['type' => 'CNAME', 'name' => "autodiscover.$this->domainName", 'value' => "$mailServerFqdn."],
|
||||||
|
|
||||||
// SRV Records für Autodiscover und Maildienste
|
// SRV Records für Autodiscover und Maildienste
|
||||||
['type' => 'SRV', 'name' => "_autodiscover._tcp.$this->domainName", 'value' => "0 0 443 {$this->domainName}."],
|
['type' => 'SRV', 'name' => "_autodiscover._tcp.$this->domainName", 'value' => "0 0 443 {$mailServerFqdn}."],
|
||||||
['type' => 'SRV', 'name' => "_imaps._tcp.$this->domainName", 'value' => "0 0 993 {$this->domainName}."],
|
['type' => 'SRV', 'name' => "_imaps._tcp.$this->domainName", 'value' => "0 0 993 {$mailServerFqdn}."],
|
||||||
['type' => 'SRV', 'name' => "_pop3s._tcp.$this->domainName", 'value' => "0 0 995 {$this->domainName}."],
|
['type' => 'SRV', 'name' => "_pop3s._tcp.$this->domainName", 'value' => "0 0 995 {$mailServerFqdn}."],
|
||||||
['type' => 'SRV', 'name' => "_submission._tcp.$this->domainName", 'value' => "0 0 587 {$this->domainName}."],
|
['type' => 'SRV', 'name' => "_submission._tcp.$this->domainName", 'value' => "0 0 587 {$mailServerFqdn}."],
|
||||||
|
|
||||||
// TXT Records
|
// TXT Records
|
||||||
['type' => 'TXT', 'name' => $this->domainName, 'value' => $spf, 'helpLabel' => 'SPF Record Syntax', 'helpUrl' => 'http://www.open-spf.org/SPF_Record_Syntax/'],
|
['type' => 'TXT', 'name' => $this->domainName, 'value' => $spf, 'helpLabel' => 'SPF Record Syntax', 'helpUrl' => 'http://www.open-spf.org/SPF_Record_Syntax/'],
|
||||||
|
|
@ -106,7 +106,6 @@ class DomainDnsModal extends ModalComponent
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function extractZone(string $fqdn): string
|
private function extractZone(string $fqdn): string
|
||||||
{
|
{
|
||||||
$fqdn = strtolower(trim($fqdn, "."));
|
$fqdn = strtolower(trim($fqdn, "."));
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
namespace App\Livewire\Ui\Mail;
|
namespace App\Livewire\Ui\Mail;
|
||||||
|
|
||||||
use App\Models\Domain;
|
use App\Models\Domain;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
@ -57,6 +58,19 @@ class MailboxList extends Component
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateMailboxStats()
|
||||||
|
{
|
||||||
|
// führe Artisan-Command direkt aus
|
||||||
|
Artisan::call('mail:update-stats');
|
||||||
|
$this->dispatch('$refresh');
|
||||||
|
$this->dispatch('toast',
|
||||||
|
type: 'done',
|
||||||
|
badge: 'Mailbox',
|
||||||
|
title: 'Mailbox aktualisiert',
|
||||||
|
text: 'Die Mailbox-Statistiken wurden aktualisiert.',
|
||||||
|
duration: 6000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
|
@ -107,9 +121,14 @@ class MailboxList extends Component
|
||||||
$domainActive = (bool)($d->is_active ?? true);
|
$domainActive = (bool)($d->is_active ?? true);
|
||||||
|
|
||||||
foreach ($d->mailUsers as $u) {
|
foreach ($d->mailUsers as $u) {
|
||||||
$quota = (int)($u->quota_mb ?? 0);
|
$usedMB = (int) round(($u->used_bytes ?? 0) / 1024 / 1024);
|
||||||
$used = (int)($u->used_mb ?? 0);
|
$quota = (int)($u->quota_mb ?? 0);
|
||||||
$usage = $quota > 0 ? min(100, (int)round($used / max(1, $quota) * 100)) : 0;
|
$usage = $quota > 0 ? min(100, (int) round($usedMB / max(1,$quota) * 100)) : 0;
|
||||||
|
|
||||||
|
|
||||||
|
// $quota = (int)($u->quota_mb ?? 0);
|
||||||
|
// $used = (int)($u->used_mb ?? 0);
|
||||||
|
// $usage = $quota > 0 ? min(100, (int)round($used / max(1, $quota) * 100)) : 0;
|
||||||
|
|
||||||
$mailboxActive = (bool)($u->is_active ?? true);
|
$mailboxActive = (bool)($u->is_active ?? true);
|
||||||
$effective = $domainActive && $mailboxActive;
|
$effective = $domainActive && $mailboxActive;
|
||||||
|
|
@ -124,9 +143,11 @@ class MailboxList extends Component
|
||||||
'id' => $u->id,
|
'id' => $u->id,
|
||||||
'localpart' => (string)$u->localpart,
|
'localpart' => (string)$u->localpart,
|
||||||
'quota_mb' => $quota,
|
'quota_mb' => $quota,
|
||||||
'used_mb' => $used,
|
|
||||||
'usage_percent' => $usage,
|
'usage_percent' => $usage,
|
||||||
'message_count' => (int)($u->message_count ?? $u->mails_count ?? 0),
|
'used_mb' => $usedMB,
|
||||||
|
'message_count' => (int) ($u->message_count ?? 0),
|
||||||
|
// 'used_mb' => $used,
|
||||||
|
// 'message_count' => (int)($u->message_count ?? $u->mails_count ?? 0),
|
||||||
'is_active' => $mailboxActive,
|
'is_active' => $mailboxActive,
|
||||||
'is_effective_active' => $effective,
|
'is_effective_active' => $effective,
|
||||||
'inactive_reason' => $reason,
|
'inactive_reason' => $reason,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ return new class extends Migration
|
||||||
|
|
||||||
$table->unsignedInteger('quota_mb')->default(0); // 0 = unlimited
|
$table->unsignedInteger('quota_mb')->default(0); // 0 = unlimited
|
||||||
$table->unsignedInteger('rate_limit_per_hour')->nullable();
|
$table->unsignedInteger('rate_limit_per_hour')->nullable();
|
||||||
|
$table->unsignedInteger('used_bytes')->default(0);
|
||||||
|
$table->unsignedInteger('message_count')->default(0);
|
||||||
|
$table->timestamp('stats_refreshed_at')->nullable();
|
||||||
$table->timestamp('last_login_at')->nullable();
|
$table->timestamp('last_login_at')->nullable();
|
||||||
|
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::table('mail_aliases', function (Blueprint $table) {
|
|
||||||
$table->string('destination', 191)->nullable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('mail_aliases', function (Blueprint $table) {
|
|
||||||
//
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
class="md:max-w-96 w-full justify-end flex-1 rounded-xl bg-white/5 border border-white/10 px-4 py-2.5 text-white/90 placeholder:text-white/50"
|
class="md:max-w-96 w-full justify-end flex-1 rounded-xl bg-white/5 border border-white/10 px-4 py-2.5 text-white/90 placeholder:text-white/50"
|
||||||
placeholder="Suchen (Domain oder Postfach) …">
|
placeholder="Suchen (Domain oder Postfach) …">
|
||||||
</div>
|
</div>
|
||||||
@if($domains->count())
|
@if($domains->count())
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
|
|
||||||
@foreach($domains as $domain)
|
@foreach($domains as $domain)
|
||||||
|
|
@ -27,10 +27,10 @@
|
||||||
<i class="ph ph-globe-hemisphere-east text-[14px]"></i> {{ $domain->domain }}
|
<i class="ph ph-globe-hemisphere-east text-[14px]"></i> {{ $domain->domain }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- <span--}}
|
{{-- <span--}}
|
||||||
{{-- class="px-2 py-0.5 rounded-full text-xs border {{ ($domain->is_active ?? true) ? 'border-emerald-400/30 text-emerald-300 bg-emerald-500/10' : 'border-white/15 text-white/60 bg-white/5' }}">--}}
|
{{-- class="px-2 py-0.5 rounded-full text-xs border {{ ($domain->is_active ?? true) ? 'border-emerald-400/30 text-emerald-300 bg-emerald-500/10' : 'border-white/15 text-white/60 bg-white/5' }}">--}}
|
||||||
{{-- {{ ($domain->is_active ?? true) ? 'aktiv' : 'inaktiv' }}--}}
|
{{-- {{ ($domain->is_active ?? true) ? 'aktiv' : 'inaktiv' }}--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">
|
class="px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">
|
||||||
|
|
@ -47,68 +47,68 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{-- Postfächer --}}
|
{{-- Postfächer --}}
|
||||||
{{-- <div class="mt-4 overflow-hidden">--}}
|
{{-- <div class="mt-4 overflow-hidden">--}}
|
||||||
{{-- <div class="divide-y divide-white/5 space-y-3">--}}
|
{{-- <div class="divide-y divide-white/5 space-y-3">--}}
|
||||||
{{-- @forelse($domain->prepared_mailboxes as $u)--}}
|
{{-- @forelse($domain->prepared_mailboxes as $u)--}}
|
||||||
|
|
||||||
{{-- <div class="rounded-xl border border-white/10 flex flex-col md:flex-row md:items-center gap-3 px-3 py-3 bg-white/[0.04]">--}}
|
{{-- <div class="rounded-xl border border-white/10 flex flex-col md:flex-row md:items-center gap-3 px-3 py-3 bg-white/[0.04]">--}}
|
||||||
{{-- <div class="min-w-0 flex-1">--}}
|
{{-- <div class="min-w-0 flex-1">--}}
|
||||||
{{-- <div class="text-white/90 font-medium truncate">--}}
|
{{-- <div class="text-white/90 font-medium truncate">--}}
|
||||||
{{-- {{ $u['localpart'] !== '' ? ($u['localpart'].'@'.$domain->domain) : '—' }}--}}
|
{{-- {{ $u['localpart'] !== '' ? ($u['localpart'].'@'.$domain->domain) : '—' }}--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
|
|
||||||
{{-- <div class="mt-1 flex items-center gap-2 flex-wrap md:flex-nowrap">--}}
|
{{-- <div class="mt-1 flex items-center gap-2 flex-wrap md:flex-nowrap">--}}
|
||||||
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border whitespace-nowrap--}}
|
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border whitespace-nowrap--}}
|
||||||
{{-- {{ $u['is_effective_active'] ? 'border-emerald-400/30 text-emerald-300 bg-emerald-500/10'--}}
|
{{-- {{ $u['is_effective_active'] ? 'border-emerald-400/30 text-emerald-300 bg-emerald-500/10'--}}
|
||||||
{{-- : 'border-white/15 text-white/60 bg-white/5' }}">--}}
|
{{-- : 'border-white/15 text-white/60 bg-white/5' }}">--}}
|
||||||
{{-- {{ $u['is_effective_active'] ? 'aktiv' : 'inaktiv' }}--}}
|
{{-- {{ $u['is_effective_active'] ? 'aktiv' : 'inaktiv' }}--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
{{-- @if(!$u['is_effective_active'] && !empty($u['inactive_reason']))--}}
|
{{-- @if(!$u['is_effective_active'] && !empty($u['inactive_reason']))--}}
|
||||||
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-amber-400/30 text-amber-300 bg-amber-500/10 whitespace-nowrap">--}}
|
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-amber-400/30 text-amber-300 bg-amber-500/10 whitespace-nowrap">--}}
|
||||||
{{-- {{ $u['inactive_reason'] }}--}}
|
{{-- {{ $u['inactive_reason'] }}--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
{{-- @endif--}}
|
{{-- @endif--}}
|
||||||
|
|
||||||
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
||||||
{{-- Max {{ $u['quota_mb'] }} MiB--}}
|
{{-- Max {{ $u['quota_mb'] }} MiB--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
||||||
{{-- Verbraucht: {{ $u['used_mb'] }} MiB ({{ $u['usage_percent'] }} %)--}}
|
{{-- Verbraucht: {{ $u['used_mb'] }} MiB ({{ $u['usage_percent'] }} %)--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
{{-- <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs border border-white/15 text-white/70 bg-white/5 whitespace-nowrap">--}}
|
||||||
{{-- <i class="ph ph-at text-[12px] mr-1"></i> {{ $u['message_count'] }} E-Mails--}}
|
{{-- <i class="ph ph-at text-[12px] mr-1"></i> {{ $u['message_count'] }} E-Mails--}}
|
||||||
{{-- </span>--}}
|
{{-- </span>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
{{-- <div class="mt-2 h-1.5 rounded-full bg-white/10 overflow-hidden {{ $u['is_effective_active'] ? '' : 'opacity-40' }}">--}}
|
{{-- <div class="mt-2 h-1.5 rounded-full bg-white/10 overflow-hidden {{ $u['is_effective_active'] ? '' : 'opacity-40' }}">--}}
|
||||||
{{-- <div class="h-full rounded-full bg-emerald-400/50" style="width: {{ $u['usage_percent'] }}%"></div>--}}
|
{{-- <div class="h-full rounded-full bg-emerald-400/50" style="width: {{ $u['usage_percent'] }}%"></div>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
|
|
||||||
{{-- <hr class="md:hidden">--}}
|
{{-- <hr class="md:hidden">--}}
|
||||||
|
|
||||||
{{-- Aktionen--}}
|
{{-- Aktionen--}}
|
||||||
{{-- <div class="md:ml-3 flex items-center gap-2 md:justify-end">--}}
|
{{-- <div class="md:ml-3 flex items-center gap-2 md:justify-end">--}}
|
||||||
{{-- Bearbeiten--}}
|
{{-- Bearbeiten--}}
|
||||||
{{-- <button--}}
|
{{-- <button--}}
|
||||||
{{-- class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20"--}}
|
{{-- class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20"--}}
|
||||||
{{-- wire:click="openMailboxEdit({{ $u['id'] }})">--}}
|
{{-- wire:click="openMailboxEdit({{ $u['id'] }})">--}}
|
||||||
{{-- <i class="ph ph-pencil-simple text-[12px]"></i> Bearbeiten--}}
|
{{-- <i class="ph ph-pencil-simple text-[12px]"></i> Bearbeiten--}}
|
||||||
{{-- </button>--}}
|
{{-- </button>--}}
|
||||||
|
|
||||||
{{-- Löschen--}}
|
{{-- Löschen--}}
|
||||||
{{-- <button--}}
|
{{-- <button--}}
|
||||||
{{-- class="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs bg-rose-500/20 text-rose-200 border border-rose-400/40 hover:bg-rose-500/30"--}}
|
{{-- class="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs bg-rose-500/20 text-rose-200 border border-rose-400/40 hover:bg-rose-500/30"--}}
|
||||||
{{-- wire:click="openMailboxDelete({{ $u['id'] }})">--}}
|
{{-- wire:click="openMailboxDelete({{ $u['id'] }})">--}}
|
||||||
{{-- <i class="ph ph-trash-simple text-[12px]"></i> Löschen--}}
|
{{-- <i class="ph ph-trash-simple text-[12px]"></i> Löschen--}}
|
||||||
{{-- </button>--}}
|
{{-- </button>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
|
|
||||||
{{-- @empty--}}
|
{{-- @empty--}}
|
||||||
{{-- <div class="px-3 py-3 text-center text-xs bg-white/[0.04] text-white/60 italic">Keine Postfächer</div>--}}
|
{{-- <div class="px-3 py-3 text-center text-xs bg-white/[0.04] text-white/60 italic">Keine Postfächer</div>--}}
|
||||||
{{-- @endforelse--}}
|
{{-- @endforelse--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
{{-- </div>--}}
|
{{-- </div>--}}
|
||||||
{{-- Postfächer (responsive: Cards < md, Table ≥ md) --}}
|
{{-- Postfächer (responsive: Cards < md, Table ≥ md) --}}
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
|
|
||||||
|
|
@ -150,6 +150,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="shrink-0 flex flex-col gap-2">
|
<div class="shrink-0 flex flex-col gap-2">
|
||||||
|
<div class="flex justify-end mb-2">
|
||||||
|
<button wire:click="updateMailboxStats"
|
||||||
|
class="px-3 py-1 text-sm rounded-md bg-blue-600 text-white hover:bg-blue-700 transition">
|
||||||
|
Jetzt aktualisieren
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20"
|
class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20"
|
||||||
wire:click="openMailboxEdit({{ $u['id'] }})">
|
wire:click="openMailboxEdit({{ $u['id'] }})">
|
||||||
|
|
@ -269,11 +275,13 @@
|
||||||
|
|
||||||
<td class="px-3 py-2">
|
<td class="px-3 py-2">
|
||||||
@if(!$u['is_effective_active'] && !empty($u['inactive_reason']))
|
@if(!$u['is_effective_active'] && !empty($u['inactive_reason']))
|
||||||
<span class="#ml-2 px-2 py-0.5 rounded-full text-xs border border-amber-400/30 text-amber-300 bg-amber-500/10">
|
<span
|
||||||
|
class="#ml-2 px-2 py-0.5 rounded-full text-xs border border-amber-400/30 text-amber-300 bg-amber-500/10">
|
||||||
{{ $u['inactive_reason'] }}
|
{{ $u['inactive_reason'] }}
|
||||||
</span>
|
</span>
|
||||||
@else
|
@else
|
||||||
<span class="px-2 py-0.5 rounded-full text-xs border border-emerald-400/30 text-emerald-300 bg-emerald-500/10">
|
<span
|
||||||
|
class="px-2 py-0.5 rounded-full text-xs border border-emerald-400/30 text-emerald-300 bg-emerald-500/10">
|
||||||
Aktiv
|
Aktiv
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -296,6 +304,10 @@
|
||||||
|
|
||||||
<td class="px-3 py-2 rounded-r-xl">
|
<td class="px-3 py-2 rounded-r-xl">
|
||||||
<div class="flex items-center gap-2 justify-end">
|
<div class="flex items-center gap-2 justify-end">
|
||||||
|
<button wire:click="updateMailboxStats"
|
||||||
|
class="px-3 py-1 text-sm rounded-md bg-blue-600 text-white hover:bg-blue-700 transition">
|
||||||
|
Jetzt aktualisieren
|
||||||
|
</button>
|
||||||
<button wire:click="openMailboxEdit({{ $u['id'] }})"
|
<button wire:click="openMailboxEdit({{ $u['id'] }})"
|
||||||
class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20">
|
class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-white/80 hover:text-white hover:border-white/20">
|
||||||
<i class="ph ph-pencil-simple text-[12px]"></i> Bearbeiten
|
<i class="ph ph-pencil-simple text-[12px]"></i> Bearbeiten
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
use Illuminate\Foundation\Inspiring;
|
use Illuminate\Foundation\Inspiring;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
|
||||||
Artisan::command('inspire', function () {
|
Artisan::command('inspire', function () {
|
||||||
$this->comment(Inspiring::quote());
|
$this->comment(Inspiring::quote());
|
||||||
})->purpose('Display an inspiring quote');
|
})->purpose('Display an inspiring quote');
|
||||||
|
|
||||||
\Illuminate\Support\Facades\Schedule::job(\App\Jobs\RunHealthChecks::class)->everytenSeconds()->withoutOverlapping();
|
Schedule::job(\App\Jobs\RunHealthChecks::class)->everytenSeconds()->withoutOverlapping();
|
||||||
|
|
||||||
|
Schedule::command('mail:update-stats')
|
||||||
|
->everyFiveMinutes()
|
||||||
|
->withoutOverlapping()
|
||||||
|
->appendOutputTo(storage_path('logs/mail_stats.log'));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue