From 1a733a6ba65adf09e14f910739e11796223b201d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 14 Oct 2026 12:41:57 +0200 Subject: [PATCH] feat: open the logs to every administrative role --- config/packages/security.yaml | 6 +++--- .../Admin/Log/DownloadController.php | 3 ++- src/Controller/Admin/Log/FilterController.php | 3 ++- src/Controller/Admin/Log/IndexController.php | 3 ++- .../Admin/Log/XmlDumpController.php | 3 ++- .../DashboardWidgetProviderInterface.php | 3 ++- .../Widget/RecentLogEntriesWidgetProvider.php | 4 ++-- src/Menu/AdminMenuBuilder.php | 21 ++++++++++--------- .../RecentLogEntriesWidgetProviderTest.php | 4 ++-- 9 files changed, 28 insertions(+), 22 deletions(-) diff --git a/config/packages/security.yaml b/config/packages/security.yaml index c9e4b43e..07084cc3 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -22,9 +22,9 @@ security: users: [] role_hierarchy: - # ROLE_CUSTOMER_EXPERT gates the booking-draft and log surfaces, which used to be - # ROLE_ADMIN only. Inheriting it here is what keeps those surfaces open to administrators - # after the #[IsGranted] attributes moved to the narrower role. + # ROLE_CUSTOMER_EXPERT gates the customer-service surfaces (booking drafts, travel + # mailing). Inheriting it here is what keeps them open to administrators: the booking + # drafts used to be ROLE_ADMIN only before their #[IsGranted] moved to the narrower role. ROLE_ADMIN: - ROLE_GROUPS_ADMIN - ROLE_CUSTOMER_EXPERT diff --git a/src/Controller/Admin/Log/DownloadController.php b/src/Controller/Admin/Log/DownloadController.php index 2c887eca..b9a7f4fb 100644 --- a/src/Controller/Admin/Log/DownloadController.php +++ b/src/Controller/Admin/Log/DownloadController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Controller\Admin\Log; +use App\Security\Voter\AdministrativeAccessVoter; use App\Service\XmlDumpReader; use League\Flysystem\FilesystemException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -12,7 +13,7 @@ use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[IsGranted('ROLE_CUSTOMER_EXPERT')] +#[IsGranted(AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS)] class DownloadController extends AbstractController { public function __construct(private readonly XmlDumpReader $xmlDumpReader) diff --git a/src/Controller/Admin/Log/FilterController.php b/src/Controller/Admin/Log/FilterController.php index e303f740..98697fec 100644 --- a/src/Controller/Admin/Log/FilterController.php +++ b/src/Controller/Admin/Log/FilterController.php @@ -8,13 +8,14 @@ use App\Controller\Traits\ListFilterTrait; use App\Form\Admin\Filter\LogEntryFilterType; use App\Form\Model\Filter\LogEntryFilterDto; use App\Repository\LogEntryRepository; +use App\Security\Voter\AdministrativeAccessVoter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[IsGranted('ROLE_CUSTOMER_EXPERT')] +#[IsGranted(AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS)] class FilterController extends AbstractController { use ListFilterTrait; diff --git a/src/Controller/Admin/Log/IndexController.php b/src/Controller/Admin/Log/IndexController.php index ffdfbee6..d0f0cc06 100644 --- a/src/Controller/Admin/Log/IndexController.php +++ b/src/Controller/Admin/Log/IndexController.php @@ -8,6 +8,7 @@ use App\Controller\Traits\ListFilterTrait; use App\Form\Admin\Filter\LogEntryFilterType; use App\Form\Model\Filter\LogEntryFilterDto; use App\Repository\LogEntryRepository; +use App\Security\Voter\AdministrativeAccessVoter; use Knp\Component\Pager\PaginatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; @@ -15,7 +16,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[IsGranted('ROLE_CUSTOMER_EXPERT')] +#[IsGranted(AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS)] class IndexController extends AbstractController { use ListFilterTrait; diff --git a/src/Controller/Admin/Log/XmlDumpController.php b/src/Controller/Admin/Log/XmlDumpController.php index 0e07acc8..70559aff 100644 --- a/src/Controller/Admin/Log/XmlDumpController.php +++ b/src/Controller/Admin/Log/XmlDumpController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Controller\Admin\Log; use App\Entity\LogEntry; +use App\Security\Voter\AdministrativeAccessVoter; use App\Service\XmlDumpReader; use League\Flysystem\FilesystemException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -12,7 +13,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; -#[IsGranted('ROLE_CUSTOMER_EXPERT')] +#[IsGranted(AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS)] class XmlDumpController extends AbstractController { public function __construct(private readonly XmlDumpReader $xmlDumpReader) diff --git a/src/Dashboard/Contract/DashboardWidgetProviderInterface.php b/src/Dashboard/Contract/DashboardWidgetProviderInterface.php index f63760f6..9d003306 100644 --- a/src/Dashboard/Contract/DashboardWidgetProviderInterface.php +++ b/src/Dashboard/Contract/DashboardWidgetProviderInterface.php @@ -17,7 +17,8 @@ interface DashboardWidgetProviderInterface { /** * The role this widget requires, checked with isGranted() — so a widget requiring - * ROLE_GROUPS_MANAGER also appears for the roles above it in the hierarchy. + * ROLE_GROUPS_MANAGER also appears for the roles above it in the hierarchy. A voter + * attribute such as ADMINISTRATIVE_ACCESS works too, for a widget every admin-area role sees. */ public function getRequiredRole(): string; diff --git a/src/Dashboard/Widget/RecentLogEntriesWidgetProvider.php b/src/Dashboard/Widget/RecentLogEntriesWidgetProvider.php index 9656c12e..3949e16a 100644 --- a/src/Dashboard/Widget/RecentLogEntriesWidgetProvider.php +++ b/src/Dashboard/Widget/RecentLogEntriesWidgetProvider.php @@ -9,7 +9,7 @@ use App\Entity\LogEntry; use App\Model\DashboardWidget; use App\Model\DashboardWidgetEntry; use App\Repository\LogEntryRepository; -use App\Security\Role; +use App\Security\Voter\AdministrativeAccessVoter; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** @@ -37,7 +37,7 @@ class RecentLogEntriesWidgetProvider implements DashboardWidgetProviderInterface public function getRequiredRole(): string { - return Role::CUSTOMER_EXPERT; + return AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS; } public function getPriority(): int diff --git a/src/Menu/AdminMenuBuilder.php b/src/Menu/AdminMenuBuilder.php index 2a8f61bd..5513057c 100644 --- a/src/Menu/AdminMenuBuilder.php +++ b/src/Menu/AdminMenuBuilder.php @@ -81,16 +81,6 @@ class AdminMenuBuilder ]); } if ($this->security->isGranted('ROLE_CUSTOMER_EXPERT')) { - $menu->addChild('Logs', [ - 'route' => 'app_admin_log', - 'linkAttributes' => [ - 'title' => 'Logs', - ], - 'extras' => [ - 'icon' => 'list', - 'routes' => [['pattern' => '/^app_admin_log/']], - ], - ]); $menu->addChild('Reise-Mailingliste', [ 'route' => 'app_admin_travelmailing', 'linkAttributes' => [ @@ -102,6 +92,17 @@ class AdminMenuBuilder ]); } + $menu->addChild('Logs', [ + 'route' => 'app_admin_log', + 'linkAttributes' => [ + 'title' => 'Logs', + ], + 'extras' => [ + 'icon' => 'list', + 'routes' => [['pattern' => '/^app_admin_log/']], + ], + ]); + $this->addLogoutItem($menu); return $menu; diff --git a/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php b/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php index a8211d37..9c46d84a 100644 --- a/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php +++ b/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php @@ -7,7 +7,7 @@ namespace App\Tests\Dashboard; use App\Dashboard\Widget\RecentLogEntriesWidgetProvider; use App\Entity\LogEntry; use App\Repository\LogEntryRepository; -use App\Security\Role; +use App\Security\Voter\AdministrativeAccessVoter; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -57,7 +57,7 @@ class RecentLogEntriesWidgetProviderTest extends TestCase $provider = new RecentLogEntriesWidgetProvider($repository, $this->urlGenerator()); - $this->assertSame(Role::CUSTOMER_EXPERT, $provider->getRequiredRole()); + $this->assertSame(AdministrativeAccessVoter::ADMINISTRATIVE_ACCESS, $provider->getRequiredRole()); $this->assertNotNull($provider->build()); }