Completed
Push — master ( 8fc13e...c19aa3 )
by Axel
06:21
created

UserAdministrationController::sendUserNameAction()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 2
dl 0
loc 17
rs 10
c 0
b 0
f 0
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\PermissionsModule\Annotation\PermissionCheck;
38
use Zikula\ThemeModule\Engine\Annotation\Theme;
39
use Zikula\UsersModule\Api\ApiInterface\CurrentUserApiInterface;
40
use Zikula\UsersModule\Collector\AuthenticationMethodCollector;
41
use Zikula\UsersModule\Constant as UsersConstant;
42
use Zikula\UsersModule\Entity\RepositoryInterface\UserRepositoryInterface;
43
use Zikula\UsersModule\Entity\UserEntity;
44
use Zikula\UsersModule\Event\UserFormAwareEvent;
45
use Zikula\UsersModule\Event\UserFormDataEvent;
46
use Zikula\UsersModule\Helper\MailHelper as UsersMailHelper;
47
use Zikula\UsersModule\Helper\RegistrationHelper;
48
use Zikula\UsersModule\HookSubscriber\UserManagementUiHooksSubscriber;
49
use Zikula\UsersModule\RegistrationEvents;
50
use Zikula\UsersModule\UserEvents;
51
use Zikula\ZAuthModule\Entity\AuthenticationMappingEntity;
52
use Zikula\ZAuthModule\Entity\RepositoryInterface\AuthenticationMappingRepositoryInterface;
53
use Zikula\ZAuthModule\Form\Type\AdminCreatedUserType;
54
use Zikula\ZAuthModule\Form\Type\AdminModifyUserType;
55
use Zikula\ZAuthModule\Form\Type\BatchForcePasswordChangeType;
56
use Zikula\ZAuthModule\Form\Type\SendVerificationConfirmationType;
57
use Zikula\ZAuthModule\Form\Type\TogglePasswordConfirmationType;
58
use Zikula\ZAuthModule\Helper\AdministrationActionsHelper;
59
use Zikula\ZAuthModule\Helper\LostPasswordVerificationHelper;
60
use Zikula\ZAuthModule\Helper\MailHelper;
61
use Zikula\ZAuthModule\Helper\RegistrationVerificationHelper;
62
use Zikula\ZAuthModule\ZAuthConstant;
63
64
/**
65
 * Class UserAdministrationController
66
 *
67
 * @Route("/admin")
68
 */
69
class UserAdministrationController extends AbstractController
70
{
71
    /**
72
     * @Route("/list/{sort}/{sortdir}/{letter}/{startnum}")
73
     * @PermissionCheck("moderate")
74
     * @Theme("admin")
75
     * @Template("@ZikulaZAuthModule/UserAdministration/list.html.twig")
76
     */
77
    public function listAction(
78
        Request $request,
79
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
80
        RouterInterface $router,
81
        AdministrationActionsHelper $actionsHelper,
82
        string $sort = 'uid',
83
        string $sortdir = 'DESC',
84
        string $letter = 'all',
85
        int $startnum = 0
86
    ): array {
87
        $startnum = $startnum > 0 ? $startnum - 1 : 0;
88
89
        $sortableColumns = new SortableColumns($router, 'zikulazauthmodule_useradministration_list', 'sort', 'sortdir');
90
        $sortableColumns->addColumns([new Column('uname'), new Column('uid')]);
91
        $sortableColumns->setOrderByFromRequest($request);
92
        $sortableColumns->setAdditionalUrlParameters([
93
            'letter' => $letter,
94
            'startnum' => $startnum
95
        ]);
96
97
        $filter = [];
98
        if (!empty($letter) && 'all' !== $letter) {
99
            $filter['uname'] = ['operator' => 'like', 'operand' => "${letter}%"];
100
        }
101
        $limit = 25;
102
103
        $mappings = $authenticationMappingRepository->query($filter, [$sort => $sortdir], $limit, $startnum);
104
105
        return [
106
            'sort' => $sortableColumns->generateSortableColumns(),
107
            'pager' => [
108
                'count' => $mappings->count(),
109
                'limit' => $limit
110
            ],
111
            'actionsHelper' => $actionsHelper,
112
            'mappings' => $mappings
113
        ];
114
    }
115
116
    /**
117
     * Called from UsersModule/Resources/public/js/Zikula.Users.Admin.View.js
118
     * to populate a username search
119
     *
120
     * @Route("/getusersbyfragmentastable", methods = {"POST"}, options={"expose"=true})
121
     */
122
    public function getUsersByFragmentAsTableAction(
123
        Request $request,
124
        AuthenticationMappingRepositoryInterface $authenticationMappingRepository,
125
        AdministrationActionsHelper $actionsHelper
126
    ): Response {
127
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
128
            return new PlainResponse('');
129
        }
130
        $fragment = $request->request->get('fragment');
131
        $filter = [
132
            'uname' => ['operator' => 'like', 'operand' => $fragment . '%']
133
        ];
134
        $mappings = $authenticationMappingRepository->query($filter);
135
136
        return $this->render('@ZikulaZAuthModule/UserAdministration/userlist.html.twig', [
137
            'mappings' => $mappings,
138
            'actionsHelper' => $actionsHelper
139
        ], new PlainResponse());
140
    }
141
142
    /**
143
     * @Route("/user/create")
144
     * @PermissionCheck("admin")
145
     * @Theme("admin")
146
     * @Template("@ZikulaZAuthModule/UserAdministration/create.html.twig")
147
     *
148
     * @return array|RedirectResponse
149
     */
150
    public function createAction(
151
        Request $request,
152
        VariableApiInterface $variableApi,
153
        AuthenticationMethodCollector $authenticationMethodCollector,
154
        UserRepositoryInterface $userRepository,
155
        RegistrationHelper $registrationHelper,
156
        UsersMailHelper $mailHelper,
157
        EventDispatcherInterface $eventDispatcher,
158
        HookDispatcherInterface $hookDispatcher
159
    ) {
160
        $mapping = new AuthenticationMappingEntity();
161
        $form = $this->createForm(AdminCreatedUserType::class, $mapping, [
162
            'minimumPasswordLength' => $variableApi->get('ZikulaZAuthModule', ZAuthConstant::MODVAR_PASSWORD_MINIMUM_LENGTH, ZAuthConstant::PASSWORD_MINIMUM_LENGTH)
163
        ]);
164
        $formEvent = new UserFormAwareEvent($form);
165
        $eventDispatcher->dispatch($formEvent, UserEvents::EDIT_FORM);
166
        $form->handleRequest($request);
167
168
        $hook = new ValidationHook(new ValidationProviders());
169
        $hookDispatcher->dispatch(UserManagementUiHooksSubscriber::EDIT_VALIDATE, $hook);
170
        $validators = $hook->getValidators();
171
172
        if ($form->isSubmitted() && $form->isValid() && !$validators->hasErrors()) {
173
            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

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