diff --git a/app/Livewire/Billing.php b/app/Livewire/Billing.php index 416bb12..0e91707 100644 --- a/app/Livewire/Billing.php +++ b/app/Livewire/Billing.php @@ -65,8 +65,13 @@ class Billing extends Component private function customer(): ?Customer { $user = auth()->user(); + if (! $user) { + return null; + } - return $user ? Customer::query()->where('email', $user->email)->first() : null; + // Prefer the explicit link; fall back to email for legacy unlinked accounts. + return Customer::query()->where('user_id', $user->id)->first() + ?? Customer::query()->where('email', $user->email)->first(); } public function render() diff --git a/database/migrations/2026_07_25_090001_create_datacenters_table.php b/database/migrations/2026_07_25_090001_create_datacenters_table.php index 4948d35..6720d90 100644 --- a/database/migrations/2026_07_25_090001_create_datacenters_table.php +++ b/database/migrations/2026_07_25_090001_create_datacenters_table.php @@ -2,7 +2,9 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Str; return new class extends Migration { @@ -17,6 +19,33 @@ return new class extends Migration $table->boolean('active')->default(true); $table->timestamps(); }); + + // The host form now only offers codes from this table, so an existing + // install must not upgrade into an empty list. Backfill every code + // already referenced by a host, plus the previously hardcoded defaults. + $names = ['fsn' => 'Falkenstein', 'hel' => 'Helsinki']; + $locations = ['fsn' => 'DE', 'hel' => 'FI']; + + $codes = ['fsn', 'hel']; + if (Schema::hasTable('hosts')) { + $codes = array_values(array_unique(array_merge( + $codes, + DB::table('hosts')->whereNotNull('datacenter')->distinct()->pluck('datacenter')->all(), + ))); + } + + $now = now(); + foreach ($codes as $code) { + DB::table('datacenters')->insert([ + 'uuid' => (string) Str::uuid(), + 'code' => $code, + 'name' => $names[$code] ?? Str::upper($code), + 'location' => $locations[$code] ?? null, + 'active' => true, + 'created_at' => $now, + 'updated_at' => $now, + ]); + } } public function down(): void diff --git a/tests/Feature/Admin/DatacenterTest.php b/tests/Feature/Admin/DatacenterTest.php index 71e41c1..278b020 100644 --- a/tests/Feature/Admin/DatacenterTest.php +++ b/tests/Feature/Admin/DatacenterTest.php @@ -27,7 +27,7 @@ it('creates a datacenter', function () { }); it('rejects a duplicate datacenter code', function () { - Datacenter::factory()->create(['code' => 'fsn']); + Datacenter::query()->firstOrCreate(['code' => 'fsn'], ['name' => 'Falkenstein']); Livewire::actingAs(admin()) ->test(Datacenters::class) @@ -45,7 +45,7 @@ it('toggles a datacenter active flag', function () { }); it('offers only known datacenter codes when adding a host', function () { - Datacenter::factory()->create(['code' => 'fsn', 'name' => 'Falkenstein']); + Datacenter::query()->firstOrCreate(['code' => 'fsn'], ['name' => 'Falkenstein']); // unknown code rejected Livewire::actingAs(admin()) diff --git a/tests/Feature/Admin/HostManagementTest.php b/tests/Feature/Admin/HostManagementTest.php index 732817e..88ae00b 100644 --- a/tests/Feature/Admin/HostManagementTest.php +++ b/tests/Feature/Admin/HostManagementTest.php @@ -39,7 +39,7 @@ it('lists real hosts for admins', function () { it('creates a host and starts onboarding with an encrypted password', function () { Queue::fake(); - \App\Models\Datacenter::factory()->create(['code' => 'fsn']); + \App\Models\Datacenter::query()->firstOrCreate(['code' => 'fsn'], ['name' => 'Falkenstein']); Livewire::actingAs(admin()) ->test(HostCreate::class) @@ -62,7 +62,7 @@ it('creates a host and starts onboarding with an encrypted password', function ( }); it('rejects a duplicate public ip', function () { - \App\Models\Datacenter::factory()->create(['code' => 'fsn']); + \App\Models\Datacenter::query()->firstOrCreate(['code' => 'fsn'], ['name' => 'Falkenstein']); Host::factory()->create(['public_ip' => '203.0.113.99']); Livewire::actingAs(admin())