Files
central-unifi/src/Models/UnifiPageGrant.php
jwed 462a1a3611 feat(1.13.0): page grants on the standard admissions-style pattern
unifi_page_grants gains role + default grantee types and can_view
(deny-by-default "Everyone else" row); enforcement moves from the
RouteMatched listener — where request->user() is always null and the
check silently failed open — into route-appended middleware with the
permission-holder pass. Pages-access endpoints gain role search +
default-row handling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 21:31:41 -04:00

66 lines
2.1 KiB
PHP

<?php
namespace Dashboard\Unifi\Models;
use App\Models\NavItem;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UnifiPageGrant extends Model
{
protected $table = 'unifi_page_grants';
protected $fillable = [
'nav_item_id',
'grantee_type', // default | user | group | role
'grantee_id', // null for grantee_type=default
'can_view',
'granted_by_user_id',
];
protected $casts = [
'can_view' => 'boolean',
];
public function navItem(): BelongsTo
{
return $this->belongsTo(NavItem::class);
}
public function grantedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'granted_by_user_id');
}
/**
* Grant check with a per-page default fallback. Passes if the user
* matches an explicit user/group/role grant; otherwise falls back
* to the page's `default` row (deny by default — no row or
* can_view=false denies). Permission-based access is checked
* separately by the caller — grants extend, never revoke.
*/
public static function userCanAccess(User $user, NavItem $navItem): bool
{
if ($user->is_super_admin) return true;
$groupIds = $user->groups()->pluck('groups.id');
$roleIds = $user->roles()->pluck('roles.id');
$hasExplicit = static::where('nav_item_id', $navItem->id)
->where('can_view', true)
->where(function ($q) use ($user, $groupIds, $roleIds) {
$q->where(fn ($u) => $u->where('grantee_type', 'user')->where('grantee_id', $user->id))
->orWhere(fn ($g) => $g->where('grantee_type', 'group')->whereIn('grantee_id', $groupIds))
->orWhere(fn ($r) => $r->where('grantee_type', 'role')->whereIn('grantee_id', $roleIds));
})
->exists();
if ($hasExplicit) return true;
return (bool) static::where('nav_item_id', $navItem->id)
->where('grantee_type', 'default')
->value('can_view');
}
}