Skip to content

Commit 96790b1

Browse files
authored
Merge pull request #5 from RhubarbPHP/feature/DefinedRolePermissions
defined role permission management
2 parents e4fa4e8 + 9389636 commit 96790b1

26 files changed

+3097
-10
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/.idea/
2+
/composer.lock
3+
/vendor/
4+
/tests/_output/*
5+
/bin/

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# Change log
22

3+
### 1.2.0
4+
5+
* Added: Codeception
6+
* Added: .gitignore file
7+
* Added: Custard command to update roles and permissions
8+
* Added: Module now has method for updating roles and managing their assigned permissions
9+
310
### 1.1.1
11+
412
* Fixed: Authentication module updated with leaf v1 support
513

614
### 1.1.0

codeception.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
actor: Tester
2+
paths:
3+
tests: tests
4+
log: tests/_output
5+
data: tests/_data
6+
support: tests/_support
7+
envs: tests/_envs
8+
settings:
9+
bootstrap: _bootstrap.php
10+
colors: true
11+
memory_limit: 1024M
12+
extensions:
13+
enabled:
14+
- Codeception\Extension\RunFailed
15+
modules:
16+
config:
17+
Db:
18+
dsn: ''
19+
user: ''
20+
password: ''
21+
dump: tests/_data/dump.sql

composer.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
"require": {
1414
"rhubarbphp/rhubarb": "^1.1",
1515
"rhubarbphp/module-stem": "^1.2",
16-
"rhubarbphp/scaffold-authentication": "^1.0"
16+
"rhubarbphp/scaffold-authentication": "^1.0",
17+
"rhubarbphp/custard": "^1.0"
1718
},
1819
"require-dev": {
19-
"phpunit/phpunit": "3.*"
20+
"codeception/codeception": "2.1.*"
21+
},
22+
"config": {
23+
"bin-dir": "bin/"
2024
}
2125
}

src/AuthenticationWithRolesModule.php

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@
1818

1919
namespace Rhubarb\Scaffolds\AuthenticationWithRoles;
2020

21+
use Rhubarb\Custard\Command\CustardCommand;
2122
use Rhubarb\Scaffolds\Authentication\AuthenticationModule;
23+
use Rhubarb\Scaffolds\AuthenticationWithRoles\Commands\UpdateRolePermissionsCommand;
24+
use Rhubarb\Stem\Exceptions\RecordNotFoundException;
25+
use Rhubarb\Stem\Filters\Equals;
26+
use Rhubarb\Stem\Filters\Not;
27+
use Rhubarb\Stem\Filters\OneOf;
2228
use Rhubarb\Stem\Schema\SolutionSchema;
2329

2430
/**
@@ -35,6 +41,78 @@ public function initialise()
3541
{
3642
parent::initialise();
3743

38-
SolutionSchema::registerSchema("Authentication", __NAMESPACE__ . '\DatabaseSchema');
44+
SolutionSchema::registerSchema('Authentication', DatabaseSchema::class);
3945
}
40-
}
46+
47+
public static function updateRolePermissions()
48+
{
49+
/** @var Role[] $roleRecords */
50+
$roleRecords = [];
51+
/** @var Permission $permissionRecords */
52+
$permissionRecords = [];
53+
54+
$permissionAssignmentIDs = [];
55+
56+
$permissionMaintainer = function (
57+
$permissionRules,
58+
$allow
59+
) use (
60+
&$permissionRecords,
61+
&$roleRecords,
62+
&$permissionAssignmentIDs
63+
) {
64+
foreach ($permissionRules as $roleName => $permissions) {
65+
if (!isset($roleRecords[$roleName])) {
66+
try {
67+
$role = Role::findFirst(new Equals('RoleName', $roleName));
68+
} catch (RecordNotFoundException $ex) {
69+
$role = new Role();
70+
$role->RoleName = $roleName;
71+
$role->save();
72+
}
73+
$roleRecords[$roleName] = $role;
74+
}
75+
76+
foreach ($permissions as $permissionPath) {
77+
if (!isset($permissionRecords[$permissionPath])) {
78+
try {
79+
$permission = Permission::findFirst(new Equals('PermissionPath', $permissionPath));
80+
} catch (RecordNotFoundException $ex) {
81+
$permission = new Permission();
82+
$permission->PermissionPath = $permissionPath;
83+
$permission->PermissionName = $permissionPath;
84+
$permission->save();
85+
}
86+
$permissionRecords[$permissionPath] = $permission;
87+
}
88+
$permissionAssignmentIDs[] = $allow
89+
? $roleRecords[$roleName]->allow($permissionRecords[$permissionPath])
90+
: $roleRecords[$roleName]->deny($permissionRecords[$permissionPath]);
91+
}
92+
}
93+
};
94+
95+
/** @var RolePermissionDefinitions $settings */
96+
$settings = RolePermissionDefinitions::singleton();
97+
98+
$permissionMaintainer($settings->allowRolePermissions, true);
99+
$permissionMaintainer($settings->denyRolePermissions, false);
100+
101+
if (count($permissionAssignmentIDs) > 0) {
102+
PermissionAssignment::find(
103+
new Not(new OneOf('PermissionAssignmentID', $permissionAssignmentIDs))
104+
)->deleteAll();
105+
}
106+
}
107+
108+
/**
109+
* @return CustardCommand[]
110+
*/
111+
public function getCustardCommands()
112+
{
113+
$commands = parent::getCustardCommands();
114+
$commands[] = new UpdateRolePermissionsCommand();
115+
116+
return $commands;
117+
}
118+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Rhubarb\Scaffolds\AuthenticationWithRoles\Commands;
4+
5+
use Rhubarb\Scaffolds\AuthenticationWithRoles\AuthenticationWithRolesModule;
6+
use Rhubarb\Stem\Custard\RequiresRepositoryCommand;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Console\Question\Question;
10+
11+
class UpdateRolePermissionsCommand extends RequiresRepositoryCommand
12+
{
13+
protected function configure()
14+
{
15+
$this->setName('auth:update-role-permissions')
16+
->setDescription('Updates Roles and Permissions according to a definitions specified in the application. Useful if the application does not allow users to customise role permissions.')
17+
->addOption('f', null, null, 'Forces update - does not prompt user');
18+
19+
parent::configure();
20+
}
21+
22+
protected function executeWithConnection(InputInterface $input, OutputInterface $output)
23+
{
24+
$helper = $this->getHelper('question');
25+
26+
$force = $input->getOption('f');
27+
28+
if (!$force) {
29+
$output->writeln('<comment>Warning: New roles may be created, and all permissions associated with a role may be updated/removed if not specified in RolePermissionDefinitions.</comment>');
30+
}
31+
$verify = new Question(
32+
'<question>Are you sure you want to proceed? [y/n] </question>'
33+
);
34+
$verify->setValidator(function ($value) use ($output) {
35+
if (stripos($value, 'y') !== 0) {
36+
$output->writeln('<error>Aborted</error>');
37+
return false;
38+
}
39+
return true;
40+
});
41+
if ($force || $helper->ask($input, $output, $verify)) {
42+
if (!$force) {
43+
$output->writeln('<comment>If you would like to suppress user verification in the future, use the --f option</comment>');
44+
}
45+
AuthenticationWithRolesModule::updateRolePermissions();
46+
$output->writeln('<info>Role Permissions Updated</info>');
47+
}
48+
}
49+
}

src/RolePermissionDefinitions.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Rhubarb\Scaffolds\AuthenticationWithRoles;
4+
5+
use Rhubarb\Crown\Settings;
6+
7+
class RolePermissionDefinitions extends Settings
8+
{
9+
public $allowRolePermissions = [];
10+
public $denyRolePermissions = [];
11+
12+
/**
13+
* @param string $role
14+
* @param array $permissions
15+
*/
16+
public function allowPermissionsForRole($role, $permissions)
17+
{
18+
$this->setRolePermissionProperty($role, $permissions, true);
19+
}
20+
21+
/**
22+
* @param string $role
23+
* @param array $permissions
24+
*/
25+
public function denyPermissionsForRole($role, $permissions)
26+
{
27+
$this->setRolePermissionProperty($role, $permissions, false);
28+
}
29+
30+
/**
31+
* @param string $role
32+
* @param array $allowPermissions
33+
* @param array $denyPermissions
34+
*/
35+
public function setPermissionsForRole($role, $allowPermissions, $denyPermissions)
36+
{
37+
$this->setRolePermissionProperty($role, $allowPermissions, true);
38+
$this->setRolePermissionProperty($role, $denyPermissions, false);
39+
}
40+
41+
/**
42+
* @param string $role
43+
* @param string $permissions
44+
* @param bool $allow
45+
*/
46+
private function setRolePermissionProperty($role, $permissions, $allow)
47+
{
48+
$property = $allow ? 'allowRolePermissions' : 'denyRolePermissions';
49+
$array = $this->$property;
50+
$array[$role] = isset($array[$role])
51+
? array_merge($array[$role], $permissions)
52+
: $permissions;
53+
$this->$property = $array;
54+
}
55+
}

tests/_bootstrap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
// This is global bootstrap for autoloading

tests/_data/dump.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* Replace this file with actual dump of your database */

tests/_output/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

0 commit comments

Comments
 (0)