withoutMiddleware(HandleInertiaRequests::class); createForumRestrictedCategoryAccessSchema(); config()->set('forum.category_role_access', [ 'administrators-and-moderators-forum' => ['admin', 'manager'], ]); }); it('hides restricted forum categories from guests and regular users', function () { seedForumAccessBoards(); $this->get(route('forum.index')) ->assertOk() ->assertDontSee('Administrators and Moderators Forum') ->assertSee('Public Forum'); $member = makeForumAccessUser('member-role', 'user'); $this->actingAs($member) ->get(route('forum.index')) ->assertOk() ->assertDontSee('Administrators and Moderators Forum') ->assertSee('Public Forum'); $this->get(route('forum.category.show', ['categorySlug' => 'administrators-and-moderators-forum']))->assertNotFound(); $this->get(route('forum.board.show', ['boardSlug' => 'administrators-and-moderators-forum']))->assertNotFound(); $this->actingAs($member) ->get(route('forum.category.show', ['categorySlug' => 'administrators-and-moderators-forum'])) ->assertNotFound(); $this->actingAs($member) ->get(route('forum.board.show', ['boardSlug' => 'administrators-and-moderators-forum'])) ->assertNotFound(); }); it('allows admin and manager roles to access restricted forum categories', function () { seedForumAccessBoards(); $admin = makeForumAccessUser('admin-role', 'admin'); $manager = makeForumAccessUser('manager-role', 'manager'); $this->actingAs($admin) ->get(route('forum.index')) ->assertOk() ->assertSee('Administrators and Moderators Forum'); $this->actingAs($admin) ->get(route('forum.category.show', ['categorySlug' => 'administrators-and-moderators-forum'])) ->assertOk(); $this->actingAs($admin) ->get(route('forum.board.show', ['boardSlug' => 'administrators-and-moderators-forum'])) ->assertOk(); $this->actingAs($manager) ->get(route('forum.index')) ->assertOk() ->assertSee('Administrators and Moderators Forum'); $this->actingAs($manager) ->get(route('forum.category.show', ['categorySlug' => 'administrators-and-moderators-forum'])) ->assertOk(); $this->actingAs($manager) ->get(route('forum.board.show', ['boardSlug' => 'administrators-and-moderators-forum'])) ->assertOk(); }); function createForumRestrictedCategoryAccessSchema(): void { foreach (['forum_posts', 'forum_topics', 'forum_boards', 'forum_categories', 'user_profiles', 'users'] as $table) { Schema::dropIfExists($table); } Schema::create('users', function (Blueprint $table): void { $table->id(); $table->string('username')->nullable(); $table->timestamp('username_changed_at')->nullable(); $table->timestamp('last_username_change_at')->nullable(); $table->string('onboarding_step')->nullable(); $table->string('name')->nullable(); $table->string('email')->nullable(); $table->timestamp('email_verified_at')->nullable(); $table->string('password')->nullable(); $table->boolean('is_active')->default(true); $table->string('role')->nullable(); $table->rememberToken(); $table->timestamps(); $table->softDeletes(); }); Schema::create('user_profiles', function (Blueprint $table): void { $table->unsignedBigInteger('user_id')->primary(); $table->string('avatar_hash')->nullable(); $table->timestamps(); }); Schema::create('forum_categories', function (Blueprint $table): void { $table->id(); $table->string('name')->nullable(); $table->string('title')->nullable(); $table->string('slug')->unique(); $table->text('description')->nullable(); $table->unsignedBigInteger('parent_id')->nullable(); $table->integer('position')->default(0); $table->boolean('is_active')->default(true); $table->timestamps(); }); Schema::create('forum_boards', function (Blueprint $table): void { $table->id(); $table->foreignId('category_id')->constrained('forum_categories')->cascadeOnDelete(); $table->unsignedBigInteger('legacy_category_id')->nullable(); $table->string('title'); $table->string('slug')->unique(); $table->text('description')->nullable(); $table->string('icon')->nullable(); $table->string('image')->nullable(); $table->integer('position')->default(0); $table->boolean('is_active')->default(true); $table->boolean('is_read_only')->default(false); $table->timestamps(); }); Schema::create('forum_topics', function (Blueprint $table): void { $table->id(); $table->foreignId('board_id')->constrained('forum_boards')->cascadeOnDelete(); $table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete(); $table->unsignedBigInteger('artwork_id')->nullable(); $table->unsignedBigInteger('legacy_thread_id')->nullable(); $table->string('title'); $table->string('slug')->unique(); $table->unsignedInteger('views')->default(0); $table->unsignedInteger('replies_count')->default(0); $table->boolean('is_pinned')->default(false); $table->boolean('is_locked')->default(false); $table->boolean('is_deleted')->default(false); $table->unsignedBigInteger('last_post_id')->nullable(); $table->timestamp('last_post_at')->nullable(); $table->timestamps(); }); Schema::create('forum_posts', function (Blueprint $table): void { $table->id(); $table->unsignedBigInteger('thread_id')->nullable(); $table->foreignId('topic_id')->nullable()->constrained('forum_topics')->nullOnDelete(); $table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete(); $table->text('content')->nullable(); $table->boolean('is_edited')->default(false); $table->timestamp('edited_at')->nullable(); $table->timestamps(); $table->softDeletes(); }); } function seedForumAccessBoards(): array { $restrictedCategory = ForumCategory::query()->create([ 'title' => 'Administrators and Moderators Forum', 'slug' => 'administrators-and-moderators-forum', 'description' => 'Restricted board.', 'is_active' => true, 'position' => 1, ]); $publicCategory = ForumCategory::query()->create([ 'title' => 'Public Forum', 'slug' => 'public-forum', 'description' => 'Visible to everyone.', 'is_active' => true, 'position' => 2, ]); $restrictedBoard = ForumBoard::query()->create([ 'category_id' => $restrictedCategory->id, 'title' => 'Administrators and Moderators Forum', 'slug' => 'administrators-and-moderators-forum', 'description' => 'Restricted board.', 'is_active' => true, 'position' => 1, ]); $publicBoard = ForumBoard::query()->create([ 'category_id' => $publicCategory->id, 'title' => 'Public Forum', 'slug' => 'public-forum', 'description' => 'Visible to everyone.', 'is_active' => true, 'position' => 1, ]); return [$restrictedCategory, $publicCategory, $restrictedBoard, $publicBoard]; } function makeForumAccessUser(string $username, string $role): User { return User::query()->create([ 'username' => $username, 'username_changed_at' => now()->subDays(120), 'last_username_change_at' => now()->subDays(120), 'onboarding_step' => 'complete', 'name' => ucfirst($role) . ' User', 'email' => $username . '@example.com', 'email_verified_at' => now(), 'password' => 'password', 'is_active' => true, 'role' => $role, ]); }