Domain Create Modal anpassen Fehler auf Null
parent
5d15a757b3
commit
a78767809d
|
|
@ -8,8 +8,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
class MailAlias extends Model
|
class MailAlias extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['domain_id','local','type','group_name','is_active','notes'];
|
protected $fillable = ['domain_id','local','type','group_name','is_active','is_system','notes'];
|
||||||
protected $casts = ['is_active' => 'bool'];
|
protected $casts = ['is_active' => 'bool', 'is_system' => 'bool'];
|
||||||
|
|
||||||
public function domain(): BelongsTo
|
public function domain(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|
@ -18,7 +18,7 @@ class MailAlias extends Model
|
||||||
|
|
||||||
public function recipients(): HasMany
|
public function recipients(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(MailAliasRecipient::class, 'alias_id');
|
return $this->hasMany(MailAliasRecipient::class, 'alias_id')->orderBy('position');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAddressAttribute(): string
|
public function getAddressAttribute(): string
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ return new class extends Migration
|
||||||
|
|
||||||
$table->boolean('is_system')->default(false)->index(); // oft nach Systemkonten filtern
|
$table->boolean('is_system')->default(false)->index(); // oft nach Systemkonten filtern
|
||||||
$table->boolean('is_active')->default(true)->index();
|
$table->boolean('is_active')->default(true)->index();
|
||||||
|
$table->boolean('can_login')->default(true)->index();
|
||||||
|
|
||||||
$table->unsignedInteger('quota_mb')->default(0); // 0 = unlimited
|
$table->unsignedInteger('quota_mb')->default(0); // 0 = unlimited
|
||||||
$table->unsignedInteger('rate_limit_per_hour')->nullable();
|
$table->unsignedInteger('rate_limit_per_hour')->nullable();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ return new class extends Migration
|
||||||
$table->enum('type', ['single','group'])->default('single');
|
$table->enum('type', ['single','group'])->default('single');
|
||||||
$table->string('group_name', 80)->nullable();
|
$table->string('group_name', 80)->nullable();
|
||||||
$table->boolean('is_active')->default(true)->index();
|
$table->boolean('is_active')->default(true)->index();
|
||||||
|
$table->boolean('is_system')->default(false)->after('is_active')->index();
|
||||||
$table->text('notes')->nullable();
|
$table->text('notes')->nullable();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,12 @@ return new class extends Migration
|
||||||
{
|
{
|
||||||
Schema::create('mail_alias_recipients', function (Blueprint $table) {
|
Schema::create('mail_alias_recipients', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
|
$table->foreignId('alias_id')->constrained('mail_aliases')->cascadeOnDelete();
|
||||||
$table->foreignId('alias_id')
|
$table->foreignId('mail_user_id')->nullable()->constrained('mail_users')->nullOnDelete();
|
||||||
->constrained('mail_aliases')
|
|
||||||
->cascadeOnDelete();
|
|
||||||
|
|
||||||
// interner Empfänger (MailUser) ODER externer Empfänger (E-Mail)
|
|
||||||
$table->foreignId('mail_user_id')
|
|
||||||
->nullable()
|
|
||||||
->constrained('mail_users') // <-- richtige Tabelle!
|
|
||||||
->nullOnDelete();
|
|
||||||
|
|
||||||
$table->string('email', 320)->nullable(); // externer Empfänger
|
$table->string('email', 320)->nullable(); // externer Empfänger
|
||||||
$table->unsignedSmallInteger('position')->default(0);
|
$table->unsignedSmallInteger('position')->default(0);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
// Duplikate vermeiden:
|
|
||||||
$table->unique(['alias_id','mail_user_id']);
|
$table->unique(['alias_id','mail_user_id']);
|
||||||
$table->unique(['alias_id','email']);
|
$table->unique(['alias_id','email']);
|
||||||
});
|
});
|
||||||
|
|
@ -4,11 +4,15 @@ namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\DkimKey;
|
use App\Models\DkimKey;
|
||||||
use App\Models\Domain;
|
use App\Models\Domain;
|
||||||
|
use App\Models\MailAlias;
|
||||||
|
use App\Models\MailAliasRecipient;
|
||||||
use App\Models\MailUser;
|
use App\Models\MailUser;
|
||||||
use App\Models\TlsaRecord;
|
use App\Models\TlsaRecord;
|
||||||
use App\Services\DnsRecordService;
|
use App\Services\DnsRecordService;
|
||||||
use App\Services\TlsaService;
|
use App\Services\TlsaService;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Foundation\Auth\User;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class SystemDomainSeeder extends Seeder
|
class SystemDomainSeeder extends Seeder
|
||||||
{
|
{
|
||||||
|
|
@ -137,7 +141,7 @@ class SystemDomainSeeder extends Seeder
|
||||||
}
|
}
|
||||||
|
|
||||||
// System-Absender (no-reply) – ohne Passwort (kein Login)
|
// System-Absender (no-reply) – ohne Passwort (kein Login)
|
||||||
MailUser::firstOrCreate(
|
$noReply = MailUser::firstOrCreate(
|
||||||
['email' => "no-reply@{$systemFqdn}"],
|
['email' => "no-reply@{$systemFqdn}"],
|
||||||
[
|
[
|
||||||
'domain_id' => $systemDomain->id,
|
'domain_id' => $systemDomain->id,
|
||||||
|
|
@ -149,35 +153,27 @@ class SystemDomainSeeder extends Seeder
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// DKIM – Key erzeugen, falls keiner aktiv existiert
|
$seedGroup = function(string $local, array $emails) use ($systemDomain, $noReply) {
|
||||||
if (!$systemDomain->dkimKeys()->where('is_active', true)->exists()) {
|
$alias = MailAlias::updateOrCreate(
|
||||||
[$privPem, $pubTxt] = $this->generateDkimKeyPair();
|
['domain_id' => $systemDomain->id, 'local' => $local],
|
||||||
$selector = 'mwl1'; // frei wählbar, später rotieren
|
['type' => 'group', 'is_active' => true, 'is_system' => true]
|
||||||
|
);
|
||||||
|
$alias->recipients()->delete();
|
||||||
|
$pos=0;
|
||||||
|
foreach ($emails as $addr) {
|
||||||
|
MailAliasRecipient::create([
|
||||||
|
'alias_id' => $alias->id,
|
||||||
|
'email' => $addr,
|
||||||
|
'position' => $pos++,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DkimKey::create([
|
// alle vier erst einmal nur ans no-reply Postfach
|
||||||
'domain_id' => $systemDomain->id,
|
$seedGroup('system', [$noReply->email]);
|
||||||
'selector' => $selector,
|
$seedGroup('bounces', [$noReply->email]);
|
||||||
'private_key_pem' => $privPem,
|
$seedGroup('postmaster', [$noReply->email]);
|
||||||
'public_key_txt' => $pubTxt,
|
$seedGroup('abuse', [$noReply->email]);
|
||||||
'is_active' => true,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->command->info("DKIM angelegt: Host = {$selector}._domainkey.{$systemFqdn}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$dk = $systemDomain->dkimKeys()->where('is_active', true)->latest()->first();
|
|
||||||
$dkimTxt = $dk ? "v=DKIM1; k=rsa; p={$dk->public_key_txt}" : null;
|
|
||||||
|
|
||||||
app(DnsRecordService::class)->provision(
|
|
||||||
$systemDomain,
|
|
||||||
dkimSelector: $dk?->selector,
|
|
||||||
dkimTxt: $dkimTxt,
|
|
||||||
opts: [
|
|
||||||
'dmarc_policy' => 'none',
|
|
||||||
'spf_tail' => '-all',
|
|
||||||
// optional: 'ipv4' => $serverIp, 'ipv6' => ...
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->command->info("System-Domain '{$systemFqdn}' fertig. SPF/DMARC/DKIM & DNS-Empfehlungen eingetragen.");
|
$this->command->info("System-Domain '{$systemFqdn}' fertig. SPF/DMARC/DKIM & DNS-Empfehlungen eingetragen.");
|
||||||
$this->printDnsHints($systemDomain);
|
$this->printDnsHints($systemDomain);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue