2200 lines
83 KiB
PHP
2200 lines
83 KiB
PHP
<?php
|
|
|
|
|
|
namespace App\Livewire\Ui\Mail\Modal;
|
|
|
|
use App\Models\Domain;
|
|
use App\Models\MailAlias;
|
|
use App\Models\MailUser;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
use LivewireUI\Modal\ModalComponent;
|
|
|
|
class AliasFormModal extends ModalComponent
|
|
{
|
|
// Eingabe / State
|
|
public ?int $aliasId = null;
|
|
public ?int $domainId = null;
|
|
public string $local = '';
|
|
public string $type = 'single'; // single|group
|
|
public ?string $group_name = null;
|
|
public bool $is_active = true;
|
|
public ?string $notes = null;
|
|
|
|
public array $recipients = [];
|
|
|
|
// UI
|
|
public int $maxGroupRecipients = 20;
|
|
public bool $canAddRecipient = false;
|
|
public array $rowState = [];
|
|
public array $disabledMailboxIdsByRow = [];
|
|
public array $rowDuplicateError = [];
|
|
|
|
// Lookup
|
|
public ?Domain $domain = null;
|
|
/** @var \Illuminate\Support\Collection<int,\App\Models\MailUser> */
|
|
public $domainMailUsers;
|
|
|
|
// -------------------- Lifecycle --------------------
|
|
|
|
public function mount(?int $aliasId = null, ?int $domainId = null): void
|
|
{
|
|
$this->aliasId = $aliasId;
|
|
$this->domainId = $domainId;
|
|
|
|
if ($this->aliasId) {
|
|
$alias = MailAlias::with(['domain', 'recipients.mailUser'])->findOrFail($this->aliasId);
|
|
if ($alias->domain->is_system) abort(403, 'System-Domains sind für Aliasse gesperrt.');
|
|
|
|
$this->domain = $alias->domain;
|
|
$this->domainId = $alias->domain_id;
|
|
|
|
$this->fill([
|
|
'local' => $alias->local,
|
|
'type' => $alias->type,
|
|
'group_name' => $alias->group_name,
|
|
'is_active' => $alias->is_active,
|
|
'notes' => $alias->notes,
|
|
]);
|
|
|
|
// vorhandene Empfänger -> mit stabiler id versehen
|
|
$this->recipients = $alias->recipients
|
|
->map(fn($r) => [
|
|
'id' => (string)Str::uuid(),
|
|
'mail_user_id' => $r->mail_user_id,
|
|
'email' => $r->email,
|
|
])
|
|
->all();
|
|
} else {
|
|
$this->domain = $this->domainId
|
|
? Domain::where('is_system', false)->findOrFail($this->domainId)
|
|
: Domain::where('is_system', false)->orderBy('domain')->first();
|
|
|
|
$this->domainId = $this->domain->id ?? null;
|
|
|
|
$this->recipients = [[
|
|
'id' => (string)Str::uuid(),
|
|
'mail_user_id' => null,
|
|
'email' => null,
|
|
]];
|
|
}
|
|
|
|
$this->domainMailUsers = $this->domain
|
|
? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
: collect();
|
|
|
|
$this->ensureAtLeastOneRow();
|
|
$this->recomputeUi();
|
|
$this->validateRecipientDuplicates();
|
|
}
|
|
|
|
// -------------------- UI-Reaktionen --------------------
|
|
|
|
public function updated($name, $value): void
|
|
{
|
|
// XOR je Zeile
|
|
if (preg_match('/^recipients\.(\d+)\.(mail_user_id|email)$/', $name, $m)) {
|
|
$i = (int)$m[1];
|
|
if ($m[2] === 'mail_user_id' && !empty($value)) {
|
|
$this->recipients[$i]['email'] = null;
|
|
} elseif ($m[2] === 'email') {
|
|
$this->recipients[$i]['mail_user_id'] = null;
|
|
$this->recipients[$i]['email'] = Str::lower(trim((string)$this->recipients[$i]['email']));
|
|
}
|
|
}
|
|
|
|
// Self-Loop Live-Feedback (extern == alias)
|
|
if (preg_match('/^recipients\.(\d+)\.email$/', $name, $m)) {
|
|
$i = (int)$m[1];
|
|
$self = $this->currentAliasAddress();
|
|
$this->resetErrorBag("recipients.$i.email");
|
|
if ($self && Str::lower(trim((string)$this->recipients[$i]['email'])) === $self) {
|
|
$this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
}
|
|
}
|
|
|
|
if ($name === 'type' && $this->type === 'single') {
|
|
$first = $this->recipients[0] ?? ['id' => (string)Str::uuid(), 'mail_user_id' => null, 'email' => null];
|
|
$first['id'] = $first['id'] ?? (string)Str::uuid();
|
|
$this->recipients = [$first];
|
|
}
|
|
|
|
$this->ensureAtLeastOneRow();
|
|
$this->recomputeUi();
|
|
$this->validateRecipientDuplicates();
|
|
}
|
|
|
|
public function updatedType(string $value): void
|
|
{
|
|
if ($value === 'single') {
|
|
$first = $this->recipients[0] ?? ['id' => (string)Str::uuid(), 'mail_user_id' => null, 'email' => null];
|
|
$first['id'] = $first['id'] ?? (string)Str::uuid();
|
|
$this->recipients = [$first];
|
|
$this->recomputeUi();
|
|
$this->validateRecipientDuplicates();
|
|
}
|
|
}
|
|
|
|
public function updatedDomainId(): void
|
|
{
|
|
$this->domain = $this->domainId
|
|
? Domain::where('is_system', false)->find($this->domainId)
|
|
: null;
|
|
|
|
$this->domainMailUsers = $this->domain
|
|
? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
: collect();
|
|
|
|
// Zeilen resetten (neue Domain)
|
|
$this->recipients = [[
|
|
'id' => (string)Str::uuid(),
|
|
'mail_user_id' => null,
|
|
'email' => null,
|
|
]];
|
|
|
|
$this->ensureAtLeastOneRow();
|
|
$this->recomputeUi();
|
|
$this->validateRecipientDuplicates();
|
|
}
|
|
|
|
public function addRecipientRow(): void
|
|
{
|
|
if ($this->type === 'single') return;
|
|
if (count($this->recipients) >= $this->maxGroupRecipients) return;
|
|
|
|
$this->recipients[] = ['id' => (string)Str::uuid(), 'mail_user_id' => null, 'email' => null];
|
|
$this->recomputeUi();
|
|
}
|
|
|
|
public function removeRecipientRow(int $index): void
|
|
{
|
|
unset($this->recipients[$index]);
|
|
$this->recipients = array_values($this->recipients);
|
|
$this->ensureAtLeastOneRow();
|
|
$this->recomputeUi();
|
|
$this->validateRecipientDuplicates();
|
|
}
|
|
|
|
// -------------------- Helpers --------------------
|
|
|
|
private function currentAliasAddress(): ?string
|
|
{
|
|
if (!$this->domainId || $this->local === '') return null;
|
|
|
|
$domainName = $this->domain?->domain ?? Domain::find($this->domainId)?->domain;
|
|
if (!$domainName) return null;
|
|
|
|
return Str::lower(trim($this->local)) . '@' . Str::lower($domainName);
|
|
}
|
|
|
|
private function ensureAtLeastOneRow(): void
|
|
{
|
|
if (empty($this->recipients)) {
|
|
$this->recipients = [[
|
|
'id' => (string)Str::uuid(),
|
|
'mail_user_id' => null,
|
|
'email' => null,
|
|
]];
|
|
}
|
|
}
|
|
|
|
private function recomputeUi(): void
|
|
{
|
|
$count = count($this->recipients);
|
|
$this->canAddRecipient = $this->type === 'group' && $count < $this->maxGroupRecipients;
|
|
|
|
$usedMailboxIds = [];
|
|
$usedExternal = [];
|
|
|
|
foreach ($this->recipients as $r) {
|
|
if (!empty($r['mail_user_id'])) $usedMailboxIds[] = (int)$r['mail_user_id'];
|
|
if (!empty($r['email'])) $usedExternal[] = Str::lower(trim((string)$r['email']));
|
|
}
|
|
|
|
$this->disabledMailboxIdsByRow = [];
|
|
$this->rowState = [];
|
|
$this->rowDuplicateError = [];
|
|
|
|
$aliasAddr = $this->currentAliasAddress();
|
|
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$myId = (int)($this->recipients[$i]['mail_user_id'] ?? 0);
|
|
$hasInternal = $myId > 0;
|
|
$hasExternal = !empty($this->recipients[$i]['email']);
|
|
$myExternal = Str::lower(trim((string)($this->recipients[$i]['email'] ?? '')));
|
|
|
|
// andere interne IDs sperren
|
|
$disabled = array_values(array_unique(array_filter(
|
|
$usedMailboxIds, fn($id) => $id && $id !== $myId
|
|
)));
|
|
|
|
// interne IDs sperren, deren Adresse in externen Feldern vorkommt
|
|
if ($this->domain) {
|
|
foreach ($this->domainMailUsers as $mu) {
|
|
$addr = Str::lower($mu->localpart . '@' . $this->domain->domain);
|
|
if (in_array($addr, $usedExternal, true) && $mu->id !== $myId) {
|
|
$disabled[] = (int)$mu->id;
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->disabledMailboxIdsByRow[$i] = array_values(array_unique($disabled));
|
|
|
|
$this->rowState[$i] = [
|
|
'disable_internal' => $hasExternal || ($aliasAddr && $aliasAddr === $myExternal),
|
|
'disable_external' => $hasInternal,
|
|
'can_remove' => !($this->type === 'single' && $count === 1),
|
|
];
|
|
}
|
|
}
|
|
|
|
private function validateRecipientDuplicates(): bool
|
|
{
|
|
$this->resetErrorBag();
|
|
|
|
$values = [];
|
|
$byAddr = [];
|
|
|
|
foreach ($this->recipients as $i => $r) {
|
|
$addr = null;
|
|
|
|
if (!empty($r['mail_user_id']) && $this->domain) {
|
|
$u = MailUser::find((int)$r['mail_user_id']);
|
|
if ($u) $addr = Str::lower($u->localpart . '@' . $this->domain->domain);
|
|
} elseif (!empty($r['email'])) {
|
|
$addr = Str::lower(trim((string)$r['email']));
|
|
}
|
|
|
|
if ($addr) {
|
|
$values[$i] = $addr;
|
|
$byAddr[$addr] = $byAddr[$addr] ?? [];
|
|
$byAddr[$addr][] = $i;
|
|
}
|
|
}
|
|
|
|
$hasDupes = false;
|
|
foreach ($byAddr as $addr => $idxs) {
|
|
if (count($idxs) <= 1) continue;
|
|
$hasDupes = true;
|
|
foreach ($idxs as $i) {
|
|
if (!empty($this->recipients[$i]['mail_user_id'])) {
|
|
$this->addError("recipients.$i.mail_user_id", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
} else {
|
|
$this->addError("recipients.$i.email", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
}
|
|
}
|
|
}
|
|
|
|
return $hasDupes;
|
|
}
|
|
|
|
private function aliasConflictsWithMailbox(): bool
|
|
{
|
|
if (!$this->domainId || $this->local === '') return false;
|
|
|
|
$local = Str::lower(trim($this->local));
|
|
return MailUser::query()
|
|
->where('domain_id', $this->domainId)
|
|
->whereRaw('LOWER(localpart) = ?', [$local])
|
|
->exists();
|
|
}
|
|
|
|
// -------------------- Save --------------------
|
|
|
|
public function save(): void
|
|
{
|
|
$this->validate($this->rules(), $this->messages());
|
|
|
|
foreach ($this->recipients as $i => $r) {
|
|
if (empty($r['mail_user_id']) && empty($r['email'])) {
|
|
$this->addError("recipients.$i.email", 'Wähle internes Postfach oder externe E-Mail.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($this->validateRecipientDuplicates()) return;
|
|
|
|
if ($aliasAddr = $this->currentAliasAddress()) {
|
|
foreach ($this->recipients as $i => $r) {
|
|
if (!empty($r['email']) && Str::lower(trim((string)$r['email'])) === $aliasAddr) {
|
|
$this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
return;
|
|
}
|
|
if (!empty($r['mail_user_id'])) {
|
|
$u = MailUser::find((int)$r['mail_user_id']);
|
|
if ($u && $this->domain && Str::lower($u->localpart . '@' . $this->domain->domain) === $aliasAddr) {
|
|
$this->addError("recipients.$i.mail_user_id", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($this->aliasConflictsWithMailbox()) {
|
|
$this->addError('local', 'Diese Adresse ist bereits als Postfach vergeben.');
|
|
return;
|
|
}
|
|
|
|
$rows = collect($this->recipients)
|
|
->map(fn($r) => [
|
|
'mail_user_id' => $r['mail_user_id'] ?: null,
|
|
'email' => isset($r['email']) && $r['email'] !== '' ? Str::lower(trim($r['email'])) : null,
|
|
])
|
|
->filter(fn($r) => $r['mail_user_id'] || $r['email'])
|
|
->values();
|
|
|
|
$isUpdate = (bool) $this->aliasId;
|
|
|
|
DB::transaction(function () use ($rows) {
|
|
/** @var MailAlias $alias */
|
|
$alias = MailAlias::updateOrCreate(
|
|
['id' => $this->aliasId],
|
|
[
|
|
'domain_id' => $this->domainId,
|
|
'local' => $this->local,
|
|
'type' => $this->type,
|
|
'group_name' => $this->type === 'group' ? ($this->group_name ?: null) : null,
|
|
'is_active' => $this->is_active,
|
|
'notes' => $this->notes,
|
|
]
|
|
);
|
|
|
|
$alias->recipients()->delete();
|
|
foreach ($rows as $i => $r) {
|
|
$alias->recipients()->create([
|
|
'mail_user_id' => $r['mail_user_id'],
|
|
'email' => $r['email'],
|
|
'position' => $i,
|
|
]);
|
|
}
|
|
|
|
$this->aliasId = $alias->id;
|
|
});
|
|
|
|
$email = $this->currentAliasAddress();
|
|
if (!$email) {
|
|
$domainName = $this->domain?->domain ?? optional(\App\Models\Domain::find($this->domainId))->domain;
|
|
$email = trim(strtolower($this->local)) . '@' . trim(strtolower((string) $domainName));
|
|
}
|
|
|
|
$this->dispatch('alias:' . ($this->aliasId ? 'updated' : 'created'));
|
|
$this->dispatch('closeModal');
|
|
$typeLabel = $this->type === 'single' ? 'Single-Alias' : 'Gruppen-Alias';
|
|
$action = $this->aliasId ? 'aktualisiert' : 'erstellt';
|
|
|
|
$this->dispatch('toast',
|
|
type: 'done',
|
|
badge: 'Alias',
|
|
title: "$typeLabel $action",
|
|
text: "Der $typeLabel <b>" . e($email) . "</b> wurde erfolgreich $action.",
|
|
duration: 6000
|
|
);
|
|
}
|
|
|
|
// -------------------- Validation --------------------
|
|
|
|
protected function rules(): array
|
|
{
|
|
$occupied = $this->domainId
|
|
? MailUser::query()
|
|
->where('domain_id', $this->domainId)
|
|
->pluck('localpart')
|
|
->map(fn($l) => Str::lower($l))
|
|
->all()
|
|
: [];
|
|
|
|
return [
|
|
'domainId' => ['required', 'exists:domains,id'],
|
|
'local' => [
|
|
'required',
|
|
'regex:/^[A-Za-z0-9._%+-]+$/',
|
|
Rule::unique('mail_aliases', 'local')
|
|
->ignore($this->aliasId)
|
|
->where(fn($q) => $q->where('domain_id', $this->domainId)),
|
|
Rule::notIn($occupied),
|
|
],
|
|
'type' => ['required', 'in:single,group'],
|
|
'group_name' => ['nullable','string','max:80','required_if:type,group'],
|
|
'recipients' => ['array', 'min:1', 'max:' . ($this->type === 'single' ? 1 : $this->maxGroupRecipients)],
|
|
'recipients.*.mail_user_id' => ['nullable', 'exists:mail_users,id'],
|
|
'recipients.*.email' => ['nullable', 'email:rfc'],
|
|
];
|
|
}
|
|
|
|
protected function messages(): array
|
|
{
|
|
return [
|
|
'local.required' => 'Alias-Adresse ist erforderlich.',
|
|
'local.regex' => 'Erlaubt sind Buchstaben, Zahlen und ._%+-',
|
|
'local.unique' => 'Dieser Alias existiert in dieser Domain bereits.',
|
|
'local.not_in' => 'Diese Adresse ist bereits als Postfach vergeben.',
|
|
'recipients.min' => 'Mindestens ein Empfänger ist erforderlich.',
|
|
'recipients.max' => $this->type === 'single'
|
|
? 'Bei „Single“ ist nur ein Empfänger zulässig.'
|
|
: 'Maximal ' . $this->maxGroupRecipients . ' Empfänger erlaubt.',
|
|
];
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.ui.mail.modal.alias-form-modal', [
|
|
'domains' => Domain::where('is_system', false)->orderBy('domain')->get(['id', 'domain']),
|
|
]);
|
|
}
|
|
}
|
|
|
|
//namespace App\Livewire\Ui\Mail\Modal;
|
|
//
|
|
//use App\Models\Domain;
|
|
//use App\Models\MailAlias;
|
|
//use App\Models\MailUser;
|
|
//use Illuminate\Support\Facades\DB;
|
|
//use Illuminate\Support\Str;
|
|
//use Illuminate\Validation\Rule;
|
|
//use LivewireUI\Modal\ModalComponent;
|
|
//
|
|
//class AliasFormModal extends ModalComponent
|
|
//{
|
|
// // Eingabe / State
|
|
// public ?int $aliasId = null;
|
|
// public ?int $domainId = null;
|
|
// public string $local = '';
|
|
// public string $type = 'single'; // single|group
|
|
// public bool $is_active = true;
|
|
// public ?string $notes = null;
|
|
//
|
|
// // Empfänger-Zeilen (each: ['mail_user_id'=>?int, 'email'=>?string])
|
|
// public array $recipients = [];
|
|
//
|
|
// // Stabile Keys je Zeile (für wire:key im Blade)
|
|
// public array $rowKeys = [];
|
|
//
|
|
// // UI-Steuerung (nur Ausgabe im Blade)
|
|
// public int $maxGroupRecipients = 20;
|
|
// public bool $canAddRecipient = false; // „+ Empfänger“ erlauben
|
|
// public array $rowState = []; // [i => ['disable_internal'=>bool,'disable_external'=>bool,'can_remove'=>bool]]
|
|
// public array $disabledMailboxIdsByRow = []; // [i => [ids...]]
|
|
//
|
|
// // Lookup
|
|
// public ?Domain $domain = null;
|
|
// /** @var \Illuminate\Support\Collection<int,\App\Models\MailUser> */
|
|
// public $domainMailUsers;
|
|
//
|
|
// // -------------------- Lifecycle --------------------
|
|
//
|
|
// public function mount(?int $aliasId = null, ?int $domainId = null): void
|
|
// {
|
|
// $this->aliasId = $aliasId;
|
|
// $this->domainId = $domainId;
|
|
//
|
|
// if ($this->aliasId) {
|
|
// $alias = MailAlias::with(['domain', 'recipients.mailUser'])->findOrFail($this->aliasId);
|
|
// if ($alias->domain->is_system) {
|
|
// abort(403, 'System-Domains sind für Aliasse gesperrt.');
|
|
// }
|
|
// $this->domain = $alias->domain;
|
|
// $this->domainId = $alias->domain_id;
|
|
//
|
|
// $this->fill([
|
|
// 'local' => $alias->local,
|
|
// 'type' => $alias->type,
|
|
// 'is_active' => $alias->is_active,
|
|
// 'notes' => $alias->notes,
|
|
// ]);
|
|
//
|
|
// $this->recipients = $alias->recipients
|
|
// ->map(fn($r) => ['mail_user_id' => $r->mail_user_id, 'email' => $r->email])
|
|
// ->all();
|
|
// } else {
|
|
// // erste Nicht-System-Domain
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->findOrFail($this->domainId)
|
|
// : Domain::where('is_system', false)->orderBy('domain')->first();
|
|
//
|
|
// $this->domainId = $this->domain->id ?? null;
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->syncRowKeysToRecipients();
|
|
//
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // sofortige Feldfehler bei vorbefüllten Daten
|
|
// }
|
|
//
|
|
// // -------------------- UI-Reaktionen --------------------
|
|
//
|
|
// public function updated($name, $value): void
|
|
// {
|
|
// // XOR: wenn intern gesetzt -> extern leeren, und umgekehrt
|
|
// if (preg_match('/^recipients\.(\d+)\.(mail_user_id|email)$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// if ($m[2] === 'mail_user_id' && !empty($value)) {
|
|
// $this->recipients[$i]['email'] = null;
|
|
// } elseif ($m[2] === 'email') {
|
|
// $this->recipients[$i]['mail_user_id'] = null;
|
|
// $this->recipients[$i]['email'] = Str::lower(trim((string)$this->recipients[$i]['email']));
|
|
// }
|
|
// }
|
|
//
|
|
// // Self-Loop Live-Feedback: extern == alias
|
|
// if (preg_match('/^recipients\.(\d+)\.email$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// $self = $this->currentAliasAddress();
|
|
// $this->resetErrorBag("recipients.$i.email");
|
|
// if ($self && Str::lower(trim((string)$this->recipients[$i]['email'])) === $self) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// }
|
|
// }
|
|
//
|
|
// if ($name === 'type' && $this->type === 'single') {
|
|
// $this->recipients = [$this->recipients[0] ?? ['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->syncRowKeysToRecipients();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // feldgenaues Feedback live
|
|
// }
|
|
//
|
|
// public function updatedType(string $value): void
|
|
// {
|
|
// if ($value === 'single') {
|
|
// $first = $this->recipients[0] ?? ['mail_user_id' => null, 'email' => null];
|
|
// $this->recipients = [$first];
|
|
// $this->syncRowKeysToRecipients();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
// }
|
|
//
|
|
// public function updatedDomainId(): void
|
|
// {
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->find($this->domainId)
|
|
// : null;
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// // Zeilen resetten, weil Empfänger domaingebunden sind
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->syncRowKeysToRecipients();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// public function addRecipientRow(): void
|
|
// {
|
|
// if ($this->type === 'single') return;
|
|
// if (count($this->recipients) >= $this->maxGroupRecipients) return;
|
|
//
|
|
// $this->recipients[] = ['mail_user_id' => null, 'email' => null];
|
|
// $this->rowKeys[] = (string)Str::uuid(); // stabiler Key für neue Zeile
|
|
//
|
|
// $this->recomputeUi();
|
|
// // kein Duplicate hier, weil leer
|
|
// }
|
|
//
|
|
// public function removeRecipientRow(int $index): void
|
|
// {
|
|
// unset($this->recipients[$index], $this->rowKeys[$index]);
|
|
// $this->recipients = array_values($this->recipients);
|
|
// $this->rowKeys = array_values($this->rowKeys);
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->syncRowKeysToRecipients();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// // -------------------- Helpers --------------------
|
|
//
|
|
// // vollständige Alias-Adresse (z.B. "info@pixio.at") oder null
|
|
// private function currentAliasAddress(): ?string
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return null;
|
|
//
|
|
// $domainName = $this->domain?->domain ?? Domain::find($this->domainId)?->domain;
|
|
// if (!$domainName) return null;
|
|
//
|
|
// return Str::lower(trim($this->local)) . '@' . Str::lower($domainName);
|
|
// }
|
|
//
|
|
// private function ensureAtLeastOneRow(): void
|
|
// {
|
|
// if (empty($this->recipients)) {
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
// }
|
|
//
|
|
// // rowKeys-Liste immer an recipients-Länge anpassen (stabile wire:key Werte)
|
|
// private function syncRowKeysToRecipients(): void
|
|
// {
|
|
// $need = count($this->recipients);
|
|
// $have = count($this->rowKeys);
|
|
//
|
|
// // auffüllen
|
|
// while ($have < $need) {
|
|
// $this->rowKeys[] = (string)Str::uuid();
|
|
// $have++;
|
|
// }
|
|
// // kürzen
|
|
// if ($have > $need) {
|
|
// $this->rowKeys = array_slice($this->rowKeys, 0, $need);
|
|
// }
|
|
// }
|
|
//
|
|
// // UI neu berechnen (inkl. Self-Loop-Schutz)
|
|
// private function recomputeUi(): void
|
|
// {
|
|
// $count = count($this->recipients);
|
|
// $this->canAddRecipient = $this->type === 'group' && $count < $this->maxGroupRecipients;
|
|
//
|
|
// // bereits gewählte interne IDs und externe Adressen einsammeln
|
|
// $usedMailboxIds = [];
|
|
// $usedExternalAddr = [];
|
|
//
|
|
// foreach ($this->recipients as $r) {
|
|
// if (!empty($r['mail_user_id'])) $usedMailboxIds[] = (int)$r['mail_user_id'];
|
|
// if (!empty($r['email'])) $usedExternalAddr[] = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow = [];
|
|
// $this->rowState = [];
|
|
//
|
|
// // Aktuelle Alias-Adresse für Self-Loop-Checks
|
|
// $aliasAddr = $this->currentAliasAddress();
|
|
//
|
|
// for ($i = 0; $i < $count; $i++) {
|
|
// $myId = (int)($this->recipients[$i]['mail_user_id'] ?? 0);
|
|
// $hasInternal = $myId > 0;
|
|
// $hasExternal = !empty($this->recipients[$i]['email']);
|
|
// $myExternal = Str::lower(trim((string)($this->recipients[$i]['email'] ?? '')));
|
|
//
|
|
// // andere bereits gewählte interne IDs sperren
|
|
// $disabled = array_values(array_unique(array_filter(
|
|
// $usedMailboxIds, fn($id) => $id && $id !== $myId
|
|
// )));
|
|
//
|
|
// // interne IDs zusätzlich sperren, deren Adresse in irgendeinem externen Feld steht
|
|
// if ($this->domain) {
|
|
// foreach ($this->domainMailUsers as $mu) {
|
|
// $addr = Str::lower($mu->localpart . '@' . $this->domain->domain);
|
|
// if (in_array($addr, $usedExternalAddr, true) && $mu->id !== $myId) {
|
|
// $disabled[] = (int)$mu->id;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow[$i] = array_values(array_unique($disabled));
|
|
//
|
|
// // Self-Loop: wenn extern == alias, internen Picker sperren
|
|
// $disableInternal = $hasExternal || ($aliasAddr && $aliasAddr === $myExternal);
|
|
//
|
|
// $this->rowState[$i] = [
|
|
// 'disable_internal' => $disableInternal, // XOR + Self-Loop
|
|
// 'disable_external' => $hasInternal, // XOR
|
|
// 'can_remove' => !($this->type === 'single' && $count === 1),
|
|
// ];
|
|
// }
|
|
// }
|
|
//
|
|
// // Duplikate feldgenau markieren (keine Exceptions)
|
|
// private function validateRecipientDuplicates(): bool
|
|
// {
|
|
// // komplette Empfänger-Fehler zurücksetzen
|
|
// $this->resetErrorBag();
|
|
//
|
|
// // Map Zeile -> normalisierte Zieladresse (intern => local@domain, extern => email)
|
|
// $values = []; // [i => 'addr']
|
|
// $byAddrIndices = []; // 'addr' => [i1,i2,...]
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// $addr = null;
|
|
//
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// if ($this->domain) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u) $addr = Str::lower($u->localpart . '@' . $this->domain->domain);
|
|
// }
|
|
// } elseif (!empty($r['email'])) {
|
|
// $addr = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// if ($addr) {
|
|
// $values[$i] = $addr;
|
|
// $byAddrIndices[$addr] = $byAddrIndices[$addr] ?? [];
|
|
// $byAddrIndices[$addr][] = $i;
|
|
// }
|
|
// }
|
|
//
|
|
// $hasDupes = false;
|
|
//
|
|
// foreach ($byAddrIndices as $addr => $indices) {
|
|
// if (count($indices) <= 1) continue;
|
|
// $hasDupes = true;
|
|
// // alle betroffenen Felder markieren (feldgenau)
|
|
// foreach ($indices as $i) {
|
|
// if (!empty($this->recipients[$i]['mail_user_id'])) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// } else {
|
|
// $this->addError("recipients.$i.email", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// return $hasDupes;
|
|
// }
|
|
//
|
|
// private function aliasConflictsWithMailbox(): bool
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return false;
|
|
//
|
|
// $local = Str::lower(trim($this->local));
|
|
// return MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->whereRaw('LOWER(localpart) = ?', [$local])
|
|
// ->exists();
|
|
// }
|
|
//
|
|
// // -------------------- Save --------------------
|
|
//
|
|
// public function save(): void
|
|
// {
|
|
// // 1) Basisregeln
|
|
// $this->validate($this->rules(), $this->messages());
|
|
//
|
|
// // 2) Zeilen dürfen nicht leer sein (weder intern noch extern)
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// if (empty($r['mail_user_id']) && empty($r['email'])) {
|
|
// $this->addError("recipients.$i.email", 'Wähle internes Postfach oder externe E-Mail.');
|
|
// return;
|
|
// }
|
|
// }
|
|
//
|
|
// // 3) Duplikate feldgenau prüfen
|
|
// if ($this->validateRecipientDuplicates()) {
|
|
// return;
|
|
// }
|
|
//
|
|
// // 3b) Self-Loop final abfangen
|
|
// if ($aliasAddr = $this->currentAliasAddress()) {
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// // extern
|
|
// if (!empty($r['email']) && Str::lower(trim((string)$r['email'])) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// // intern (falls je relevant)
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u && $this->domain && Str::lower($u->localpart . '@' . $this->domain->domain) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// // 4) Alias-Adresse darf kein bestehendes Postfach sein
|
|
// if ($this->aliasConflictsWithMailbox()) {
|
|
// $this->addError('local', 'Diese Adresse ist bereits als Postfach vergeben.');
|
|
// return;
|
|
// }
|
|
//
|
|
// // 5) Persistieren
|
|
// $rows = collect($this->recipients)
|
|
// ->map(fn($r) => [
|
|
// 'mail_user_id' => $r['mail_user_id'] ?: null,
|
|
// 'email' => isset($r['email']) && $r['email'] !== '' ? Str::lower(trim($r['email'])) : null,
|
|
// ])
|
|
// ->filter(fn($r) => $r['mail_user_id'] || $r['email'])
|
|
// ->values();
|
|
//
|
|
// DB::transaction(function () use ($rows) {
|
|
// /** @var MailAlias $alias */
|
|
// $alias = MailAlias::updateOrCreate(
|
|
// ['id' => $this->aliasId],
|
|
// [
|
|
// 'domain_id' => $this->domainId,
|
|
// 'local' => $this->local,
|
|
// 'type' => $this->type,
|
|
// 'is_active' => $this->is_active,
|
|
// 'notes' => $this->notes,
|
|
// ]
|
|
// );
|
|
//
|
|
// $alias->recipients()->delete();
|
|
// foreach ($rows as $i => $r) {
|
|
// $alias->recipients()->create([
|
|
// 'mail_user_id' => $r['mail_user_id'],
|
|
// 'email' => $r['email'],
|
|
// 'position' => $i,
|
|
// ]);
|
|
// }
|
|
//
|
|
// $this->aliasId = $alias->id;
|
|
// });
|
|
//
|
|
// $this->dispatch('alias:' . ($this->aliasId ? 'updated' : 'created'));
|
|
// $this->dispatch('closeModal');
|
|
// }
|
|
//
|
|
// // -------------------- Validation --------------------
|
|
//
|
|
// protected function rules(): array
|
|
// {
|
|
// // blocke offensichtliche Kollisionen mit Mailboxen (gleiche Domain)
|
|
// $occupied = $this->domainId
|
|
// ? MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->pluck('localpart')
|
|
// ->map(fn($l) => Str::lower($l))
|
|
// ->all()
|
|
// : [];
|
|
//
|
|
// return [
|
|
// 'domainId' => ['required', 'exists:domains,id'],
|
|
// 'local' => [
|
|
// 'required',
|
|
// 'regex:/^[A-Za-z0-9._%+-]+$/',
|
|
// Rule::unique('mail_aliases', 'local')
|
|
// ->ignore($this->aliasId)
|
|
// ->where(fn($q) => $q->where('domain_id', $this->domainId)),
|
|
// Rule::notIn($occupied),
|
|
// ],
|
|
// 'type' => ['required', 'in:single,group'],
|
|
//
|
|
// 'recipients' => ['array', 'min:1', 'max:' . ($this->type === 'single' ? 1 : $this->maxGroupRecipients)],
|
|
// 'recipients.*.mail_user_id' => ['nullable', 'exists:mail_users,id'],
|
|
// 'recipients.*.email' => ['nullable', 'email:rfc'],
|
|
// ];
|
|
// }
|
|
//
|
|
// protected function messages(): array
|
|
// {
|
|
// return [
|
|
// 'local.required' => 'Alias-Adresse ist erforderlich.',
|
|
// 'local.regex' => 'Erlaubt sind Buchstaben, Zahlen und ._%+-',
|
|
// 'local.unique' => 'Dieser Alias existiert in dieser Domain bereits.',
|
|
// 'local.not_in' => 'Diese Adresse ist bereits als Postfach vergeben.',
|
|
// 'recipients.min' => 'Mindestens ein Empfänger ist erforderlich.',
|
|
// 'recipients.max' => $this->type === 'single'
|
|
// ? 'Bei „Single“ ist nur ein Empfänger zulässig.'
|
|
// : 'Maximal ' . $this->maxGroupRecipients . ' Empfänger erlaubt.',
|
|
// ];
|
|
// }
|
|
//
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.mail.modal.alias-form-modal', [
|
|
// 'domains' => Domain::where('is_system', false)
|
|
// ->orderBy('domain')
|
|
// ->get(['id', 'domain']),
|
|
// ]);
|
|
// }
|
|
//}
|
|
|
|
|
|
//namespace App\Livewire\Ui\Mail\Modal;
|
|
//
|
|
//use App\Models\Domain;
|
|
//use App\Models\MailAlias;
|
|
//use App\Models\MailUser;
|
|
//use Illuminate\Support\Facades\DB;
|
|
//use Illuminate\Support\Str;
|
|
//use Illuminate\Validation\Rule;
|
|
//use LivewireUI\Modal\ModalComponent;
|
|
//
|
|
//class AliasFormModal extends ModalComponent
|
|
//{
|
|
// // Eingabe / State
|
|
// public ?int $aliasId = null;
|
|
// public ?int $domainId = null;
|
|
// public string $local = '';
|
|
// public string $type = 'single'; // single|group
|
|
// public bool $is_active = true;
|
|
// public ?string $notes = null;
|
|
//
|
|
// // Empfänger-Zeilen (each: ['mail_user_id'=>?int, 'email'=>?string])
|
|
// public array $recipients = [];
|
|
//
|
|
// // UI-Steuerung (nur Ausgabe im Blade)
|
|
// public int $maxGroupRecipients = 20;
|
|
// public bool $canAddRecipient = false; // „+ Empfänger“ erlauben
|
|
// public array $rowState = []; // [i => ['disable_internal'=>bool,'disable_external'=>bool,'can_remove'=>bool]]
|
|
// public array $disabledMailboxIdsByRow = []; // [i => [ids...]]
|
|
//
|
|
// // Lookup
|
|
// public ?Domain $domain = null;
|
|
// /** @var \Illuminate\Support\Collection<int,\App\Models\MailUser> */
|
|
// public $domainMailUsers;
|
|
//
|
|
// // -------------------- Lifecycle --------------------
|
|
//
|
|
// public function mount(?int $aliasId = null, ?int $domainId = null): void
|
|
// {
|
|
// $this->aliasId = $aliasId;
|
|
// $this->domainId = $domainId;
|
|
//
|
|
// if ($this->aliasId) {
|
|
// $alias = MailAlias::with(['domain', 'recipients.mailUser'])->findOrFail($this->aliasId);
|
|
// if ($alias->domain->is_system) {
|
|
// abort(403, 'System-Domains sind für Aliasse gesperrt.');
|
|
// }
|
|
// $this->domain = $alias->domain;
|
|
// $this->domainId = $alias->domain_id;
|
|
//
|
|
// $this->fill([
|
|
// 'local' => $alias->local,
|
|
// 'type' => $alias->type,
|
|
// 'is_active' => $alias->is_active,
|
|
// 'notes' => $alias->notes,
|
|
// ]);
|
|
//
|
|
// $this->recipients = $alias->recipients
|
|
// ->map(fn($r) => ['mail_user_id' => $r->mail_user_id, 'email' => $r->email])
|
|
// ->all();
|
|
// } else {
|
|
// // erste Nicht-System-Domain
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->findOrFail($this->domainId)
|
|
// : Domain::where('is_system', false)->orderBy('domain')->first();
|
|
//
|
|
// $this->domainId = $this->domain->id ?? null;
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // sofortige Feldfehler bei vorbefüllten Daten
|
|
// }
|
|
//
|
|
// // -------------------- UI-Reaktionen --------------------
|
|
//
|
|
// public function updated($name, $value): void
|
|
// {
|
|
// // XOR: wenn intern gesetzt -> extern leeren, und umgekehrt
|
|
// if (preg_match('/^recipients\.(\d+)\.(mail_user_id|email)$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// if ($m[2] === 'mail_user_id' && !empty($value)) {
|
|
// $this->recipients[$i]['email'] = null;
|
|
// } elseif ($m[2] === 'email') {
|
|
// $this->recipients[$i]['mail_user_id'] = null;
|
|
// $this->recipients[$i]['email'] = Str::lower(trim((string)$this->recipients[$i]['email']));
|
|
// }
|
|
// }
|
|
//
|
|
// // Self-Loop Live-Feedback: extern == alias
|
|
// if (preg_match('/^recipients\.(\d+)\.email$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// $self = $this->currentAliasAddress();
|
|
// $this->resetErrorBag("recipients.$i.email");
|
|
// if ($self && Str::lower(trim((string)$this->recipients[$i]['email'])) === $self) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// }
|
|
// }
|
|
//
|
|
// if ($name === 'type' && $this->type === 'single') {
|
|
// $this->recipients = [$this->recipients[0] ?? ['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // feldgenaues Feedback live
|
|
// }
|
|
//
|
|
// public function updatedType(string $value): void
|
|
// {
|
|
// if ($value === 'single') {
|
|
// $first = $this->recipients[0] ?? ['mail_user_id' => null, 'email' => null];
|
|
// $this->recipients = [$first];
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
// }
|
|
//
|
|
// public function updatedDomainId(): void
|
|
// {
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->find($this->domainId)
|
|
// : null;
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// // Zeilen resetten, weil Empfänger domaingebunden sind
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// public function addRecipientRow(): void
|
|
// {
|
|
// if ($this->type === 'single') return;
|
|
// if (count($this->recipients) >= $this->maxGroupRecipients) return;
|
|
//
|
|
// $this->recipients[] = ['mail_user_id' => null, 'email' => null];
|
|
// $this->recomputeUi();
|
|
// }
|
|
//
|
|
// public function removeRecipientRow(int $index): void
|
|
// {
|
|
// unset($this->recipients[$index]);
|
|
// $this->recipients = array_values($this->recipients);
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// // -------------------- Helpers --------------------
|
|
//
|
|
// // vollständige Alias-Adresse (z.B. "info@pixio.at") oder null
|
|
// private function currentAliasAddress(): ?string
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return null;
|
|
//
|
|
// $domainName = $this->domain?->domain ?? Domain::find($this->domainId)?->domain;
|
|
// if (!$domainName) return null;
|
|
//
|
|
// return Str::lower(trim($this->local)) . '@' . Str::lower($domainName);
|
|
// }
|
|
//
|
|
// private function ensureAtLeastOneRow(): void
|
|
// {
|
|
// if (empty($this->recipients)) {
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
// }
|
|
//
|
|
// // UI neu berechnen (inkl. Self-Loop-Schutz)
|
|
// private function recomputeUi(): void
|
|
// {
|
|
// $count = count($this->recipients);
|
|
// $this->canAddRecipient = $this->type === 'group' && $count < $this->maxGroupRecipients;
|
|
//
|
|
// // bereits gewählte interne IDs und externe Adressen einsammeln
|
|
// $usedMailboxIds = [];
|
|
// $usedExternalAddr = [];
|
|
//
|
|
// foreach ($this->recipients as $r) {
|
|
// if (!empty($r['mail_user_id'])) $usedMailboxIds[] = (int)$r['mail_user_id'];
|
|
// if (!empty($r['email'])) $usedExternalAddr[] = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow = [];
|
|
// $this->rowState = [];
|
|
//
|
|
// // Aktuelle Alias-Adresse für Self-Loop-Checks
|
|
// $aliasAddr = $this->currentAliasAddress();
|
|
//
|
|
// for ($i = 0; $i < $count; $i++) {
|
|
// $myId = (int)($this->recipients[$i]['mail_user_id'] ?? 0);
|
|
// $hasInternal = $myId > 0;
|
|
// $hasExternal = !empty($this->recipients[$i]['email']);
|
|
// $myExternal = Str::lower(trim((string)($this->recipients[$i]['email'] ?? '')));
|
|
//
|
|
// // andere bereits gewählte internen IDs sperren
|
|
// $disabled = array_values(array_unique(array_filter(
|
|
// $usedMailboxIds, fn($id) => $id && $id !== $myId
|
|
// )));
|
|
//
|
|
// // interne IDs zusätzlich sperren, deren Adresse in irgendeinem externen Feld steht
|
|
// if ($this->domain) {
|
|
// foreach ($this->domainMailUsers as $mu) {
|
|
// $addr = Str::lower($mu->localpart . '@' . $this->domain->domain);
|
|
// if (in_array($addr, $usedExternalAddr, true) && $mu->id !== $myId) {
|
|
// $disabled[] = (int)$mu->id;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow[$i] = array_values(array_unique($disabled));
|
|
//
|
|
// // Self-Loop verhindern: wenn extern == alias, internen Picker sperren
|
|
// $disableInternal = $hasExternal || ($aliasAddr && $aliasAddr === $myExternal);
|
|
//
|
|
// $this->rowState[$i] = [
|
|
// 'disable_internal' => $disableInternal, // XOR + Self-Loop
|
|
// 'disable_external' => $hasInternal, // XOR
|
|
// 'can_remove' => !($this->type === 'single' && $count === 1),
|
|
// ];
|
|
// }
|
|
// }
|
|
//
|
|
// // Duplikate feldgenau markieren (keine Exceptions)
|
|
// private function validateRecipientDuplicates(): bool
|
|
// {
|
|
// // komplette Empfänger-Fehler zurücksetzen
|
|
// $this->resetErrorBag();
|
|
//
|
|
// // Map Zeile -> normalisierte Zieladresse (intern => local@domain, extern => email)
|
|
// $values = []; // [i => 'addr']
|
|
// $byAddrIndices = []; // 'addr' => [i1,i2,...]
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// $addr = null;
|
|
//
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// if ($this->domain) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u) $addr = Str::lower($u->localpart . '@' . $this->domain->domain);
|
|
// }
|
|
// } elseif (!empty($r['email'])) {
|
|
// $addr = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// if ($addr) {
|
|
// $values[$i] = $addr;
|
|
// $byAddrIndices[$addr] = $byAddrIndices[$addr] ?? [];
|
|
// $byAddrIndices[$addr][] = $i;
|
|
// }
|
|
// }
|
|
//
|
|
// $hasDupes = false;
|
|
//
|
|
// foreach ($byAddrIndices as $addr => $indices) {
|
|
// if (count($indices) <= 1) continue;
|
|
// $hasDupes = true;
|
|
// // alle betroffenen Felder markieren (feldgenau)
|
|
// foreach ($indices as $i) {
|
|
// if (!empty($this->recipients[$i]['mail_user_id'])) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// } else {
|
|
// $this->addError("recipients.$i.email", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// return $hasDupes;
|
|
// }
|
|
//
|
|
// private function aliasConflictsWithMailbox(): bool
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return false;
|
|
//
|
|
// $local = Str::lower(trim($this->local));
|
|
// return MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->whereRaw('LOWER(localpart) = ?', [$local])
|
|
// ->exists();
|
|
// }
|
|
//
|
|
// // -------------------- Save --------------------
|
|
//
|
|
// public function save(): void
|
|
// {
|
|
// // 1) Basisregeln
|
|
// $this->validate($this->rules(), $this->messages());
|
|
//
|
|
// // 2) Zeilen dürfen nicht leer sein (weder intern noch extern)
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// if (empty($r['mail_user_id']) && empty($r['email'])) {
|
|
// $this->addError("recipients.$i.email", 'Wähle internes Postfach oder externe E-Mail.');
|
|
// return;
|
|
// }
|
|
// }
|
|
//
|
|
// // 3) Duplikate feldgenau prüfen
|
|
// if ($this->validateRecipientDuplicates()) {
|
|
// return;
|
|
// }
|
|
//
|
|
// // 3b) Self-Loop final abfangen
|
|
// if ($aliasAddr = $this->currentAliasAddress()) {
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// // extern
|
|
// if (!empty($r['email']) && Str::lower(trim((string)$r['email'])) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// // intern (falls je relevant)
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u && $this->domain && Str::lower($u->localpart . '@' . $this->domain->domain) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// // 4) Alias-Adresse darf kein bestehendes Postfach sein
|
|
// if ($this->aliasConflictsWithMailbox()) {
|
|
// $this->addError('local', 'Diese Adresse ist bereits als Postfach vergeben.');
|
|
// return;
|
|
// }
|
|
//
|
|
// // 5) Persistieren
|
|
// $rows = collect($this->recipients)
|
|
// ->map(fn($r) => [
|
|
// 'mail_user_id' => $r['mail_user_id'] ?: null,
|
|
// 'email' => isset($r['email']) && $r['email'] !== '' ? Str::lower(trim($r['email'])) : null,
|
|
// ])
|
|
// ->filter(fn($r) => $r['mail_user_id'] || $r['email'])
|
|
// ->values();
|
|
//
|
|
// DB::transaction(function () use ($rows) {
|
|
// /** @var MailAlias $alias */
|
|
// $alias = MailAlias::updateOrCreate(
|
|
// ['id' => $this->aliasId],
|
|
// [
|
|
// 'domain_id' => $this->domainId,
|
|
// 'local' => $this->local,
|
|
// 'type' => $this->type,
|
|
// 'is_active' => $this->is_active,
|
|
// 'notes' => $this->notes,
|
|
// ]
|
|
// );
|
|
//
|
|
// $alias->recipients()->delete();
|
|
// foreach ($rows as $i => $r) {
|
|
// $alias->recipients()->create([
|
|
// 'mail_user_id' => $r['mail_user_id'],
|
|
// 'email' => $r['email'],
|
|
// 'position' => $i,
|
|
// ]);
|
|
// }
|
|
//
|
|
// $this->aliasId = $alias->id;
|
|
// });
|
|
//
|
|
// $this->dispatch('alias:' . ($this->aliasId ? 'updated' : 'created'));
|
|
// $this->dispatch('closeModal');
|
|
// }
|
|
//
|
|
// // -------------------- Validation --------------------
|
|
//
|
|
// protected function rules(): array
|
|
// {
|
|
// // blocke offensichtliche Kollisionen mit Mailboxen (gleiche Domain)
|
|
// $occupied = $this->domainId
|
|
// ? MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->pluck('localpart')
|
|
// ->map(fn($l) => Str::lower($l))
|
|
// ->all()
|
|
// : [];
|
|
//
|
|
// return [
|
|
// 'domainId' => ['required', 'exists:domains,id'],
|
|
// 'local' => [
|
|
// 'required',
|
|
// 'regex:/^[A-Za-z0-9._%+-]+$/',
|
|
// Rule::unique('mail_aliases', 'local')
|
|
// ->ignore($this->aliasId)
|
|
// ->where(fn($q) => $q->where('domain_id', $this->domainId)),
|
|
// Rule::notIn($occupied),
|
|
// ],
|
|
// 'type' => ['required', 'in:single,group'],
|
|
//
|
|
// 'recipients' => ['array', 'min:1', 'max:' . ($this->type === 'single' ? 1 : $this->maxGroupRecipients)],
|
|
// 'recipients.*.mail_user_id' => ['nullable', 'exists:mail_users,id'],
|
|
// 'recipients.*.email' => ['nullable', 'email:rfc'],
|
|
// ];
|
|
// }
|
|
//
|
|
// protected function messages(): array
|
|
// {
|
|
// return [
|
|
// 'local.required' => 'Alias-Adresse ist erforderlich.',
|
|
// 'local.regex' => 'Erlaubt sind Buchstaben, Zahlen und ._%+-',
|
|
// 'local.unique' => 'Dieser Alias existiert in dieser Domain bereits.',
|
|
// 'local.not_in' => 'Diese Adresse ist bereits als Postfach vergeben.',
|
|
// 'recipients.min' => 'Mindestens ein Empfänger ist erforderlich.',
|
|
// 'recipients.max' => $this->type === 'single'
|
|
// ? 'Bei „Single“ ist nur ein Empfänger zulässig.'
|
|
// : 'Maximal ' . $this->maxGroupRecipients . ' Empfänger erlaubt.',
|
|
// ];
|
|
// }
|
|
//
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.mail.modal.alias-form-modal', [
|
|
// 'domains' => Domain::where('is_system', false)
|
|
// ->orderBy('domain')
|
|
// ->get(['id', 'domain']),
|
|
// ]);
|
|
// }
|
|
//}
|
|
|
|
|
|
|
|
//namespace App\Livewire\Ui\Mail\Modal;
|
|
//
|
|
//use App\Models\Domain;
|
|
//use App\Models\MailAlias;
|
|
//use App\Models\MailUser;
|
|
//use Illuminate\Support\Facades\DB;
|
|
//use Illuminate\Support\Str;
|
|
//use Illuminate\Validation\Rule;
|
|
//use LivewireUI\Modal\ModalComponent;
|
|
//
|
|
//class AliasFormModal extends ModalComponent
|
|
//{
|
|
// // Eingabe / State
|
|
// public ?int $aliasId = null;
|
|
// public ?int $domainId = null;
|
|
// public string $local = '';
|
|
// public string $type = 'single'; // single|group
|
|
// public bool $is_active = true;
|
|
// public ?string $notes = null;
|
|
//
|
|
// // Empfänger-Zeilen (each: ['mail_user_id'=>?int, 'email'=>?string])
|
|
// public array $recipients = [];
|
|
//
|
|
// // UI-Steuerung (nur Ausgabe im Blade)
|
|
// public int $maxGroupRecipients = 20;
|
|
// public bool $canAddRecipient = false; // „+ Empfänger“ erlauben
|
|
// public array $rowState = []; // [i => ['disable_internal'=>bool,'disable_external'=>bool,'can_remove'=>bool]]
|
|
// public array $disabledMailboxIdsByRow = []; // [i => [ids...]]
|
|
//
|
|
// // Lookup
|
|
// public ?Domain $domain = null;
|
|
// /** @var \Illuminate\Support\Collection<int,\App\Models\MailUser> */
|
|
// public $domainMailUsers;
|
|
//
|
|
// // -------------------- Lifecycle --------------------
|
|
//
|
|
// public function mount(?int $aliasId = null, ?int $domainId = null): void
|
|
// {
|
|
// $this->aliasId = $aliasId;
|
|
// $this->domainId = $domainId;
|
|
//
|
|
// if ($this->aliasId) {
|
|
// $alias = MailAlias::with(['domain','recipients.mailUser'])->findOrFail($this->aliasId);
|
|
// if ($alias->domain->is_system) {
|
|
// abort(403, 'System-Domains sind für Aliasse gesperrt.');
|
|
// }
|
|
// $this->domain = $alias->domain;
|
|
// $this->domainId = $alias->domain_id;
|
|
//
|
|
// $this->fill([
|
|
// 'local' => $alias->local,
|
|
// 'type' => $alias->type,
|
|
// 'is_active' => $alias->is_active,
|
|
// 'notes' => $alias->notes,
|
|
// ]);
|
|
//
|
|
// $this->recipients = $alias->recipients
|
|
// ->map(fn($r) => ['mail_user_id' => $r->mail_user_id, 'email' => $r->email])
|
|
// ->all();
|
|
// } else {
|
|
// // erste Nicht-System-Domain
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->findOrFail($this->domainId)
|
|
// : Domain::where('is_system', false)->orderBy('domain')->first();
|
|
//
|
|
// $this->domainId = $this->domain->id ?? null;
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // sofortige Feldfehler bei vorbefüllten Daten
|
|
// }
|
|
//
|
|
// // -------------------- UI-Reaktionen --------------------
|
|
//
|
|
// public function updated($name, $value): void
|
|
// {
|
|
// // XOR: wenn intern gesetzt -> extern leeren, und umgekehrt
|
|
// if (preg_match('/^recipients\.(\d+)\.(mail_user_id|email)$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// if ($m[2] === 'mail_user_id' && !empty($value)) {
|
|
// $this->recipients[$i]['email'] = null;
|
|
// } elseif ($m[2] === 'email') {
|
|
// $this->recipients[$i]['mail_user_id'] = null;
|
|
// $this->recipients[$i]['email'] = Str::lower(trim((string)$this->recipients[$i]['email']));
|
|
// }
|
|
// }
|
|
//
|
|
// if (preg_match('/^recipients\.(\d+)\.email$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// $self = $this->currentAliasAddress();
|
|
// $this->resetErrorBag("recipients.$i.email");
|
|
// if ($self && \Illuminate\Support\Str::lower(trim((string)$this->recipients[$i]['email'])) === $self) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// }
|
|
// }
|
|
//
|
|
// if ($name === 'type' && $this->type === 'single') {
|
|
// $this->recipients = [ $this->recipients[0] ?? ['mail_user_id'=>null,'email'=>null] ];
|
|
// }
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates(); // feldgenaues Feedback live
|
|
// }
|
|
//
|
|
// public function updatedType(string $value): void
|
|
// {
|
|
// if ($value === 'single') {
|
|
// $first = $this->recipients[0] ?? ['mail_user_id'=>null,'email'=>null];
|
|
// $this->recipients = [ $first ];
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
// }
|
|
//
|
|
// public function updatedDomainId(): void
|
|
// {
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->find($this->domainId)
|
|
// : null;
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// // Zeilen resetten, weil Empfänger domaingebunden sind
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// public function addRecipientRow(): void
|
|
// {
|
|
// if ($this->type === 'single') return;
|
|
// if (count($this->recipients) >= $this->maxGroupRecipients) return;
|
|
//
|
|
// $this->recipients[] = ['mail_user_id'=>null,'email'=>null];
|
|
// $this->recomputeUi();
|
|
// // kein Duplicate hier, weil leer
|
|
// }
|
|
//
|
|
// public function removeRecipientRow(int $index): void
|
|
// {
|
|
// unset($this->recipients[$index]);
|
|
// $this->recipients = array_values($this->recipients);
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// // -------------------- Helpers --------------------
|
|
//
|
|
// private function currentAliasAddress(): ?string
|
|
// {
|
|
// if (!$this->domainId || $this->local === '' || !$this->domain) return null;
|
|
// return \Illuminate\Support\Str::lower(trim($this->local).'@'.$this->domain->domain);
|
|
// }
|
|
//
|
|
// private function ensureAtLeastOneRow(): void
|
|
// {
|
|
// if (empty($this->recipients)) {
|
|
// $this->recipients = [['mail_user_id'=>null,'email'=>null]];
|
|
// }
|
|
// }
|
|
//
|
|
// private function recomputeUi(): void
|
|
// {
|
|
// $count = count($this->recipients);
|
|
// $this->canAddRecipient = $this->type === 'group' && $count < $this->maxGroupRecipients;
|
|
//
|
|
// // bereits gewählte interne IDs und externe Adressen einsammeln
|
|
// $usedMailboxIds = [];
|
|
// $usedExternalAddrs = []; // ['a@b.tld', ...] normalisiert
|
|
//
|
|
// foreach ($this->recipients as $r) {
|
|
// if (!empty($r['mail_user_id'])) $usedMailboxIds[] = (int)$r['mail_user_id'];
|
|
// if (!empty($r['email'])) $usedExternalAddrs[] = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow = [];
|
|
// $this->rowState = [];
|
|
//
|
|
// // Helper: internes Postfach -> vollständige Adresse
|
|
// $mailboxEmail = function (?int $id): ?string {
|
|
// if (!$id || !$this->domain) return null;
|
|
// $u = MailUser::find($id);
|
|
// return $u ? Str::lower($u->localpart.'@'.$this->domain->domain) : null;
|
|
// };
|
|
//
|
|
// for ($i = 0; $i < $count; $i++) {
|
|
// $myId = (int)($this->recipients[$i]['mail_user_id'] ?? 0);
|
|
// $hasInternal = $myId > 0;
|
|
// $hasExternal = !empty($this->recipients[$i]['email']);
|
|
//
|
|
// // Basis: andere bereits gewählte interne IDs sperren
|
|
// $disabled = array_values(array_unique(array_filter(
|
|
// $usedMailboxIds, fn($id) => $id && $id !== $myId
|
|
// )));
|
|
//
|
|
// // Zusätzlich: interne IDs sperren, deren Adresse in irgendeinem externen Feld steht
|
|
// if ($this->domain) {
|
|
// foreach ($this->domainMailUsers as $mu) {
|
|
// $addr = Str::lower($mu->localpart.'@'.$this->domain->domain);
|
|
// if (in_array($addr, $usedExternalAddrs, true) && $mu->id !== $myId) {
|
|
// $disabled[] = (int)$mu->id;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// $this->disabledMailboxIdsByRow[$i] = array_values(array_unique($disabled));
|
|
//
|
|
// $this->rowState[$i] = [
|
|
// 'disable_internal' => $hasExternal, // XOR
|
|
// 'disable_external' => $hasInternal, // XOR
|
|
// 'can_remove' => !($this->type === 'single' && $count === 1),
|
|
// ];
|
|
// }
|
|
// }
|
|
//
|
|
//
|
|
// // Duplikate feldgenau markieren (keine Exceptions)
|
|
// private function validateRecipientDuplicates(): bool
|
|
// {
|
|
// // komplette Empfänger-Fehler zurücksetzen
|
|
// $this->resetErrorBag();
|
|
//
|
|
// // Map Zeile -> normalisierte Zieladresse (intern => local@domain, extern => email)
|
|
// $values = []; // [i => 'addr']
|
|
// $byAddrIndices = []; // 'addr' => [i1,i2,...]
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// $addr = null;
|
|
//
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// if ($this->domain) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u) $addr = Str::lower($u->localpart.'@'.$this->domain->domain);
|
|
// }
|
|
// } elseif (!empty($r['email'])) {
|
|
// $addr = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// if ($addr) {
|
|
// $values[$i] = $addr;
|
|
// $byAddrIndices[$addr] = $byAddrIndices[$addr] ?? [];
|
|
// $byAddrIndices[$addr][] = $i;
|
|
// }
|
|
// }
|
|
//
|
|
// $hasDupes = false;
|
|
//
|
|
// foreach ($byAddrIndices as $addr => $indices) {
|
|
// if (count($indices) <= 1) continue;
|
|
// $hasDupes = true;
|
|
// // alle betroffenen Felder markieren (feldgenau)
|
|
// foreach ($indices as $i) {
|
|
// if (!empty($this->recipients[$i]['mail_user_id'])) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// } else {
|
|
// $this->addError("recipients.$i.email", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// return $hasDupes;
|
|
// }
|
|
//
|
|
// private function aliasConflictsWithMailbox(): bool
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return false;
|
|
//
|
|
// $local = Str::lower(trim($this->local));
|
|
// return MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->whereRaw('LOWER(localpart) = ?', [$local])
|
|
// ->exists();
|
|
// }
|
|
//
|
|
// // -------------------- Save --------------------
|
|
//
|
|
// public function save(): void
|
|
// {
|
|
// // 1) Basisregeln
|
|
// $this->validate($this->rules(), $this->messages());
|
|
//
|
|
// // 2) Zeilen dürfen nicht leer sein (weder intern noch extern)
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// if (empty($r['mail_user_id']) && empty($r['email'])) {
|
|
// $this->addError("recipients.$i.email", 'Wähle internes Postfach oder externe E-Mail.');
|
|
// return;
|
|
// }
|
|
// }
|
|
//
|
|
// // 3) Duplikate feldgenau prüfen
|
|
// if ($this->validateRecipientDuplicates()) {
|
|
// return;
|
|
// }
|
|
//
|
|
// if ($aliasAddr = $this->currentAliasAddress()) {
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// // extern
|
|
// if (!empty($r['email']) && \Illuminate\Support\Str::lower(trim((string)$r['email'])) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.email", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// // intern (falls es später mal interne Empfänger ohne existierendes Postfach geben sollte)
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// $u = \App\Models\MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u && $this->domain && \Illuminate\Support\Str::lower($u->localpart.'@'.$this->domain->domain) === $aliasAddr) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Alias darf nicht an sich selbst weiterleiten.');
|
|
// return;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// // 4) Alias-Adresse darf kein bestehendes Postfach sein
|
|
// if ($this->aliasConflictsWithMailbox()) {
|
|
// $this->addError('local', 'Diese Adresse ist bereits als Postfach vergeben.');
|
|
// return;
|
|
// }
|
|
//
|
|
// // 5) Persistieren
|
|
// $rows = collect($this->recipients)
|
|
// ->map(fn($r) => [
|
|
// 'mail_user_id' => $r['mail_user_id'] ?: null,
|
|
// 'email' => isset($r['email']) && $r['email'] !== '' ? Str::lower(trim($r['email'])) : null,
|
|
// ])
|
|
// ->filter(fn($r) => $r['mail_user_id'] || $r['email'])
|
|
// ->values();
|
|
//
|
|
// DB::transaction(function () use ($rows) {
|
|
// /** @var MailAlias $alias */
|
|
// $alias = MailAlias::updateOrCreate(
|
|
// ['id' => $this->aliasId],
|
|
// [
|
|
// 'domain_id' => $this->domainId,
|
|
// 'local' => $this->local,
|
|
// 'type' => $this->type,
|
|
// 'is_active' => $this->is_active,
|
|
// 'notes' => $this->notes,
|
|
// ]
|
|
// );
|
|
//
|
|
// $alias->recipients()->delete();
|
|
// foreach ($rows as $i => $r) {
|
|
// $alias->recipients()->create([
|
|
// 'mail_user_id' => $r['mail_user_id'],
|
|
// 'email' => $r['email'],
|
|
// 'position' => $i,
|
|
// ]);
|
|
// }
|
|
//
|
|
// $this->aliasId = $alias->id;
|
|
// });
|
|
//
|
|
// $this->dispatch('alias:' . ($this->aliasId ? 'updated' : 'created'));
|
|
// $this->dispatch('closeModal');
|
|
// }
|
|
//
|
|
// // -------------------- Validation --------------------
|
|
//
|
|
// protected function rules(): array
|
|
// {
|
|
// // blocke offensichtliche Kollisionen mit Mailboxen (gleiche Domain)
|
|
// $occupied = $this->domainId
|
|
// ? MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->pluck('localpart')
|
|
// ->map(fn($l) => Str::lower($l))
|
|
// ->all()
|
|
// : [];
|
|
//
|
|
// return [
|
|
// 'domainId' => ['required','exists:domains,id'],
|
|
// 'local' => [
|
|
// 'required',
|
|
// 'regex:/^[A-Za-z0-9._%+-]+$/',
|
|
// Rule::unique('mail_aliases','local')
|
|
// ->ignore($this->aliasId)
|
|
// ->where(fn($q) => $q->where('domain_id', $this->domainId)),
|
|
// Rule::notIn($occupied),
|
|
// ],
|
|
// 'type' => ['required','in:single,group'],
|
|
//
|
|
// 'recipients' => ['array','min:1','max:'.($this->type==='single' ? 1 : $this->maxGroupRecipients)],
|
|
// 'recipients.*.mail_user_id' => ['nullable','exists:mail_users,id'],
|
|
// 'recipients.*.email' => ['nullable','email:rfc'],
|
|
// ];
|
|
// }
|
|
//
|
|
// protected function messages(): array
|
|
// {
|
|
// return [
|
|
// 'local.required' => 'Alias-Adresse ist erforderlich.',
|
|
// 'local.regex' => 'Erlaubt sind Buchstaben, Zahlen und ._%+-',
|
|
// 'local.unique' => 'Dieser Alias existiert in dieser Domain bereits.',
|
|
// 'local.not_in' => 'Diese Adresse ist bereits als Postfach vergeben.',
|
|
// 'recipients.min' => 'Mindestens ein Empfänger ist erforderlich.',
|
|
// 'recipients.max' => $this->type === 'single'
|
|
// ? 'Bei „Single“ ist nur ein Empfänger zulässig.'
|
|
// : 'Maximal '.$this->maxGroupRecipients.' Empfänger erlaubt.',
|
|
// ];
|
|
// }
|
|
//
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.mail.modal.alias-form-modal', [
|
|
// 'domains' => Domain::where('is_system', false)
|
|
// ->orderBy('domain')
|
|
// ->get(['id','domain']),
|
|
// ]);
|
|
// }
|
|
//}
|
|
|
|
|
|
//
|
|
//namespace App\Livewire\Ui\Mail\Modal;
|
|
//
|
|
//use App\Models\Domain;
|
|
//use App\Models\MailAlias;
|
|
//use App\Models\MailAliasRecipient;
|
|
//use App\Models\MailUser;
|
|
//use Illuminate\Support\Facades\DB;
|
|
//use Illuminate\Support\Str;
|
|
//use Illuminate\Validation\Rule;
|
|
//use Livewire\Attributes\On;
|
|
//use LivewireUI\Modal\ModalComponent;
|
|
//
|
|
//class AliasFormModal extends ModalComponent
|
|
//{
|
|
// // Eingabe-Props
|
|
// public ?int $aliasId = null; // wenn gesetzt -> Edit
|
|
// public ?int $domainId = null; // Create: vorbelegen (oder Auswahl)
|
|
// public string $local = '';
|
|
// public string $type = 'single'; // 'single' | 'group'
|
|
// public bool $is_active = true;
|
|
// public ?string $notes = null;
|
|
// public int $maxGroupRecipients = 20;
|
|
// public bool $canAddRecipient = false;
|
|
// public array $rowState = [];
|
|
// public array $disabledMailboxIdsByRow = [];
|
|
//
|
|
// // optionale UI-Fehler pro Zeile (Anzeige)
|
|
// public array $rowDuplicateError = [];
|
|
//
|
|
// public array $recipients = [];
|
|
//
|
|
// // UI-Daten
|
|
// public ?Domain $domain = null;
|
|
// /** @var \Illuminate\Support\Collection<int,MailUser> */
|
|
// public $domainMailUsers;
|
|
//
|
|
// public function mount(?int $aliasId = null, ?int $domainId = null): void
|
|
// {
|
|
// $this->aliasId = $aliasId;
|
|
// $this->domainId = $domainId;
|
|
//
|
|
// if ($this->aliasId) {
|
|
// $alias = MailAlias::with(['domain','recipients.mailUser'])->findOrFail($this->aliasId);
|
|
// if ($alias->domain->is_system) {
|
|
// abort(403, 'System-Domains sind für Aliasse gesperrt.');
|
|
// }
|
|
// $this->domain = $alias->domain;
|
|
// $this->domainId = $alias->domain_id;
|
|
//
|
|
// $this->fill([
|
|
// 'local' => $alias->local,
|
|
// 'type' => $alias->type,
|
|
// 'is_active' => $alias->is_active,
|
|
// 'notes' => $alias->notes,
|
|
// ]);
|
|
//
|
|
// $this->recipients = $alias->recipients->map(fn($r) => [
|
|
// 'mail_user_id' => $r->mail_user_id,
|
|
// 'email' => $r->email,
|
|
// ])->all();
|
|
// } else {
|
|
// // Erst NICHT-System-Domain
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->findOrFail($this->domainId)
|
|
// : Domain::where('is_system', false)->orderBy('domain')->first();
|
|
//
|
|
// $this->domainId = $this->domain->id ?? null;
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
// }
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// }
|
|
//
|
|
// public function updatedType(string $value): void
|
|
// {
|
|
// if ($value === 'single') {
|
|
// // exakt eine Zeile behalten
|
|
// $first = $this->recipients[0] ?? ['mail_user_id'=>null,'email'=>null];
|
|
// $this->recipients = [ $first ];
|
|
// }
|
|
// }
|
|
//
|
|
// private function validateRecipientDuplicates(): bool
|
|
// {
|
|
// // vorhandene Feldfehler für Empfänger leeren
|
|
// $this->resetErrorBag('recipients');
|
|
//
|
|
// // Map: Zielstring je Zeile -> Anzahl
|
|
// $values = []; // [i => 'office@pixio.at']
|
|
// $counts = []; // 'office@pixio.at' => n
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// $val = null;
|
|
//
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u && $this->domain) {
|
|
// $val = Str::lower($u->localpart.'@'.$this->domain->domain);
|
|
// }
|
|
// } elseif (!empty($r['email'])) {
|
|
// $val = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// if ($val) {
|
|
// $values[$i] = $val;
|
|
// $counts[$val] = ($counts[$val] ?? 0) + 1;
|
|
// }
|
|
// }
|
|
//
|
|
// $hasDupes = false;
|
|
//
|
|
// foreach ($values as $i => $val) {
|
|
// if (($counts[$val] ?? 0) > 1) {
|
|
// // Feldgenau markieren
|
|
// if (!empty($this->recipients[$i]['mail_user_id'])) {
|
|
// $this->addError("recipients.$i.mail_user_id", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// } else {
|
|
// $this->addError("recipients.$i.email", 'Dieser Empfänger ist bereits hinzugefügt.');
|
|
// }
|
|
// $hasDupes = true;
|
|
// }
|
|
// }
|
|
//
|
|
// return $hasDupes;
|
|
// }
|
|
//
|
|
//
|
|
// // Livewire v3: universeller Hook für verschachtelte Felder
|
|
// public function updated($name, $value): void
|
|
// {
|
|
// // XOR je Zeile
|
|
// if (preg_match('/^recipients\.(\d+)\.(mail_user_id|email)$/', $name, $m)) {
|
|
// $i = (int)$m[1];
|
|
// if ($m[2] === 'mail_user_id' && !empty($value)) {
|
|
// $this->recipients[$i]['email'] = null;
|
|
// } elseif ($m[2] === 'email' && !empty($value)) {
|
|
// $this->recipients[$i]['mail_user_id'] = null;
|
|
// $this->recipients[$i]['email'] = Str::lower(trim((string)$this->recipients[$i]['email']));
|
|
// }
|
|
// }
|
|
//
|
|
// if ($name === 'type' && $this->type === 'single') {
|
|
// $this->recipients = [ $this->recipients[0] ?? ['mail_user_id'=>null,'email'=>null] ];
|
|
// }
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
//
|
|
// // sofortiges, feldgenaues Duplikat-Feedback
|
|
// $this->validateRecipientDuplicates();
|
|
// }
|
|
//
|
|
// public function addRecipientRow(): void
|
|
// {
|
|
// if ($this->type === 'single') return;
|
|
// if (count($this->recipients) >= $this->maxGroupRecipients) return;
|
|
//
|
|
// $this->recipients[] = ['mail_user_id'=>null,'email'=>null];
|
|
// $this->recomputeUi();
|
|
// }
|
|
//
|
|
// public function updatedDomainId(): void
|
|
// {
|
|
// $this->domain = $this->domainId
|
|
// ? Domain::where('is_system', false)->find($this->domainId)
|
|
// : null;
|
|
//
|
|
// $this->domainMailUsers = $this->domain
|
|
// ? MailUser::where('domain_id', $this->domain->id)->orderBy('localpart')->get()
|
|
// : collect();
|
|
//
|
|
// $this->recipients = [['mail_user_id' => null, 'email' => null]];
|
|
//
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// }
|
|
//
|
|
//
|
|
// public function removeRecipientRow(int $index): void
|
|
// {
|
|
// unset($this->recipients[$index]);
|
|
// $this->recipients = array_values($this->recipients);
|
|
// $this->ensureAtLeastOneRow();
|
|
// $this->recomputeUi();
|
|
// }
|
|
//
|
|
// private function ensureAtLeastOneRow(): void
|
|
// {
|
|
// if (empty($this->recipients)) {
|
|
// $this->recipients = [['mail_user_id'=>null,'email'=>null]];
|
|
// }
|
|
// }
|
|
//
|
|
// private function recomputeUi(): void
|
|
// {
|
|
// $count = count($this->recipients);
|
|
//
|
|
// // Button „+ Empfänger“
|
|
// $this->canAddRecipient = $this->type === 'group' && $count < $this->maxGroupRecipients;
|
|
//
|
|
// // Sammle bereits gewählte interne Mailbox-IDs und externe E-Mails (normalisiert)
|
|
// $usedMailboxIds = [];
|
|
// $usedExternal = [];
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// if (!empty($r['mail_user_id'])) $usedMailboxIds[] = (int)$r['mail_user_id'];
|
|
// if (!empty($r['email'])) $usedExternal[] = Str::lower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// // pro Zeile: welche Mailbox-IDs sollen disabled sein (alle used außer die eigene)
|
|
// $this->disabledMailboxIdsByRow = [];
|
|
// $this->rowState = [];
|
|
// $this->rowDuplicateError = [];
|
|
//
|
|
// for ($i=0; $i<$count; $i++) {
|
|
// $myId = (int)($this->recipients[$i]['mail_user_id'] ?? 0);
|
|
// $myEmail = Str::lower(trim((string)($this->recipients[$i]['email'] ?? '')));
|
|
//
|
|
// $disabled = array_values(array_unique(array_filter($usedMailboxIds, fn($id) => $id && $id !== $myId)));
|
|
// $this->disabledMailboxIdsByRow[$i] = $disabled;
|
|
//
|
|
// $hasInternal = $myId > 0;
|
|
// $hasExternal = $myEmail !== '';
|
|
//
|
|
// $this->rowState[$i] = [
|
|
// 'disable_internal' => $hasExternal, // XOR
|
|
// 'disable_external' => $hasInternal, // XOR
|
|
// 'can_remove' => !($this->type === 'single' && $count === 1),
|
|
// ];
|
|
//
|
|
// // Duplikats-UI: wenn meine Zieladresse mehrfach vorkommt -> Fehlermeldung für diese Zeile
|
|
// if ($hasInternal && count(array_filter($usedMailboxIds, fn($id) => $id === $myId)) > 1) {
|
|
// $this->rowDuplicateError[$i] = 'Dieses Postfach ist bereits Empfänger.';
|
|
// }
|
|
// if ($hasExternal && count(array_filter($usedExternal, fn($e) => $e === $myEmail)) > 1) {
|
|
// $this->rowDuplicateError[$i] = 'Diese E-Mail ist bereits Empfänger.';
|
|
// }
|
|
// }
|
|
//
|
|
// $this->hasDuplicatesAndMarkUi();
|
|
// }
|
|
//
|
|
//// private function assertNoDuplicates(): void
|
|
//// {
|
|
//// // Ziel-Strings bilden: intern -> localpart@domain, extern -> E-Mail
|
|
//// $targets = [];
|
|
//// foreach ($this->recipients as $r) {
|
|
//// if (!empty($r['mail_user_id'])) {
|
|
//// $u = MailUser::find((int)$r['mail_user_id']);
|
|
//// if ($u && $this->domain) {
|
|
//// $targets[] = Str::lower($u->localpart.'@'.$this->domain->domain);
|
|
//// }
|
|
//// } elseif (!empty($r['email'])) {
|
|
//// $targets[] = Str::lower(trim((string)$r['email']));
|
|
//// }
|
|
//// }
|
|
//// $dupes = array_unique(array_diff_key($targets, array_unique($targets)));
|
|
//// if (!empty($dupes)) {
|
|
//// $this->addError('recipients', 'Doppelte Empfänger nicht erlaubt.');
|
|
//// throw new \RuntimeException('duplicates'); // brich Save clean ab
|
|
//// }
|
|
//// }
|
|
//
|
|
// private function hasDuplicatesAndMarkUi(): bool
|
|
// {
|
|
// // Ziel-String pro Zeile: intern => local@domain, extern => email
|
|
// $targets = []; // [i => 'office@pixio.at']
|
|
// $byValueCount = []; // 'office@pixio.at' => n
|
|
//
|
|
// $this->rowDuplicateError = []; // UI reset
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// $val = null;
|
|
//
|
|
// if (!empty($r['mail_user_id'])) {
|
|
// $u = MailUser::find((int)$r['mail_user_id']);
|
|
// if ($u && $this->domain) {
|
|
// $val = mb_strtolower($u->localpart.'@'.$this->domain->domain);
|
|
// }
|
|
// } elseif (!empty($r['email'])) {
|
|
// $val = mb_strtolower(trim((string)$r['email']));
|
|
// }
|
|
//
|
|
// if ($val) {
|
|
// $targets[$i] = $val;
|
|
// $byValueCount[$val] = ($byValueCount[$val] ?? 0) + 1;
|
|
// }
|
|
// }
|
|
//
|
|
// $hasDupes = false;
|
|
// foreach ($targets as $i => $val) {
|
|
// if (($byValueCount[$val] ?? 0) > 1) {
|
|
// $this->rowDuplicateError[$i] = 'Dieser Empfänger ist bereits hinzugefügt.';
|
|
// $hasDupes = true;
|
|
// }
|
|
// }
|
|
//
|
|
// return $hasDupes;
|
|
// }
|
|
//
|
|
//
|
|
//
|
|
// public function save(): void
|
|
// {
|
|
// $this->validate($this->rules(), $this->messages());
|
|
//
|
|
// // XOR-Check Empfänger + Single/Group-Logik
|
|
// $rows = collect($this->recipients)
|
|
// ->map(fn($r) => [
|
|
// 'mail_user_id' => $r['mail_user_id'] ?: null,
|
|
// 'email' => isset($r['email']) && $r['email'] !== '' ? mb_strtolower(trim($r['email'])) : null,
|
|
// ])
|
|
// ->filter(fn($r) => $r['mail_user_id'] || $r['email'])
|
|
// ->values();
|
|
//
|
|
// if ($rows->isEmpty()) {
|
|
// $this->addError('recipients', 'Mindestens ein Empfänger erforderlich.');
|
|
// return;
|
|
// }
|
|
// if ($this->type === 'single' && $rows->count() !== 1) {
|
|
// $this->addError('recipients', 'Bei Single-Alias ist genau ein Empfänger erlaubt.');
|
|
// return;
|
|
// }
|
|
//
|
|
// foreach ($this->recipients as $i => $r) {
|
|
// if (empty($r['mail_user_id']) && empty($r['email'])) {
|
|
// $this->addError("recipients.$i", 'Wähle internes Postfach oder externe E-Mail.');
|
|
// return;
|
|
// }
|
|
// }
|
|
//
|
|
// if ($this->validateRecipientDuplicates()) {
|
|
// return; // freundlich abbrechen, keine Exception
|
|
// }
|
|
//
|
|
// // 4) Alias-Adresse vs. bestehende Mailboxen (siehe Teil B)
|
|
// if ($this->aliasConflictsWithMailbox()) {
|
|
// $this->addError('local', 'Diese Adresse ist bereits als Postfach vergeben.');
|
|
// return;
|
|
// }
|
|
//
|
|
//
|
|
// DB::transaction(function () use ($rows) {
|
|
// /** @var MailAlias $alias */
|
|
// $alias = MailAlias::updateOrCreate(
|
|
// ['id' => $this->aliasId],
|
|
// [
|
|
// 'domain_id' => $this->domainId,
|
|
// 'local' => $this->local,
|
|
// 'type' => $this->type,
|
|
// 'is_active' => $this->is_active,
|
|
// 'notes' => $this->notes,
|
|
// ]
|
|
// );
|
|
//
|
|
// // Empfänger neu schreiben (einfach & robust)
|
|
// $alias->recipients()->delete();
|
|
// foreach ($rows as $i => $r) {
|
|
// $alias->recipients()->create([
|
|
// 'mail_user_id' => $r['mail_user_id'],
|
|
// 'email' => $r['email'],
|
|
// 'position' => $i,
|
|
// ]);
|
|
// }
|
|
//
|
|
// $this->aliasId = $alias->id;
|
|
// });
|
|
//
|
|
// $this->dispatch('alias:' . ($this->aliasId ? 'updated' : 'created'));
|
|
// $this->dispatch('closeModal');
|
|
// }
|
|
//
|
|
// private function aliasConflictsWithMailbox(): bool
|
|
// {
|
|
// if (!$this->domainId || $this->local === '') return false;
|
|
//
|
|
// $local = Str::lower(trim($this->local));
|
|
//
|
|
// return MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->whereRaw('LOWER(localpart) = ?', [$local])
|
|
// ->exists();
|
|
// }
|
|
//
|
|
// protected function rules(): array
|
|
// {
|
|
// $occupied = MailUser::query()
|
|
// ->where('domain_id', $this->domainId)
|
|
// ->pluck('localpart')
|
|
// ->map(fn($l) => Str::lower($l))
|
|
// ->all();
|
|
//
|
|
// return [
|
|
// 'domainId' => ['required','exists:domains,id'],
|
|
// 'local' => [
|
|
// 'required',
|
|
// 'regex:/^[A-Za-z0-9._%+-]+$/',
|
|
// Rule::unique('mail_aliases','local')
|
|
// ->ignore($this->aliasId)
|
|
// ->where(fn($q) => $q->where('domain_id', $this->domainId)),
|
|
// Rule::notIn($occupied), // verhindert offensichtliche Kollisionen
|
|
// ],
|
|
// 'type' => ['required','in:single,group'],
|
|
// 'recipients' => ['array','min:1','max:'.($this->type==='single'?1:$this->maxGroupRecipients)],
|
|
// 'recipients.*.mail_user_id' => ['nullable','exists:mail_users,id'],
|
|
// 'recipients.*.email' => ['nullable','email:rfc'],
|
|
// ];
|
|
// }
|
|
//
|
|
//
|
|
// protected function messages(): array
|
|
// {
|
|
// return [
|
|
// 'local.not_in' => 'Diese Adresse ist bereits als Postfach vergeben.',
|
|
// 'local.unique' => 'Dieser Alias existiert in dieser Domain bereits.',
|
|
// 'local.regex' => 'Erlaubt sind Buchstaben, Zahlen und ._%+-',
|
|
// 'recipients.min' => 'Mindestens ein Empfänger ist erforderlich.',
|
|
// 'recipients.max' => $this->type === 'single'
|
|
// ? 'Bei „Single“ ist nur ein Empfänger zulässig.'
|
|
// : 'Maximal '.$this->maxGroupRecipients.' Empfänger erlaubt.',
|
|
// ];
|
|
// }
|
|
//
|
|
//
|
|
// public function render()
|
|
// {
|
|
// return view('livewire.ui.mail.modal.alias-form-modal', [
|
|
// 'domains' => Domain::where('is_system', false)->orderBy('domain')->get(['id','domain']),
|
|
// ]);
|
|
// }
|
|
//}
|