Passed
Push — master ( 3b4589...c000e4 )
by Derek Stephen
02:59
created

UserController::lostPasswordAction()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 9.9
c 0
b 0
f 0
cc 4
nc 4
nop 0
crap 4
1
<?php
2
3
namespace App\Controller;
4
5
use App\Form\User\RegistrationForm;
6
use App\Form\User\ResetPasswordForm;
7
use Bone\Mvc\Registry;
8
use Bone\Service\MailService;
9
use Del\Common\ContainerService;
10
use Del\Exception\EmailLinkException;
11
use Del\Exception\UserException;
12
use Del\Service\UserService;
13
use Del\Value\User\State;
14
use Exception;
15
use Zend\Validator\EmailAddress;
16
17
class UserController extends BaseController
18
{
19
    /** @var UserService */
20
    private $userService;
21
22 12
    public function init()
23
    {
24 12
        $c = ContainerService::getInstance()->getContainer();
25 12
        $this->userService = $c['service.user'];
26 12
    }
27
28
    /**
29
     * Fetch user details by ID.
30
     *
31
     * @SWG\Get(
32
     *     path="/user/{id}",
33
     *     tags={"users"},
34
     *     @SWG\Parameter(
35
     *         name="id",
36
     *         in="path",
37
     *         type="integer",
38
     *         description="the type of response",
39
     *         required=false,
40
     *         default=1
41
     *     ),
42
     *     @SWG\Response(response="200", description="Sends user details")
43
     * )
44
     *
45
     */
46 1
    public function indexAction()
47
    {
48 1
        if (!$this->httpMethodCheck('GET')) { return; }
49
50 1
        $id = $this->getParam('id');
51
52
        /** @var UserService $userSvc */
53 1
        $userSvc = ContainerService::getInstance()->getContainer()['service.user'];
54
55 1
        $user = $userSvc->findUserById($id);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type string; however, parameter $id of Del\Service\UserService::findUserById() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

55
        $user = $userSvc->findUserById(/** @scrutinizer ignore-type */ $id);
Loading history...
56 1
        if (!$user) {
57
            $this->sendJsonResponse(['error' => 'User not found'], 404);
58
            return;
59
        }
60
61 1
        $this->sendJsonObjectResponse($user);
62 1
    }
63
64
65
66
    /**
67
     * Activate from the email link token.
68
     *
69
     * @SWG\Get(
70
     *     path="/{locale}/user/activate/{email}/{token}",
71
     *     tags={"users"},
72
     *     @SWG\Response(response="200", description="Registers a new unactivated user"),
73
     *     @SWG\Parameter(
74
     *         name="locale",
75
     *         in="path",
76
     *         type="string",
77
     *         description="the locale to use",
78
     *         required=true,
79
     *         default="en_GB"
80
     *     ),
81
     *     @SWG\Parameter(
82
     *         name="email",
83
     *         in="path",
84
     *         type="string",
85
     *         description="the users email",
86
     *         required=true,
87
     *         default="[email protected]"
88
     *     ),
89
     *     @SWG\Parameter(
90
     *         name="token",
91
     *         in="path",
92
     *         type="string",
93
     *         description="the email link token",
94
     *         required=true,
95
     *         default="r4nd0mT0k3n"
96
     *     )
97
     * )
98
     * @throws Exception
99
     */
100 6
    public function activateAction()
101
    {
102 6
        if (!$this->httpMethodCheck('GET')) { return; }
103
104 6
        $email = $this->getParam('email');
105 6
        $token = $this->getParam('token');
106
107 6
        $userService = $this->userService;
108
109
        try {
110
111 6
            $link = $userService->findEmailLink($email, $token);
112
113 2
            $user = $link->getUser();
114 2
            $user->setState(new State(State::STATE_ACTIVATED));
115 2
            $userService->saveUser($user);
116 2
            $userService->deleteEmailLink($link);
117 2
            $data = ['success' => true];
118 2
            $code = 200;
119
120 4
        } catch (EmailLinkException $e) {
121 4
            switch ($e->getMessage()) {
122 4
                case EmailLinkException::LINK_EXPIRED:
123 3
                case EmailLinkException::LINK_NO_MATCH:
124
                    $data = [
125 1
                        'success' => false,
126 1
                        'error' => $e->getMessage(),
127
                    ];
128 1
                    $code = 403;
129 1
                    break;
130 3
                case EmailLinkException::LINK_NOT_FOUND:
131
                    $data = [
132 3
                        'success' => false,
133 3
                        'error' => $e->getMessage(),
134
                    ];
135 3
                    $code = 404;
136 3
                    break;
137
                default:
138
                    $data = [
139
                        'success' => false,
140
                        'error' => $e->getMessage(),
141
                    ];
142
                    $code = 500;
143
                    break;
144
            }
145
        }
146
147 6
        $this->sendJsonResponse($data, $code);
148 6
    }
149
150
151
    /**
152
     * Refresh the activation email link token.
153
     *
154
     * @SWG\Get(
155
     *     path="/{locale}/user/activate/resend/{email}",
156
     *     tags={"users"},
157
     *     @SWG\Parameter(
158
     *         name="locale",
159
     *         in="path",
160
     *         type="string",
161
     *         description="the locale to use",
162
     *         required=true,
163
     *         default="en_GB"
164
     *     ),
165
     *     @SWG\Parameter(
166
     *         name="email",
167
     *         in="path",
168
     *         type="string",
169
     *         description="the email of the user registering",
170
     *         required=true,
171
     *         default="[email protected]"
172
     *     ),
173
     *     @SWG\Response(response="200", description="Sends email link details")
174
     * )
175
     * @throws Exception
176
     */
177 2
    public function resendActivationAction()
178
    {
179 2
        if (!$this->httpMethodCheck('GET')) { return; }
180
181 2
        $email = $this->getParam('email');
182
183 2
        $user = $this->userService->findUserByEmail($email);
184 2
        if (!$user) {
185
            $this->sendJsonResponse(['error' => UserException::USER_NOT_FOUND], 404);
186
            return;
187
        }
188
189 2
        if ($user->getState()->getValue() == State::STATE_ACTIVATED) {
190 1
            $this->sendJsonResponse(['error' => UserException::USER_ACTIVATED], 400);
191 1
            return;
192
        }
193
194 1
        $link = $this->userService->generateEmailLink($user);
195
196 1
        $mail = $this->getMailService();
197 1
        $env = $this->getServerEnvironment();
198 1
        $email = $user->getEmail();
199 1
        $token = $link->getToken();
200
201 1
        $message = $this->getViewEngine()->render('emails/user_registration/user_registration', [
202 1
            'siteUrl' => $env->getSiteURL(),
203 1
            'activationLink' => '/' . $this->getParam('locale') . '/user/activate/' . $email . '/' . $token,
204
        ]);
205
206 1
        $mail->setFrom('noreply@' . $env->getServerName())
207 1
            ->setTo($user->getEmail())
208 1
            ->setSubject($this->getTranslator()
209 1
                    ->translate('email.user.register.thankswith') . ' ' . Registry::ahoy()->get('site')['name'])
210 1
            ->setMessage($message)
211 1
            ->send();
212
213
214 1
        $this->sendJsonObjectResponse($link);
215 1
    }
216
217
    /**
218
     * Get a lost password email link token.
219
     *
220
     * @SWG\Get(
221
     *     path="/{locale}/user/lost-password/{email}",
222
     *     tags={"users"},
223
     *     @SWG\Parameter(
224
     *         name="locale",
225
     *         in="path",
226
     *         type="string",
227
     *         description="the locale to use",
228
     *         required=true,
229
     *         default="en_GB"
230
     *     ),
231
     *     @SWG\Parameter(
232
     *         name="email",
233
     *         in="path",
234
     *         type="string",
235
     *         description="the email of the user",
236
     *         required=true,
237
     *         default="[email protected]"
238
     *     ),
239
     *     @SWG\Response(response="200", description="Sends email link details")
240
     * )
241
     * @throws Exception
242
     */
243 3
    public function lostPasswordAction()
244
    {
245 3
        if (!$this->httpMethodCheck('GET')) { return; }
246
247 3
        $email = $this->getParam('email');
248
249 3
        $user = $this->userService->findUserByEmail($email);
250 3
        if (!$user) {
251 1
            $this->sendJsonResponse(['error' => UserException::USER_NOT_FOUND], 404);
252 1
            return;
253
        }
254
255 2
        if ($user->getState()->getValue() == State::STATE_UNACTIVATED) {
256 1
            $this->sendJsonResponse(['error' => UserException::USER_UNACTIVATED], 400);
257 1
            return;
258
        }
259
260 1
        $link = $this->userService->generateEmailLink($user);
261 1
        $this->sendJsonObjectResponse($link);
262 1
    }
263
264
    /**
265
     * Register as a new user. Returns an email link token.
266
     *
267
     * @SWG\Post(
268
     *     path="/{locale}/user/register",
269
     *     tags={"users"},
270
     *     @SWG\Response(response="200", description="Registers a new unactivated user"),
271
     *     @SWG\Parameter(
272
     *         name="locale",
273
     *         in="path",
274
     *         type="string",
275
     *         description="the locale to use",
276
     *         required=true,
277
     *         default="en_GB"
278
     *     ),
279
     *     @SWG\Parameter(
280
     *         name="email",
281
     *         in="formData",
282
     *         type="string",
283
     *         description="the users email",
284
     *         required=true,
285
     *         default="[email protected]"
286
     *     ),
287
     *     @SWG\Parameter(
288
     *         name="password",
289
     *         in="formData",
290
     *         type="string",
291
     *         description="a password for the user",
292
     *         required=true,
293
     *         default="password"
294
     *     ),
295
     *     @SWG\Parameter(
296
     *         name="confirm",
297
     *         in="formData",
298
     *         type="string",
299
     *         description="password confirmation",
300
     *         required=true,
301
     *         default="password"
302
     *     )
303
     * )
304
     * @throws Exception
305
     */
306 7
    public function registerAction()
307
    {
308 7
        if (!$this->httpMethodCheck('POST')) { return; }
309
310 7
        $form = new RegistrationForm('register');
311
312 7
        if ($this->getRequest()->getMethod() == 'POST') {
313
314 7
            $formData = $this->getRequest()->getParsedBody();
315 7
            $form->populate($formData);
0 ignored issues
show
Bug introduced by
It seems like $formData can also be of type null and object; however, parameter $data of Del\Form\AbstractForm::populate() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

315
            $form->populate(/** @scrutinizer ignore-type */ $formData);
Loading history...
316
317 7
            if ($form->isValid()) {
318
                try {
319 7
                    $data = $form->getValues();
320 7
                    $user = $this->userService->registerUser($data);
321 7
                    $link = $this->userService->generateEmailLink($user);
322 7
                    $mail = $this->getMailService();
323 7
                    $env = $this->getServerEnvironment();
324 7
                    $email = $user->getEmail();
325 7
                    $token = $link->getToken();
326
327 7
                    $message = $this->getViewEngine()->render('emails/user_registration/user_registration', [
328 7
                        'siteUrl' => $env->getSiteURL(),
329 7
                        'activationLink' => '/' . $this->getParam('locale') . '/user/activate/' . $email . '/' . $token,
330
                    ]);
331
332 7
                    $mail->setFrom('noreply@' . $env->getServerName())
333 7
                        ->setTo($user->getEmail())
334 7
                        ->setSubject($this->getTranslator()
335 7
                            ->translate('email.user.register.thankswith') . ' ' . Registry::ahoy()->get('site')['name'])
336 7
                        ->setMessage($message)
337 7
                        ->send();
338 7
                    $this->sendJsonObjectResponse($link);
339
340
                } catch (UserException $e) {
341
342
                    switch ($e->getMessage()) {
343
                        case UserException::USER_EXISTS:
344
                        case UserException::WRONG_PASSWORD:
345
                            throw new Exception($e->getMessage(), 400);
346
                            break;
347
                    }
348
                    throw $e;
349
                }
350
            } else {
351
                throw new Exception('Invalid request data;', 400);
352
            }
353
354
        }
355 7
    }
356
357
    /**
358
     * Resets the users password. Requires an email link token.
359
     *
360
     * @SWG\Post(
361
     *     path="/{locale}/user/reset-password/{email}/{token}",
362
     *     tags={"users"},
363
     *     @SWG\Response(response="200", description="Resets a users email"),
364
     *     @SWG\Parameter(
365
     *         name="locale",
366
     *         in="path",
367
     *         type="string",
368
     *         description="the locale to use",
369
     *         required=true,
370
     *         default="en_GB"
371
     *     ),
372
     *     @SWG\Parameter(
373
     *         name="email",
374
     *         in="path",
375
     *         type="string",
376
     *         description="the email of the user",
377
     *         required=true,
378
     *         default="[email protected]"
379
     *     ),
380
     *     @SWG\Parameter(
381
     *         name="token",
382
     *         in="path",
383
     *         type="string",
384
     *         description="the email link token",
385
     *         required=true,
386
     *         default="r4nd0mT0k3n"
387
     *     ),
388
     *     @SWG\Parameter(
389
     *         name="password",
390
     *         in="formData",
391
     *         type="string",
392
     *         description="a password for the user",
393
     *         required=true,
394
     *         default="password"
395
     *     ),
396
     *     @SWG\Parameter(
397
     *         name="confirm",
398
     *         in="formData",
399
     *         type="string",
400
     *         description="password confirmation",
401
     *         required=true,
402
     *         default="password"
403
     *     )
404
     * )
405
     * @throws Exception
406
     */
407
    public function resetPassAction()
408
    {
409
        if (!$this->httpMethodCheck('POST')) { return; }
410
411
        $email = $this->getParam('email');
412
        $token = $this->getParam('token');
413
414
        $user = $this->userService->findUserByEmail($email);
415
        if (!$user) {
416
            $this->sendJsonResponse(['error' => UserException::USER_NOT_FOUND], 404);
417
            return;
418
        }
419
420
        try {
421
            $link = $this->userService->findEmailLink($email, $token);
422
        } catch (EmailLinkException $e) {
423
            $code = $e->getMessage() == EmailLinkException::LINK_EXPIRED ? 400 : 404;
424
            $this->sendJsonResponse(['error' => $e->getMessage(), $code]);
425
            return;
426
        }
427
428
        $form = new ResetPasswordForm('reset-pass');
429
430
        $data = $this->getRequest()->getParsedBody();
431
432
        $form->populate($data);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type null and object; however, parameter $data of Del\Form\AbstractForm::populate() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

432
        $form->populate(/** @scrutinizer ignore-type */ $data);
Loading history...
433
434
        if ($form->isValid()) {
435
436
            if ($data['password'] == $data['confirm']) {
437
                $this->userService->changePassword($user, $data['password']);
438
                $this->userService->deleteEmailLink($link);
439
                $this->sendJsonResponse(['success' => 'Password successfully changed']);
440
                return;
441
            } else {
442
                $this->sendJsonResponse(['error' => 'Passwords did not match, please try again.'], 400);
443
            }
444
        } else {
445
            $errors = [];
446
            $fields = $form->getFields();
447
            foreach ($fields as $field) {
448
                $validators = $field->getValidators();
449
                foreach ($validators as $validator) {
450
                    $errors[$field->getName()] = $validator->getMessages();
451
                }
452
            }
453
            $this->sendJsonResponse(['error' => $errors], 400);
454
        }
455
    }
456
}
457