Add Instructors admin page (create + per-capability access)
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
Completes the instructor-management half of #9: the studio admin can now create instructor accounts and toggle each instructor's capabilities. - InstructorController (manage_instructors): list instructors, create a us_instructor WP user (emailing a set-password link), and a per-instructor capability detail view. - InstructorCapabilities: pure, unit-tested rules for which managed caps an admin may assign and how a submitted form maps to assignments. Managed caps are manage_offerings, manage_questions, view_own_payments, export_payments; manage_availability and view_own_lessons are core to every instructor. - A studio admin can never grant a capability it does not itself hold: only held caps (checked via current_user_can, so an administrator's dynamic grant counts) are offered, and on creation any managed cap the admin lacks is denied on the new instructor so they never exceed their creator. The role grants the managed caps by default; the page layers per-user overrides. - AdminMenu: register the Instructors page in the people section. - Tests for the capability logic; docs/features/user-roles.md updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Unsupervised\Schedular\Tests\Unit\Auth;
|
||||
|
||||
use Unsupervised\Schedular\Auth\InstructorCapabilities;
|
||||
use Unsupervised\Schedular\Auth\RoleManager;
|
||||
use Unsupervised\Schedular\Tests\Unit\TestCase;
|
||||
|
||||
class InstructorCapabilitiesTest extends TestCase
|
||||
{
|
||||
public function testGrantableReturnsOnlyManagedCapsTheAdminHolds(): void
|
||||
{
|
||||
$grantable = InstructorCapabilities::grantable([
|
||||
RoleManager::CAP_MANAGE_OFFERINGS => true,
|
||||
RoleManager::CAP_EXPORT_PAYMENTS => true,
|
||||
// A non-instructor cap the admin holds is irrelevant here.
|
||||
RoleManager::CAP_MANAGE_POLICIES => true,
|
||||
]);
|
||||
|
||||
self::assertContains(RoleManager::CAP_MANAGE_OFFERINGS, $grantable);
|
||||
self::assertContains(RoleManager::CAP_EXPORT_PAYMENTS, $grantable);
|
||||
self::assertNotContains(RoleManager::CAP_MANAGE_QUESTIONS, $grantable);
|
||||
self::assertNotContains(RoleManager::CAP_MANAGE_POLICIES, $grantable);
|
||||
}
|
||||
|
||||
public function testGrantableExcludesCapsTheAdminLacksOrHasDisabled(): void
|
||||
{
|
||||
self::assertSame([], InstructorCapabilities::grantable([
|
||||
RoleManager::CAP_MANAGE_OFFERINGS => false,
|
||||
]));
|
||||
|
||||
self::assertSame([], InstructorCapabilities::grantable([]));
|
||||
}
|
||||
|
||||
public function testResolveMapsEachGrantableCapToWhetherItWasSubmitted(): void
|
||||
{
|
||||
$resolved = InstructorCapabilities::resolve(
|
||||
[RoleManager::CAP_MANAGE_OFFERINGS],
|
||||
[RoleManager::CAP_MANAGE_OFFERINGS, RoleManager::CAP_EXPORT_PAYMENTS]
|
||||
);
|
||||
|
||||
self::assertTrue($resolved[RoleManager::CAP_MANAGE_OFFERINGS]);
|
||||
self::assertFalse($resolved[RoleManager::CAP_EXPORT_PAYMENTS]);
|
||||
}
|
||||
|
||||
public function testResolveIgnoresSubmittedCapsOutsideTheGrantableSet(): void
|
||||
{
|
||||
// The form posts a cap the admin may not grant; it must be dropped, so a
|
||||
// studio admin can never assign a capability it does not itself hold.
|
||||
$resolved = InstructorCapabilities::resolve(
|
||||
[RoleManager::CAP_MANAGE_QUESTIONS, RoleManager::CAP_MANAGE_POLICIES],
|
||||
[RoleManager::CAP_MANAGE_OFFERINGS]
|
||||
);
|
||||
|
||||
self::assertSame([RoleManager::CAP_MANAGE_OFFERINGS => false], $resolved);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user