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>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Brings unifi_page_grants to parity with adm_access_grants /
|
||||
* directory_access_grants: widens grantee_type to include 'default' and
|
||||
* 'role', allows a NULL grantee_id (used by the per-page default row),
|
||||
* and adds a can_view column. The default row's can_view carries the
|
||||
* deny/allow fallback for users not matched by a more specific grant
|
||||
* (deny by default — no row means deny).
|
||||
*
|
||||
* Existing user/group rows keep working: adding can_view with a default
|
||||
* of true backfills them as explicit allow grants.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('unifi_page_grants')) return;
|
||||
|
||||
// Widen the enum and allow NULL grantee_id (default rows). MySQL
|
||||
// enum changes require raw DDL.
|
||||
DB::statement("ALTER TABLE unifi_page_grants MODIFY grantee_type ENUM('default','user','group','role') NOT NULL");
|
||||
DB::statement("ALTER TABLE unifi_page_grants MODIFY grantee_id BIGINT UNSIGNED NULL");
|
||||
|
||||
if (! Schema::hasColumn('unifi_page_grants', 'can_view')) {
|
||||
Schema::table('unifi_page_grants', function (Blueprint $table) {
|
||||
$table->boolean('can_view')->default(true)->after('grantee_id');
|
||||
});
|
||||
|
||||
// Belt and braces: make sure every pre-existing user/group row
|
||||
// is an explicit allow grant.
|
||||
DB::table('unifi_page_grants')->update(['can_view' => true]);
|
||||
}
|
||||
|
||||
// The unique index on (nav_item_id, grantee_type, grantee_id)
|
||||
// already exists from the create migration
|
||||
// ('unifi_page_grants_unique') and still applies — grantee_id is
|
||||
// NULL for default rows, and MySQL treats NULLs as distinct, so
|
||||
// app code enforces one default row per nav_item.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! Schema::hasTable('unifi_page_grants')) return;
|
||||
|
||||
if (Schema::hasColumn('unifi_page_grants', 'can_view')) {
|
||||
Schema::table('unifi_page_grants', function (Blueprint $table) {
|
||||
$table->dropColumn('can_view');
|
||||
});
|
||||
}
|
||||
|
||||
DB::table('unifi_page_grants')->whereIn('grantee_type', ['default', 'role'])->delete();
|
||||
|
||||
DB::statement("ALTER TABLE unifi_page_grants MODIFY grantee_type ENUM('user','group') NOT NULL");
|
||||
DB::statement("ALTER TABLE unifi_page_grants MODIFY grantee_id BIGINT UNSIGNED NOT NULL");
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user