diff --git a/app/Models/Node.php b/app/Models/Node.php index 69b1072d51..f6828212a3 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -13,7 +13,6 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Http; @@ -277,9 +276,9 @@ public function databaseHosts(): BelongsToMany return $this->belongsToMany(DatabaseHost::class); } - public function roles(): HasManyThrough + public function roles(): BelongsToMany { - return $this->hasManyThrough(Role::class, NodeRole::class, 'node_id', 'id', 'id', 'role_id'); + return $this->belongsToMany(Role::class, NodeRole::class); } /** diff --git a/app/Models/User.php b/app/Models/User.php index 7a969ec915..56baed314a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -266,7 +266,7 @@ public function activity(): MorphToMany */ public function accessibleServers(): Builder { - if ($this->canned('viewAny', Server::class)) { + if ($this->canViewServers()) { return Server::select('servers.*') ->leftJoin('subusers', 'subusers.server_id', '=', 'servers.id') ->where(function (Builder $builder) { @@ -278,6 +278,22 @@ public function accessibleServers(): Builder return $this->directAccessibleServers(); } + /** + * Check if the user has permission to view servers via role permissions. + */ + public function canViewServers(): bool + { + if ($this->isRootAdmin()) { + return true; + } + + try { + return $this->hasPermissionTo('viewList server'); + } catch (\Spatie\Permission\Exceptions\PermissionDoesNotExist) { + return false; + } + } + /** * Returns all the servers that a user can access "directly". * This means either because they are the owner or a subuser of the server. @@ -438,13 +454,21 @@ public function getTenants(Panel $panel): array|Collection public function canAccessTenant(Model $tenant): bool { if ($tenant instanceof Server) { - if ($this->canned('view', $tenant) || $tenant->owner_id === $this->id) { + if ($tenant->owner_id === $this->id) { return true; } $subuser = $tenant->subusers->where('user_id', $this->id)->first(); + if ($subuser !== null) { + return true; + } - return $subuser !== null; + // Check if user has role-based access to this server's node + if ($this->canViewServers() && $this->canTarget($tenant->node)) { + return true; + } + + return false; } return false; diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 6f58b28fbe..fe955c59e6 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -22,12 +22,12 @@ public function before(User $user, string $ability, string|Server $server): ?boo return null; } - if (Subuser::doesPermissionExist($ability)) { - // Owner has full server permissions - if ($server->owner_id === $user->id) { - return true; - } + // Owner has full server permissions + if ($server->owner_id === $user->id) { + return true; + } + if (Subuser::doesPermissionExist($ability)) { $subuser = $server->subusers->where('user_id', $user->id)->first(); // If the user is a subuser check their permissions if ($subuser && in_array($ability, $subuser->permissions)) { @@ -40,6 +40,16 @@ public function before(User $user, string $ability, string|Server $server): ?boo return false; } + // Check if user has role-based permission for this specific ability + $permissionName = $ability . ' ' . $this->modelName; + try { + if ($user->hasPermissionTo($permissionName)) { + return true; + } + } catch (\Spatie\Permission\Exceptions\PermissionDoesNotExist) { + // Permission doesn't exist, continue to default policies + } + // Return null to let default policies take over return null; }