Completed
Push — master ( fd10c7...b50c82 )
by Craig
06:29
created

getUsersByFragmentAsTableAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zikula\ZAuthModule\Controller;
13
14
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
15
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
16
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
20
use Zikula\Bundle\HookBundle\Hook\ProcessHook;
21
use Zikula\Bundle\HookBundle\Hook\ValidationHook;
22
use Zikula\Bundle\HookBundle\Hook\ValidationProviders;
23
use Zikula\Component\SortableColumns\Column;
24
use Zikula\Component\SortableColumns\SortableColumns;
25
use Zikula\Core\Controller\AbstractController;
26
use Zikula\Core\Event\GenericEvent;
27
use Zikula\Core\Response\PlainResponse;
28
use Zikula\ThemeModule\Engine\Annotation\Theme;
29
use Zikula\UsersModule\Constant as UsersConstant;
30
use Zikula\UsersModule\Container\HookContainer;
31
use Zikula\UsersModule\Entity\UserEntity;
32
use Zikula\UsersModule\Event\UserFormAwareEvent;
33
use Zikula\UsersModule\Event\UserFormDataEvent;
34
use Zikula\UsersModule\RegistrationEvents;
35
use Zikula\UsersModule\UserEvents;
36
use Zikula\ZAuthModule\Entity\AuthenticationMappingEntity;
37
use Zikula\ZAuthModule\Form\Type\AdminCreatedUserType;
38
use Zikula\ZAuthModule\Form\Type\AdminModifyUserType;
39
use Zikula\ZAuthModule\Form\Type\SendVerificationConfirmationType;
40
use Zikula\ZAuthModule\Form\Type\TogglePasswordConfirmationType;
41
use Zikula\ZAuthModule\ZAuthConstant;
42
43
/**
44
 * Class UserAdministrationController
45
 * @Route("/admin")
46
 */
47
class UserAdministrationController extends AbstractController
48
{
49
    /**
50
     * @Route("/list/{sort}/{sortdir}/{letter}/{startnum}")
51
     * @Theme("admin")
52
     * @Template
53
     * @param Request $request
54
     * @param string $sort
55
     * @param string $sortdir
56
     * @param string $letter
57
     * @param integer $startnum
58
     * @return array
59
     */
60
    public function listAction(Request $request, $sort = 'uid', $sortdir = 'DESC', $letter = 'all', $startnum = 0)
61
    {
62
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
63
            throw new AccessDeniedException();
64
        }
65
        $startnum = $startnum > 0 ? $startnum - 1 : 0;
66
67
        $sortableColumns = new SortableColumns($this->get('router'), 'zikulazauthmodule_useradministration_list', 'sort', 'sortdir');
68
        $sortableColumns->addColumns([new Column('uname'), new Column('uid')]);
69
        $sortableColumns->setOrderByFromRequest($request);
70
        $sortableColumns->setAdditionalUrlParameters([
71
            'letter' => $letter,
72
            'startnum' => $startnum
73
        ]);
74
75
        $filter = [];
76 View Code Duplication
        if (!empty($letter) && 'all' != $letter) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
77
            $filter['uname'] = ['operator' => 'like', 'operand' => "$letter%"];
78
        }
79
        $limit = 25; // @todo make this configurable?
80
81
        $mappings = $this->get('zikula_zauth_module.authentication_mapping_repository')->query(
82
            $filter,
83
            [$sort => $sortdir],
84
            $limit,
85
            $startnum
86
        );
87
88
        return [
89
            'sort' => $sortableColumns->generateSortableColumns(),
90
            'pager' => [
91
                'count' => $mappings->count(),
92
                'limit' => $limit
93
            ],
94
            'actionsHelper' => $this->get('zikula_zauth_module.helper.administration_actions_helper'),
95
            'mappings' => $mappings
96
        ];
97
    }
98
99
    /**
100
     * Called from UsersModule/Resources/public/js/Zikula.Users.Admin.View.js
101
     * to populate a username search
102
     *
103
     * @Route("/getusersbyfragmentastable", options={"expose"=true})
104
     * @Method("POST")
105
     * @param Request $request
106
     * @return PlainResponse
107
     */
108
    public function getUsersByFragmentAsTableAction(Request $request)
109
    {
110
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
111
            return new PlainResponse('');
112
        }
113
        $fragment = $request->request->get('fragment');
114
        $filter = [
115
            'uname' => ['operator' => 'like', 'operand' => "$fragment%"]
116
        ];
117
        $mappings = $this->get('zikula_zauth_module.authentication_mapping_repository')->query($filter);
118
119
        return $this->render('@ZikulaZAuthModule/UserAdministration/userlist.html.twig', [
120
            'mappings' => $mappings,
121
            'actionsHelper' => $this->get('zikula_zauth_module.helper.administration_actions_helper'),
122
        ], new PlainResponse());
123
    }
124
125
    /**
126
     * @Route("/user/create")
127
     * @Theme("admin")
128
     * @Template()
129
     * @param Request $request
130
     * @return array
131
     */
132
    public function createAction(Request $request)
133
    {
134
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_ADMIN)) {
135
            throw new AccessDeniedException();
136
        }
137
        $dispatcher = $this->get('event_dispatcher');
138
139
        $mapping = new AuthenticationMappingEntity();
140
        $form = $this->createForm(AdminCreatedUserType::class, $mapping, [
141
            'translator' => $this->get('translator.default')
142
        ]);
143
        $formEvent = new UserFormAwareEvent($form);
144
        $dispatcher->dispatch(UserEvents::EDIT_FORM, $formEvent);
145
        $form->handleRequest($request);
146
147
        $hook = new ValidationHook(new ValidationProviders());
148
        $this->get('hook_dispatcher')->dispatch(HookContainer::EDIT_VALIDATE, $hook);
149
        $validators = $hook->getValidators();
150
151
        if ($form->isValid() && !$validators->hasErrors()) {
152
            if ($form->get('submit')->isClicked()) {
153
                $mapping = $form->getData();
154
                $passToSend = $form['sendpass']->getData() ? $mapping->getPass() : '';
155
                $authMethodName = ($mapping->getMethod() == ZAuthConstant::AUTHENTICATION_METHOD_EITHER) ? ZAuthConstant::AUTHENTICATION_METHOD_UNAME : $mapping->getMethod();
156
                $authMethod = $this->get('zikula_users_module.internal.authentication_method_collector')->get($authMethodName);
157
                $user = new UserEntity();
158
                $user->merge($mapping->getUserEntityData());
159
                $user->setAttribute(UsersConstant::AUTHENTICATION_METHOD_ATTRIBUTE_KEY, $mapping->getMethod());
160
                $this->get('zikula_users_module.helper.registration_helper')->registerNewUser($user);
161
                if ($user->getActivated() == UsersConstant::ACTIVATED_PENDING_REG) {
162
                    $notificationErrors = $this->get('zikula_users_module.helper.mail_helper')->createAndSendRegistrationMail($user, $form['usernotification']->getData(), $form['adminnotification']->getData(), $passToSend);
163
                } else {
164
                    $notificationErrors = $this->get('zikula_users_module.helper.mail_helper')->createAndSendUserMail($user, $form['usernotification']->getData(), $form['adminnotification']->getData(), $passToSend);
165
                }
166
                if (!empty($notificationErrors)) {
167
                    $this->addFlash('error', $this->__('Errors creating user!'));
168
                    $this->addFlash('error', implode('<br>', $notificationErrors));
169
                }
170
                $mapping->setUid($user->getUid());
171 View Code Duplication
                if (!$authMethod->register($mapping->toArray())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
                    $this->addFlash('error', $this->__('The create process failed for an unknown reason.'));
173
                    $this->get('zikula_users_module.user_repository')->removeAndFlush($user);
174
                    $dispatcher->dispatch(RegistrationEvents::DELETE_REGISTRATION, new GenericEvent($user->getUid()));
175
176
                    return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
177
                }
178
                $formDataEvent = new UserFormDataEvent($user, $form);
179
                $dispatcher->dispatch(UserEvents::EDIT_FORM_HANDLE, $formDataEvent);
180
                $hook = new ProcessHook($user->getUid());
181
                $this->get('hook_dispatcher')->dispatch(HookContainer::EDIT_PROCESS, $hook);
182
                $dispatcher->dispatch(RegistrationEvents::REGISTRATION_SUCCEEDED, new GenericEvent($user));
183
184
                if ($user->getActivated() == UsersConstant::ACTIVATED_PENDING_REG) {
185
                    $this->addFlash('status', $this->__('Done! Created new registration application.'));
186
                } elseif (null !== $user->getActivated()) {
187
                    $this->addFlash('status', $this->__('Done! Created new user account.'));
188
                } else {
189
                    $this->addFlash('error', $this->__('Warning! New user information has been saved, however there may have been an issue saving it properly.'));
190
                }
191
192
                return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
193
            }
194
            if ($form->get('cancel')->isClicked()) {
195
                $this->addFlash('status', $this->__('Operation cancelled.'));
196
            }
197
        }
198
199
        return [
200
            'form' => $form->createView(),
201
            'additional_templates' => isset($formEvent) ? $formEvent->getTemplates() : []
202
        ];
203
    }
204
205
    /**
206
     * @Route("/user/modify/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
207
     * @Theme("admin")
208
     * @Template()
209
     * @param Request $request
210
     * @param AuthenticationMappingEntity $mapping
211
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
212
     */
213
    public function modifyAction(Request $request, AuthenticationMappingEntity $mapping)
214
    {
215 View Code Duplication
        if (!$this->hasPermission('ZikulaZAuthModule::', $mapping->getUname() . "::" . $mapping->getUid(), ACCESS_EDIT)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
            throw new AccessDeniedException();
217
        }
218
        if (1 === $mapping->getUid()) {
219
            throw new AccessDeniedException($this->__("Error! You can't edit the guest account."));
220
        }
221
        $dispatcher = $this->get('event_dispatcher');
222
223
        $form = $this->createForm(AdminModifyUserType::class, $mapping, [
224
            'translator' => $this->get('translator.default')
225
        ]);
226
        $originalMapping = clone $mapping;
227
        $formEvent = new UserFormAwareEvent($form);
228
        $dispatcher->dispatch(UserEvents::EDIT_FORM, $formEvent);
229
        $form->handleRequest($request);
230
231
        $hook = new ValidationHook(new ValidationProviders());
232
        $this->get('hook_dispatcher')->dispatch(HookContainer::EDIT_VALIDATE, $hook);
233
        $validators = $hook->getValidators();
234
235
        if ($form->isValid() && !$validators->hasErrors()) {
236
            if ($form->get('submit')->isClicked()) {
237
                /** @var AuthenticationMappingEntity $mapping */
238
                $mapping = $form->getData();
239
                if ($form->get('setpass')->getData()) {
240
                    $mapping->setPass($this->get('zikula_zauth_module.api.password')->getHashedPassword($mapping->getPass()));
241
                } else {
242
                    $mapping->setPass($originalMapping->getPass());
243
                }
244
                $this->get('zikula_zauth_module.authentication_mapping_repository')->persistAndFlush($mapping);
245
                $userEntity = $this->get('zikula_users_module.user_repository')->find($mapping->getUid());
246
                $userEntity->merge($mapping->getUserEntityData());
247
                $this->get('zikula_users_module.user_repository')->persistAndFlush($userEntity);
248
                $eventArgs = [
249
                    'action'    => 'setVar',
250
                    'field'     => 'uname',
251
                    'attribute' => null,
252
                ];
253
                $eventData = ['old_value' => $originalMapping->getUname()];
254
                $updateEvent = new GenericEvent($userEntity, $eventArgs, $eventData);
255
                $dispatcher->dispatch(UserEvents::UPDATE_ACCOUNT, $updateEvent);
256
257
                $formDataEvent = new UserFormDataEvent($userEntity, $form);
258
                $dispatcher->dispatch(UserEvents::EDIT_FORM_HANDLE, $formDataEvent);
259
                $this->get('hook_dispatcher')->dispatch(HookContainer::EDIT_PROCESS, new ProcessHook($mapping->getUid()));
260
261
                $this->addFlash('status', $this->__("Done! Saved user's account information."));
262
            }
263
            if ($form->get('cancel')->isClicked()) {
264
                $this->addFlash('status', $this->__('Operation cancelled.'));
265
            }
266
267
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
268
        }
269
270
        return [
271
            'form' => $form->createView(),
272
            'additional_templates' => isset($formEvent) ? $formEvent->getTemplates() : []
273
        ];
274
    }
275
276
    /**
277
     * @Route("/verify/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
278
     * @Theme("admin")
279
     * @Template()
280
     * @param Request $request
281
     * @param AuthenticationMappingEntity $mapping
282
     * @return array
283
     */
284
    public function verifyAction(Request $request, AuthenticationMappingEntity $mapping)
285
    {
286
        if (!$this->hasPermission('ZikulaZAuthModule', '::', ACCESS_MODERATE)) {
287
            throw new AccessDeniedException();
288
        }
289
        $form = $this->createForm(SendVerificationConfirmationType::class, [
290
            'mapping' => $mapping->getId()
291
        ], [
292
            'translator' => $this->get('translator.default')
293
        ]);
294
295
        $form->handleRequest($request);
296
        if ($form->isSubmitted() && $form->isValid()) {
297
            if ($form->get('confirm')->isClicked()) {
298
                $mapping = $this->get('zikula_zauth_module.authentication_mapping_repository')->find($form->get('mapping')->getData());
299
                $verificationSent = $this->get('zikula_zauth_module.helper.registration_verification_helper')->sendVerificationCode($mapping);
300
                if (!$verificationSent) {
301
                    $this->addFlash('error', $this->__f('Sorry! There was a problem sending a verification code to %sub%.', ['%sub%' => $mapping->getUname()]));
302
                } else {
303
                    $this->addFlash('status', $this->__f('Done! Verification code sent to %sub%.', ['%sub%' => $mapping->getUname()]));
304
                }
305
            }
306
            if ($form->get('cancel')->isClicked()) {
307
                $this->addFlash('status', $this->__('Operation cancelled.'));
308
            }
309
310
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
311
        }
312
313
        return [
314
            'form' => $form->createView(),
315
            'mapping' => $mapping
316
        ];
317
    }
318
319
    /**
320
     * @Route("/send-confirmation/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
321
     * @param Request $request
322
     * @param AuthenticationMappingEntity $mapping
323
     * @return RedirectResponse
324
     */
325
    public function sendConfirmationAction(Request $request, AuthenticationMappingEntity $mapping)
326
    {
327 View Code Duplication
        if (!$this->hasPermission('ZikulaZAuthModule', $mapping->getUname() . '::' . $mapping->getUid(), ACCESS_MODERATE)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
            throw new AccessDeniedException();
329
        }
330
        $changePasswordExpireDays = $this->getVar(ZAuthConstant::MODVAR_EXPIRE_DAYS_CHANGE_PASSWORD, ZAuthConstant::DEFAULT_EXPIRE_DAYS_CHANGE_PASSWORD);
331
        $lostPasswordId = $this->get('zikula_zauth_module.helper.lost_password_verification_helper')->createLostPasswordId($mapping);
332
        $mailSent = $this->get('zikula_zauth_module.helper.mail_helper')->sendNotification($mapping->getEmail(), 'lostpassword', [
333
            'uname' => $mapping->getUname(),
334
            'validDays' => $changePasswordExpireDays,
335
            'lostPasswordId' => $lostPasswordId,
336
            'requestedByAdmin' => true
337
        ]);
338
        if ($mailSent) {
339
            $this->addFlash('status', $this->__f('Done! The password recovery verification link for %s has been sent via e-mail.', ['%s' => $mapping->getUname()]));
340
        }
341
342
        return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
343
    }
344
345
    /**
346
     * @Route("/send-username/{mapping}", requirements={"mapping" = "^[1-9]\d*$"})
347
     * @param Request $request
348
     * @param AuthenticationMappingEntity $mapping
349
     * @return RedirectResponse
350
     */
351
    public function sendUserNameAction(Request $request, AuthenticationMappingEntity $mapping)
352
    {
353 View Code Duplication
        if (!$this->hasPermission('ZikulaZAuthModule', $mapping->getUname() . '::' . $mapping->getUid(), ACCESS_MODERATE)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
354
            throw new AccessDeniedException();
355
        }
356
        $mailSent = $this->get('zikula_zauth_module.helper.mail_helper')->sendNotification($mapping->getEmail(), 'lostuname', [
357
            'uname' => $mapping->getUname(),
358
            'requestedByAdmin' => true,
359
        ]);
360
361
        if ($mailSent) {
362
            $this->addFlash('status', $this->__f('Done! The user name for %s has been sent via e-mail.', ['%s' => $mapping->getUname()]));
363
        }
364
365
        return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
366
    }
367
368
    /**
369
     * @Route("/toggle-password-change/{user}", requirements={"user" = "^[1-9]\d*$"})
370
     * @Theme("admin")
371
     * @Template
372
     * @param Request $request
373
     * @param UserEntity $user // note: this is intentionally left as UserEntity instead of mapping because of need to access attributes
374
     * @return array|RedirectResponse
375
     */
376
    public function togglePasswordChangeAction(Request $request, UserEntity $user)
377
    {
378 View Code Duplication
        if (!$this->hasPermission('ZikulaZAuthModule', $user->getUname() . '::' . $user->getUid(), ACCESS_MODERATE)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
            throw new AccessDeniedException();
380
        }
381
        if ($user->getAttributes()->containsKey(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY)) {
1 ignored issue
show
Bug introduced by
The method containsKey() does not seem to exist on object<Zikula\UsersModul...ty\UserAttributeEntity>.

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...
382
            $mustChangePass = $user->getAttributes()->get(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY);
1 ignored issue
show
Bug introduced by
The method get() does not seem to exist on object<Zikula\UsersModul...ty\UserAttributeEntity>.

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...
383
        } else {
384
            $mustChangePass = false;
385
        }
386
        $form = $this->createForm(TogglePasswordConfirmationType::class, [
387
            'uid' => $user->getUid(),
388
        ], [
389
            'mustChangePass' => $mustChangePass,
390
            'translator' => $this->get('translator.default')
391
        ]);
392
        $form->handleRequest($request);
393
        if ($form->isSubmitted() && $form->isValid()) {
394
            if ($form->get('toggle')->isClicked()) {
395
                if ($user->getAttributes()->containsKey(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY) && (bool)$user->getAttributes()->get(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY)) {
2 ignored issues
show
Bug introduced by
The method containsKey() does not seem to exist on object<Zikula\UsersModul...ty\UserAttributeEntity>.

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...
Bug introduced by
The method get() does not seem to exist on object<Zikula\UsersModul...ty\UserAttributeEntity>.

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...
396
                    $user->getAttributes()->remove(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY);
1 ignored issue
show
Bug introduced by
The method remove() does not seem to exist on object<Zikula\UsersModul...ty\UserAttributeEntity>.

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...
397
                    $this->addFlash('success', $this->__f('Done! A password change will no longer be required for %uname.', ['%uname' => $user->getUname()]));
398
                } else {
399
                    $user->setAttribute(ZAuthConstant::REQUIRE_PASSWORD_CHANGE_KEY, true);
400
                    $this->addFlash('success', $this->__f('Done! A password change will be required the next time %uname logs in.', ['%uname' => $user->getUname()]));
401
                }
402
                $this->get('doctrine')->getManager()->flush();
403
            }
404
            if ($form->get('cancel')->isClicked()) {
405
                $this->addFlash('info', $this->__('Operation cancelled.'));
406
            }
407
408
            return $this->redirectToRoute('zikulazauthmodule_useradministration_list');
409
        }
410
411
        return [
412
            'form' => $form->createView(),
413
            'mustChangePass' => $mustChangePass,
414
            'user' => $user
415
        ];
416
    }
417
}
418