Skip to content
This repository was archived by the owner on Aug 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function form(Schema $schema): Schema
// Obtener hosts que NO están ya asignados a este usuario
$assignedHostIds = $this->getOwnerRecord()->hosts()->pluck('hosts.id')->toArray();

return Host::whereNotIn('id', $assignedHostIds)
return Host::whereNotIn('hosts.id', $assignedHostIds)
->get()
->mapWithKeys(fn ($host) => [
$host->id => "{$host->fqdn} ({$host->ip}) - {$host->panel->getLabel()}",
Expand Down Expand Up @@ -102,7 +102,7 @@ public function table(Table $table): Table
// Solo mostrar hosts que NO están ya asignados a este usuario
$assignedHostIds = $this->getOwnerRecord()->hosts()->pluck('hosts.id')->toArray();

return $query->whereNotIn('id', $assignedHostIds);
return $query->whereNotIn('hosts.id', $assignedHostIds);
})
->recordSelectSearchColumns(['fqdn', 'alias', 'ip'])
->recordTitle(fn ($record) => "{$record->fqdn} ({$record->ip}) - {$record->panel->getLabel()}"),
Expand Down Expand Up @@ -137,7 +137,7 @@ public function table(Table $table): Table
->recordSelectOptionsQuery(function ($query) {
$assignedHostIds = $this->getOwnerRecord()->hosts()->pluck('hosts.id')->toArray();

return $query->whereNotIn('id', $assignedHostIds);
return $query->whereNotIn('hosts.id', $assignedHostIds);
})
->recordSelectSearchColumns(['fqdn', 'alias', 'ip'])
->recordTitle(fn ($record) => "{$record->fqdn} ({$record->ip}) - {$record->panel->getLabel()}"),
Expand Down
41 changes: 41 additions & 0 deletions tests/Feature/Filament/UserResourceRelationManagersTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?php

use App\Filament\Resources\UserResource\Pages\EditUser;
use App\Filament\Resources\UserResource\RelationManagers\HostsRelationManager;
use App\Models\{Host, Hosting, User, UserHostingPermission};

use function Pest\Livewire\livewire;

// Tests to verify that business logic works correctly
test('admin can access user edit page', function () {
// Arrange - Create complete setup
Expand Down Expand Up @@ -132,6 +136,43 @@
expect($authorizedUser->fresh()->hasAccessToHost($host->id))->toBeTrue();
});

test('server assignment action loads for a user that already has hosts (regression: ambiguous column id)', function () {
// Arrange - admin session (OTP verified)
$admin = User::factory()->admin()->create();
$this->actingAs($admin);
session()->put('admin_otp_verified', true);
session()->put('admin_otp_user_id', $admin->id);
session()->put('admin_otp_verified_at', now()->timestamp);

// The owner user ALREADY has a host assigned, so $assignedHostIds is non-empty
// and the whereNotIn(...) clause is actually emitted. With an unqualified 'id'
// over the BelongsToMany base query (which joins user_host_permissions),
// this triggers "ambiguous column name: id" before the fix.
$owner = User::factory()->create(['parent_user_id' => null]);
$assignedHost = Host::factory()->create();
$owner->hosts()->attach($assignedHost->id, ['is_active' => true]);

// Another host available to be assigned
$availableHost = Host::factory()->create();

// Act - run the full "Asignar Servidor" flow: selecting a host forces Filament
// to resolve its option label against the record-select options query, which is
// where the unqualified whereNotIn('id', ...) over the joined base query blows up
// with "ambiguous column name: id" (the production symptom).
livewire(HostsRelationManager::class, [
'ownerRecord' => $owner,
'pageClass' => EditUser::class,
])
->callTableAction('attach', data: [
'recordId' => $availableHost->id,
'is_active' => true,
])
->assertHasNoTableActionErrors();

// Assert - the host was actually attached (flow completed end to end)
expect($owner->fresh()->hosts()->whereKey($availableHost->id)->exists())->toBeTrue();
});

test('unauthorized users cannot access admin panel', function () {
// Arrange - Create users
$regularUser = User::factory()->create(['is_admin' => false]);
Expand Down