Passed
Push — main ( b15a24...935ae5 )
by Axel
04:15
created

UsersUiSubscriber::acceptPolicies()   C

Complexity

Conditions 15
Paths 26

Size

Total Lines 39
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 24
nc 26
nop 1
dl 0
loc 39
rs 5.9166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Zikula\LegalBundle\EventSubscriber;
15
16
use Symfony\Bundle\SecurityBundle\Security;
17
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18
use Symfony\Component\Form\FormFactoryInterface;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\Routing\RouterInterface;
21
use Twig\Environment;
22
use Zikula\LegalBundle\Form\Type\PolicyType;
23
use Zikula\LegalBundle\Helper\AcceptPoliciesHelper;
24
use Zikula\LegalBundle\LegalConstant;
25
use Zikula\UsersBundle\Event\EditUserFormPostCreatedEvent;
0 ignored issues
show
Bug introduced by
The type Zikula\UsersBundle\Event...serFormPostCreatedEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use Zikula\UsersBundle\Event\EditUserFormPostValidatedEvent;
0 ignored issues
show
Bug introduced by
The type Zikula\UsersBundle\Event...rFormPostValidatedEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use Zikula\UsersBundle\Event\UserAccountDisplayEvent;
28
use Zikula\UsersBundle\Event\UserPreLoginSuccessEvent;
0 ignored issues
show
Bug introduced by
The type Zikula\UsersBundle\Event\UserPreLoginSuccessEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use Zikula\UsersBundle\UsersConstant;
30
31
/**
32
 * Handles hook-like event notifications from log-in and registration for the acceptance of policies.
33
 */
34
class UsersUiSubscriber implements EventSubscriberInterface
35
{
36
    /**
37
     * @var string
38
     */
39
    private const EVENT_KEY = 'module.legal.users_ui_handler';
40
41
    public function __construct(
42
        private readonly RequestStack $requestStack,
43
        private readonly Environment $twig,
44
        private readonly RouterInterface $router,
45
        private readonly AcceptPoliciesHelper $acceptPoliciesHelper,
46
        private readonly FormFactoryInterface $formFactory,
47
        private readonly Security $security
48
    ) {
49
    }
50
51
    public static function getSubscribedEvents(): array
52
    {
53
        return [
54
            UserAccountDisplayEvent::class => ['uiView'],
55
            UserPreLoginSuccessEvent::class => ['acceptPolicies'],
56
            EditUserFormPostCreatedEvent::class => ['amendForm', -256],
57
            EditUserFormPostValidatedEvent::class => ['editFormHandler'],
58
        ];
59
    }
60
61
    /**
62
     * Responds to ui.view hook-like event notifications.
63
     */
64
    public function uiView(UserAccountDisplayEvent $event): void
65
    {
66
        $activePolicies = $this->acceptPoliciesHelper->getActivePolicies();
67
        $user = $event->getUser();
68
        if (!isset($user) || empty($user) || 1 > array_sum($activePolicies)) {
69
            return;
70
        }
71
72
        $acceptedPolicies = $this->acceptPoliciesHelper->getAcceptedPolicies($user->getUid());
0 ignored issues
show
Bug introduced by
The method getUid() does not exist on Zikula\UsersBundle\Entity\User. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        $acceptedPolicies = $this->acceptPoliciesHelper->getAcceptedPolicies($user->/** @scrutinizer ignore-call */ getUid());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
73
        $viewablePolicies = $this->acceptPoliciesHelper->getViewablePolicies($user->getUid());
74
        if (1 > array_sum($viewablePolicies)) {
75
            return;
76
        }
77
78
        $templateParameters = [
79
            'activePolicies' => $activePolicies,
80
            'viewablePolicies' => $viewablePolicies,
81
            'acceptedPolicies' => $acceptedPolicies,
82
        ];
83
84
        $event->addContent(self::EVENT_KEY, $this->twig->render('@ZikulaLegal/UsersUI/view.html.twig', $templateParameters));
85
    }
86
87
    /**
88
     * Vetoes (denies) a login attempt, and forces the user to accept policies.
89
     *
90
     * This handler is triggered by the 'Zikula\UsersBundle\Event\UserPreLoginSuccessEvent' event.  It vetoes (denies) a
91
     * login attempt if the users's Legal record is flagged to force the user to accept
92
     * one or more legal agreements.
93
     */
94
    public function acceptPolicies(UserPreLoginSuccessEvent $event): void
95
    {
96
        $activePolicies = $this->acceptPoliciesHelper->getActivePolicies();
97
        if (1 > array_sum($activePolicies)) {
98
            return;
99
        }
100
101
        $user = $event->getUser();
102
        if (!isset($user) || $user->getUid() <= UsersConstant::USER_ID_ADMIN) {
103
            return;
104
        }
105
106
        $attributeIsEmpty = function ($name) use ($user) {
107
            if ($user->hasAttribute($name)) {
108
                $v = $user->getAttributeValue($name);
109
110
                return empty($v);
111
            }
112
113
            return true;
114
        };
115
        $privacyPolicyAccepted = $activePolicies['privacyPolicy'] ? !$attributeIsEmpty(LegalConstant::ATTRIBUTE_PRIVACYPOLICY_ACCEPTED) : true;
116
        $termsOfUseAccepted = $activePolicies['termsOfUse'] ? !$attributeIsEmpty(LegalConstant::ATTRIBUTE_TERMSOFUSE_ACCEPTED) : true;
117
        $tradeConditionsAccepted = true; // $activePolicies['tradeConditions'] ? !$attributeIsEmpty(LegalConstant::ATTRIBUTE_TRADECONDITIONS_ACCEPTED) : true;
118
        $cancellationRightPolicyAccepted = true; // $activePolicies['cancellationRightPolicy'] ? !$attributeIsEmpty(LegalConstant::ATTRIBUTE_CANCELLATIONRIGHTPOLICY_ACCEPTED) : true;
119
        $agePolicyAccepted = $activePolicies['agePolicy'] ? !$attributeIsEmpty(LegalConstant::ATTRIBUTE_AGEPOLICY_CONFIRMED) : true;
120
121
        if ($privacyPolicyAccepted && $termsOfUseAccepted && $tradeConditionsAccepted && $cancellationRightPolicyAccepted && $agePolicyAccepted) {
122
            return;
123
        }
124
125
        $event->stopPropagation();
126
        $event->setRedirectUrl($this->router->generate('zikulalegalbundle_user_acceptpolicies'));
127
128
        $request = $this->requestStack->getMainRequest();
129
        if ($request->hasSession() && ($session = $request->getSession())) {
130
            $session->set(LegalConstant::FORCE_POLICY_ACCEPTANCE_SESSION_UID_KEY, $user->getUid());
131
        }
132
        $event->addFlash('Your log-in request was not completed. You must review and confirm your acceptance of one or more site policies prior to logging in.');
133
    }
134
135
    public function amendForm(EditUserFormPostCreatedEvent $event): void
136
    {
137
        $activePolicies = $this->acceptPoliciesHelper->getActivePolicies();
138
        if (1 > array_sum($activePolicies)) {
139
            return;
140
        }
141
142
        $user = $event->getFormData();
143
        $uid = !empty($user['uid']) ? $user['uid'] : null;
144
        $uname = !empty($user['uname']) ? $user['uname'] : null;
0 ignored issues
show
Unused Code introduced by
The assignment to $uname is dead and can be removed.
Loading history...
145
        $policyForm = $this->formFactory->create(PolicyType::class, [], [
146
            'error_bubbling' => true,
147
            'auto_initialize' => false,
148
            'mapped' => false,
149
            'userEditAccess' => $this->security->isGranted('ROLE_EDITOR'),
150
        ]);
151
        $acceptedPolicies = $this->acceptPoliciesHelper->getAcceptedPolicies($uid);
152
        $event
153
            ->formAdd($policyForm)
154
            ->addTemplate('@ZikulaLegal/UsersUI/editRegistration.html.twig', [
155
                'activePolicies' => $this->acceptPoliciesHelper->getActivePolicies(),
156
                'acceptedPolicies' => $acceptedPolicies,
157
            ])
158
        ;
159
    }
160
161
    public function editFormHandler(EditUserFormPostValidatedEvent $event): void
162
    {
163
        $userEntity = $event->getUser();
164
        $formData = $event->getFormData(LegalConstant::FORM_BLOCK_PREFIX);
165
        if (!isset($formData)) {
166
            return;
167
        }
168
        $policiesToCheck = [
169
            'termsOfUse' => LegalConstant::ATTRIBUTE_TERMSOFUSE_ACCEPTED,
170
            'privacyPolicy' => LegalConstant::ATTRIBUTE_PRIVACYPOLICY_ACCEPTED,
171
            'agePolicy' => LegalConstant::ATTRIBUTE_AGEPOLICY_CONFIRMED,
172
            'tradeConditions' => LegalConstant::ATTRIBUTE_TRADECONDITIONS_ACCEPTED,
173
            'cancellationRightPolicy' => LegalConstant::ATTRIBUTE_CANCELLATIONRIGHTPOLICY_ACCEPTED,
174
        ];
175
        $nowUTC = new \DateTime('now', new \DateTimeZone('UTC'));
176
        $nowUTCStr = $nowUTC->format(\DateTime::ATOM);
177
        $activePolicies = $this->acceptPoliciesHelper->getActivePolicies();
178
        foreach ($policiesToCheck as $policyName => $acceptedVar) {
179
            if ($formData['acceptedpolicies_policies'] && $activePolicies[$policyName]) {
180
                $userEntity->setAttribute($acceptedVar, $nowUTCStr);
181
            } else {
182
                $userEntity->delAttribute($acceptedVar);
183
            }
184
        }
185
186
        // we do not call flush here on purpose because maybe
187
        // other modules need to care for certain things before
188
        // the Users module calls flush after all listeners finished
189
    }
190
}
191