Skip to content

Commit

Permalink
roles matrix sort by admin and group
Browse files Browse the repository at this point in the history
admin roles sort by admin config and group config
admin_label set admin translation domain
  • Loading branch information
piddubnij committed Dec 9, 2022
1 parent 4e74d54 commit 0f3e6f2
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 40 deletions.
18 changes: 14 additions & 4 deletions src/Resources/views/Form/roles_matrix.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,26 @@ file that was distributed with this source code.
<table class="table table-condensed">
<thead>
<tr>
<th></th>
<th></th>
{% for label in permission_labels|sort %}
<th> {{ label }} </th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for admin_label, roles in grouped_roles %}
<tr>
<th>{{ admin_label }}</th>
{% for group_code, admin_roles in grouped_roles %}
{% set new_group = true %}
{% for admin_code, roles in admin_roles %}
<tr>
{% for role, attributes in roles|sort %}
{% if loop.first %}
{% if new_group %}
{% set new_group = false %}
<th rowspan="{{ admin_roles|length }}" scope="rowgroup">{{ attributes.group_label|default('') }}</th>
{% endif %}
<th>{{ attributes.admin_label|default('') }}</th>
{% endif %}
<td>
{{ form_widget(attributes.form, { label: false }) }}
{% if not attributes.is_granted %}
Expand All @@ -34,7 +43,8 @@ file that was distributed with this source code.
{% endif %}
</td>
{% endfor %}
</tr>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
Expand Down
72 changes: 56 additions & 16 deletions src/Security/RolesBuilder/AdminRolesBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

/**
* @author Silas Joisten <[email protected]>
*
* @phpstan-import-type Role from RolesBuilderInterface
*/
final class AdminRolesBuilder implements AdminRolesBuilderInterface
{
Expand Down Expand Up @@ -76,27 +78,65 @@ public function addExcludeAdmin(string $exclude): void

public function getRoles(?string $domain = null): array
{
$adminServiceCodes = array_diff($this->pool->getAdminServiceCodes(), $this->excludeAdmins);

// get groups and admins sort by config
$adminRoles = [];
foreach ($this->pool->getAdminServiceCodes() as $code) {
if (\in_array($code, $this->excludeAdmins, true)) {
continue;
}
foreach ($this->pool->getAdminGroups() as $groupCode => $group) {
foreach ($group['items'] as $item) {
if (!isset($item['admin'])) {
continue;
}

$key = array_search($item['admin'], $adminServiceCodes, true);
if (false === $key) {
continue;
}
unset($adminServiceCodes[$key]);

$admin = $this->pool->getInstance($code);
$securityHandler = $admin->getSecurityHandler();
$baseRole = $securityHandler->getBaseRole($admin);
foreach (array_keys($admin->getSecurityInformation()) as $key) {
$role = sprintf($baseRole, $key);
$adminRoles[$role] = [
'role' => $role,
'label' => $key,
'role_translated' => $this->translateRole($role, $domain),
'is_granted' => $this->isMaster($admin) || $this->authorizationChecker->isGranted($role),
'admin_label' => $admin->getTranslator()->trans($admin->getLabel() ?? ''),
];
$groupLabelTranslated = $this->translator->trans($group['label'], [], $group['translation_domain']);

$adminRoles = array_merge($adminRoles, $this->getAdminRolesByAdminCode($item['admin'], $domain, $groupLabelTranslated, $groupCode));
}
}

// admin with config "show_in_dashboard" set "false" does not have group
$defaultGroupLabelTranslated = $this->translator->trans('_', [], $domain);
$defaultGroupCode = '_';
foreach ($adminServiceCodes as $code) {
$adminRoles = array_merge($adminRoles, $this->getAdminRolesByAdminCode($code, $domain, $defaultGroupLabelTranslated, $defaultGroupCode));
}

return $adminRoles;
}

/**
* @return array<string, array<string, string|bool>>
*
* @phpstan-return array<string, Role>
*/
private function getAdminRolesByAdminCode(string $code, ?string $domain = null, string $groupLabelTranslated = '_', string $groupCode = '_'): array
{
$adminRoles = [];
$admin = $this->pool->getInstance($code);
$securityHandler = $admin->getSecurityHandler();
$baseRole = $securityHandler->getBaseRole($admin);
$adminLabelTranslated = $admin->getTranslator()->trans($admin->getLabel() ?? '', [], $admin->getTranslationDomain());
$isMasterAdmin = $this->isMaster($admin);
foreach (array_keys($admin->getSecurityInformation()) as $key) {
$role = sprintf($baseRole, $key);
$adminRoles[$role] = [
'role' => $role,
'label' => $key,
'role_translated' => $this->translateRole($role, $domain),
'is_granted' => $isMasterAdmin || $this->authorizationChecker->isGranted($role),
'admin_label' => $adminLabelTranslated,
'admin_code' => $code,
'group_label' => $groupLabelTranslated,
'group_code' => $groupCode,
];
}

return $adminRoles;
}

Expand Down
5 changes: 4 additions & 1 deletion src/Security/RolesBuilder/RolesBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
* role_translated: string,
* is_granted: boolean,
* label?: string,
* admin_label?: string
* admin_label?: string,
* admin_code?: string,
* group_label?: string,
* group_code?: string
* }
*/
interface RolesBuilderInterface
Expand Down
7 changes: 4 additions & 3 deletions src/Twig/RolesMatrixExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ public function renderMatrix(Environment $environment, FormView $form): string
{
$groupedRoles = [];
foreach ($this->rolesBuilder->getRoles() as $role => $attributes) {
if (!isset($attributes['admin_label'])) {
if (!isset($attributes['admin_code'])) {
continue;
}

$groupedRoles[$attributes['admin_label']][$role] = $attributes;
$groupCode = $attributes['group_code'] ?? '_';
$groupedRoles[$groupCode][$attributes['admin_code']][$role] = $attributes;
foreach ($form->getIterator() as $child) {
if ($child->vars['value'] === $role) {
$groupedRoles[$attributes['admin_label']][$role]['form'] = $child;
$groupedRoles[$groupCode][$attributes['admin_code']][$role]['form'] = $child;
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion tests/Security/RolesBuilder/AdminRolesBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,19 @@ protected function setUp(): void
$container = new Container();
$container->set('sonata.admin.bar', $this->admin);

$this->pool = new Pool($container, ['sonata.admin.bar']);
$adminGroups = [
'bar' => [
'label' => 'Bar',
'translation_domain' => '',
'icon' => '<i class="fas fa-edit"></i>',
'items' => [['admin' => 'sonata.admin.bar', 'roles' => [], 'route_absolute' => false, 'route_params' => []]],
'keep_open' => false,
'on_top' => false,
'roles' => [],
],
];

$this->pool = new Pool($container, ['sonata.admin.bar'], $adminGroups);
$this->configuration = new SonataConfiguration('title', 'logo', [
'confirm_exit' => true,
'default_admin_route' => 'show',
Expand Down Expand Up @@ -170,27 +182,39 @@ public function testGetRoles(): void
'role_translated' => 'ROLE_SONATA_FOO_GUEST',
'is_granted' => false,
'admin_label' => 'Foo',
'admin_code' => 'sonata.admin.bar',
'group_label' => 'Foo',
'group_code' => 'bar',
],
'ROLE_SONATA_FOO_STAFF' => [
'role' => 'ROLE_SONATA_FOO_STAFF',
'label' => 'STAFF',
'role_translated' => 'ROLE_SONATA_FOO_STAFF',
'is_granted' => false,
'admin_label' => 'Foo',
'admin_code' => 'sonata.admin.bar',
'group_label' => 'Foo',
'group_code' => 'bar',
],
'ROLE_SONATA_FOO_EDITOR' => [
'role' => 'ROLE_SONATA_FOO_EDITOR',
'label' => 'EDITOR',
'role_translated' => 'ROLE_SONATA_FOO_EDITOR',
'is_granted' => false,
'admin_label' => 'Foo',
'admin_code' => 'sonata.admin.bar',
'group_label' => 'Foo',
'group_code' => 'bar',
],
'ROLE_SONATA_FOO_ADMIN' => [
'role' => 'ROLE_SONATA_FOO_ADMIN',
'label' => 'ADMIN',
'role_translated' => 'ROLE_SONATA_FOO_ADMIN',
'is_granted' => false,
'admin_label' => 'Foo',
'admin_code' => 'sonata.admin.bar',
'group_label' => 'Foo',
'group_code' => 'bar',
],
];

Expand Down
46 changes: 31 additions & 15 deletions tests/Twig/RolesMatrixExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ public function testRenderMatrix(): void
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'admin_code' => 'fooadmin',
'group_label' => 'BarGroup',
'group_code' => 'bargroup',
],
];
$this->rolesBuilder
Expand All @@ -226,14 +229,19 @@ public function testRenderMatrix(): void
->method('render')
->with('@SonataUser/Form/roles_matrix.html.twig', [
'grouped_roles' => [
'fooadmin' => [
'BASE_ROLE_FOO_EDIT' => [
'role' => 'BASE_ROLE_FOO_EDIT',
'label' => 'EDIT',
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'form' => $form,
'bargroup' => [
'fooadmin' => [
'BASE_ROLE_FOO_EDIT' => [
'role' => 'BASE_ROLE_FOO_EDIT',
'label' => 'EDIT',
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'admin_code' => 'fooadmin',
'group_label' => 'BarGroup',
'group_code' => 'bargroup',
'form' => $form,
],
],
],
],
Expand All @@ -254,6 +262,9 @@ public function testRenderMatrixFormVarsNotSet(): void
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'admin_code' => 'fooadmin',
'group_label' => 'BarGroup',
'group_code' => 'bargroup',
],
];
$this->rolesBuilder
Expand All @@ -279,13 +290,18 @@ public function testRenderMatrixFormVarsNotSet(): void
->method('render')
->with('@SonataUser/Form/roles_matrix.html.twig', [
'grouped_roles' => [
'fooadmin' => [
'BASE_ROLE_FOO_%s' => [
'role' => 'BASE_ROLE_FOO_EDIT',
'label' => 'EDIT',
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'bargroup' => [
'fooadmin' => [
'BASE_ROLE_FOO_%s' => [
'role' => 'BASE_ROLE_FOO_EDIT',
'label' => 'EDIT',
'role_translated' => 'ROLE FOO TRANSLATED',
'admin_label' => 'fooadmin',
'is_granted' => true,
'admin_code' => 'fooadmin',
'group_label' => 'BarGroup',
'group_code' => 'bargroup',
],
],
],
],
Expand Down

0 comments on commit 0f3e6f2

Please sign in to comment.