mailwolt/app/Livewire/Setup/Wizard.php

150 lines
5.6 KiB
PHP

<?php
namespace App\Livewire\Setup;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Layout('layouts.setup')]
#[Title('Einrichtung · Mailwolt')]
class Wizard extends Component
{
public int $step = 1;
public int $totalSteps = 4;
// Schritt 1 — System
public string $instance_name = 'Mailwolt';
public string $locale = 'de';
public string $timezone = 'Europe/Berlin';
// Schritt 2 — Domains
public string $ui_domain = '';
public string $mail_domain = '';
public string $webmail_domain = '';
// Schritt 3 — Admin-Account
public string $admin_name = '';
public string $admin_email = '';
public string $admin_password = '';
public string $admin_password_confirmation = '';
public function mount(): void
{
$this->instance_name = config('app.name', 'Mailwolt');
$this->timezone = Setting::get('timezone', 'Europe/Berlin');
$this->locale = Setting::get('locale', 'de');
$this->ui_domain = Setting::get('ui_domain', '');
$this->mail_domain = Setting::get('mail_domain', '');
$this->webmail_domain = Setting::get('webmail_domain', '');
}
public function next(): void
{
match ($this->step) {
1 => $this->validate([
'instance_name' => 'required|string|min:2|max:64',
'locale' => 'required|in:de,en,fr',
'timezone' => 'required|timezone',
]),
2 => $this->validate([
'ui_domain' => ['required', 'regex:/^(?!https?:\/\/)(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/'],
'mail_domain' => ['required', 'regex:/^(?!https?:\/\/)(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/'],
'webmail_domain' => ['required', 'regex:/^(?!https?:\/\/)(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/'],
], [
'ui_domain.required' => 'Pflichtfeld.',
'mail_domain.required' => 'Pflichtfeld.',
'webmail_domain.required' => 'Pflichtfeld.',
'ui_domain.regex' => 'Ungültige Domain — kein Schema (http://) erlaubt.',
'mail_domain.regex' => 'Ungültige Domain — kein Schema (http://) erlaubt.',
'webmail_domain.regex' => 'Ungültige Domain — kein Schema (http://) erlaubt.',
]),
3 => $this->validate([
'admin_name' => 'required|string|min:2|max:64',
'admin_email' => 'required|email|max:190',
'admin_password' => 'required|string|min:10|same:admin_password_confirmation',
'admin_password_confirmation' => 'required',
], [
'admin_password.min' => 'Mindestens 10 Zeichen.',
'admin_password.same' => 'Passwörter stimmen nicht überein.',
]),
default => null,
};
$this->step = min($this->step + 1, $this->totalSteps);
}
public function back(): void
{
$this->step = max($this->step - 1, 1);
}
public function finish(): mixed
{
// Schritt-3-Validierung nochmals sicherstellen
$this->validate([
'admin_name' => 'required|string|min:2|max:64',
'admin_email' => 'required|email|max:190',
'admin_password' => 'required|string|min:10|same:admin_password_confirmation',
]);
// Settings speichern
Setting::setMany([
'locale' => $this->locale,
'timezone' => $this->timezone,
'ui_domain' => $this->ui_domain,
'mail_domain' => $this->mail_domain,
'webmail_domain' => $this->webmail_domain,
'setup_completed' => '1',
]);
// .env aktualisieren
$this->writeEnv([
'APP_NAME' => $this->instance_name,
'APP_HOST' => $this->ui_domain,
'APP_URL' => 'https://' . $this->ui_domain,
'MTA_SUB' => explode('.', $this->mail_domain)[0] ?? '',
'WEBMAIL_DOMAIN' => $this->webmail_domain,
]);
// Admin anlegen oder aktualisieren
$user = User::where('email', $this->admin_email)->first() ?? new User();
$user->name = $this->admin_name;
$user->email = $this->admin_email;
$user->password = Hash::make($this->admin_password);
$user->role = 'admin';
$user->save();
return redirect()->route('login')->with('setup_done', true);
}
private function writeEnv(array $values): void
{
$path = base_path('.env');
$content = @file_get_contents($path) ?: '';
foreach ($values as $key => $value) {
$escaped = str_contains($value, ' ') ? '"' . $value . '"' : $value;
$line = $key . '=' . $escaped;
$pattern = '/^' . preg_quote($key, '/') . '=[^\r\n]*/m';
if (preg_match($pattern, $content)) {
$content = preg_replace($pattern, $line, $content);
} else {
$content .= "\n{$line}";
}
}
file_put_contents($path, $content);
}
public function render()
{
$timezones = \DateTimeZone::listIdentifiers(\DateTimeZone::ALL);
return view('livewire.setup.wizard', compact('timezones'));
}
}