Skip to content

Commit

Permalink
(test): UserRoles
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonvanWijhe committed Nov 7, 2024
1 parent 269981d commit 467f914
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 64 deletions.
14 changes: 13 additions & 1 deletion src/Console/UserRolesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@ public function handle(): void
{
$this->info('Updating roles...');

UserRoles::setRoles();
$this->createRolesForSites();

$this->info('All done!');
}

private function createRolesForSites(): void
{
if (true === is_multisite()) {
foreach (get_sites(['fields' => 'ids']) as $siteId) {
switch_to_blog($siteId);
UserRoles::createRoles();
}
} else {
UserRoles::createRoles();
}
}
}
2 changes: 1 addition & 1 deletion src/Facades/UserRoles.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Illuminate\Support\Facades\Facade;

/**
* @method static void setRoles()
* @method static void createRoles()
*/
class UserRoles extends Facade
{
Expand Down
132 changes: 94 additions & 38 deletions src/UserRoles.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,99 @@
use Role_Command;
use Webmozart\Assert\Assert;
use WP_CLI;
use WP_CLI\ExitException;

class UserRoles
{
public function __construct(private Role_Command $roleCommand)
private string $prefix;

/**
* @param array<mixed> $config
*
* @throws ExitException
*/
public function __construct(private array $config, private Role_Command $roleCommand, private WP_CLI $wpCli)
{
$this->prefix = $this->prefixValidate($config);
}

public function setRoles(): void
/**
* (Re)creates roles based on the provided configuration.
*/
public function createRoles(): void
{
if (is_multisite()) {
foreach (get_sites(['fields' => 'ids']) as $siteId) {
switch_to_blog($siteId);
$this->setRolesForSite();
}
} else {
$this->setRolesForSite();
}
$this->deleteCustomRoles();
$this->resetCoreRoles();
$this->addCustomRoles();
$this->deleteCoreRoles();
}

private function setRolesForSite(): void
/**
* @param array<mixed> $config
*
* @throws ExitException
*/
private function prefixValidate(array $config): string
{
$prefix = config('user-roles.prefix');
Assert::stringNotEmpty($prefix);
$prefix = $config['prefix'] ?? '';

$this->removeCustomRoles();
$this->resetCoreRoles();
$this->addCustomRoles();
$this->removeCoreRoles();
if (! is_string($prefix) || '' === $prefix) {
$this->wpCli::error('No prefix found in configuration file. Aborting role creation.');
}

return $prefix . '_';
}

private function removeCustomRoles(): void
private function deleteCustomRoles(): void
{
WP_CLI::log(WP_CLI::colorize('%MDelete custom roles:%n'));
$this->wpCli::log($this->wpCli::colorize('%MDelete custom roles:%n'));

$prefix = config('user-roles.prefix');
$currentCustomRoles = wp_roles()->roles;
$currentCustomRoles = array_filter(
array_keys($currentCustomRoles),
fn (string $role): bool => str_starts_with($role, $prefix)
);
foreach ($currentCustomRoles as $role) {
$customRoles = $this->getCurrentCustomRoles();

if (0 === count($customRoles)) {
$this->wpCli::warning("No custom roles with prefix '" . $this->prefix . "' found in database. Skipping custom role deletion.");

return;
}

foreach ($customRoles as $role) {
$this->roleCommand->delete([$role]);
}
}

/**
* @return array<int, string>
*/
private function getCurrentCustomRoles(): array
{
return array_filter(
array_keys(wp_roles()->roles),
fn (string $role): bool => str_starts_with($role, $this->prefix)
);
}

private function addCustomRoles(): void
{
WP_CLI::log(WP_CLI::colorize('%MCreate custom roles:%n'));
$this->wpCli::log($this->wpCli::colorize('%MCreate custom roles:%n'));

if (false === $this->rolesValid()) {
$this->wpCli::warning('No roles found in config. Skipping custom role creation.');

return;
}

$prefix = config('user-roles.prefix');
$roles = config('user-roles.roles');
Assert::isArray($roles);
$roles = $this->config['roles'];

foreach ($roles as $role => $properties) {
if (! isset($properties['display_name']) || ! is_string($properties['display_name'])) {
$this->wpCli::warning("No display name configured for role $role. Skipping role creation.");

continue;
}

$capabilities = [];
if (! empty($properties['cap_groups'])) {
$capGroups = config('user-roles.cap_groups');
$capGroups = $this->config['cap_groups'];
Assert::isArray($capGroups);
Assert::isArray($properties['cap_groups']);
foreach ($properties['cap_groups'] as $group) {
Expand All @@ -81,7 +117,7 @@ private function addCustomRoles(): void
foreach ($properties['post_type_caps'] as $postType) {
$postTypeCaps = get_post_type_object($postType)?->cap;
if (null === $postTypeCaps) {
WP_CLI::warning("Post type $postType does not exist. Skipping post type caps.");
$this->wpCli::warning("Post type '$postType' does not exist. Skipping post type caps.");

continue;
}
Expand All @@ -104,11 +140,11 @@ private function addCustomRoles(): void
}

$this->roleCommand->create([
$prefix . '_' . $role,
$this->prefix . $role,
$properties['display_name'],
], $clone);

$role = get_role($prefix . '_' . $role);
$role = get_role($this->prefix . $role);

Assert::notNull($role);

Expand All @@ -118,23 +154,43 @@ private function addCustomRoles(): void
}
}

private function rolesValid(): bool
{
return isset($this->config['roles'])
&& is_array($this->config['roles'])
&& 0 !== count($this->config['roles']);
}

private function resetCoreRoles(): void
{
WP_CLI::log(WP_CLI::colorize('%MReset core roles:%n'));
$this->wpCli::log($this->wpCli::colorize('%MReset core roles:%n'));

$this->roleCommand->reset([], ['all' => true]);
}

private function removeCoreRoles(): void
private function deleteCoreRoles(): void
{
WP_CLI::log(WP_CLI::colorize('%MDelete core roles:%n'));
$this->wpCli::log($this->wpCli::colorize('%MDelete core roles:%n'));

$coreRoles = config('user-roles.core_roles');
if (! $this->coreRolesValid()) {
$this->wpCli::warning('No core roles found in config. Skipping core role deletion.');

return;
}

$coreRoles = $this->config['core_roles'];

foreach ($coreRoles as $role => $shouldStay) {
if (false === $shouldStay) {
$this->roleCommand->delete([$role]);
}
}
}

private function coreRolesValid(): bool
{
return isset($this->config['core_roles'])
&& is_array($this->config['core_roles'])
&& 0 !== count($this->config['core_roles']);
}
}
6 changes: 5 additions & 1 deletion src/UserRolesServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public function configurePackage(Package $package): void

public function packageRegistered(): void
{
$this->app->singleton(UserRoles::class, fn () => new UserRoles(new \Role_Command));
$this->app->bind(UserRoles::class, fn () => new UserRoles(
config('user-roles'),
new \Role_Command(),
new \WP_CLI()
));
}
}
31 changes: 28 additions & 3 deletions tests/Console/UserRolesCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,35 @@

declare(strict_types=1);

use Yard\UserRoles\Facades\UserRoles;
use Facades\Yard\UserRoles\UserRoles;

it('calls setRoles on UserRoles and outputs messages', function () {
UserRoles::shouldReceive('setRoles')->once();
it('creates roles once when not in multisite', function () {
WP_Mock::userFunction('is_multisite', [
'return' => false,
]);

UserRoles::shouldReceive('createRoles')->once();

$this->artisan('roles:create')
->expectsOutput('Updating roles...')
->expectsOutput('All done!')
->assertExitCode(0);
});

it('creates roles for each site when in multisite', function () {
WP_Mock::userFunction('is_multisite', [
'return' => true,
]);

WP_Mock::userFunction('get_sites', [
'return' => [1, 2, 3],
]);

WP_Mock::userFunction('switch_to_blog', [
'times' => 3,
]);

UserRoles::shouldReceive('createRoles')->times(3);

$this->artisan('roles:create')
->expectsOutput('Updating roles...')
Expand Down
13 changes: 13 additions & 0 deletions tests/Facades/UserRolesFacadeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

use Mockery\MockInterface;

it('can call createRoles statically on UserRoles using the facade', function () {
$this->mock(\Yard\UserRoles\UserRoles::class, function (MockInterface $mock) {
$mock->shouldReceive('createRoles')->once();
});

Yard\UserRoles\Facades\UserRoles::createRoles();
});
3 changes: 0 additions & 3 deletions tests/Facades/UserRolesTest.php

This file was deleted.

Loading

0 comments on commit 467f914

Please sign in to comment.