diff --git a/src/Zikula/Bundle/FormExtensionBundle/Event/FormTypeChoiceEvent.php b/src/Zikula/Bundle/FormExtensionBundle/Event/FormTypeChoiceEvent.php index ba07f77c4b..5dd3d4e408 100644 --- a/src/Zikula/Bundle/FormExtensionBundle/Event/FormTypeChoiceEvent.php +++ b/src/Zikula/Bundle/FormExtensionBundle/Event/FormTypeChoiceEvent.php @@ -17,7 +17,7 @@ class FormTypeChoiceEvent { - public function __construct(private readonly FormTypesChoices $choices) + public function __construct(private FormTypesChoices $choices) { } diff --git a/src/system/CategoriesBundle/Entity/Category.php b/src/system/CategoriesBundle/Entity/Category.php index 1e1f57cb12..d5ab5bb27e 100644 --- a/src/system/CategoriesBundle/Entity/Category.php +++ b/src/system/CategoriesBundle/Entity/Category.php @@ -32,7 +32,7 @@ class Category #[ORM\Id] #[ORM\Column] #[ORM\GeneratedValue] - private ?int $id; + private ?int $id = null; #[ORM\Column] #[Gedmo\TreeLeft] @@ -245,9 +245,9 @@ public function setDisplayDesc(array $displayDesc): self return $this; } - public function getStatus(): bool + public function getStatus(): string { - return 'A' === $this->status; + return $this->status; } public function setStatus($status): self diff --git a/src/system/CategoriesBundle/Menu/ExtensionMenu.php b/src/system/CategoriesBundle/Menu/ExtensionMenu.php index a8d2f85678..0329f041e0 100644 --- a/src/system/CategoriesBundle/Menu/ExtensionMenu.php +++ b/src/system/CategoriesBundle/Menu/ExtensionMenu.php @@ -14,12 +14,20 @@ namespace Zikula\CategoriesBundle\Menu; use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; +use Zikula\CategoriesBundle\Entity\Category; use Zikula\ThemeBundle\ExtensionMenu\AbstractExtensionMenu; +use function Symfony\Component\Translation\t; class ExtensionMenu extends AbstractExtensionMenu { protected function getAdmin(): iterable { + yield MenuItem::linkToCrud(t('Categories'), 'fas fa-sitemap', Category::class); + yield MenuItem::linkToCrud(t('Add category'), 'fas fa-plus', Category::class) + ->setAction('new'); + + yield MenuItem::section('Old stuff'); + yield MenuItem::linktoRoute('Category tree', 'fas fa-tree', 'zikulacategoriesbundle_category_listcategories') ->setPermission('ROLE_EDITOR'); yield MenuItem::linktoRoute('Category registry', 'fas fa-archive', 'zikulacategoriesbundle_registry_edit') diff --git a/src/system/LegalBundle/Controller/UserController.php b/src/system/LegalBundle/Controller/UserController.php index 51db90cf03..603239befa 100644 --- a/src/system/LegalBundle/Controller/UserController.php +++ b/src/system/LegalBundle/Controller/UserController.php @@ -14,17 +14,18 @@ namespace Zikula\LegalBundle\Controller; use Doctrine\Persistence\ManagerRegistry; +use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Zikula\Bundle\CoreBundle\Site\SiteDefinitionInterface; use Zikula\LegalBundle\Form\Type\AcceptPoliciesType; use Zikula\LegalBundle\Helper\AcceptPoliciesHelper; use Zikula\LegalBundle\LegalConstant; +use Zikula\ThemeBundle\Controller\Dashboard\UserDashboardController; use Zikula\UsersBundle\Api\ApiInterface\CurrentUserApiInterface; use Zikula\UsersBundle\Entity\User; use Zikula\UsersBundle\Helper\AccessHelper; @@ -44,9 +45,15 @@ public function __construct( * Redirects to the Terms of Use legal document. */ #[Route('', name: 'zikulalegalbundle_user_index', methods: ['GET'])] - public function index(RouterInterface $router): RedirectResponse + public function index(AdminUrlGenerator $urlGenerator): RedirectResponse { - return $this->redirectToRoute('zikulalegalbundle_user_legalnotice'); + return $this->redirect( + $urlGenerator + ->setDashboard(UserDashboardController::class) + ->setController(self::class) + ->setRoute('zikulalegalbundle_user_legalnotice') + ->generateUrl() + ); } /** diff --git a/src/system/LegalBundle/Resources/views/User/acceptPolicies.html.twig b/src/system/LegalBundle/Resources/views/User/acceptPolicies.html.twig index 4ae9be9ab7..4d46f548d8 100644 --- a/src/system/LegalBundle/Resources/views/User/acceptPolicies.html.twig +++ b/src/system/LegalBundle/Resources/views/User/acceptPolicies.html.twig @@ -1,28 +1,30 @@ -{{ pageSetVar('title', 'Site policies'|trans) }} -

{{ 'Site policies'|trans }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{% if login %} -
- {% trans %}In order to log in you must accept this site\'s policies. If you have accepted the site\'s policies in the past, then they have been updated and we ask that you review the changes.{% endtrans %} -
- {% trans %}If you leave this page without successfully accepting the policies, then you will not be logged in.{% endtrans %} -
-{% endif %} +{% block content_title 'Site policies'|trans %} +{% block main %} + {% if login %} +
+ {% trans %}In order to log in you must accept this site\'s policies. If you have accepted the site\'s policies in the past, then they have been updated and we ask that you review the changes.{% endtrans %} +
+ {% trans %}If you leave this page without successfully accepting the policies, then you will not be logged in.{% endtrans %} +
+ {% endif %} - + +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/accessibilityStatement.html.twig b/src/system/LegalBundle/Resources/views/User/accessibilityStatement.html.twig index f51115752d..64e71dc5ea 100644 --- a/src/system/LegalBundle/Resources/views/User/accessibilityStatement.html.twig +++ b/src/system/LegalBundle/Resources/views/User/accessibilityStatement.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Accessibility statement for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Accessibility statement for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/accessibilityStatement.html.twig') }} +{% block content_title 'Accessibility statement for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/accessibilityStatement.html.twig') }} +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/cancellationRightPolicy.html.twig b/src/system/LegalBundle/Resources/views/User/cancellationRightPolicy.html.twig index aa598ae86b..2d5e539da9 100644 --- a/src/system/LegalBundle/Resources/views/User/cancellationRightPolicy.html.twig +++ b/src/system/LegalBundle/Resources/views/User/cancellationRightPolicy.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Cancellation right policy for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Cancellation right policy for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/cancellationRightPolicy.html.twig') }} +{% block content_title 'Cancellation right policy for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/cancellationRightPolicy.html.twig') }} +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/legalNotice.html.twig b/src/system/LegalBundle/Resources/views/User/legalNotice.html.twig index f9dc0f8550..04e22b0144 100644 --- a/src/system/LegalBundle/Resources/views/User/legalNotice.html.twig +++ b/src/system/LegalBundle/Resources/views/User/legalNotice.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Legal notice for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Legal notice for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/legalNotice.html.twig') }} +{% block content_title 'Legal notice for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/legalNotice.html.twig') }} +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/policyNotActive.html.twig b/src/system/LegalBundle/Resources/views/User/policyNotActive.html.twig index 0023f23310..80b6a6c35f 100644 --- a/src/system/LegalBundle/Resources/views/User/policyNotActive.html.twig +++ b/src/system/LegalBundle/Resources/views/User/policyNotActive.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Policy not available'|trans) }} -

{{ 'Policy not available'|trans }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -

{% trans %}The selected policy is not available.{% endtrans %}

+{% block content_title 'Policy not available'|trans %} +{% block main %} +

{% trans %}The selected policy is not available.{% endtrans %}

+{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/privacyPolicy.html.twig b/src/system/LegalBundle/Resources/views/User/privacyPolicy.html.twig index ef1bd717d4..e884fc8528 100644 --- a/src/system/LegalBundle/Resources/views/User/privacyPolicy.html.twig +++ b/src/system/LegalBundle/Resources/views/User/privacyPolicy.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Privacy policy for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Privacy policy for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/privacyPolicy.html.twig') }} +{% block content_title 'Privacy policy for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/privacyPolicy.html.twig') }} +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/termsOfUse.html.twig b/src/system/LegalBundle/Resources/views/User/termsOfUse.html.twig index d011f4288f..44f878ed10 100644 --- a/src/system/LegalBundle/Resources/views/User/termsOfUse.html.twig +++ b/src/system/LegalBundle/Resources/views/User/termsOfUse.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Terms of use for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Terms of use for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/termsOfUse.html.twig') }} +{% block content_title 'Terms of use for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/termsOfUse.html.twig') }} +{% endblock %} diff --git a/src/system/LegalBundle/Resources/views/User/tradeConditions.html.twig b/src/system/LegalBundle/Resources/views/User/tradeConditions.html.twig index 58cdbfbb6e..afea06780e 100644 --- a/src/system/LegalBundle/Resources/views/User/tradeConditions.html.twig +++ b/src/system/LegalBundle/Resources/views/User/tradeConditions.html.twig @@ -1,4 +1,6 @@ -{{ pageSetVar('title', 'Trade conditions for %s%'|trans({ '%s%': siteName() })) }} -

{{ 'Trade conditions for %s%'|trans({ '%s%': siteName() }) }}

+{% extends '@EasyAdmin/page/content.html.twig' %} -{{ include('@ZikulaLegal/' ~ app.request.locale ~ '/tradeConditions.html.twig') }} +{% block content_title 'Trade conditions for %s%'|trans({ '%s%': siteName() }) %} +{% block main %} + {{ include('@ZikulaLegal/' ~ app.request.locale ~ '/tradeConditions.html.twig') }} +{% endblock %} diff --git a/src/system/ProfileBundle/Bridge/ProfileBundleBridge.php b/src/system/ProfileBundle/Bridge/ProfileBundleBridge.php index 5a74e70a84..494f482f2a 100644 --- a/src/system/ProfileBundle/Bridge/ProfileBundleBridge.php +++ b/src/system/ProfileBundle/Bridge/ProfileBundleBridge.php @@ -20,11 +20,10 @@ use Zikula\ProfileBundle\Helper\GravatarHelper; use Zikula\ProfileBundle\ProfileConstant; use Zikula\UsersBundle\Entity\User; -use Zikula\UsersBundle\ProfileBundle\ProfileBundleInterface; use Zikula\UsersBundle\Repository\UserRepositoryInterface; use function Symfony\Component\String\s; -class ProfileBundleBridge implements ProfileBundleInterface +class ProfileBundleBridge { public function __construct( private readonly RouterInterface $router, diff --git a/src/system/ProfileBundle/Menu/ExtensionMenu.php b/src/system/ProfileBundle/Menu/ExtensionMenu.php index 37c164a659..52e5cfe523 100644 --- a/src/system/ProfileBundle/Menu/ExtensionMenu.php +++ b/src/system/ProfileBundle/Menu/ExtensionMenu.php @@ -15,14 +15,9 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; use Zikula\ThemeBundle\ExtensionMenu\AbstractExtensionMenu; -use Zikula\UsersBundle\ProfileBundle\ProfileBundleCollector; class ExtensionMenu extends AbstractExtensionMenu { - public function __construct(private readonly ProfileBundleCollector $profileBundleCollector) - { - } - protected function getAdmin(): iterable { yield MenuItem::linktoRoute('Property list', 'fas fa-list', 'zikulaprofilebundle_property_listproperties') @@ -43,14 +38,9 @@ protected function getUser(): iterable protected function getAccount(): iterable { - // do not show any account links if Profile is not the Profile manager - if ($this->profileBundleCollector->getSelectedName() !== $this->getBundleName()) { - return null; - } - - yield MenuItem::linktoRoute('Profile', 'fas fa-user', 'zikulaprofilebundle_profile_display', [ + yield MenuItem::linktoRoute('Profile', 'fas fa-user', 'zikulaprofilebundle_profile_display'/*, [ 'uid' => $this->currentUserApi->get('uid'), - ]) + ]*/) ->setPermission('IS_AUTHENTICATED'); } diff --git a/src/system/UsersBundle/Twig/Extension/ProfileExtension.php b/src/system/ProfileBundle/Twig/Extension/ProfileExtension.php similarity index 89% rename from src/system/UsersBundle/Twig/Extension/ProfileExtension.php rename to src/system/ProfileBundle/Twig/Extension/ProfileExtension.php index 84e165e670..abd5b15013 100644 --- a/src/system/UsersBundle/Twig/Extension/ProfileExtension.php +++ b/src/system/ProfileBundle/Twig/Extension/ProfileExtension.php @@ -11,12 +11,12 @@ * file that was distributed with this source code. */ -namespace Zikula\UsersBundle\Twig\Extension; +namespace Zikula\ProfileBundle\Twig\Extension; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; use Twig\TwigFunction; -use Zikula\UsersBundle\Twig\Runtime\ProfileRuntime; +use Zikula\ProfileBundle\Twig\Runtime\ProfileRuntime; class ProfileExtension extends AbstractExtension { diff --git a/src/system/UsersBundle/Twig/Runtime/ProfileRuntime.php b/src/system/ProfileBundle/Twig/Runtime/ProfileRuntime.php similarity index 90% rename from src/system/UsersBundle/Twig/Runtime/ProfileRuntime.php rename to src/system/ProfileBundle/Twig/Runtime/ProfileRuntime.php index 15e9211a82..492f726cd1 100644 --- a/src/system/UsersBundle/Twig/Runtime/ProfileRuntime.php +++ b/src/system/ProfileBundle/Twig/Runtime/ProfileRuntime.php @@ -11,21 +11,21 @@ * file that was distributed with this source code. */ -namespace Zikula\UsersBundle\Twig\Runtime; +namespace Zikula\ProfileBundle\Twig\Runtime; use InvalidArgumentException; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Extension\RuntimeExtensionInterface; +use Zikula\ProfileBundle\Bridge\ProfileBundleBridge; use Zikula\UsersBundle\Entity\User; -use Zikula\UsersBundle\ProfileBundle\ProfileBundleCollector; use Zikula\UsersBundle\Repository\UserRepositoryInterface; use function Symfony\Component\String\s; class ProfileRuntime implements RuntimeExtensionInterface { public function __construct( + private readonly ProfileBundleBridge $profile, private readonly UserRepositoryInterface $userRepository, - private readonly ProfileBundleCollector $profileBundleCollector, private readonly TranslatorInterface $translator ) { } @@ -37,7 +37,7 @@ public function __construct( */ public function getUserAvatar($userId = 0, array $parameters = []): string { - return $this->profileBundleCollector->getSelected()->getAvatar($userId, $parameters); + return $this->profile->getAvatar($userId, $parameters); } /** @@ -116,7 +116,7 @@ private function determineProfileLink( return $userId . $userName; // one or the other is empty } - $userDisplayName = $this->profileBundleCollector->getSelected()->getDisplayName($user->getUid()); + $userDisplayName = $this->profile->getDisplayName($user->getUid()); if (!$userDisplayName) { $userDisplayName = $user->getUname(); } @@ -133,7 +133,7 @@ private function determineProfileLink( } else { $show = htmlspecialchars($userDisplayName, ENT_QUOTES); } - $href = $this->profileBundleCollector->getSelected()->getProfileUrl($user->getUid()); + $href = $this->profile->getProfileUrl($user->getUid()); if ('#' === $href) { return $userDisplayName; } diff --git a/src/system/ProfileBundle/Twig/TwigExtension.php b/src/system/ProfileBundle/Twig/TwigExtension.php index 3c82dc32e2..a930cdc113 100644 --- a/src/system/ProfileBundle/Twig/TwigExtension.php +++ b/src/system/ProfileBundle/Twig/TwigExtension.php @@ -28,10 +28,8 @@ public function getFilters() ]; } - public function formatPropertyForDisplay( - Property $property, - UserAttribute $attribute - ): string { + public function formatPropertyForDisplay(Property $property, UserAttribute $attribute): string + { $value = $attribute->getValue(); if (empty($value)) { return $value; diff --git a/src/system/ThemeBundle/Controller/Dashboard/AbstractThemedDashboardController.php b/src/system/ThemeBundle/Controller/Dashboard/AbstractThemedDashboardController.php index 3cc4e16313..ac2ca069f3 100644 --- a/src/system/ThemeBundle/Controller/Dashboard/AbstractThemedDashboardController.php +++ b/src/system/ThemeBundle/Controller/Dashboard/AbstractThemedDashboardController.php @@ -16,24 +16,30 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Assets; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; +use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; +use EasyCorp\Bundle\EasyAdminBundle\Config\UserMenu; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Translation\TranslatableMessage; use Zikula\Bundle\CoreBundle\Site\SiteDefinitionInterface; use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuCollector; +use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuInterface; use Zikula\ThemeBundle\Helper\AdminBundleHelper; use Zikula\ThemeBundle\Helper\AdminCategoryHelper; +use Zikula\ThemeBundle\Helper\UserMenuExtensionHelper; abstract class AbstractThemedDashboardController extends AbstractDashboardController { public function __construct( protected readonly KernelInterface $kernel, - protected readonly AdminUrlGenerator $adminUrlGenerator, + protected readonly AdminUrlGenerator $urlGenerator, protected readonly AdminCategoryHelper $adminCategoryHelper, protected readonly AdminBundleHelper $adminBundleHelper, protected readonly ExtensionMenuCollector $extensionMenuCollector, + protected readonly UserMenuExtensionHelper $userMenuExtensionHelper, protected readonly SiteDefinitionInterface $site, protected readonly array $themeConfig ) { @@ -84,6 +90,11 @@ public function configureCrud(): Crud ; } + public function configureUserMenu(UserInterface $user): UserMenu + { + return $this->userMenuExtensionHelper->configureUserMenu(parent::configureUserMenu($user), $user); + } + public function index(): Response { $contentConfig = $this->themeConfig['content']; @@ -94,12 +105,12 @@ public function index(): Response if (null !== $contentConfig['redirect']['crud']) { // redirect to a CRUD controller page - return $this->redirect($this->adminUrlGenerator->setController($contentConfig['redirect']['crud'])->generateUrl()); + return $this->redirect($this->urlGenerator->setController($contentConfig['redirect']['crud'])->generateUrl()); } if (null !== $contentConfig['redirect']['route']) { // redirect to a Symfony route - return $this->redirectToRoute($contentConfig['redirect']['route'], $contentConfig['redirect']['route_parameters']); + return $this->redirect($this->urlGenerator->setRoute($contentConfig['redirect']['route'], $contentConfig['redirect']['route_parameters'])->generateUrl()); } // render EAB welcome page diff --git a/src/system/ThemeBundle/Controller/Dashboard/AdminDashboardController.php b/src/system/ThemeBundle/Controller/Dashboard/AdminDashboardController.php index c46a7ee91d..16babc4c42 100644 --- a/src/system/ThemeBundle/Controller/Dashboard/AdminDashboardController.php +++ b/src/system/ThemeBundle/Controller/Dashboard/AdminDashboardController.php @@ -18,9 +18,8 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; -use Zikula\CategoriesBundle\Entity\Category; use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuInterface; -use Zikula\UsersBundle\Entity\User; +use Zikula\ThemeBundle\Helper\ResourceMenuProvider; use function Symfony\Component\Translation\t; #[IsGranted('ROLE_ADMIN')] @@ -39,15 +38,8 @@ public function configureDashboard(): Dashboard public function configureMenuItems(): iterable { yield MenuItem::linkToDashboard(t('Dashboard'), 'fa fa-gauge-high'); - // yield MenuItem::linktoRoute(t('Website frontend'), 'fas fa-home', 'user_dashboard'); yield MenuItem::linktoUrl(t('Website frontend'), 'fas fa-home', '/'); - yield MenuItem::linkToCrud(t('Users'), 'fas fa-user', User::class); - yield MenuItem::linkToCrud(t('Groups'), 'fas fa-people-group', Group::class); - yield MenuItem::linkToCrud(t('Categories'), 'fas fa-sitemap', Category::class); - yield MenuItem::linkToCrud(t('Add category'), 'fas fa-plus', Category::class) - ->setAction('new'); - foreach ($this->adminCategoryHelper->getCategories() as $category) { yield MenuItem::section($category->getName(), $category->getIcon()); $bundleNames = $this->adminCategoryHelper->getBundleAssignments($category); @@ -72,20 +64,10 @@ public function configureMenuItems(): iterable } } - yield MenuItem::section(t('Resources'), 'fas fa-book'); - yield MenuItem::subMenu(t('Zikula'), 'fas fa-rocket')->setSubItems([ - MenuItem::linkToUrl(t('Website'), 'fas fa-house', 'https://ziku.la/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('Docs'), 'fas fa-file-contract', 'https://docs.ziku.la/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('Support Slack'), 'fab fa-slack', 'https://joinslack.ziku.la/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('ModuleStudio'), 'fas fa-wand-sparkles', 'https://modulestudio.de/en/documentation/')->setLinkTarget('_blank'), - ]); - yield MenuItem::subMenu(t('Foundation'), 'fas fa-cubes-stacked')->setSubItems([ - MenuItem::linkToUrl(t('Symfony'), 'fab fa-symfony', 'https://symfony.com/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('Twig'), 'fas fa-file-lines', 'https://twig.symfony.com/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('Doctrine'), 'fas fa-database', 'https://www.doctrine-project.org/')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('EasyAdmin'), 'fas fa-screwdriver-wrench', 'https://symfony.com/bundles/EasyAdminBundle/current/index.html')->setLinkTarget('_blank'), - MenuItem::linkToUrl(t('Bootstrap'), 'fab fa-bootstrap', 'https://getbootstrap.com/')->setLinkTarget('_blank'), - ]); + $resources = ResourceMenuProvider::getResources(); + foreach ($resources as $resourceItem) { + yield $resourceItem; + } } #[Route('/admin', name: 'admin_dashboard')] diff --git a/src/system/ThemeBundle/Controller/Dashboard/UserDashboardController.php b/src/system/ThemeBundle/Controller/Dashboard/UserDashboardController.php index 97ee525555..b2a3cd097c 100644 --- a/src/system/ThemeBundle/Controller/Dashboard/UserDashboardController.php +++ b/src/system/ThemeBundle/Controller/Dashboard/UserDashboardController.php @@ -17,9 +17,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Zikula\CategoriesBundle\Entity\Category; use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuInterface; -use Zikula\UsersBundle\Entity\User; use function Symfony\Component\Translation\t; class UserDashboardController extends AbstractThemedDashboardController @@ -37,10 +35,7 @@ public function configureDashboard(): Dashboard public function configureMenuItems(): iterable { yield MenuItem::linkToDashboard(t('Home'), 'fas fa-home'); - // yield MenuItem::linktoRoute(t('Administration'), 'fas fa-wrench', 'home_admin'); - yield MenuItem::linkToUrl(t('Administration'), 'fas fa-wrench', '/admin'); - yield MenuItem::linkToCrud(t('Users'), 'fas fa-people-group', User::class); - yield MenuItem::linkToCrud(t('Categories'), 'fas fa-sitemap', Category::class); + yield MenuItem::linkToUrl(t('Administration'), 'fas fa-wrench', '/admin')->setPermission('ROLE_ADMIN'); yield MenuItem::section(); $menuItemsByBundle = $this->extensionMenuCollector->getAllByContext(ExtensionMenuInterface::CONTEXT_USER); @@ -52,10 +47,10 @@ public function configureMenuItems(): iterable if (!count($menuItems)) { continue; } - // yield MenuItem::subMenu($bundleInfo->getDisplayName(), $bundleInfo->getIcon())->setSubItems($menuItems); - foreach ($menuItems as $item) { + yield MenuItem::subMenu($bundleInfo->getDisplayName(), $bundleInfo->getIcon())->setSubItems($menuItems); + /*foreach ($menuItems as $item) { yield $item; - } + }*/ } } diff --git a/src/system/ThemeBundle/Helper/AdminCategoryHelper.php b/src/system/ThemeBundle/Helper/AdminCategoryHelper.php index 921165cef7..48c1197730 100644 --- a/src/system/ThemeBundle/Helper/AdminCategoryHelper.php +++ b/src/system/ThemeBundle/Helper/AdminCategoryHelper.php @@ -95,7 +95,7 @@ public function getBundleAssignments(AdminCategory $category): array return match ($category->getSlug()) { 'system' => ['ZikulaThemeBundle'], 'users' => ['ZikulaGroupsBundle', 'ZikulaLegalBundle', 'ZikulaProfileBundle', 'ZikulaUsersBundle'], - 'content' => ['ZikulaStaticContentBundle'], + 'content' => ['ZikulaCategoriesBundle'], }; } } diff --git a/src/system/ThemeBundle/Helper/ResourceMenuProvider.php b/src/system/ThemeBundle/Helper/ResourceMenuProvider.php new file mode 100644 index 0000000000..df854ae451 --- /dev/null +++ b/src/system/ThemeBundle/Helper/ResourceMenuProvider.php @@ -0,0 +1,38 @@ +setSubItems([ + MenuItem::linkToUrl(t('Website'), 'fas fa-house', 'https://ziku.la/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('Docs'), 'fas fa-file-contract', 'https://docs.ziku.la/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('Support Slack'), 'fab fa-slack', 'https://joinslack.ziku.la/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('ModuleStudio'), 'fas fa-wand-sparkles', 'https://modulestudio.de/en/documentation/')->setLinkTarget('_blank'), + ]); + yield MenuItem::subMenu(t('Foundation'), 'fas fa-cubes-stacked')->setSubItems([ + MenuItem::linkToUrl(t('Symfony'), 'fab fa-symfony', 'https://symfony.com/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('Twig'), 'fas fa-file-lines', 'https://twig.symfony.com/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('Doctrine'), 'fas fa-database', 'https://www.doctrine-project.org/')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('EasyAdmin'), 'fas fa-screwdriver-wrench', 'https://symfony.com/bundles/EasyAdminBundle/current/index.html')->setLinkTarget('_blank'), + MenuItem::linkToUrl(t('Bootstrap'), 'fab fa-bootstrap', 'https://getbootstrap.com/')->setLinkTarget('_blank'), + ]); + } +} diff --git a/src/system/ThemeBundle/Helper/UserMenuExtensionHelper.php b/src/system/ThemeBundle/Helper/UserMenuExtensionHelper.php new file mode 100644 index 0000000000..872779c9c0 --- /dev/null +++ b/src/system/ThemeBundle/Helper/UserMenuExtensionHelper.php @@ -0,0 +1,57 @@ +setName($user->getFullName()) + + // TODO avatar + // the default user avatar is a generic avatar icon + // you can return an URL with the avatar image + //->setAvatarUrl($user->getProfileImageUrl()) + // use this method if you don't want to display the user image + //->displayUserAvatar(false) + // you can also pass an email address to use gravatar's service + ->setGravatarEmail($user->getEmailCanonical()) + + // additional account menu items contributed by extensions + ->addMenuItems(iterator_to_array($this->configureUserMenuItems())) + ; + } + + private function configureUserMenuItems(): iterable + { + $menuItemsByBundle = $this->extensionMenuCollector->getAllByContext(ExtensionMenuInterface::CONTEXT_ACCOUNT); + foreach ($menuItemsByBundle as $bundleName => $extensionMenuItems) { + $menuItems = is_array($extensionMenuItems) ? $extensionMenuItems : iterator_to_array($extensionMenuItems); + foreach ($menuItems as $item) { + yield $item; + } + } + } +} diff --git a/src/system/UsersBundle/Controller/AccessController.php b/src/system/UsersBundle/Controller/AccessController.php deleted file mode 100644 index fefd5cd35e..0000000000 --- a/src/system/UsersBundle/Controller/AccessController.php +++ /dev/null @@ -1,229 +0,0 @@ -isLoggedIn()) { - return $this->redirectToRoute('zikulausersbundle_account_menu'); - } - $returnUrl = $request->query->get('returnUrl', ''); - - $session = $request->hasSession() ? $request->getSession() : null; - - $selectedMethod = null !== $session ? $session->get('authenticationMethod') : ''; - $selectedMethod = $request->query->get('authenticationMethod', $selectedMethod); - if (empty($selectedMethod) && count($authenticationMethodCollector->getActiveKeys()) > 1) { - // there are multiple authentication methods available and none selected yet, so let the user choose one - return $this->render('@ZikulaUsers/Access/authenticationMethodSelector.html.twig', [ - 'collector' => $authenticationMethodCollector, - 'path' => 'zikulausersbundle_access_login' - ]); - } - if (empty($selectedMethod) && 1 === count($authenticationMethodCollector->getActiveKeys())) { - // there is only one authentication method available, so use this - $selectedMethod = $authenticationMethodCollector->getActiveKeys()[0]; - } - if (null !== $session) { - // save method to session for reEntrant needs - $session->set('authenticationMethod', $selectedMethod); - if (!empty($returnUrl)) { - // save returnUrl to session for reEntrant needs - $session->set('returnUrl', $returnUrl); - } - } - - $authenticationMethod = $authenticationMethodCollector->get($selectedMethod); - $rememberMe = false; - - $loginHeader = $this->renderView('@ZikulaUsers/Access/loginHeader.html.twig'); - $loginFooter = $this->renderView('@ZikulaUsers/Access/loginFooter.html.twig'); - - $form = null; - if ($authenticationMethod instanceof NonReEntrantAuthenticationMethodInterface) { - $form = $this->createForm($authenticationMethod->getLoginFormClassName()); - if (!$form->has('rememberme')) { - throw new InvalidAuthenticationMethodLoginFormException(); - } - $loginFormEvent = new LoginFormPostCreatedEvent($form); - $eventDispatcher->dispatch($loginFormEvent); - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - $data = $form->getData(); - $rememberMe = $data['rememberme']; - $uid = $authenticationMethod->authenticate($data); - } else { - return $this->render($authenticationMethod->getLoginTemplateName(), [ - 'loginHeader' => $loginHeader, - 'loginFooter' => $loginFooter, - 'form' => $form->createView(), - 'additionalTemplates' => isset($loginFormEvent) ? $loginFormEvent->getTemplates() : [], - 'registrationEnabled' => $registrationHelper->isRegistrationEnabled(), - ]); - } - } elseif ($authenticationMethod instanceof ReEntrantAuthenticationMethodInterface) { - // provide temp value for uid until form gives real value. - $uid = Request::METHOD_POST === $request->getMethod() ? UsersConstant::USER_ID_ANONYMOUS : $authenticationMethod->authenticate(); - $hasListeners = $eventDispatcher->hasListeners(LoginFormPostCreatedEvent::class); - if ($hasListeners) { - $form = $this->createForm(DefaultLoginType::class, ['uid' => $uid]); - $loginFormEvent = new LoginFormPostCreatedEvent($form); - $eventDispatcher->dispatch($loginFormEvent); - if ($form->count() > 3) { // count > 3 means that the LoginFormPostCreatedEvent event added some form children - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - $uid = $form->get('uid')->getData(); - $rememberMe = $form->get('rememberme')->getData(); - } else { - return $this->render('@ZikulaUsers/Access/defaultLogin.html.twig', [ - 'loginHeader' => $loginHeader, - 'loginFooter' => $loginFooter, - 'form' => $form->createView(), - 'additionalTemplates' => isset($loginFormEvent) ? $loginFormEvent->getTemplates() : [] - ]); - } - } - } - } else { - throw new LogicException($this->translator->trans('Invalid authentication method.')); - } - $user = null; - if (isset($uid)) { - /** @var User $user */ - $user = $userRepository->find($uid); - if (isset($user)) { - if ($accessHelper->loginAllowed($user)) { - if (isset($form)) { - $formDataEvent = new LoginFormPostValidatedEvent($form, $user); - $eventDispatcher->dispatch($formDataEvent); - } - $userPreSuccessLoginEvent = new UserPreLoginSuccessEvent($user, $selectedMethod); - $eventDispatcher->dispatch($userPreSuccessLoginEvent); - if (!$userPreSuccessLoginEvent->isPropagationStopped()) { - $returnUrlFromSession = null !== $session ? $session->get('returnUrl', $returnUrl) : $returnUrl; - $returnUrlFromSession = urldecode($returnUrlFromSession); - $accessHelper->login($user, $rememberMe); - $userPostSuccessLoginEvent = new UserPostLoginSuccessEvent($user, $selectedMethod); - $userPostSuccessLoginEvent->setRedirectUrl($returnUrlFromSession); - $eventDispatcher->dispatch($userPostSuccessLoginEvent); - $returnUrl = $userPostSuccessLoginEvent->getRedirectUrl(); - } else { - if ($userPreSuccessLoginEvent->hasFlashes()) { - $this->addFlash('danger', $userPreSuccessLoginEvent->getFlashesAsString()); - } - $returnUrl = $userPreSuccessLoginEvent->getRedirectUrl(); - } - - return !empty($returnUrl) ? $this->redirect($this->sanitizeReturnUrl($request, $returnUrl)) : $this->redirectToRoute('home'); - } - } - } - // login failed - $this->addFlash('error', 'Login failed.'); - if (null !== $session) { - $session->remove('authenticationMethod'); - } - $userPostFailLoginEvent = new UserPostLoginFailureEvent($user, $authenticationMethod->getAlias()); - $userPostFailLoginEvent->setRedirectUrl($returnUrl); - $eventDispatcher->dispatch($userPostFailLoginEvent); - $returnUrl = $userPostFailLoginEvent->getRedirectUrl(); - - return !empty($returnUrl) ? $this->redirect($this->sanitizeReturnUrl($request, $returnUrl)) : $this->redirectToRoute('home'); - } - - #[Route('/logout/{returnUrl}', name: 'zikulausersbundle_access_logout')] - public function logout( - Request $request, - CurrentUserApiInterface $currentUserApi, - UserRepositoryInterface $userRepository, - AccessHelper $accessHelper, - EventDispatcherInterface $eventDispatcher, - string $returnUrl = null - ): RedirectResponse { - if ($currentUserApi->isLoggedIn()) { - $uid = $currentUserApi->get('uid'); - $user = $userRepository->find($uid); - if ($accessHelper->logout()) { - $eventDispatcher->dispatch(new UserPostLogoutSuccessEvent($user)); - } else { - $this->addFlash('error', 'Error! You have not been logged out.'); - } - } - - return isset($returnUrl) - ? $this->redirect($this->sanitizeReturnUrl($request, $returnUrl)) - : $this->redirectToRoute('home', ['_locale' => $this->getParameter('locale')]) - ; - } - - private function sanitizeReturnUrl(Request $request, $returnUrl = null) - { - if (null === $returnUrl || empty($returnUrl)) { - return $returnUrl; - } - - if (false !== mb_strpos($returnUrl, $request->getUriForPath(''))) { - return $returnUrl; - } - - if ('/' !== mb_substr($returnUrl, 0, 1)) { - $returnUrl = '/' . $returnUrl; - } - - return $request->getUriForPath($returnUrl); - } -} diff --git a/src/system/UsersBundle/Controller/AccountController.php b/src/system/UsersBundle/Controller/AccountController.php index 9118f5c49f..15472ab484 100644 --- a/src/system/UsersBundle/Controller/AccountController.php +++ b/src/system/UsersBundle/Controller/AccountController.php @@ -15,7 +15,6 @@ use Locale; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Intl\Languages; @@ -24,9 +23,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\Translation\TranslatorInterface; use Zikula\Bundle\CoreBundle\Api\ApiInterface\LocaleApiInterface; -use Zikula\Bundle\FormExtensionBundle\Form\Type\DeletionType; -use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuCollector; -use Zikula\ThemeBundle\ExtensionMenu\ExtensionMenuInterface; use Zikula\UsersBundle\Api\ApiInterface\CurrentUserApiInterface; use Zikula\UsersBundle\Entity\User; use Zikula\UsersBundle\Event\DeleteUserFormPostCreatedEvent; @@ -51,24 +47,9 @@ public function __construct( * @throws AccessDeniedException Thrown if the user isn't logged in */ #[Route('', name: 'zikulausersbundle_account_menu')] - public function menu(ExtensionMenuCollector $extensionMenuCollector): Response + public function menu(): Response { - $accountMenus = $extensionMenuCollector->getAllByContext(ExtensionMenuInterface::CONTEXT_ACCOUNT); - - foreach ($accountMenus as $accountMenu) { - /** @var \Knp\Menu\ItemInterface $accountMenu */ - $accountMenu->setChildrenAttribute('class', 'list-group'); - foreach ($accountMenu->getChildren() as $child) { - $child->setAttribute('class', 'list-group-item'); - $icon = $child->getAttribute('icon'); - $icon = $this->displayGraphics ? $icon . ' fa-fw fa-2x' : null; - $child->setAttribute('icon', $icon); - } - } - - return $this->render('@ZikulaUsers/Account/menu.html.twig', [ - 'accountMenus' => $accountMenus, - ]); + return $this->redirect('/'); } /** @@ -115,57 +96,4 @@ public function changeLanguage( 'multilingual' => $localeApi->multilingual(), ]); } - - /** - * @throws AccessDeniedException Thrown if the user isn't logged in - */ - #[Route('/delete', name: 'zikulausersbundle_account_deletemyaccount')] - public function deleteMyAccount( - Request $request, - CurrentUserApiInterface $currentUserApi, - UserRepositoryInterface $userRepository, - EventDispatcherInterface $eventDispatcher, - DeleteHelper $deleteHelper - ): Response { - if (!$currentUserApi->isLoggedIn()) { - throw new AccessDeniedException(); - } - if (!$this->allowSelfDeletion) { - $this->addFlash('error', 'Self deletion is disabled by the site administrator.'); - - return $this->redirectToRoute('zikulausersbundle_account_menu'); - } - if (UsersConstant::USER_ID_ADMIN === $currentUserApi->get('uid')) { - $this->addFlash('error', 'Self deletion is not possible for main administrator.'); - - return $this->redirectToRoute('zikulausersbundle_account_menu'); - } - $form = $this->createForm(DeletionType::class); - $deleteUserFormPostCreatedEvent = new DeleteUserFormPostCreatedEvent($form); - $eventDispatcher->dispatch($deleteUserFormPostCreatedEvent); - $form->handleRequest($request); - if ($form->isSubmitted()) { - if ($form->get('cancel')->isClicked()) { - $this->addFlash('status', 'Operation cancelled.'); - - return $this->redirectToRoute('zikulausersbundle_account_menu'); - } - if ($form->get('delete')->isClicked()) { - if ($form->isValid()) { - $deletedUser = $userRepository->find($currentUserApi->get('uid')); - $deleteHelper->deleteUser($deletedUser); - $eventDispatcher->dispatch(new DeleteUserFormPostValidatedEvent($form, $deletedUser)); - $request->getSession()->invalidate(); // logout - $this->addFlash('success', 'Success. Account deleted!'); - - return $this->redirectToRoute('home'); - } - } - } - - return $this->render('@ZikulaUsers/Account/delete.html.twig', [ - 'form' => $form->createView(), - 'additionalTemplates' => isset($deleteUserFormPostCreatedEvent) ? $deleteUserFormPostCreatedEvent->getTemplates() : [], - ]); - } } diff --git a/src/system/UsersBundle/Controller/FileIOController.php b/src/system/UsersBundle/Controller/FileIOController.php deleted file mode 100644 index c1a8c9205e..0000000000 --- a/src/system/UsersBundle/Controller/FileIOController.php +++ /dev/null @@ -1,89 +0,0 @@ -createForm(ExportUsersType::class, []); - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - if ($form->get('download')->isClicked()) { - $data = $form->getData(); - $response = new StreamedResponse(); - $response->setCallback(function () use ($data, $userRepository) { - $fields = ['uid', 'uname', 'activated', 'email', 'registrationDate', 'lastLogin', 'groups']; - foreach ($fields as $k => $field) { - if (isset($data[$field]) && !$data[$field]) { - unset($fields[$k]); // remove unwanted fields - } - } - $handle = fopen('php://output', 'wb+'); - if ($data['title']) { - fputcsv($handle, $fields, $data['delimiter']); - } - $users = $userRepository->findAllAsIterable(); - /** @var User $user */ - foreach ($users as $user) { - $row = []; - foreach ($fields as $field) { - if ('groups' === $field) { - $gids = []; - /** @var Group $group */ - foreach ($user[0]->getGroups() as $group) { - $gids[] = $group->getGid(); - } - $row[] = implode('|', $gids); - } else { - $method = 'get' . ucwords($field); - $value = $user[0]->{$method}(); - $row[] = $value instanceof DateTime ? $value->format('c') : $value; - } - } - fputcsv($handle, $row, $data['delimiter']); - } - fclose($handle); - }); - - $response->setStatusCode(200); - $response->headers->set('Content-Type', 'text/csv; charset=utf-8'); - $response->headers->set('Content-Disposition', 'attachment; filename="' . $data['filename'] . '"'); - - return $response; - } - if ($form->get('cancel')->isClicked()) { - $this->addFlash('status', 'Operation cancelled.'); - } - } - - return $this->render('@ZikulaUsers/FileIO/export.html.twig', [ - 'form' => $form->createView(), - ]); - } -} diff --git a/src/system/UsersBundle/Controller/GroupCrudController.php b/src/system/UsersBundle/Controller/GroupCrudController.php new file mode 100644 index 0000000000..3e1a6af310 --- /dev/null +++ b/src/system/UsersBundle/Controller/GroupCrudController.php @@ -0,0 +1,107 @@ +groupManager->createGroup('new group'); + } + + public function configureCrud(Crud $crud): Crud + { + return $crud + ->setEntityLabelInSingular( + fn (?Group $group, ?string $pageName) => $group ?? 'Group' + ) + ->setEntityLabelInPlural('Groups') + ->setPageTitle('index', '%entity_label_plural% list') + ->setPageTitle('detail', fn (Group $group) => $group) + ->setPageTitle('edit', fn (Group $group) => sprintf('Edit %s', $group)) + ; + } + + public function configureFields(string $pageName): iterable + { + yield 'id' => IdField::new('id', t('Id'))->hideOnForm()->setTextAlign('right')->setRequired(true); + yield 'name' => TextField::new('name', t('Group name'))->setRequired(true); + yield 'roles' => ChoiceField::new('roles', t('Roles'))->setRequired(false)->setChoices($this->roleHelper->getRoleOptions())->allowMultipleChoices(); + } + + public function configureFilters(Filters $filters): Filters + { + return $filters + ->add('id') + ->add('name') + ->add(ChoiceFilter::new('roles')->setChoices($this->roleHelper->getRoleOptions())->canSelectMultiple()) + ; + } + + public function configureActions(Actions $actions): Actions + { + return $actions + ->add(Crud::PAGE_INDEX, Action::DETAIL) + ->add(Crud::PAGE_EDIT, Action::INDEX) + ->add(Crud::PAGE_NEW, Action::INDEX) + ->add(Crud::PAGE_EDIT, Action::DETAIL) + ->add(Crud::PAGE_EDIT, Action::DELETE) + ->add(Crud::PAGE_NEW, Action::SAVE_AND_CONTINUE) + ; + } + + public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->groupManager->updateGroup($entityInstance); + } + + public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->groupManager->updateGroup($entityInstance); + } + + public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->groupManager->deleteGroup($entityInstance); + } +} diff --git a/src/system/UsersBundle/Controller/RegistrationController.php b/src/system/UsersBundle/Controller/RegistrationController.php index 6df07ba42d..3ef58c6766 100644 --- a/src/system/UsersBundle/Controller/RegistrationController.php +++ b/src/system/UsersBundle/Controller/RegistrationController.php @@ -172,7 +172,7 @@ public function register( } $route = 'zikulausersbundle_registration_register'; if (in_array(ValidUserFieldsValidator::DUP_EMAIL_ALT_AUTH, $codes, true)) { - $route = 'zikulausersbundle_access_login'; + $route = 'nucleos_user_security_login'; } return $this->redirectToRoute($route); // try again. @@ -213,7 +213,7 @@ public function register( return $this->redirectToRoute('home'); } - return $this->redirectToRoute('zikulausersbundle_access_login'); + return $this->redirectToRoute('nucleos_user_security_login'); } if (null !== $session) { $session->invalidate(); diff --git a/src/system/UsersBundle/Controller/UserAdministrationController.php b/src/system/UsersBundle/Controller/UserAdministrationController.php deleted file mode 100644 index 7b415c251c..0000000000 --- a/src/system/UsersBundle/Controller/UserAdministrationController.php +++ /dev/null @@ -1,402 +0,0 @@ - '\d+'])] - public function listUsers( - Request $request, - UserRepositoryInterface $userRepository, - RouterInterface $router, - AdministrationActionsHelper $actionsHelper, - AuthenticationMethodCollector $authenticationMethodCollector, - string $sort = 'uid', - string $sortdir = 'DESC', - string $letter = 'all', - int $page = 1 - ): Response { - /*$sortableColumns = new SortableColumns($router, 'zikulausersbundle_useradministration_listusers', 'sort', 'sortdir'); - $sortableColumns->addColumns([new Column('uname'), new Column('uid'), new Column('registrationDate'), new Column('lastLogin'), new Column('activated')]); - $sortableColumns->setOrderByFromRequest($request); - $sortableColumns->setAdditionalUrlParameters([ - 'letter' => $letter, - 'page' => $page - ]); - - */ - $filter = []; - if (!empty($letter) && 'all' !== $letter) { - $filter['uname'] = ['operator' => 'like', 'operand' => "${letter}%"]; - } - $paginator = $userRepository->paginatedQuery($filter, [$sort => $sortdir], 'and', $page, $this->itemsPerPage); - $paginator->setRoute('zikulausersbundle_useradministration_listusers'); - $routeParameters = [ - 'sort' => $sort, - 'sortdir' => $sortdir, - 'letter' => $letter, - ]; - $paginator->setRouteParameters($routeParameters); - - return $this->render('@ZikulaUsers/UserAdministration/list.html.twig', [ - // 'sort' => $sortableColumns->generateSortableColumns(), - 'actionsHelper' => $actionsHelper, - 'authMethodCollector' => $authenticationMethodCollector, - 'alpha' => new AlphaFilter('zikulausersbundle_useradministration_listusers', $routeParameters, $letter), - 'paginator' => $paginator, - ]); - } - - /** - * Called from UsersBundle/Resources/public/js/Zikula.Users.Admin.View.js - * to populate a username search - */ - #[Route('/getusersbyfragmentastable', name: 'zikulausersbundle_useradministration_getusersbyfragmentastable', methods: ['POST'], options: ['expose' => true])] - public function getUsersByFragmentAsTable( - Request $request, - UserRepositoryInterface $userRepository, - AdministrationActionsHelper $actionsHelper - ): Response { - $fragment = $request->request->get('fragment'); - $filter = [ - 'activated' => ['operator' => 'notIn', 'operand' => [ - UsersConstant::ACTIVATED_PENDING_REG, - UsersConstant::ACTIVATED_PENDING_DELETE, - ]], - 'uname' => ['operator' => 'like', 'operand' => "${fragment}%"] - ]; - $users = $userRepository->query($filter); - - return $this->render('@ZikulaUsers/UserAdministration/userlist.html.twig', [ - 'users' => $users, - 'actionsHelper' => $actionsHelper, - ], new PlainResponse()); - } - - /** - * @throws AccessDeniedException Thrown if guest user is being edited - */ - #[Route('/user/modify/{user}', name: 'zikulausersbundle_useradministration_modify', requirements: ['user' => '^[1-9]\d*$'])] - public function modify( - Request $request, - User $user, - ManagerRegistry $doctrine, - CurrentUserApiInterface $currentUserApi, - EventDispatcherInterface $eventDispatcher - ): Response { - if (UsersConstant::USER_ID_ANONYMOUS === $user->getUid()) { - throw new AccessDeniedException($this->trans("Error! You can't edit the guest account.")); - } - - $form = $this->createForm(AdminModifyUserType::class, $user); - $originalUser = clone $user; - $editUserFormPostCreatedEvent = new EditUserFormPostCreatedEvent($form); - $eventDispatcher->dispatch($editUserFormPostCreatedEvent); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - if ($form->get('submit')->isClicked()) { - $user = $form->getData(); - $this->checkSelf($currentUserApi, $user, $originalUser->getGroups()->toArray()); - - $eventDispatcher->dispatch(new EditUserFormPostValidatedEvent($form, $user)); - - $doctrine->getManager()->flush(); - - $updateEvent = UsersConstant::ACTIVATED_PENDING_REG === $user->getActivated() - ? new RegistrationPostUpdatedEvent($user, $originalUser) - : new ActiveUserPostUpdatedEvent($user, $originalUser); - $eventDispatcher->dispatch($updateEvent); - - $this->addFlash('status', "Done! Saved user's account information."); - } elseif ($form->get('cancel')->isClicked()) { - $this->addFlash('status', 'Operation cancelled.'); - } - - return $this->redirectToRoute('zikulausersbundle_useradministration_listusers'); - } - - return $this->render('@ZikulaUsers/UserAdministration/modify.html.twig', [ - 'form' => $form->createView(), - 'additionalTemplates' => isset($editUserFormPostCreatedEvent) ? $editUserFormPostCreatedEvent->getTemplates() : [], - ]); - } - - #[Route('/user/approve/{user}/{force}', name: 'zikulausersbundle_useradministration_approve', requirements: ['user' => '^[1-9]\d*$'])] - public function approve( - Request $request, - User $user, - RegistrationHelper $registrationHelper, - MailHelper $mailHelper, - bool $force = false - ): Response { - $forceVerification = $force; - $form = $this->createForm(ApproveRegistrationConfirmationType::class, [ - 'user' => $user->getUid(), - 'force' => $forceVerification - ], [ - 'buttonLabel' => $this->translator->trans('Approve') - ]); - $redirectToRoute = 'zikulausersbundle_useradministration_listusers'; - - if (!$forceVerification && $user->isApproved()) { - $this->addFlash('error', $this->translator->trans('Warning! Nothing to do! %sub% is already approved.', ['%sub%' => $user->getUname()])); - - return $this->redirectToRoute($redirectToRoute); - } - - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - if ($form->get('confirm')->isClicked()) { - $registrationHelper->approve($user); - if (UsersConstant::ACTIVATED_PENDING_REG === $user->getActivated()) { - $notificationErrors = $mailHelper->createAndSendRegistrationMail($user, true, false); - } else { - $notificationErrors = $mailHelper->createAndSendUserMail($user, true, false); - } - - if ($notificationErrors) { - $this->addFlash('error', implode('
', $notificationErrors)); - } - $this->addFlash('status', $this->translator->trans('Done! %sub% has been approved.', ['%sub%' => $user->getUname()])); - } elseif ($form->get('cancel')->isClicked()) { - $this->addFlash('status', 'Operation cancelled.'); - } - - return $this->redirectToRoute($redirectToRoute); - } - - return $this->render('@ZikulaUsers/UserAdministration/approve.html.twig', [ - 'form' => $form->createView(), - 'user' => $user, - ]); - } - - #[Route('/delete/{user}', name: 'zikulausersbundle_useradministration_delete', requirements: ['user' => '^[1-9]\d*$'])] - public function delete( - Request $request, - CurrentUserApiInterface $currentUserApi, - UserRepositoryInterface $userRepository, - EventDispatcherInterface $eventDispatcher, - DeleteHelper $deleteHelper, - User $user = null - ): Response { - $uids = []; - if (!isset($user) && Request::METHOD_POST === $request->getMethod() && $request->request->has('zikulausersbundle_delete')) { - $deletionData = $request->request->get('zikulausersbundle_delete'); - if (isset($deletionData['users']) && !empty($deletionData['users'])) { - $uids = $deletionData['users']; - } - } elseif (isset($user)) { - $uids = [$user->getUid()]; - } - if (!count($uids) && !$request->request->has('zikulausersbundle_deleteconfirmation')) { - $this->addFlash('warning', 'No users selected.'); - - return $this->redirectToRoute('zikulausersbundle_useradministration_listusers'); - } - $usersImploded = implode(',', $uids); - - $deleteConfirmationForm = $this->createForm(DeleteConfirmationType::class, [ - 'users' => $usersImploded - ]); - $deleteUserFormPostCreatedEvent = new DeleteUserFormPostCreatedEvent($deleteConfirmationForm); - $eventDispatcher->dispatch($deleteUserFormPostCreatedEvent); - $deleteConfirmationForm->handleRequest($request); - if ($deleteConfirmationForm->isSubmitted()) { - if ($deleteConfirmationForm->get('cancel')->isClicked()) { - $this->addFlash('success', 'Operation cancelled.'); - - return $this->redirectToRoute('zikulausersbundle_useradministration_listusers'); - } - $userIdsImploded = $deleteConfirmationForm->get('users')->getData(); - $userIds = explode(',', $userIdsImploded); - $valid = true; - foreach ($userIds as $k => $uid) { - if (in_array($uid, [UsersConstant::USER_ID_ANONYMOUS, UsersConstant::USER_ID_ADMIN, $currentUserApi->get('uid')], true)) { - unset($userIds[$k]); - $this->addFlash('danger', $this->translator->trans('You are not allowed to delete user id %uid%', ['%uid%' => $uid])); - continue; - } - } - if ($valid && $deleteConfirmationForm->isValid()) { - $deletedUsers = $userRepository->query(['uid' => ['operator' => 'in', 'operand' => $userIds]]); - $force = $deleteConfirmationForm->get('force')->getData(); - foreach ($deletedUsers as $deletedUser) { - $deleteHelper->deleteUser($deletedUser, $force); - $eventDispatcher->dispatch(new DeleteUserFormPostValidatedEvent($deleteConfirmationForm, $deletedUser)); - } - $this->addFlash( - 'success', - /** @Desc("{count, plural,\n one {User deleted!}\n other {# users deleted!}\n}") */ - $this->translator->trans( - 'plural_n.users.deleted', - ['%count%' => count($deletedUsers)] - ) - ); - - return $this->redirectToRoute('zikulausersbundle_useradministration_listusers'); - } - } - $users = $userRepository->findByUids($uids); - - return $this->render('@ZikulaUsers/UserAdministration/delete.html.twig', [ - 'users' => $users, - 'form' => $deleteConfirmationForm->createView(), - 'additionalTemplates' => isset($deleteUserFormPostCreatedEvent) ? $deleteUserFormPostCreatedEvent->getTemplates() : [], - ]); - } - - #[Route('/search', name: 'zikulausersbundle_useradministration_search')] - public function search( - Request $request, - UserRepositoryInterface $userRepository, - SiteDefinitionInterface $site - ): Response { - $form = $this->createForm(SearchUserType::class, []); - $form->handleRequest($request); - if ($form->isSubmitted()) { - $resultsForm = $this->createForm(DeleteType::class, [], [ - 'choices' => $userRepository->queryBySearchForm($form->getData()), - 'action' => $this->generateUrl('zikulausersbundle_useradministration_delete') - ]); - - return $this->render('@ZikulaUsers/UserAdministration/searchResults.html.twig', [ - 'resultsForm' => $resultsForm->createView(), - 'mailForm' => $this->buildMailForm($site)->createView() - ]); - } - - return $this->render('@ZikulaUsers/UserAdministration/search.html.twig', [ - 'form' => $form->createView(), - ]); - } - - #[Route('/mail', name: 'zikulausersbundle_useradministration_mailusers')] - public function mailUsers( - Request $request, - UserRepositoryInterface $userRepository, - MailHelper $mailHelper, - SiteDefinitionInterface $site - ): RedirectResponse { - $mailForm = $this->buildMailForm($site); - $mailForm->handleRequest($request); - if ($mailForm->isSubmitted() && $mailForm->isValid()) { - $data = $mailForm->getData(); - $users = $userRepository->query(['uid' => ['operator' => 'in', 'operand' => explode(',', $data['userIds'])]]); - if (empty($users)) { - throw new \InvalidArgumentException($this->translator->trans('No users found.')); - } - if ($mailHelper->mailUsers($users, $data)) { - $this->addFlash('success', 'Done! Mail sent.'); - } else { - $this->addFlash('error', 'Could not send mail.'); - } - } else { - $this->addFlash('error', 'Could not send mail.'); - } - - return $this->redirectToRoute('zikulausersbundle_useradministration_search'); - } - - private function buildMailForm(SiteDefinitionInterface $site): FormInterface - { - return $this->createForm(MailType::class, [ - 'from' => $site->getName(), - 'replyto' => $site->getAdminMail(), - 'format' => 'text', - 'batchsize' => 100, - ], [ - 'action' => $this->generateUrl('zikulausersbundle_useradministration_mailusers') - ]); - } - - /** - * Prevent user from modifying certain aspects of self. - */ - private function checkSelf( - CurrentUserApiInterface $currentUserApi, - User $userBeingModified, - array $originalGroups = [] - ): void { - $currentUserId = $currentUserApi->get('uid'); - if ($currentUserId !== $userBeingModified->getUid()) { - return; - } - - // current user not allowed to deactivate self - if (UsersConstant::ACTIVATED_ACTIVE !== $userBeingModified->getActivated()) { - $this->addFlash('info', 'You are not allowed to alter your own active state.'); - $userBeingModified->setActivated(UsersConstant::ACTIVATED_ACTIVE); - } - /* - // current user not allowed to remove self from default group - $defaultGroupId = $this->defaultHelper->getDefaultGroupId(); - if (!$userBeingModified->getGroups()->containsKey($defaultGroupId)) { - $this->addFlash('info', 'You are not allowed to remove yourself from the default group.'); - $userBeingModified->getGroups()->add($originalGroups[$defaultGroupId]); - } - // current user not allowed to remove self from admin group if currently a member - if (isset($originalGroups[GroupsConstant::GROUP_ID_ADMIN]) && !$userBeingModified->getGroups()->containsKey(GroupsConstant::GROUP_ID_ADMIN)) { - $this->addFlash('info', 'You are not allowed to remove yourself from the primary administrator group.'); - $userBeingModified->getGroups()->add($originalGroups[GroupsConstant::GROUP_ID_ADMIN]); - }*/ - } -} diff --git a/src/system/UsersBundle/Controller/UserCrudController.php b/src/system/UsersBundle/Controller/UserCrudController.php index 544e754574..e2a0680cf8 100644 --- a/src/system/UsersBundle/Controller/UserCrudController.php +++ b/src/system/UsersBundle/Controller/UserCrudController.php @@ -13,38 +13,140 @@ namespace Zikula\UsersBundle\Controller; +use Doctrine\ORM\EntityManagerInterface; +use EasyCorp\Bundle\EasyAdminBundle\Config\Action; +use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; +use EasyCorp\Bundle\EasyAdminBundle\Config\Filters; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; +use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; +use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField; +use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; +use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField; +use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField; +use EasyCorp\Bundle\EasyAdminBundle\Field\IdField; +use EasyCorp\Bundle\EasyAdminBundle\Field\LocaleField; +use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField; +use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; +use EasyCorp\Bundle\EasyAdminBundle\Field\TimezoneField; +use EasyCorp\Bundle\EasyAdminBundle\Filter\ChoiceFilter; +use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter; +use EasyCorp\Bundle\EasyAdminBundle\Filter\DateTimeFilter; +use EasyCorp\Bundle\EasyAdminBundle\Filter\TextFilter; +use Nucleos\UserBundle\Model\UserInterface; +use Nucleos\UserBundle\Model\UserManager; +use Symfony\Component\Form\Extension\Core\Type\LocaleType; +use Symfony\Component\Form\Extension\Core\Type\TimezoneType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\RepeatedType; +use Symfony\Component\Security\Http\Attribute\IsGranted; +use Zikula\Bundle\CoreBundle\Api\ApiInterface\LocaleApiInterface; use Zikula\UsersBundle\Entity\User; +use Zikula\UsersBundle\Helper\RoleHelper; +use function Symfony\Component\Translation\t; +#[IsGranted('ROLE_ADMIN')] class UserCrudController extends AbstractCrudController { + public function __construct( + private readonly UserManager $userManager, + private readonly LocaleApiInterface $localeApi, + private readonly RoleHelper $roleHelper + ) { + } + public static function getEntityFqcn(): string { return User::class; } + public function createEntity(string $entityFqcn): UserInterface + { + return $this->userManager->createUser(); + } + public function configureCrud(Crud $crud): Crud { return $crud - ->setEntityLabelInSingular('User') + ->setEntityLabelInSingular( + fn (?User $user, ?string $pageName) => $user ?? 'User' + ) ->setEntityLabelInPlural('Users') ->setPageTitle('index', '%entity_label_plural% list') ->setPageTitle('detail', fn (User $user) => $user) - ->setPageTitle('edit', fn (User $user) => sprintf('Editing %s', $user)) -// ->setDateFormat('...') - // ... + ->setPageTitle('edit', fn (User $user) => sprintf('Edit %s', $user)) + ->setDateFormat(DateTimeField::FORMAT_MEDIUM) + ->setDateTimeFormat(DateTimeField::FORMAT_MEDIUM, DateTimeField::FORMAT_SHORT) ; } - /* public function configureFields(string $pageName): iterable { - return [ - IdField::new('id'), - TextField::new('title'), - TextEditorField::new('description'), - ]; + yield 'id' => IdField::new('id', t('Id'))->hideOnForm()->setTextAlign('right')->setRequired(true); + yield 'username' => TextField::new('username', t('User name'))->setRequired(true); + yield 'email' => EmailField::new('email', t('Email address'))->setRequired(true); + yield 'enabled' => BooleanField::new('enabled', t('Enabled'))->setTextAlign('center'); + yield 'plainPassword' => TextField::new('plainPassword', t('New password'))->hideOnIndex()->setHelp(t('used for resetting')); + yield 'lastLogin' => DateTimeField::new('lastLogin', t('Last login')); + yield 'confirmationToken' => TextField::new('confirmationToken', t('Confirmation token'))->onlyOnDetail(); + yield 'passwordRequestedAt' => DateTimeField::new('passwordRequestedAt', t('Password requested at'))->hideOnIndex(); + yield 'roles' => ChoiceField::new('roles', t('Roles'))->setRequired(true)->setChoices($this->roleHelper->getRoleOptions())->allowMultipleChoices(); + yield 'groups' => AssociationField::new('groups', t('Groups')); + yield 'locale' => LocaleField::new('locale', t('Locale'))->includeOnly($this->localeApi->getSupportedLocales()); + yield 'timezone' => TimezoneField::new('timezone', t('Timezone')); + + // custom additions + yield 'approvedDate' => DateTimeField::new('approvedDate', t('Approved at'))->hideOnIndex(); + yield 'approvedBy' => NumberField::new('approvedBy', t('Approved by'))->hideOnIndex(); // TODO replace by AssociationField + yield 'registrationDate' => DateTimeField::new('registrationDate', t('Registered at'))->hideOnIndex(); + + // yield 'attributes' => CollectionField... if eventually needed + } + + public function configureFilters(Filters $filters): Filters + { + return $filters + ->add('id') + ->add('username') + ->add('email') + ->add('enabled') + ->add(DateTimeFilter::new('lastLogin')) + ->add(DateTimeFilter::new('passwordRequestedAt')) + ->add(ChoiceFilter::new('roles')->setChoices($this->roleHelper->getRoleOptions())->canSelectMultiple()) + ->add(EntityFilter::new('groups')->canSelectMultiple()) + + ->add(TextFilter::new('locale')->setFormTypeOptions(['value_type' => LocaleType::class, 'value_type_options.placeholder' => t('All')])) + ->add(TextFilter::new('timezone')->setFormTypeOptions(['value_type' => TimezoneType::class, 'value_type_options.placeholder' => t('All')])) + ->add(DateTimeFilter::new('approvedDate')) + ->add('approvedBy') + ->add(DateTimeFilter::new('registrationDate')) + ; + } + + public function configureActions(Actions $actions): Actions + { + return $actions + ->add(Crud::PAGE_INDEX, Action::DETAIL) + ->add(Crud::PAGE_EDIT, Action::INDEX) + ->add(Crud::PAGE_NEW, Action::INDEX) + ->add(Crud::PAGE_EDIT, Action::DETAIL) + ->add(Crud::PAGE_EDIT, Action::DELETE) + ->add(Crud::PAGE_NEW, Action::SAVE_AND_CONTINUE) + ; + } + + public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->userManager->updateUser($entityInstance); + } + + public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->userManager->updateUser($entityInstance); + } + + public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void + { + $this->userManager->deleteUser($entityInstance); } - */ } diff --git a/src/system/UsersBundle/DependencyInjection/Configuration.php b/src/system/UsersBundle/DependencyInjection/Configuration.php index 66b131f77b..6d92abbfe9 100644 --- a/src/system/UsersBundle/DependencyInjection/Configuration.php +++ b/src/system/UsersBundle/DependencyInjection/Configuration.php @@ -25,12 +25,6 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder->getRootNode() ->children() - ->integerNode('items_per_page') - ->info('Number of items (e.g., user account records) displayed per page.') - ->defaultValue(25) - ->min(1) - ->max(999) - ->end() ->booleanNode('display_graphics_on_account_page') ->info('Display graphics on user\'s account page.') ->defaultTrue() diff --git a/src/system/UsersBundle/DependencyInjection/ZikulaUsersExtension.php b/src/system/UsersBundle/DependencyInjection/ZikulaUsersExtension.php index 2b40ac2125..0f5ab115ed 100644 --- a/src/system/UsersBundle/DependencyInjection/ZikulaUsersExtension.php +++ b/src/system/UsersBundle/DependencyInjection/ZikulaUsersExtension.php @@ -19,11 +19,9 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Zikula\UsersBundle\Controller\AccountController; use Zikula\UsersBundle\Controller\RegistrationController; -use Zikula\UsersBundle\Controller\UserAdministrationController; use Zikula\UsersBundle\Helper\MailHelper; use Zikula\UsersBundle\Helper\RegistrationHelper; use Zikula\UsersBundle\Menu\ExtensionMenu; -use Zikula\UsersBundle\ProfileBundle\ProfileBundleCollector; use Zikula\UsersBundle\Validator\Constraints\ValidEmailValidator; use Zikula\UsersBundle\Validator\Constraints\ValidUnameValidator; @@ -47,12 +45,6 @@ public function load(array $configs, ContainerBuilder $container) ->setArgument('$useAutoLogin', $config['registration']['auto_login']) ->setArgument('$illegalUserAgents', $config['registration']['illegal_user_agents']); - $container->getDefinition(UserAdministrationController::class) - ->setArgument('$itemsPerPage', $config['items_per_page']); - - $container->getDefinition(ProfileBundleCollector::class) - ->setArgument('$currentProfileBundleName', $config['integration']['profile_bundle']); - $container->getDefinition(MailHelper::class) ->setArgument('$registrationNotificationEmail', $config['registration']['admin_notification_mail']); $container->getDefinition(RegistrationHelper::class) diff --git a/src/system/UsersBundle/Entity/Group.php b/src/system/UsersBundle/Entity/Group.php index 954eae42e7..f5ddf3f43f 100644 --- a/src/system/UsersBundle/Entity/Group.php +++ b/src/system/UsersBundle/Entity/Group.php @@ -23,14 +23,14 @@ class Group extends BaseGroup #[ORM\Id] #[ORM\Column] #[ORM\GeneratedValue(strategy: 'AUTO')] - protected int $id; + protected ?int $id = null; - public function getId(): int + public function getId(): ?int { return $this->id; } - public function setId(int $id): void + public function setId(?int $id): void { $this->id = $id; } diff --git a/src/system/UsersBundle/Entity/User.php b/src/system/UsersBundle/Entity/User.php index 32873535bb..20a91a6bc9 100644 --- a/src/system/UsersBundle/Entity/User.php +++ b/src/system/UsersBundle/Entity/User.php @@ -35,7 +35,7 @@ class User extends BaseUser #[ORM\Id] #[ORM\Column] #[ORM\GeneratedValue(strategy: 'AUTO')] - protected int $id; + protected ?int $id = null; #[Assert\Length(min: 12)] #[PasswordPattern(minUpper: 1, minLower: 1, minNumeric: 1, minSpecial: 1)] @@ -93,12 +93,12 @@ public function __construct() $this->attributes = new ArrayCollection(); } - public function getId(): int + public function getId(): ?int { return $this->id; } - public function setId(int $id): void + public function setId(?int $id): void { $this->id = $id; } diff --git a/src/system/UsersBundle/Helper/RoleHelper.php b/src/system/UsersBundle/Helper/RoleHelper.php new file mode 100644 index 0000000000..3ec59117fb --- /dev/null +++ b/src/system/UsersBundle/Helper/RoleHelper.php @@ -0,0 +1,52 @@ +roleHierarchy = $roleHierarchy; + } + + public function getRoleOptions(): array + { + $systemRoles = [ + 'User' => 'ROLE_USER', + 'Editor' => 'ROLE_EDITOR', + 'Administrator' => 'ROLE_ADMIN', + 'Super administrator' => 'ROLE_SUPER_ADMIN', + ]; + + $definedRoles = []; + array_walk_recursive($this->roleHierarchy, function($role) use (&$roles) { + $definedRoles[$role] = $role; + }); + + $roles = $systemRoles; + foreach ($definedRoles as $role) { + if (!in_array($role, $roles, true)) { + $roles[$role] = $role; + } + } + + return $roles; + } +} diff --git a/src/system/UsersBundle/Menu/ExtensionMenu.php b/src/system/UsersBundle/Menu/ExtensionMenu.php index be5b43732b..9d2a00cab5 100644 --- a/src/system/UsersBundle/Menu/ExtensionMenu.php +++ b/src/system/UsersBundle/Menu/ExtensionMenu.php @@ -16,9 +16,12 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; use Symfony\Bundle\SecurityBundle\Security; use Zikula\Bundle\CoreBundle\Api\ApiInterface\LocaleApiInterface; +use Zikula\UsersBundle\Entity\Group; +use Zikula\UsersBundle\Entity\User; use Zikula\ThemeBundle\ExtensionMenu\AbstractExtensionMenu; use Zikula\UsersBundle\Helper\RegistrationHelper; use Zikula\UsersBundle\UsersConstant; +use function Symfony\Component\Translation\t; class ExtensionMenu extends AbstractExtensionMenu { @@ -32,18 +35,14 @@ public function __construct( protected function getAdmin(): iterable { - yield MenuItem::linktoRoute('Users list', 'fas fa-list', 'zikulausersbundle_useradministration_listusers') - ->setPermission('ROLE_ADMIN'); - yield MenuItem::linktoRoute('Export users', 'fas fa-download', 'zikulausersbundle_fileio_export') - ->setPermission('ROLE_ADMIN'); - yield MenuItem::linktoRoute('Find & Mail|Delete users', 'fas fa-search', 'zikulausersbundle_useradministration_search') - ->setPermission('ROLE_ADMIN'); + yield MenuItem::linkToCrud(t('Users'), 'fas fa-user', User::class); + yield MenuItem::linkToCrud(t('Groups'), 'fas fa-people-group', Group::class); } protected function getUser(): iterable { if (null === $this->security->getUser()) { - yield MenuItem::linktoRoute('Help', 'fas fa-ambulance', 'zikulausersbundle_account_menu'); + yield MenuItem::linktoRoute('Login', 'fas fa-sign-in-alt', 'nucleos_user_security_login'); if ($this->registrationHelper->isRegistrationEnabled()) { yield MenuItem::linktoRoute('New account', 'fas fa-plus', 'zikulausersbundle_registration_register'); } @@ -54,26 +53,41 @@ protected function getUser(): iterable protected function getAccount(): iterable { - if (null === $this->security->getUser()) { - yield MenuItem::linktoRoute('I would like to login', 'fas fa-sign-in-alt', 'zikulausersbundle_access_login'); + $loggedIn = null !== $this->security->getUser(); + if (!$loggedIn) { + yield MenuItem::linktoRoute('I would like to login', 'fas fa-sign-in-alt', 'nucleos_user_security_login'); if ($this->registrationHelper->isRegistrationEnabled()) { yield MenuItem::linktoRoute('I would like to create a new account', 'fas fa-plus', 'zikulausersbundle_registration_register'); + // TODO maybe move to ProfileBundle if we keep one + // | Registration | nucleos_profile_registration_check_email | /registration/check-email | + // | Registration | nucleos_profile_registration_confirmed | /registration/confirmed | + // | Registration | nucleos_profile_registration_register | /registration/ | } - } else { + } + yield MenuItem::linktoRoute('Reset password', 'fas fa-refresh', 'nucleos_user_resetting_request'); + if ($loggedIn) { + yield MenuItem::linktoRoute('Change password', 'fas fa-lock', 'nucleos_user_change_password'); + if ($this->localeApi->multilingual()) { $locales = $this->localeApi->getSupportedLocales(); if (1 < count($locales)) { yield MenuItem::linktoRoute('Language switcher', 'fas fa-language', 'zikulausersbundle_account_changelanguage'); } } + + // TODO maybe move to ProfileBundle if we keep one + yield MenuItem::linktoRoute('My profile', 'fas fa-user', 'nucleos_profile_profile_show'); + yield MenuItem::linktoRoute('Edit profile', 'fas fa-user-pen', 'nucleos_profile_profile_edit'); + if ($this->allowSelfDeletion) { if (UsersConstant::USER_ID_ADMIN !== $this->currentUserApi->get('uid')) { - yield MenuItem::linktoRoute('Delete my account', 'fas fa-trash-alt', 'zikulausersbundle_account_deletemyaccount') + yield MenuItem::linktoRoute('Delete my account', 'fas fa-trash-alt', 'nucleos_user_delete_account') ->setCssClass('text-danger') ; } } - yield MenuItem::linktoRoute('Log out', 'fas fa-power-off', 'zikulausersbundle_access_logout') + // TODO remove this test entry again + yield MenuItem::linktoRoute('Delete my account', 'fas fa-trash-alt', 'nucleos_user_delete_account') ->setCssClass('text-danger') ; } diff --git a/src/system/UsersBundle/ProfileBundle/IdentityProfileBundle.php b/src/system/UsersBundle/ProfileBundle/IdentityProfileBundle.php deleted file mode 100644 index d3a43e00e9..0000000000 --- a/src/system/UsersBundle/ProfileBundle/IdentityProfileBundle.php +++ /dev/null @@ -1,52 +0,0 @@ -security->getUser()?->getUserIdentifier() ?? ''; - } - - /** @var User $user */ - $user = $this->userRepository->find($userId); - - return $user?->getUname() ?? ''; - } - - public function getProfileUrl($userId = null): string - { - return '#'; - } - - public function getAvatar($userId = null, array $parameters = []): string - { - return ''; - } - - public function getBundleName(): string - { - return 'ZikulaUsersBundle'; - } -} diff --git a/src/system/UsersBundle/ProfileBundle/ProfileBundleCollector.php b/src/system/UsersBundle/ProfileBundle/ProfileBundleCollector.php deleted file mode 100644 index acbbc70162..0000000000 --- a/src/system/UsersBundle/ProfileBundle/ProfileBundleCollector.php +++ /dev/null @@ -1,90 +0,0 @@ - => ] - */ - private array $profileBundles = []; - - public function __construct( - #[TaggedIterator(ProfileBundleInterface::class)] - iterable $bundles, - private readonly ?string $currentProfileBundleName - ) { - foreach ($bundles as $bundle) { - $this->add($bundle); - } - } - - /** - * Add a service to the collection. - */ - public function add(/* ProfileBundleInterface */ $service): void - { - $bundleName = $service->getBundleName(); - if ('ZikulaUsersBundle' === $bundleName) { - return; - } - if (isset($this->profileBundles[$bundleName])) { - throw new InvalidArgumentException('Attempting to register a profile bundle with a duplicate bundle name. (' . $bundleName . ')'); - } - $this->profileBundles[$bundleName] = $service; - } - - /** - * Get a ProfileBundleInterface from the collection by bundle name. - */ - public function get(string $bundleName): ?ProfileBundleInterface - { - return $this->profileBundles[$bundleName] ?? null; - } - - /** - * Get all the bundles in the collection. - * - * @return ProfileBundleInterface[] - */ - public function getAll(): iterable - { - return $this->profileBundles; - } - - /** - * Get an array of service aliases. - */ - public function getKeys(): array - { - return array_keys($this->profileBundles); - } - - public function getSelected(): ProfileBundleInterface - { - if (!empty($this->currentProfileBundleName) && isset($this->profileBundles[$this->currentProfileBundleName])) { - return $this->profileBundles[$this->currentProfileBundleName]; - } - - return $this->profileBundles['ZikulaUsersBundle']; - } - - public function getSelectedName(): string - { - return $this->currentProfileBundleName ?? 'ZikulaUsersBundle'; - } -} diff --git a/src/system/UsersBundle/ProfileBundle/ProfileBundleInterface.php b/src/system/UsersBundle/ProfileBundle/ProfileBundleInterface.php deleted file mode 100644 index 737e84e2ba..0000000000 --- a/src/system/UsersBundle/ProfileBundle/ProfileBundleInterface.php +++ /dev/null @@ -1,52 +0,0 @@ -{% trans %}Choose a login authentication method{% endtrans %} - diff --git a/src/system/UsersBundle/Resources/views/Access/defaultLogin.html.twig b/src/system/UsersBundle/Resources/views/Access/defaultLogin.html.twig deleted file mode 100644 index 7b1419b9b7..0000000000 --- a/src/system/UsersBundle/Resources/views/Access/defaultLogin.html.twig +++ /dev/null @@ -1,25 +0,0 @@ -{{ pageSetVar('title', 'Login'|trans) }} -

{{ 'Login'|trans }}

- -
- {{ loginHeader|raw }} - {{ form_start(form) }} - {{ form_errors(form) }} - - {{ form_row(form.rememberme) }} - - {% for template in additionalTemplates %} - {{ include(template.view, template.params, ignore_missing = true) }} - {% endfor %} - -
-
- {{ form_widget(form.submit) }} - {% trans %}Cancel{% endtrans %} -
-
- - {{ form_end(form) }} - {{ loginFooter|raw }} -
-{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/Access/loginFooter.html.twig b/src/system/UsersBundle/Resources/views/Access/loginFooter.html.twig deleted file mode 100644 index 8b13789179..0000000000 --- a/src/system/UsersBundle/Resources/views/Access/loginFooter.html.twig +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/system/UsersBundle/Resources/views/Access/loginHeader.html.twig b/src/system/UsersBundle/Resources/views/Access/loginHeader.html.twig deleted file mode 100644 index 8b13789179..0000000000 --- a/src/system/UsersBundle/Resources/views/Access/loginHeader.html.twig +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/system/UsersBundle/Resources/views/Account/delete.html.twig b/src/system/UsersBundle/Resources/views/Account/delete.html.twig deleted file mode 100644 index f15d2fee60..0000000000 --- a/src/system/UsersBundle/Resources/views/Account/delete.html.twig +++ /dev/null @@ -1,27 +0,0 @@ -

- - {% trans %}Delete confirmation{% endtrans %} - {{ pageSetVar('title', 'Delete confirmation'|trans) }} -

-{{ form_start(form) }} -{{ form_errors(form) }} -{% for template in additionalTemplates %} - {{ include(template.view, template.params, ignore_missing = true) }} -{% endfor %} -
-

{% trans %}Deleting your Account is not recommended.{% endtrans %}

- {% trans %}If you choose to proceed, your personal data will be removed from the site.{% endtrans %} - {% trans %}This includes your username, email, profile data and so forth.{% endtrans %} - {% trans %}Third party modules are responsible to remove their own data tied to your account.{% endtrans %} - {% trans %}However, your user ID will remain valid and be associated to a 'ghost' username where required.{% endtrans %} - {% trans %}This is needed to maintain data-integrity on the site.{% endtrans %}

- {% trans %}If you require more action than this, please contact the site administrator.{% endtrans %} -
-
-
- {{ form_widget(form.delete, {attr: {class: 'btn-outline-danger'}}) }} - {{ form_widget(form.cancel, {attr: {class: 'btn-success'}}) }} -
-
-{{ form_end(form) }} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/Account/menu.html.twig b/src/system/UsersBundle/Resources/views/Account/menu.html.twig deleted file mode 100644 index 9102db62df..0000000000 --- a/src/system/UsersBundle/Resources/views/Account/menu.html.twig +++ /dev/null @@ -1,8 +0,0 @@ -{{ pageSetVar('title', 'My account'|trans) }} -

{{ 'My account'|trans }}

- -{% for menu in accountMenus|default %} - {{ knp_menu_render(menu, {template: '@ZikulaTheme/Menu/bootstrap_fontawesome.html.twig'}) }} -{% endfor %} - -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/approve.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/approve.html.twig deleted file mode 100644 index 4ad6771315..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/approve.html.twig +++ /dev/null @@ -1,56 +0,0 @@ -

- - {% trans with {"%sub%": user.uname} %}Approve registration of %sub%{% endtrans %} - {{ pageSetVar('title', 'Approve registration'|trans) }} -

-
- {% trans %}Account Information{% endtrans %} -
- -
-
{{ user.uname }}
-
-
-
- -
-
- {% if user.email|default %} - {{ user.email }} - {% else %} - --- - {% endif %} -
-
-
-
- -{#% set userAccountDisplayEvent = dispatchEvent('Zikula\\UsersBundle\\Event\\UserAccountDisplayEvent', [user]) %} -{{ userAccountDisplayEvent|raw }#} - -
- {% trans %}Registration Status{% endtrans %} -
- -
-
- {% if user.isapproved is empty or not user.isapproved %} - {% trans %}Not yet approved{% endtrans %} - {% else %} - {% trans %}Approved{% endtrans %} {% trans %}(or approval was not required when the registration was completed){% endtrans %} - {% endif %} -
-
-
-
-
-{{ form_start(form) }} -{{ form_errors(form) }} -
-
- {{ form_widget(form.confirm) }} - {{ form_widget(form.cancel) }} -
-
-{{ form_end(form) }} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/delete.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/delete.html.twig deleted file mode 100644 index aae71cee27..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/delete.html.twig +++ /dev/null @@ -1,31 +0,0 @@ -

- - {% trans %}Delete confirmation{% endtrans %} - {{ pageSetVar('title', 'Delete confirmation'|trans) }} -

-{% for user in users %} -
- {% trans with {'%un': user.uname} %}Are you sure you want to delete the user (%un)?{% endtrans %} -
-{% endfor %} -{{ form_start(form) }} -{{ form_errors(form) }} -{% for template in additionalTemplates %} - {{ include(template.view, template.params, ignore_missing = true) }} -{% endfor %} -
- {% trans %}Fully deleting a user can have unintended side effects and is not recommended.{% endtrans %}

- {% trans %}Deleting could 'orphan' data in the system and cause display errors or other unknown problems.{% endtrans %} - {% trans %}Instead, users can be 'ghosted'. In this case, the private user data is removed, but the internal user ID remains valid.{% endtrans %} - {% trans %}This makes the possibility of orphaned data much less likely and is therefore the recommended option.{% endtrans %}
- {% trans %}In either case, the username will then be forbidden from future use and the user cannot be reinstated.{% endtrans %} -
-{{ form_row(form.force) }} -
-
- {{ form_widget(form.delete) }} - {{ form_widget(form.cancel) }} -
-
-{{ form_end(form) }} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/list.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/list.html.twig deleted file mode 100644 index 53d03695b4..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/list.html.twig +++ /dev/null @@ -1,81 +0,0 @@ -

- - {% trans %}Users list{% endtrans %} - {{ pageSetVar('title', 'Users list'|trans) }} -

- -
-
- -
- -
-
- - {% trans %}This search does not include pending users.{% endtrans %} - -
-

{% trans %}Please enter at least 3 characters{% endtrans %}

- -
{{ include(alpha.template) }}
- -
- - - - - - - - - - - - - - - - - - - - - - - - - {{ include('@ZikulaUsers/UserAdministration/userlist.html.twig', {users: paginator.results}) }} - -
{% trans %}User name{% endtrans %}{% trans %}Internal ID{% endtrans %}{% trans %}Registration date{% endtrans %}{% trans %}Last login{% endtrans %}{% trans %}Auth Method{% endtrans %}{% trans %}Users groups{% endtrans %}{% trans %}Status{% endtrans %}{% trans %}Actions{% endtrans %}
- {{ include(paginator.template) }} -
- -{# This table is for ajax search results and is hidden until needed and populated then with the results. #} - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans %}User name{% endtrans %}{% trans %}Internal ID{% endtrans %}{% trans %}Registration date{% endtrans %}{% trans %}Last login{% endtrans %}{% trans %}Auth Method{% endtrans %}{% trans %}Users groups{% endtrans %}{% trans %}Status{% endtrans %}{% trans %}Actions{% endtrans %}
-{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} -{{ pageAddAsset('javascript', zasset('@ZikulaUsersBundle:js/Zikula.Users.Admin.View.js')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/modify.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/modify.html.twig deleted file mode 100644 index d02889f6e5..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/modify.html.twig +++ /dev/null @@ -1,60 +0,0 @@ -

- - {% trans with {'%uname': form.vars.value.uname} %}Edit user account of %uname{% endtrans %} - {{ pageSetVar('title', 'Edit user account'|trans) }} -

-

{% trans %}The items that are marked with an asterisk ('*') are required entries.{% endtrans %}

-{% if form.vars.value.uid == currentUser.uid %} -

{% trans %}WARNING: You appear to be editing your OWN account. You will not be able to modify active status, some group memberships or delete yourself.{% endtrans %}

-{% endif %} -{{ form_start(form) }} -{{ form_errors(form) }} -
- {% trans %}Account information{% endtrans %} - {{ form_row(form.activated) }} -

{% trans %}Setting a user theme is no longer available.{% endtrans %}

-
-
- {% trans %}Group membership{% endtrans %} - - - - - - - - - - - - - {% for group in form.groups %} - - - - - {% endfor %} - -
{% trans %}Group{% endtrans %}{% trans %}Member{% endtrans %}
{{ group.vars.label }}{{ form_widget(group) }}
-
-{% for template in additionalTemplates %} - {{ include(template.view, template.params, ignore_missing = true) }} -{% endfor %} -
-
- {{ form_widget(form.submit) }} - {{ form_widget(form.cancel) }} -
-
-
- - {% trans with {'%s': form.vars.value.uname} %}Other actions for %s{% endtrans %} - - -
-{{ form_end(form) }} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/search.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/search.html.twig deleted file mode 100644 index 19fb4e76e0..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/search.html.twig +++ /dev/null @@ -1,24 +0,0 @@ -

- - {% trans %}Find users{% endtrans %} - {{ pageSetVar('title', 'Find users'|trans) }} -

-{{ form_start(form) }} -{{ form_errors(form) }} -
- {% trans %}Find users{% endtrans %} - {{ form_row(form.uname) }} - {{ form_row(form.email) }} - {{ form_row(form.activated) }} - {{ form_row(form.groups) }} - {{ form_row(form.registered_after) }} - {{ form_row(form.registered_before) }} -
-
-
- {{ form_widget(form.search) }} - {{ form_widget(form.cancel) }} -
-
-{{ form_end(form) }} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/searchResults.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/searchResults.html.twig deleted file mode 100644 index 350c65b136..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/searchResults.html.twig +++ /dev/null @@ -1,107 +0,0 @@ -{% from '@ZikulaUsers/UserAdministration/userlist.html.twig' import userStatus as userStatus %} -

- - {% trans %}Search results{% endtrans %} - {{ pageSetVar('title', 'Search results'|trans) }} -

- -
- - {{ form_start(resultsForm) }} - {{ form_errors(resultsForm) }} - - - {% if is_granted('ROLE_ADMIN') %} - - {% endif %} - - - - - - - - {% if is_granted('ROLE_ADMIN') %} - - {% endif %} - - - - - - - - {% for user in resultsForm.users %} - {% set excluded = user.vars.name <= 2 ? true : false %} - - {% if is_granted('ROLE_ADMIN') %} - - {% endif %} - - - - - - {% endfor %} - -
 {% trans %}User name{% endtrans %}{% trans %}Email address{% endtrans %}{% trans %}Status{% endtrans %}{% trans %}Actions{% endtrans %}
- {{ form_widget(user, {title: 'Delete %n'|trans({'%n': user.vars.label}), disabled:excluded}) }} - {{ user.vars.label }} - {% if (user.parent.vars.choices[user.vars.name].data.email is defined) %} - {{ user.parent.vars.choices[user.vars.name].data.email }} - {% endif %} - - {% if (user.parent.vars.choices[user.vars.name].data.activated is defined) %} - {{ userStatus(user.parent.vars.choices[user.vars.name].data.activated) }} - {% endif %} - - {% if is_granted('ROLE_EDITOR') and user.vars.name > 1 %} - - {% endif %} - {% if not excluded and currentUser.uid != user.vars.name and is_granted('ROLE_ADMIN') %} - - {% endif %} -
- - {% if is_granted('ROLE_ADMIN') %} -

{% trans %}Select all{% endtrans %} / {% trans %}De-select all{% endtrans %}

- {% endif %} - -
-
- - {% if is_granted('ROLE_ADMIN') %} - {{ form_widget(resultsForm.delete) }} - {% endif %} - {% trans %}Return to User Administration{% endtrans %} -
-
- {{ form_end(resultsForm) }} -
- -
-
- {{ form_start(mailForm) }} - {{ form_errors(mailForm) }} -
- {{ form_row(mailForm.from) }} - {{ form_row(mailForm.replyto) }} - {{ form_row(mailForm.subject) }} - {{ form_row(mailForm.format) }} - {{ form_row(mailForm.message) }} - {{ form_row(mailForm.batchsize) }} -
-
- {{ form_widget(mailForm.send) }} - -
-
-
- {{ form_end(mailForm) }} -
-{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} -{% if is_granted('ROLE_ADMIN') %} - {{ pageAddAsset('javascript', zasset('@ZikulaUsersBundle:js/ZikulaUsersModule.Admin.SearchResults.js')) }} -{% endif %} diff --git a/src/system/UsersBundle/Resources/views/UserAdministration/userlist.html.twig b/src/system/UsersBundle/Resources/views/UserAdministration/userlist.html.twig deleted file mode 100644 index 52201048ac..0000000000 --- a/src/system/UsersBundle/Resources/views/UserAdministration/userlist.html.twig +++ /dev/null @@ -1,57 +0,0 @@ -{% for user in users %} - - {{ user.uname }} - {{ user.uid }} - - {% if user.uid != constant('Zikula\\UsersBundle\\UsersConstant::USER_ID_ANONYMOUS') %} - {{ user.registrationDate|format_datetime('medium', 'short') }} - {% endif %} - - - {% if user.uid != constant('Zikula\\UsersBundle\\UsersConstant::USER_ID_ANONYMOUS') %} - {{ user.lastLogin|format_datetime('medium', 'short') }} - {% endif %} - - - {{ _self.authMethod(user, authMethodCollector) }} - - - {% for group in user.groups %} -
{{ group.name }}
- {% endfor %} - - - {{ _self.userStatus(user.activated) }} - - - {% if user.uid == constant('Zikula\\UsersBundle\\UsersConstant::USER_ID_ANONYMOUS') %} - {% trans %}Edit?{% endtrans %} - {% endif %} - {% for action in actionsHelper.user(user) %} - - {% endfor %} - - -{% else %} - {% trans %}No records found.{% endtrans %} -{% endfor %} - -{% macro authMethod(user, authMethodCollector) %} - {% set alias = user.attributes.authenticationMethod|default %} - {{ authMethodCollector.get(alias).getDisplayName }} -{% endmacro %} - -{% macro userStatus(status) %} - {% if status == constant('Zikula\\UsersBundle\\UsersConstant::ACTIVATED_ACTIVE') %} - {% trans %}Active{% endtrans %} - {% elseif status == constant('Zikula\\UsersBundle\\UsersConstant::ACTIVATED_INACTIVE') %} - {% trans %}Inactive{% endtrans %} - {% elseif status == constant('Zikula\\UsersBundle\\UsersConstant::ACTIVATED_PENDING_REG') %} - {% trans %}Pending{% endtrans %} - {% elseif status == constant('Zikula\\UsersBundle\\UsersConstant::ACTIVATED_PENDING_DELETE') %} - {% trans %}Marked for deletion{% endtrans %} - {% else %} - {% trans %}Status unknown{% endtrans %} - {% endif %} -{% endmacro %} -{{ pageAddAsset('stylesheet', zasset('@ZikulaUsersBundle:css/style.css')) }} diff --git a/templates/bundles/NucleosUserBundle/layout.html.twig b/templates/bundles/NucleosUserBundle/layout.html.twig new file mode 100644 index 0000000000..97a583df14 --- /dev/null +++ b/templates/bundles/NucleosUserBundle/layout.html.twig @@ -0,0 +1,19 @@ +{% extends '@EasyAdmin/page/content.html.twig' %} + +{% block content_title 'Your account'|trans %} +{% block main %} +
+ {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %} + {{ 'layout.logged_in_as'|trans({'%username%': app.user.username}, 'NucleosUserBundle') }} | + + {{ 'layout.logout'|trans({}, 'NucleosUserBundle') }} + + {% else %} + {{ 'layout.login'|trans({}, 'NucleosUserBundle') }} + {% endif %} +
+
+ {% block nucleos_user_content %} + {% endblock nucleos_user_content %} +
+{% endblock %}