Completed
Push — master ( 4b4e40...af8835 )
by Craig
10:40 queued 04:02
created

UserAdministrationController   F

Complexity

Total Complexity 78

Size/Duplication

Total Lines 490
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 247
dl 0
loc 490
rs 2.16
c 0
b 0
f 0
wmc 78

10 Methods

Rating   Name   Duplication   Size   Complexity  
B batchForcePasswordChangeAction() 0 32 8
A getUsersByFragmentAsTableAction() 0 18 2
A sendUserNameAction() 0 17 3
C getUsers() 0 44 12
A listAction() 0 39 5
B verifyAction() 0 35 7
A sendConfirmationAction() 0 21 3
B togglePasswordChangeAction() 0 37 9
F createAction() 0 88 19
B modifyAction() 0 67 10

How to fix   Complexity   

Complex Class

Complex classes like UserAdministrationController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UserAdministrationController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula Foundation - 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\ZAuthModule\Controller;
15
16
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\Routing\Annotation\Route;
21
use Symfony\Component\Routing\RouterInterface;
22
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
23
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
24
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
25
use Translation\Extractor\Annotation\Desc;
26
use Zikula\Bundle\CoreBundle\Controller\AbstractController;
27
use Zikula\Bundle\CoreBundle\Event\GenericEvent;
28
use Zikula\Bundle\CoreBundle\Response\PlainResponse;
29
use Zikula\Bundle\HookBundle\Dispatcher\HookDispatcherInterface;
30
use Zikula\Bundle\HookBundle\Hook\ProcessHook;
31
use Zikula\Bundle\HookBundle\Hook\ValidationHook;
32
use Zikula\Bundle\HookBundle\Hook\ValidationProviders;
33
use Zikula\Component\SortableColumns\Column;
34
use Zikula\Component\SortableColumns\SortableColumns;
35
use Zikula\ExtensionsModule\Api\ApiInterface\VariableApiInterface;
36
use Zikula\GroupsModule\Entity\GroupEntity;
37
use Zikula\ThemeModule\Engine\Annotation\Theme;
38
use Zikula\UsersModule\Api\ApiInterface\CurrentUserApiInterface;
39
use Zikula\UsersModule\Collector\AuthenticationMethodCollector;
40
use Zikula\UsersModule\Constant as UsersConstant;
41
use Zikula\UsersModule\Entity\RepositoryInterface\UserRepositoryInterface;
42
use Zikula\UsersModule\Entity\UserEntity;
43
use Zikula\UsersModule\Event\UserFormAwareEvent;
44
use Zikula\UsersModule\Event\UserFormDataEvent;
45
use Zikula\UsersModule\Helper\MailHelper as UsersMailHelper;
46
use Zikula\UsersModule\Helper\RegistrationHelper;
47
use Zikula\UsersModule\HookSubscriber\UserManagementUiHooksSubscriber;
48
use Zikula\UsersModule\RegistrationEvents;
49
use Zikula\UsersModule\UserEvents;
50
use Zikula\ZAuthModule\Entity\AuthenticationMappingEntity;
51
use Zikula\ZAuthModule\Entity\RepositoryInterface\AuthenticationMappingRepositoryInterface;
52
use Zikula\ZAuthModule\Form\Type\AdminCreatedUserType;
53
use Zikula\ZAuthModule\Form\Type\AdminModifyUserType;
54
use Zikula\ZAuthModule\Form\Type\BatchForcePasswordChangeType;
55
use Zikula\ZAuthModule\Form\Type\SendVerificationConfirmationType;
56
use Zikula\ZAuthModule\Form\Type\TogglePasswordConfirmationType;
57
use Zikula\ZAuthModule\Helper\AdministrationActionsHelper;
58
use Zikula\ZAuthModule\Helper\LostPasswordVerificationHelper;
59
use Zikula\ZAuthModule\Helper\MailHelper;
60
use Zikula\ZAuthModule\Helper\RegistrationVerificationHelper;
61
use Zikula\ZAuthModule\ZAuthConstant;
62
63
/**
64
 * Class UserAdministrationController
65
 * @Route("/admin")
66
 */
67
class UserAdministrationController extends AbstractController
68
{
69
    /**
70
     * @Route("/list/{sort}/{sortdir}/{letter}/{startnum}")
71
     * @Theme("admin")
72
     * @Template("@ZikulaZAuthModule/UserAdministration/list.html.twig")
73
     *
74
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the module
75
     */
76
    public function listAction(
77
        Request $request,
78
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
79
        RouterInterface $router,
80
        AdministrationActionsHelper $actionsHelper,
81
        string $sort = 'uid',
82
        string $sortdir = 'DESC',
83
        string $letter = 'all',
84
        int $startnum = 0
85
    ): array {
86
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
87
            throw new AccessDeniedException();
88
        }
89
        $startnum = $startnum > 0 ? $startnum - 1 : 0;
90
91
        $sortableColumns = new SortableColumns($router, 'zikulazauthmodule_useradministration_list', 'sort', 'sortdir');
92
        $sortableColumns->addColumns([new Column('uname'), new Column('uid')]);
93
        $sortableColumns->setOrderByFromRequest($request);
94
        $sortableColumns->setAdditionalUrlParameters([
95
            'letter' => $letter,
96
            'startnum' => $startnum
97
        ]);
98
99
        $filter = [];
100
        if (!empty($letter) && 'all' !== $letter) {
101
            $filter['uname'] = ['operator' => 'like', 'operand' => "${letter}%"];
102
        }
103
        $limit = 25;
104
105
        $mappings = $authenticationMappingRepository->query($filter, [$sort => $sortdir], $limit, $startnum);
106
107
        return [
108
            'sort' => $sortableColumns->generateSortableColumns(),
109
            'pager' => [
110
                'count' => $mappings->count(),
111
                'limit' => $limit
112
            ],
113
            'actionsHelper' => $actionsHelper,
114
            'mappings' => $mappings
115
        ];
116
    }
117
118
    /**
119
     * Called from UsersModule/Resources/public/js/Zikula.Users.Admin.View.js
120
     * to populate a username search
121
     *
122
     * @Route("/getusersbyfragmentastable", methods = {"POST"}, options={"expose"=true})
123
     */
124
    public function getUsersByFragmentAsTableAction(
125
        Request $request,
126
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
127
        AdministrationActionsHelper $actionsHelper
128
    ): Response {
129
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
130
            return new PlainResponse('');
131
        }
132
        $fragment = $request->request->get('fragment');
133
        $filter = [
134
            'uname' => ['operator' => 'like', 'operand' => $fragment . '%']
135
        ];
136
        $mappings = $authenticationMappingRepository->query($filter);
137
138
        return $this->render('@ZikulaZAuthModule/UserAdministration/userlist.html.twig', [
139
            'mappings' => $mappings,
140
            'actionsHelper' => $actionsHelper
141
        ], new PlainResponse());
142
    }
143
144
    /**
145
     * @Route("/user/create")
146
     * @Theme("admin")
147
     * @Template("@ZikulaZAuthModule/UserAdministration/create.html.twig")
148
     *
149
     * @return array|RedirectResponse
150
     * @throws AccessDeniedException Thrown if the user hasn't admin permissions for the module
151
     */
152
    public function createAction(
153
        Request $request,
154
        VariableApiInterface $variableApi,
155
        AuthenticationMethodCollector $authenticationMethodCollector,
156
        UserRepositoryInterface $userRepository,
157
        RegistrationHelper $registrationHelper,
158
        UsersMailHelper $mailHelper,
159
        EventDispatcherInterface $eventDispatcher,
160
        HookDispatcherInterface $hookDispatcher
161
    ) {
162
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_ADMIN)) {
163
            throw new AccessDeniedException();
164
        }
165
166
        $mapping = new AuthenticationMappingEntity();
167
        $form = $this->createForm(AdminCreatedUserType::class, $mapping, [
168
            'minimumPasswordLength' => $variableApi->get('ZikulaZAuthModule', ZAuthConstant::MODVAR_PASSWORD_MINIMUM_LENGTH, ZAuthConstant::PASSWORD_MINIMUM_LENGTH)
169
        ]);
170
        $formEvent = new UserFormAwareEvent($form);
171
        $eventDispatcher->dispatch($formEvent, UserEvents::EDIT_FORM);
172
        $form->handleRequest($request);
173
174
        $hook = new ValidationHook(new ValidationProviders());
175
        $hookDispatcher->dispatch(UserManagementUiHooksSubscriber::EDIT_VALIDATE, $hook);
176
        $validators = $hook->getValidators();
177
178
        if ($form->isSubmitted() && $form->isValid() && !$validators->hasErrors()) {
179
            if ($form->get('submit')->isClicked()) {
0 ignored issues
show
Bug introduced by
The method isClicked() does not exist on Symfony\Component\Form\FormInterface. It seems like you code against a sub-type of Symfony\Component\Form\FormInterface such as Symfony\Component\Form\SubmitButton. ( Ignorable by Annotation )

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

179
            if ($form->get('submit')->/** @scrutinizer ignore-call */ isClicked()) {
Loading history...
180
                $mapping = $form->getData();
181
                $passToSend = $form['sendpass']->getData() ? $mapping->getPass() : '';
182
                $authMethodName = (ZAuthConstant::AUTHENTICATION_METHOD_EITHER === $mapping->getMethod()) ? ZAuthConstant::AUTHENTICATION_METHOD_UNAME : $mapping->getMethod();
183
                $authMethod = $authenticationMethodCollector->get($authMethodName);
184
185
                if ($request->hasSession() && ($session = $request->getSession())) {
186
                    $session->set(ZAuthConstant::MODVAR_EMAIL_VERIFICATION_REQUIRED, ($form['usermustverify']->getData() ? 'Y' : 'N'));
187
                }
188
189
                $userData = $mapping->getUserEntityData();
190
                if (null === $userData['uid']) {
191
                    unset($userData['uid']);
192
                }
193
                $user = new UserEntity();
194
                $user->merge($userData);
195
                $user->setAttribute(UsersConstant::AUTHENTICATION_METHOD_ATTRIBUTE_KEY, $mapping->getMethod());
196
                $registrationHelper->registerNewUser($user);
197
                if (UsersConstant::ACTIVATED_PENDING_REG === $user->getActivated()) {
198
                    $notificationErrors = $mailHelper->createAndSendRegistrationMail($user, $form['usernotification']->getData(), $form['adminnotification']->getData(), $passToSend);
199
                } else {
200
                    $notificationErrors = $mailHelper->createAndSendUserMail($user, $form['usernotification']->getData(), $form['adminnotification']->getData(), $passToSend);
201
                }
202
                if (!empty($notificationErrors)) {
203
                    $this->addFlash('error', 'Errors creating user!');
204
                    $this->addFlash('error', implode('<br />', $notificationErrors));
205
                }
206
                $userId = $user->getUid();
207
                $mapping->setUid($user->getUid());
208
                $mapping->setVerifiedEmail(!$form['usermustverify']->getData());
209
                if (!$authMethod->register($mapping->toArray())) {
210
                    $this->addFlash('error', 'The create process failed for an unknown reason.');
211
                    $userRepository->removeAndFlush($user);
212
                    $eventDispatcher->dispatch(new GenericEvent($userId), RegistrationEvents::DELETE_REGISTRATION);
213
214
                    return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
215
                }
216
                $formDataEvent = new UserFormDataEvent($user, $form);
217
                $eventDispatcher->dispatch($formDataEvent, UserEvents::EDIT_FORM_HANDLE);
218
                $hook = new ProcessHook($userId);
219
                $hookDispatcher->dispatch(UserManagementUiHooksSubscriber::EDIT_PROCESS, $hook);
220
                $eventDispatcher->dispatch(new GenericEvent($user), RegistrationEvents::REGISTRATION_SUCCEEDED);
221
222
                if (UsersConstant::ACTIVATED_PENDING_REG === $user->getActivated()) {
223
                    $this->addFlash('status', 'Done! Created new registration application.');
224
                } elseif (null !== $user->getActivated()) {
0 ignored issues
show
introduced by
The condition null !== $user->getActivated() is always true.
Loading history...
225
                    $this->addFlash('status', 'Done! Created new user account.');
226
                } else {
227
                    $this->addFlash('error', 'Warning! New user information has been saved, however there may have been an issue saving it properly.');
228
                }
229
230
                return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
231
            }
232
            if ($form->get('cancel')->isClicked()) {
233
                $this->addFlash('status', 'Operation cancelled.');
234
            }
235
        }
236
237
        return [
238
            'form' => $form->createView(),
239
            'additional_templates' => isset($formEvent) ? $formEvent->getTemplates() : []
240
        ];
241
    }
242
243
    /**
244
     * @Route("/user/modify/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
245
     * @Theme("admin")
246
     * @Template("@ZikulaZAuthModule/UserAdministration/modify.html.twig")
247
     *
248
     * @return array|RedirectResponse
249
     * @throws AccessDeniedException Thrown if the user hasn't edit permissions for the mapping record
250
     */
251
    public function modifyAction(
252
        Request $request,
253
        AuthenticationMappingEntity $mapping,
254
        VariableApiInterface $variableApi,
255
        EncoderFactoryInterface $encoderFactory,
256
        UserRepositoryInterface $userRepository,
257
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
258
        EventDispatcherInterface $eventDispatcher,
259
        HookDispatcherInterface $hookDispatcher
260
    ) {
261
        if (!$this->hasPermission('ZikulaZAuthModule::', $mapping->getUname() . '::' . $mapping->getUid(), ACCESS_EDIT)) {
262
            throw new AccessDeniedException();
263
        }
264
        if (1 === $mapping->getUid()) {
265
            throw new AccessDeniedException($this->trans("Error! You can't edit the guest account."));
266
        }
267
268
        $form = $this->createForm(AdminModifyUserType::class, $mapping, [
269
            'minimumPasswordLength' => $variableApi->get('ZikulaZAuthModule', ZAuthConstant::MODVAR_PASSWORD_MINIMUM_LENGTH, ZAuthConstant::PASSWORD_MINIMUM_LENGTH)
270
        ]);
271
        $originalMapping = clone $mapping;
272
        $formEvent = new UserFormAwareEvent($form);
273
        $eventDispatcher->dispatch($formEvent, UserEvents::EDIT_FORM);
274
        $form->handleRequest($request);
275
276
        $hook = new ValidationHook(new ValidationProviders());
277
        $hookDispatcher->dispatch(UserManagementUiHooksSubscriber::EDIT_VALIDATE, $hook);
278
        $validators = $hook->getValidators();
279
280
        if ($form->isSubmitted() && $form->isValid() && !$validators->hasErrors()) {
281
            if ($form->get('submit')->isClicked()) {
282
                /** @var AuthenticationMappingEntity $mapping */
283
                $mapping = $form->getData();
284
                if ($form->get('setpass')->getData()) {
285
                    $mapping->setPass($encoderFactory->getEncoder($mapping)->encodePassword($mapping->getPass(), null));
286
                } else {
287
                    $mapping->setPass($originalMapping->getPass());
288
                }
289
                $authenticationMappingRepository->persistAndFlush($mapping);
290
                /** @var UserEntity $user */
291
                $user = $userRepository->find($mapping->getUid());
292
                $user->merge($mapping->getUserEntityData());
293
                $userRepository->persistAndFlush($user);
294
                $eventArgs = [
295
                    'action'    => 'setVar',
296
                    'field'     => 'uname',
297
                    'attribute' => null,
298
                ];
299
                $eventData = ['old_value' => $originalMapping->getUname()];
300
                $updateEvent = new GenericEvent($user, $eventArgs, $eventData);
301
                $eventDispatcher->dispatch($updateEvent, UserEvents::UPDATE_ACCOUNT);
302
303
                $formDataEvent = new UserFormDataEvent($user, $form);
304
                $eventDispatcher->dispatch($formDataEvent, UserEvents::EDIT_FORM_HANDLE);
305
                $hookDispatcher->dispatch(UserManagementUiHooksSubscriber::EDIT_PROCESS, new ProcessHook($mapping->getUid()));
306
307
                $this->addFlash('status', "Done! Saved user's account information.");
308
            } elseif ($form->get('cancel')->isClicked()) {
309
                $this->addFlash('status', 'Operation cancelled.');
310
            }
311
312
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
313
        }
314
315
        return [
316
            'form' => $form->createView(),
317
            'additional_templates' => isset($formEvent) ? $formEvent->getTemplates() : []
318
        ];
319
    }
320
321
    /**
322
     * @Route("/verify/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
323
     * @Theme("admin")
324
     * @Template("@ZikulaZAuthModule/UserAdministration/verify.html.twig")
325
     *
326
     * @return array|RedirectResponse
327
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the module
328
     */
329
    public function verifyAction(
330
        Request $request,
331
        AuthenticationMappingEntity $mapping,
332
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
333
        RegistrationVerificationHelper $registrationVerificationHelper
334
    ) {
335
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
336
            throw new AccessDeniedException();
337
        }
338
        $form = $this->createForm(SendVerificationConfirmationType::class, [
339
            'mapping' => $mapping->getId()
340
        ]);
341
342
        $form->handleRequest($request);
343
        if ($form->isSubmitted() && $form->isValid()) {
344
            if ($form->get('confirm')->isClicked()) {
345
                /** @var AuthenticationMappingEntity $modifiedMapping */
346
                $modifiedMapping = $authenticationMappingRepository->find($form->get('mapping')->getData());
347
                $verificationSent = $registrationVerificationHelper->sendVerificationCode($modifiedMapping);
348
                if (!$verificationSent) {
349
                    $this->addFlash('error', $this->trans('Sorry! There was a problem sending a verification code to %sub%.', ['%sub%' => $modifiedMapping->getUname()]));
350
                } else {
351
                    $this->addFlash('status', $this->trans('Done! Verification code sent to %sub%.', ['%sub%' => $modifiedMapping->getUname()]));
352
                }
353
            }
354
            if ($form->get('cancel')->isClicked()) {
355
                $this->addFlash('status', 'Operation cancelled.');
356
            }
357
358
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
359
        }
360
361
        return [
362
            'form' => $form->createView(),
363
            'mapping' => $mapping
364
        ];
365
    }
366
367
    /**
368
     * @Route("/send-confirmation/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
369
     *
370
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the mapping record
371
     */
372
    public function sendConfirmationAction(
373
        AuthenticationMappingEntity $mapping,
374
        LostPasswordVerificationHelper $lostPasswordVerificationHelper,
375
        MailHelper $mailHelper
376
    ): RedirectResponse {
377
        if (!$this->hasPermission('ZikulaZAuthModule', $mapping->getUname() . '::' . $mapping->getUid(), ACCESS_MODERATE)) {
378
            throw new AccessDeniedException();
379
        }
380
        $changePasswordExpireDays = $this->getVar(ZAuthConstant::MODVAR_EXPIRE_DAYS_CHANGE_PASSWORD, ZAuthConstant::DEFAULT_EXPIRE_DAYS_CHANGE_PASSWORD);
381
        $lostPasswordId = $lostPasswordVerificationHelper->createLostPasswordId($mapping);
382
        $mailSent = $mailHelper->sendNotification($mapping->getEmail(), 'lostpassword', [
383
            'uname' => $mapping->getUname(),
384
            'validDays' => $changePasswordExpireDays,
385
            'lostPasswordId' => $lostPasswordId,
386
            'requestedByAdmin' => true
387
        ]);
388
        if ($mailSent) {
389
            $this->addFlash('status', $this->trans('Done! The password recovery verification link for %userName% has been sent via e-mail.', ['%userName%' => $mapping->getUname()]));
390
        }
391
392
        return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
393
    }
394
395
    /**
396
     * @Route("/send-username/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
397
     *
398
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the mapping record
399
     */
400
    public function sendUserNameAction(
401
        AuthenticationMappingEntity $mapping,
402
        MailHelper $mailHelper
403
    ): RedirectResponse {
404
        if (!$this->hasPermission('ZikulaZAuthModule', $mapping->getUname() . '::' . $mapping->getUid(), ACCESS_MODERATE)) {
405
            throw new AccessDeniedException();
406
        }
407
        $mailSent = $mailHelper->sendNotification($mapping->getEmail(), 'lostuname', [
408
            'uname' => $mapping->getUname(),
409
            'requestedByAdmin' => true,
410
        ]);
411
412
        if ($mailSent) {
413
            $this->addFlash('status', $this->trans('Done! The user name for %userName% has been sent via e-mail.', ['%userName%' => $mapping->getUname()]));
414
        }
415
416
        return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
417
    }
418
419
    /**
420
     * @Route("/toggle-password-change/{user}", requirements={"user" = "^[1-9]\d*$"})
421
     * @Theme("admin")
422
     * @Template("@ZikulaZAuthModule/UserAdministration/togglePasswordChange.html.twig")
423
     *
424
     * @param Request $request
425
     * @param UserEntity $user // note: this is intentionally left as UserEntity instead of mapping because of need to access attributes
426
     *
427
     * @return array|RedirectResponse
428
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the user record
429
     */
430
    public function togglePasswordChangeAction(Request $request, UserEntity $user)
431
    {
432
        if (!$this->hasPermission('ZikulaZAuthModule', $user->getUname() . '::' . $user->getUid(), ACCESS_MODERATE)) {
433
            throw new AccessDeniedException();
434
        }
435
        if ($user->getAttributes()->containsKey(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY)) {
436
            $mustChangePass = $user->getAttributes()->get(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY);
437
        } else {
438
            $mustChangePass = false;
439
        }
440
        $form = $this->createForm(TogglePasswordConfirmationType::class, [
441
            'uid' => $user->getUid()
442
        ], [
443
            'mustChangePass' => $mustChangePass
444
        ]);
445
        $form->handleRequest($request);
446
        if ($form->isSubmitted() && $form->isValid()) {
447
            if ($form->get('toggle')->isClicked()) {
448
                if ($user->getAttributes()->containsKey(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY) && (bool)$user->getAttributes()->get(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY)) {
449
                    $user->getAttributes()->remove(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY);
450
                    $this->addFlash('success', $this->trans('Done! A password change will no longer be required for %userName%.', ['%userName%' => $user->getUname()]));
451
                } else {
452
                    $user->setAttribute(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY, true);
453
                    $this->addFlash('success', $this->trans('Done! A password change will be required the next time %userName% logs in.', ['%userName%' => $user->getUname()]));
454
                }
455
                $this->getDoctrine()->getManager()->flush();
456
            } elseif ($form->get('cancel')->isClicked()) {
457
                $this->addFlash('info', 'Operation cancelled.');
458
            }
459
460
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
461
        }
462
463
        return [
464
            'form' => $form->createView(),
465
            'mustChangePass' => $mustChangePass,
466
            'user' => $user
467
        ];
468
    }
469
470
    /**
471
     * @Route("/batch-force-password-change")
472
     * @Theme("admin")
473
     * @Template("@ZikulaZAuthModule/UserAdministration/batchForcePasswordChange.html.twig")
474
     *
475
     * @return array|RedirectResponse
476
     * @throws AccessDeniedException Thrown if the user hasn't moderate permissions for the user record
477
     */
478
    public function batchForcePasswordChangeAction(
479
        CurrentUserApiInterface $currentUserApi,
480
        Request $request
481
    ) {
482
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_ADMIN)) {
483
            throw new AccessDeniedException();
484
        }
485
        $form = $this->createForm(BatchForcePasswordChangeType::class);
486
        $form->handleRequest($request);
487
        if ($form->isSubmitted() && $form->isValid()) {
488
            if ($form->get('submit')->isClicked()) {
489
                $users = $this->getUsers($form->get('group')->getData(), $currentUserApi->get('uid'));
490
                $count = 0;
491
                foreach ($users as $user) {
492
                    $user->setAttribute(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY, true);
493
                    $count++;
494
                    if ($count % 20 === 0) {
495
                        $this->getDoctrine()->getManager()->flush(); // flush manager every 20 reps
496
                    }
497
                }
498
                $this->getDoctrine()->getManager()->flush(); // flush remaining
499
                /** @Desc("{count, plural,\n  one   {# user was processed!}\n  other {# users were processed!}\n}") */
500
                $this->addFlash('info', $this->trans('plural_n.users.processed.', ['%count%' => $count]));
501
            } elseif ($form->get('cancel')->isClicked()) {
502
                $this->addFlash('info', 'Operation cancelled.');
503
            }
504
505
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
506
        }
507
508
        return [
509
            'form' => $form->createView(),
510
        ];
511
    }
512
513
    private function getUsers($selector, int $currentUser)
514
    {
515
        if (!in_array($selector, ['all', 'old']) && !is_int($selector)) {
516
            return [];
517
        }
518
        $authenticationMappingRepository = $this->getDoctrine()->getRepository(AuthenticationMappingEntity::class);
519
        $toUsersArray = function($mappings) {
520
            $uids = [];
521
            foreach ($mappings as $mapping) {
522
                $uids[] = $mapping->getUid();
523
            }
524
            $userRepository = $this->getDoctrine()->getRepository(UserEntity::class);
525
526
            return $userRepository->findByUids($uids);
527
        };
528
        switch ($selector) {
529
            case 'old':
530
                $mappings = $authenticationMappingRepository->getByExpiredPasswords();
531
                $users = $toUsersArray($mappings);
532
                break;
533
            case 'all':
534
                $mappings = $authenticationMappingRepository->findAll();
535
                $users = $toUsersArray($mappings);
536
                break;
537
            default: //group id
538
                $groupRepository = $this->getDoctrine()->getRepository(GroupEntity::class);
539
                $group = $groupRepository->find($selector);
540
                if ($group && $group instanceof GroupEntity) {
541
                    $users = $group->getUsers();
542
                    foreach ($users as $user) {
543
                        if (!$authenticationMappingRepository->getByZikulaId($user->getUid())) {
544
                            $users->removeElement($user);
545
                        }
546
                    }
547
                    $users = $users->toArray();
548
                }
549
        }
550
551
        if (is_array($users) && isset($users[$currentUser])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $users does not seem to be defined for all execution paths leading up to this point.
Loading history...
552
            unset($users[$currentUser]); // remove the current user (admin)
553
            unset($users[1]); // remove guest user if included
554
        }
555
556
        return $users;
557
    }
558
}
559