Files
ignacionelson 6e47d76ba6 ProjectSend 2.0.0
Client file sharing, rebuilt from the ground up: a private area per
client, resumable uploads, folders, groups and categories, sharing with
expiry dates and download limits, comments, file versions, an activity
log, a REST API, and sixteen languages.

This repository begins here. ProjectSend 2 was developed privately, and
that development history is not published — the previous generation
remains available, with its own history, at projectsend/legacy.

Free software under the GNU General Public License v2, or (at your
option) any later version.
2026-08-14 01:38:12 -03:00

125 lines
4.8 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Models\User;
use App\Modules\Identity\Models\Role;
use App\Modules\Identity\Models\RolePermission;
use App\Modules\Identity\Permissions\Permission;
use App\Modules\Identity\Permissions\PermissionChecker;
use App\Modules\Identity\Permissions\SystemRole;
use Inertia\Testing\AssertableInertia;
test('the migration seeds the built-in system roles', function () {
// Uploader is NOT seeded on fresh installs — it is a legacy role only
// recreated by the v1 migration tool.
expect(Role::query()->where('is_system', true)->pluck('name')->sort()->values()->all())
->toBe(['Account Manager', 'Client', 'Client Manager', 'System Administrator']);
expect(Role::query()->where('is_administrator', true)->sole()->name)->toBe('System Administrator');
// Only the Client Manager role is client-scoped.
expect(Role::query()->where('client_scoped', true)->pluck('name')->all())->toBe(['Client Manager']);
});
// The full matrix from the brief (§10): every permission key × every
// system role, asserted against the v1-parity default sets.
test('permission matrix matches the v1 defaults', function (SystemRole $systemRole) {
$user = User::factory()->role($systemRole)->create();
$expected = array_map(
fn (Permission $permission): string => $permission->value,
$systemRole->defaultPermissions(),
);
foreach (Permission::cases() as $permission) {
expect($user->can($permission->value))
->toBe(in_array($permission->value, $expected, true), "{$systemRole->value} / {$permission->value}");
}
})->with(SystemRole::cases());
test('a user without a role is denied everything', function () {
$user = User::factory()->create(['role_id' => null]);
foreach (Permission::cases() as $permission) {
expect($user->can($permission->value))->toBeFalse($permission->value);
}
});
test('the administrator role grants permissions added after seeding', function () {
// No pivot rows exist for the administrator role — every permission
// is granted by construction, so new enum cases can never be missing.
$admin = User::factory()->create();
expect(RolePermission::query()->where('role_id', $admin->role_id)->count())->toBe(0)
->and($admin->can(Permission::ManageUpdates->value))->toBeTrue();
});
test('granted permissions are shared with the frontend per role', function () {
$uploader = User::factory()->role(SystemRole::Uploader)->create();
$expected = array_map(
fn (Permission $permission): string => $permission->value,
SystemRole::Uploader->defaultPermissions(),
);
sort($expected);
$this->actingAs($uploader)->get('/dashboard')->assertInertia(
fn (AssertableInertia $page) => $page->where(
'auth.permissions',
fn ($granted) => collect($granted)->sort()->values()->all() === $expected,
),
);
});
test('an uploader can view the activity log but not system settings', function () {
$uploader = User::factory()->role(SystemRole::Uploader)->create();
$this->actingAs($uploader);
$this->get('/activity')->assertOk();
$this->get('/system/settings/general')->assertForbidden();
$this->patch('/system/settings/general', ['site_name' => 'Nope'])->assertForbidden();
});
test('an account manager can view the activity log but not edit settings', function () {
$manager = User::factory()->role(SystemRole::AccountManager)->create();
$this->actingAs($manager);
$this->get('/activity')->assertOk();
$this->get('/system/settings/security')->assertForbidden();
});
test('setup assigns the System Administrator role to the first admin', function () {
$this->post('/setup', [
'site_name' => 'ProjectSend',
'name' => 'Admin',
'email' => 'admin@example.com',
'password' => 'super-secret-password',
'password_confirmation' => 'super-secret-password',
]);
$admin = User::query()->sole();
expect($admin->role?->is_administrator)->toBeTrue();
});
test('the projectsend:admin command assigns the System Administrator role', function () {
$this->artisan('projectsend:admin', [
'--name' => 'CLI Admin',
'--email' => 'cli@example.com',
'--password' => 'super-secret-password',
]);
expect(User::query()->sole()->role?->is_administrator)->toBeTrue();
});
test('stale permission keys in the pivot are ignored', function () {
$role = Role::query()->create(['name' => 'Custom']);
RolePermission::query()->create(['role_id' => $role->id, 'permission' => 'a_removed_permission']);
RolePermission::query()->create(['role_id' => $role->id, 'permission' => Permission::Upload->value]);
$user = User::factory()->create(['role_id' => $role->id]);
expect($user->can(Permission::Upload->value))->toBeTrue()
->and(app(PermissionChecker::class)->grantedKeys($user))->toBe(['upload']);
});