permissions refactoring

This commit is contained in:
2026-04-12 19:21:04 +02:00
parent 51014395a2
commit 9dcdfb981a
64 changed files with 1842 additions and 656 deletions
@@ -0,0 +1,119 @@
<?php
namespace Tests\Feature\Permissions;
use App\Actions\Permissions\PermissionService;
use App\Enums\Permission;
use App\Models\Project;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PermissionServiceTest extends TestCase
{
use RefreshDatabase;
/**
* Ensure direct project permissions expand through the configured hierarchy.
*/
public function test_direct_project_permissions_expand_through_hierarchy(): void
{
$service = app(PermissionService::class);
$user = User::factory()->create();
$project = Project::factory()->create();
$service->sync($user, $project, [Permission::ProjectWrite]);
$this->assertTrue($service->allows($user, Permission::ProjectRead, $project));
$this->assertTrue($service->allows($user, Permission::ProjectWrite, $project));
$this->assertFalse($service->allows($user, Permission::ProjectAdmin, $project));
}
/**
* Ensure project permissions assigned to teams are inherited by team members.
*/
public function test_team_project_permissions_are_inherited_by_members(): void
{
$service = app(PermissionService::class);
$user = User::factory()->create();
$team = Team::factory()->create();
$project = Project::factory()->create();
$team->users()->attach($user);
$service->sync($team, $project, [Permission::ProjectRead]);
$this->assertTrue($service->allows($user, Permission::ProjectRead, $project));
}
/**
* Ensure user and team permissions are combined instead of one replacing the other.
*/
public function test_direct_user_permissions_are_combined_with_inherited_team_permissions(): void
{
$service = app(PermissionService::class);
$user = User::factory()->create();
$team = Team::factory()->create();
$project = Project::factory()->create();
$team->users()->attach($user);
$service->sync($team, $project, [Permission::ProjectWrite]);
$service->sync($user, $project, [Permission::ProjectRead]);
$this->assertTrue($service->allows($user, Permission::ProjectWrite, $project));
$this->assertTrue($service->allows($user, Permission::ProjectRead, $project));
}
/**
* Ensure team-scoped permissions are granted directly to users and do not come from membership alone.
*/
public function test_team_permissions_only_apply_when_directly_assigned_to_the_user(): void
{
$service = app(PermissionService::class);
$manager = User::factory()->create();
$member = User::factory()->create();
$team = Team::factory()->create();
$team->users()->attach([$manager->id, $member->id]);
$service->sync($manager, $team, [Permission::TeamManage]);
$this->assertTrue($service->allows($manager, Permission::TeamManage, $team));
$this->assertFalse($service->allows($member, Permission::TeamManage, $team));
}
/**
* Ensure global admins can perform global, project, and team-scoped actions.
*/
public function test_global_admin_overrides_every_scope(): void
{
$service = app(PermissionService::class);
$admin = User::factory()->create();
$project = Project::factory()->create();
$team = Team::factory()->create();
$service->sync($admin, null, [Permission::GlobalAdmin]);
$this->assertTrue($service->allows($admin, Permission::ProjectCreate));
$this->assertTrue($service->allows($admin, Permission::ProjectAdmin, $project));
$this->assertTrue($service->allows($admin, Permission::TeamManage, $team));
}
/**
* Ensure the service can surface accessible project ids and manageable team ids.
*/
public function test_scope_lookup_helpers_return_expected_ids(): void
{
$service = app(PermissionService::class);
$user = User::factory()->create();
$team = Team::factory()->create();
$project = Project::factory()->create();
$team->users()->attach($user);
$service->sync($team, $project, [Permission::ProjectRead]);
$service->sync($user, $team, [Permission::TeamManage]);
$this->assertSame([$project->id], $service->viewableProjectIds($user));
$this->assertSame([$team->id], $service->manageableTeamIds($user));
$this->assertTrue($service->canManageAnyTeam($user));
}
}