parent
300928851a
commit
a8e7aedadf
|
|
@ -48,6 +48,7 @@ class AliasList extends Component
|
||||||
|
|
||||||
$domains = Domain::query()
|
$domains = Domain::query()
|
||||||
->where('is_system', false)
|
->where('is_system', false)
|
||||||
|
->where('is_server', false)
|
||||||
->withCount(['mailAliases'])
|
->withCount(['mailAliases'])
|
||||||
->with([
|
->with([
|
||||||
'mailAliases' => fn ($q) => $q
|
'mailAliases' => fn ($q) => $q
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ use Livewire\Component;
|
||||||
class MailboxList extends Component
|
class MailboxList extends Component
|
||||||
{
|
{
|
||||||
public string $search = '';
|
public string $search = '';
|
||||||
public bool $showSystemCard = false;
|
|
||||||
|
|
||||||
#[On('mailbox:updated')]
|
#[On('mailbox:updated')]
|
||||||
#[On('mailbox:deleted')]
|
#[On('mailbox:deleted')]
|
||||||
|
|
@ -23,18 +22,6 @@ class MailboxList extends Component
|
||||||
$this->dispatch('$refresh');
|
$this->dispatch('$refresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[On('focus:domain')]
|
|
||||||
public function focusDomain(int $id): void
|
|
||||||
{
|
|
||||||
// optional: Domain hervorheben
|
|
||||||
}
|
|
||||||
|
|
||||||
#[On('focus:user')]
|
|
||||||
public function focusUser(int $id): void
|
|
||||||
{
|
|
||||||
// optional
|
|
||||||
}
|
|
||||||
|
|
||||||
public function openMailboxCreate(int $domainId): void
|
public function openMailboxCreate(int $domainId): void
|
||||||
{
|
{
|
||||||
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-create-modal', arguments: [
|
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-create-modal', arguments: [
|
||||||
|
|
@ -42,24 +29,25 @@ class MailboxList extends Component
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function openMailboxEdit(int $domainId): void
|
public function openMailboxEdit(int $mailUserId): void
|
||||||
{
|
{
|
||||||
// $domainId == mailbox_id
|
|
||||||
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-edit-modal', arguments: [
|
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-edit-modal', arguments: [
|
||||||
$domainId,
|
$mailUserId,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function openMailboxDelete(int $domainId): void
|
public function openMailboxDelete(int $mailUserId): void
|
||||||
{
|
{
|
||||||
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-delete-modal', arguments: [
|
$this->dispatch('openModal', component: 'ui.mail.modal.mailbox-delete-modal', arguments: [
|
||||||
$domainId,
|
$mailUserId,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateMailboxStats(): void
|
public function updateMailboxStats(): void
|
||||||
{
|
{
|
||||||
Artisan::call('mail:update-stats');
|
// läuft asynchron → UI blockiert nicht
|
||||||
|
dispatch(fn() => Artisan::call('mail:update-stats'));
|
||||||
|
|
||||||
$this->dispatch('$refresh');
|
$this->dispatch('$refresh');
|
||||||
$this->dispatch('toast',
|
$this->dispatch('toast',
|
||||||
type: 'done',
|
type: 'done',
|
||||||
|
|
@ -72,57 +60,68 @@ class MailboxList extends Component
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$system = Domain::query()->where('is_system', true)->first();
|
|
||||||
$term = trim($this->search);
|
$term = trim($this->search);
|
||||||
$hasTerm = $term !== '';
|
$hasTerm = $term !== '';
|
||||||
$needle = '%' . str_replace(['%', '_'], ['\%', '\_'], $term) . '%';
|
$needle = '%' . str_replace(['%', '_'], ['\%', '\_'], $term) . '%';
|
||||||
|
|
||||||
|
// Nur Domains, die NICHT system und NICHT server sind
|
||||||
$domains = Domain::query()
|
$domains = Domain::query()
|
||||||
->when($system, fn($q) => $q->whereKeyNot($system->id))
|
->where('is_system', false)
|
||||||
|
->where('is_server', false)
|
||||||
->when($hasTerm, function ($q) use ($needle) {
|
->when($hasTerm, function ($q) use ($needle) {
|
||||||
$q->where(function ($w) use ($needle) {
|
$q->where(function ($w) use ($needle) {
|
||||||
$w->where('domain', 'like', $needle)
|
$w->where('domain', 'like', $needle)
|
||||||
->orWhereHas('mailUsers', fn($u) => $u->where('localpart', 'like', $needle));
|
->orWhereHas('mailUsers', fn($u) => $u
|
||||||
|
->where('is_active', true)
|
||||||
|
->where('is_system', false)
|
||||||
|
->where('localpart', 'like', $needle)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
->withCount(['mailUsers'])
|
->withCount(['mailUsers as mail_users_count' => fn($u) => $u
|
||||||
->with([
|
->where('is_active', true)
|
||||||
'mailUsers' => function ($q) use ($hasTerm, $needle) {
|
->where('is_system', false)
|
||||||
if ($hasTerm) {
|
|
||||||
$q->where('localpart', 'like', $needle);
|
|
||||||
}
|
|
||||||
$q->orderBy('localpart');
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
->with(['mailUsers' => function ($q) use ($hasTerm, $needle) {
|
||||||
|
$q->where('is_active', true)
|
||||||
|
->where('is_system', false);
|
||||||
|
if ($hasTerm) {
|
||||||
|
$q->where('localpart', 'like', $needle);
|
||||||
|
}
|
||||||
|
$q->orderBy('localpart');
|
||||||
|
}])
|
||||||
->orderBy('domain')
|
->orderBy('domain')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
// Wenn Domain direkt matcht → alle Benutzer dieser Domain zeigen
|
||||||
if ($hasTerm) {
|
if ($hasTerm) {
|
||||||
$lower = Str::lower($term);
|
$lower = Str::lower($term);
|
||||||
foreach ($domains as $d) {
|
foreach ($domains as $d) {
|
||||||
if (Str::contains(Str::lower($d->domain), $lower)) {
|
if (Str::contains(Str::lower($d->domain), $lower)) {
|
||||||
$d->setRelation('mailUsers', $d->mailUsers()->orderBy('localpart')->get());
|
$d->setRelation('mailUsers', $d->mailUsers()
|
||||||
$d->setRelation('mailAliases', $d->mailAliases()->orderBy('local')->get());
|
->where('is_active', true)
|
||||||
|
->where('is_system', false)
|
||||||
|
->orderBy('localpart')
|
||||||
|
->get()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Anzeige vorbereiten (mit korrekter Prozent-Berechnung) ----
|
// ---- Anzeige vorbereiten ----
|
||||||
foreach ($domains as $d) {
|
foreach ($domains as $d) {
|
||||||
$prepared = [];
|
$prepared = [];
|
||||||
$domainActive = (bool)($d->is_active ?? true);
|
$domainActive = (bool)($d->is_active ?? true);
|
||||||
|
|
||||||
foreach ($d->mailUsers as $u) {
|
foreach ($d->mailUsers as $u) {
|
||||||
// Stats aus Settings (Redis → DB Fallback)
|
$email = $u->email ?? ($u->address ?? null);
|
||||||
$stats = Setting::get("mailbox.{$u->email}", []);
|
$stats = $email ? (Setting::get("mailbox.{$email}", []) ?: []) : [];
|
||||||
$usedBytes = (int)($stats['used_bytes'] ?? ($u->used_bytes ?? 0));
|
|
||||||
$messageCount = (int)($stats['message_count'] ?? ($u->message_count ?? 0));
|
|
||||||
|
|
||||||
// Anzeige in MiB (nur fürs UI runden)
|
$usedBytes = (int)($stats['used_bytes'] ?? 0);
|
||||||
$usedMiB = (float)round($usedBytes / 1048576, 2);
|
$messageCount = (int)($stats['message_count'] ?? 0);
|
||||||
|
$usedMiB = round($usedBytes / 1048576, 2);
|
||||||
$quotaMiB = (int)($u->quota_mb ?? 0);
|
$quotaMiB = (int)($u->quota_mb ?? 0);
|
||||||
|
|
||||||
// Prozent aus Bytes/Quota (ohne Vorab-Rundung auf MiB!)
|
|
||||||
$usage = $quotaMiB > 0
|
$usage = $quotaMiB > 0
|
||||||
? min(100, (int)round($usedBytes / ($quotaMiB * 1048576) * 100))
|
? min(100, (int)round($usedBytes / ($quotaMiB * 1048576) * 100))
|
||||||
: 0;
|
: 0;
|
||||||
|
|
@ -132,7 +131,8 @@ class MailboxList extends Component
|
||||||
|
|
||||||
$reason = null;
|
$reason = null;
|
||||||
if (!$effective) {
|
if (!$effective) {
|
||||||
$reason = !$domainActive ? 'Domain inaktiv'
|
$reason = !$domainActive
|
||||||
|
? 'Domain inaktiv'
|
||||||
: (!$mailboxActive ? 'Postfach inaktiv' : null);
|
: (!$mailboxActive ? 'Postfach inaktiv' : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,11 +154,170 @@ class MailboxList extends Component
|
||||||
|
|
||||||
return view('livewire.ui.mail.mailbox-list', [
|
return view('livewire.ui.mail.mailbox-list', [
|
||||||
'domains' => $domains,
|
'domains' => $domains,
|
||||||
'system' => $this->showSystemCard ? $system : null,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//namespace App\Livewire\Ui\Mail;
|
||||||
|
//
|
||||||
|
//use App\Models\Domain;
|
||||||
|
//use App\Models\Setting;
|
||||||
|
//use Illuminate\Support\Facades\Artisan;
|
||||||
|
//use Illuminate\Support\Str;
|
||||||
|
//use Livewire\Attributes\On;
|
||||||
|
//use Livewire\Component;
|
||||||
|
//
|
||||||
|
//class MailboxList extends Component
|
||||||
|
//{
|
||||||
|
// public string $search = '';
|
||||||
|
// public bool $showSystemCard = false;
|
||||||
|
//
|
||||||
|
// #[On('mailbox:updated')]
|
||||||
|
// #[On('mailbox:deleted')]
|
||||||
|
// #[On('mailbox:created')]
|
||||||
|
// public function refreshMailboxList(): void
|
||||||
|
// {
|
||||||
|
// $this->dispatch('$refresh');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[On('focus:domain')]
|
||||||
|
// public function focusDomain(int $id): void
|
||||||
|
// {
|
||||||
|
// // optional: Domain hervorheben
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[On('focus:user')]
|
||||||
|
// public function focusUser(int $id): void
|
||||||
|
// {
|
||||||
|
// // optional
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function openMailboxCreate(int $domainId): void
|
||||||
|
// {
|
||||||
|
// $this->dispatch('openModal', component: 'ui.mail.modal.mailbox-create-modal', arguments: [
|
||||||
|
// 'domainId' => $domainId,
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function openMailboxEdit(int $domainId): void
|
||||||
|
// {
|
||||||
|
// // $domainId == mailbox_id
|
||||||
|
// $this->dispatch('openModal', component: 'ui.mail.modal.mailbox-edit-modal', arguments: [
|
||||||
|
// $domainId,
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function openMailboxDelete(int $domainId): void
|
||||||
|
// {
|
||||||
|
// $this->dispatch('openModal', component: 'ui.mail.modal.mailbox-delete-modal', arguments: [
|
||||||
|
// $domainId,
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function updateMailboxStats(): void
|
||||||
|
// {
|
||||||
|
//// Artisan::call('mail:update-stats');
|
||||||
|
// dispatch(fn () => 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()
|
||||||
|
// {
|
||||||
|
// $system = Domain::query()->where('is_system', true)->first();
|
||||||
|
// $term = trim($this->search);
|
||||||
|
// $hasTerm = $term !== '';
|
||||||
|
// $needle = '%' . str_replace(['%', '_'], ['\%', '\_'], $term) . '%';
|
||||||
|
//
|
||||||
|
// $domains = Domain::query()
|
||||||
|
// ->when($system, fn($q) => $q->whereKeyNot($system->id))
|
||||||
|
// ->when($hasTerm, function ($q) use ($needle) {
|
||||||
|
// $q->where(function ($w) use ($needle) {
|
||||||
|
// $w->where('domain', 'like', $needle)
|
||||||
|
// ->orWhereHas('mailUsers', fn($u) => $u->where('localpart', 'like', $needle));
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// ->withCount(['mailUsers'])
|
||||||
|
// ->with([
|
||||||
|
// 'mailUsers' => function ($q) use ($hasTerm, $needle) {
|
||||||
|
// if ($hasTerm) {
|
||||||
|
// $q->where('localpart', 'like', $needle);
|
||||||
|
// }
|
||||||
|
// $q->orderBy('localpart');
|
||||||
|
// },
|
||||||
|
// ])
|
||||||
|
// ->orderBy('domain')
|
||||||
|
// ->get();
|
||||||
|
//
|
||||||
|
// if ($hasTerm) {
|
||||||
|
// $lower = Str::lower($term);
|
||||||
|
// foreach ($domains as $d) {
|
||||||
|
// if (Str::contains(Str::lower($d->domain), $lower)) {
|
||||||
|
// $d->setRelation('mailUsers', $d->mailUsers()->orderBy('localpart')->get());
|
||||||
|
// $d->setRelation('mailAliases', $d->mailAliases()->orderBy('local')->get());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ---- Anzeige vorbereiten (mit korrekter Prozent-Berechnung) ----
|
||||||
|
// foreach ($domains as $d) {
|
||||||
|
// $prepared = [];
|
||||||
|
// $domainActive = (bool)($d->is_active ?? true);
|
||||||
|
//
|
||||||
|
// foreach ($d->mailUsers as $u) {
|
||||||
|
// // Stats aus Settings (Redis → DB Fallback)
|
||||||
|
// $stats = Setting::get("mailbox.{$u->email}", []);
|
||||||
|
// $usedBytes = (int)($stats['used_bytes'] ?? ($u->used_bytes ?? 0));
|
||||||
|
// $messageCount = (int)($stats['message_count'] ?? ($u->message_count ?? 0));
|
||||||
|
//
|
||||||
|
// // Anzeige in MiB (nur fürs UI runden)
|
||||||
|
// $usedMiB = (float)round($usedBytes / 1048576, 2);
|
||||||
|
// $quotaMiB = (int)($u->quota_mb ?? 0);
|
||||||
|
//
|
||||||
|
// // Prozent aus Bytes/Quota (ohne Vorab-Rundung auf MiB!)
|
||||||
|
// $usage = $quotaMiB > 0
|
||||||
|
// ? min(100, (int)round($usedBytes / ($quotaMiB * 1048576) * 100))
|
||||||
|
// : 0;
|
||||||
|
//
|
||||||
|
// $mailboxActive = (bool)($u->is_active ?? true);
|
||||||
|
// $effective = $domainActive && $mailboxActive;
|
||||||
|
//
|
||||||
|
// $reason = null;
|
||||||
|
// if (!$effective) {
|
||||||
|
// $reason = !$domainActive ? 'Domain inaktiv'
|
||||||
|
// : (!$mailboxActive ? 'Postfach inaktiv' : null);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $prepared[] = [
|
||||||
|
// 'id' => $u->id,
|
||||||
|
// 'localpart' => (string)$u->localpart,
|
||||||
|
// 'quota_mb' => $quotaMiB,
|
||||||
|
// 'used_mb' => $usedMiB,
|
||||||
|
// 'usage_percent' => $usage,
|
||||||
|
// 'message_count' => $messageCount,
|
||||||
|
// 'is_active' => $mailboxActive,
|
||||||
|
// 'is_effective_active' => $effective,
|
||||||
|
// 'inactive_reason' => $reason,
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $d->prepared_mailboxes = $prepared;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return view('livewire.ui.mail.mailbox-list', [
|
||||||
|
// 'domains' => $domains,
|
||||||
|
// 'system' => $this->showSystemCard ? $system : null,
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
//namespace App\Livewire\Ui\Mail;
|
//namespace App\Livewire\Ui\Mail;
|
||||||
//
|
//
|
||||||
//use App\Models\Domain;
|
//use App\Models\Domain;
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,21 @@ class AppServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
Domain::observe(DomainObserver::class);
|
Domain::observe(DomainObserver::class);
|
||||||
|
|
||||||
$ver = trim(@file_get_contents(base_path('VERSION'))) ?: 'dev';
|
// $ver = trim(@file_get_contents(base_path('VERSION'))) ?: 'dev';
|
||||||
config(['app.version' => $ver]);
|
// config(['app.version' => $ver]);
|
||||||
|
|
||||||
|
|
||||||
|
config(['app.version' => trim(@file_get_contents('/var/lib/mailwolt/version')) ?: 'dev']);
|
||||||
|
if (file_exists(base_path('.git/HEAD'))) {
|
||||||
|
$ref = trim(file_get_contents(base_path('.git/HEAD')));
|
||||||
|
if (str_starts_with($ref, 'ref:')) {
|
||||||
|
$refFile = base_path('.git/' . substr($ref, 5));
|
||||||
|
$commit = @file_get_contents($refFile);
|
||||||
|
} else {
|
||||||
|
$commit = $ref;
|
||||||
|
}
|
||||||
|
config(['app.git_commit' => substr($commit ?? '', 0, 7)]);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$S = app(\App\Support\SettingsRepository::class);
|
$S = app(\App\Support\SettingsRepository::class);
|
||||||
|
|
|
||||||
|
|
@ -123,5 +123,6 @@ return [
|
||||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
],
|
],
|
||||||
|
|
||||||
'version' => env('APP_VERSION', '1.0.0')
|
'version' => env('APP_VERSION', '1.0.0'),
|
||||||
|
'git_commit' => env('APP_GIT_COMMIT', ''),
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
<div class="p-3 border-t hr flex justify-between items-center">
|
<div class="p-3 border-t hr flex justify-between items-center">
|
||||||
{{-- Version (z.B. aus config/app.php 'version' oder env) --}}
|
{{-- Version (z.B. aus config/app.php 'version' oder env) --}}
|
||||||
<div class="sidebar-label text-[10px] text-slate-300/70">
|
<div class="sidebar-label text-[10px] text-slate-300/70">
|
||||||
MailWolt <span class="font-semibold">{{ config('app.version', 'v1.0.0') }}</span>
|
<span class="text-xs text-white/40">v{{ config('app.version') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
|
|
||||||
|
|
@ -305,10 +305,11 @@
|
||||||
<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="updateMailboxStatsOne('{{ $u['localpart'].'@'.$domain->domain }}')">Jetzt aktualisieren</button>--}}
|
{{-- <button wire:click="updateMailboxStatsOne('{{ $u['localpart'].'@'.$domain->domain }}')">Jetzt aktualisieren</button>--}}
|
||||||
|
|
||||||
<button wire:click="updateMailboxStats"
|
<button wire:click="updateMailboxStats"
|
||||||
class="px-3 py-1 text-sm rounded-md bg-blue-600 text-white hover:bg-blue-700 transition">
|
class="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs
|
||||||
Jetzt aktualisieren
|
bg-blue-500/20 text-blue-200 border border-blue-400/40
|
||||||
|
hover:bg-blue-500/30 hover:text-white transition">
|
||||||
|
<i class="ph ph-arrow-clockwise text-[12px]"></i> Jetzt aktualisieren
|
||||||
</button>
|
</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">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue