Domain Create Modal anpassen Fehler auf Null

main
boban 2025-10-18 21:28:51 +02:00
parent 50202b5245
commit 5d15a757b3
12 changed files with 105 additions and 105 deletions

View File

@ -112,7 +112,7 @@ class Wizard extends Component
$user->name = $this->form_admin_name;
$user->is_admin = true;
$user->password = Hash::make($this->form_admin_password);
$user->must_change_pw = true;
$user->required_change_password = true;
$user->save();
// 3) Zertifikat jetzt ausstellen (optional)

View File

@ -31,7 +31,6 @@ class MailboxCreateModal extends ModalComponent
public int $quota_mb = 0;
public ?int $rate_limit_per_hour = null;
public bool $is_active = true;
public bool $must_change_pw = true;
// Limits / Status
public ?int $limit_max_mailboxes = null;
@ -85,7 +84,6 @@ class MailboxCreateModal extends ModalComponent
'quota_mb' => ['required', 'integer', 'min:0', 'max:' . $cap],
'rate_limit_per_hour' => ['nullable', 'integer', 'min:1'],
'is_active' => ['boolean'],
'must_change_pw' => ['boolean'],
];
}
@ -256,7 +254,6 @@ class MailboxCreateModal extends ModalComponent
$u->password_hash = $this->password ? Hash::make($this->password) : null;
$u->is_system = false;
$u->is_active = (bool)$data['is_active'];
$u->must_change_pw = (bool)$data['must_change_pw'];
$u->quota_mb = (int)$data['quota_mb'];
$u->rate_limit_per_hour = $data['rate_limit_per_hour'];
$u->save();

View File

@ -20,7 +20,6 @@ class MailboxEditModal extends ModalComponent
public int $quota_mb = 0;
public ?int $rate_limit_per_hour = null;
public bool $is_active = true;
public bool $must_change_pw = true;
// UI
public string $email_readonly = '';
@ -42,7 +41,6 @@ class MailboxEditModal extends ModalComponent
$this->quota_mb = (int)$this->mailbox->quota_mb;
$this->rate_limit_per_hour = $this->mailbox->rate_limit_per_hour;
$this->is_active = (bool)$this->mailbox->is_active;
$this->must_change_pw = (bool)$this->mailbox->must_change_pw;
$dom = $this->mailbox->domain;
$this->email_readonly = $this->mailbox->localpart . '@' . $dom->domain;
@ -105,7 +103,6 @@ class MailboxEditModal extends ModalComponent
'quota_mb' => ['required', 'integer', 'min:0', 'max:' . $cap],
'rate_limit_per_hour' => ['nullable', 'integer', 'min:1'],
'is_active' => ['boolean'],
'must_change_pw' => ['boolean'],
];
}
@ -121,12 +118,10 @@ class MailboxEditModal extends ModalComponent
$u->display_name = $this->display_name ?: null;
if (!empty($this->password)) {
$u->password_hash = Hash::make($this->password);
$u->must_change_pw = true;
}
$u->quota_mb = (int)$this->quota_mb;
$u->rate_limit_per_hour = $this->rate_limit_readonly ? $d->rate_limit_per_hour : $this->rate_limit_per_hour;
$u->is_active = (bool)$this->is_active;
$u->must_change_pw = (bool)$this->must_change_pw;
$u->save();
$mailbox = $u->localpart . '@' . $d->domain;

View File

@ -11,14 +11,13 @@ class MailUser extends Model
protected $fillable = [
'domain_id','localpart','email','display_name','password_hash',
'is_active','must_change_pw','quota_mb','is_system'
'is_active','quota_mb','is_system'
];
protected $hidden = ['password_hash'];
protected $casts = [
'is_active'=>'bool',
'is_system' => 'boolean',
'must_change_pw'=>'bool',
'quota_mb'=>'int',
'last_login_at'=>'datetime',
];

View File

@ -17,9 +17,10 @@ class User extends Authenticatable
'name',
'username',
'email',
'admin_email',
'password',
'is_active',
'must_change_pw',
'required_change_password',
'role',
];
@ -29,10 +30,10 @@ class User extends Authenticatable
];
protected $casts = [
'email_verified_at' => 'datetime',
'is_active' => 'boolean',
'must_change_pw' => 'boolean',
'role' => Role::class,
'email_verified_at' => 'datetime',
'is_active' => 'boolean',
'required_change_password' => 'boolean',
'role' => Role::class,
];
/** Quick helper: check if user is admin */
@ -41,6 +42,19 @@ class User extends Authenticatable
return $this->role === Role::Admin;
}
// Fallback: admin_email || email
public function getSystemNotifyEmailAttribute(): string
{
$admin = trim((string)$this->admin_email);
return filter_var($admin, FILTER_VALIDATE_EMAIL) ? $admin : $this->email;
}
// Wenn du Laravel Notifications nutzt:
public function routeNotificationForMail($notification): string
{
return $this->system_notify_email;
}
public function twoFactorMethods()
{
return $this->hasMany(\App\Models\TwoFactorMethod::class);

View File

@ -16,6 +16,10 @@ class DomainObserver
*/
public function created(Domain $domain): void
{
if ($domain->is_server) {
return;
}
$selector = (string) config('mailpool.defaults.dkim_selector', 'mwl1');
$bits = (int) config('mailpool.defaults.dkim_bits', 2048);
@ -51,6 +55,8 @@ class DomainObserver
]
);
}
// public function created(Domain $domain): void
// {
// // Standardwerte aus Config oder .env

View File

@ -16,10 +16,11 @@ return new class extends Migration
$table->string('name')->unique();
$table->string('username')->nullable()->unique();
$table->string('email')->unique();
$table->string('admin_email', 255)->nullable()->index();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->boolean('is_active')->default(true)->index();
$table->boolean('must_change_pw')->default(true)->index();
$table->boolean('required_change_password')->default(false)->index();
$table->boolean('two_factor_enabled')->default(false);
$table->boolean('two_factor_email_enabled')->default(false);
$table->string('totp_secret')->nullable();

View File

@ -24,7 +24,6 @@ return new class extends Migration
$table->boolean('is_system')->default(false)->index(); // oft nach Systemkonten filtern
$table->boolean('is_active')->default(true)->index();
$table->boolean('must_change_pw')->default(true)->index();
$table->unsignedInteger('quota_mb')->default(0); // 0 = unlimited
$table->unsignedInteger('rate_limit_per_hour')->nullable();

View File

@ -1,46 +0,0 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class AdminUserSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$name = env('APP_ADMIN_USER', 'mailwolt');
$email = env('APP_ADMIN_EMAIL', 'admin@localhost');
$pass = env('APP_ADMIN_PASS', 'ChangeMe'); // Wird beim ersten Login geändert
$user = User::firstOrCreate(
['email' => $email],
[
'name' => $name,
'username' => $name,
'password' => Hash::make($pass),
'is_active' => true,
'must_change_pw' => true,
'role' => 'admin',
'email_verified_at' => now(),
'remember_token' => Str::random(10),
]
);
// falls es den User schon gab, Flags sicher setzen
if (!$user->wasRecentlyCreated) {
$user->forceFill([
'is_active' => true,
'must_change_pw' => true,
'role' => 'admin',
])->save();
}
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
}
}

View File

@ -32,9 +32,39 @@ class SystemDomainSeeder extends Seeder
// =========================================================================
$serverDomain = Domain::firstOrCreate(
['domain' => $serverFqdn],
['is_active' => true, 'is_system' => false, 'is_server' => true]
[
'is_active' => true,
'is_system' => false,
'is_server' => true,
// nix anlegen unter mx.<base>
'max_mailboxes' => 0,
'max_aliases' => 0,
// Quotas praktisch sperren
'default_quota_mb' => 0,
'max_quota_per_mailbox_mb' => 0,
'total_quota_mb' => 0,
// kein Versand über diese Domain
'rate_limit_per_hour' => 0,
'rate_limit_override' => false,
]
);
$serverDomain->fill([
'is_active' => true,
'is_system' => false,
'is_server' => true,
'max_mailboxes' => 0,
'max_aliases' => 0,
'default_quota_mb' => 0,
'max_quota_per_mailbox_mb' => 0,
'total_quota_mb' => 0,
'rate_limit_per_hour' => 0,
'rate_limit_override' => false,
])->save();
Domain::where('is_server', true)
->where('id', '!=', $serverDomain->id)
->update(['is_server' => false]);
@ -71,8 +101,37 @@ class SystemDomainSeeder extends Seeder
// =========================================================================
$systemDomain = Domain::firstOrCreate(
['domain' => $systemFqdn],
['is_active' => true, 'is_system' => true]
[
'is_active' => true,
'is_system' => true,
// Limits
'max_aliases' => 20,
'max_mailboxes'=> 1,
// Quota
'default_quota_mb' => 512,
'max_quota_per_mailbox_mb' => 2048,
'total_quota_mb' => 2048,
// Rate limiting
'rate_limit_per_hour' => 600,
'rate_limit_override' => false,
]
);
$systemDomain->fill([
'is_active' => true,
'is_system' => true,
'max_aliases' => 20,
'max_mailboxes' => 1,
'default_quota_mb' => 512,
'max_quota_per_mailbox_mb' => 2048,
'total_quota_mb' => 2048,
'rate_limit_per_hour' => 600,
'rate_limit_override' => false,
])->save();
if ($systemDomain->wasRecentlyCreated) {
$this->command->line("System-Domain angelegt: {$systemDomain->domain}");
}
@ -81,13 +140,12 @@ class SystemDomainSeeder extends Seeder
MailUser::firstOrCreate(
['email' => "no-reply@{$systemFqdn}"],
[
'domain_id' => $systemDomain->id,
'localpart' => 'no-reply',
'password_hash' => null,
'is_active' => true,
'is_system' => true,
'must_change_pw' => false,
'quota_mb' => 0,
'domain_id' => $systemDomain->id,
'localpart' => 'no-reply',
'password_hash' => null,
'is_active' => true,
'is_system' => true,
'quota_mb' => 0,
]
);

View File

@ -164,15 +164,15 @@
<span class="text-white/80 text-sm">Postfach aktivieren</span>
</label>
<label class="inline-flex items-center gap-2 cursor-pointer select-none group">
<input type="checkbox" wire:model="must_change_pw" class="peer sr-only">
<span class="w-5 h-5 flex items-center justify-center rounded-md border border-white/15 bg-white/5
peer-checked:bg-sky-500/20 peer-checked:border-sky-400/40
group-hover:border-white/25 transition">
<i class="ph ph-check text-[12px] text-sky-300 opacity-0 peer-checked:opacity-100 transition"></i>
</span>
<span class="text-white/80 text-sm">Passwort bei erstem Login ändern</span>
</label>
{{-- <label class="inline-flex items-center gap-2 cursor-pointer select-none group">--}}
{{-- <input type="checkbox" wire:model="must_change_pw" class="peer sr-only">--}}
{{-- <span class="w-5 h-5 flex items-center justify-center rounded-md border border-white/15 bg-white/5--}}
{{-- peer-checked:bg-sky-500/20 peer-checked:border-sky-400/40--}}
{{-- group-hover:border-white/25 transition">--}}
{{-- <i class="ph ph-check text-[12px] text-sky-300 opacity-0 peer-checked:opacity-100 transition"></i>--}}
{{-- </span>--}}
{{-- <span class="text-white/80 text-sm">Passwort bei erstem Login ändern</span>--}}
{{-- </label>--}}
</div>
</div>
</div>