Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.42% covered (success)
92.42%
61 / 66
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
UpdateUserEndpoint
92.42% covered (success)
92.42%
61 / 66
0.00% covered (danger)
0.00%
0 / 1
20.17
0.00% covered (danger)
0.00%
0 / 1
 handle
92.42% covered (success)
92.42%
61 / 66
0.00% covered (danger)
0.00%
0 / 1
20.17
1<?php
2
3namespace Olz\Users\Endpoints;
4
5use Olz\Api\OlzUpdateEntityTypedEndpoint;
6use Olz\Entity\Roles\Role;
7use Olz\Entity\Users\User;
8use PhpTypeScriptApi\Fields\ValidationError;
9use PhpTypeScriptApi\HttpError;
10
11/**
12 * @phpstan-import-type OlzUserId from UserEndpointTrait
13 * @phpstan-import-type OlzUserData from UserEndpointTrait
14 *
15 * @extends OlzUpdateEntityTypedEndpoint<OlzUserId, OlzUserData, never, array{
16 *   status: 'OK'|'OK_NO_EMAIL_VERIFICATION'|'DENIED'|'ERROR',
17 * }>
18 */
19class UpdateUserEndpoint extends OlzUpdateEntityTypedEndpoint {
20    use UserEndpointTrait;
21
22    protected function handle(mixed $input): mixed {
23        $user_repo = $this->entityManager()->getRepository(User::class);
24        $role_repo = $this->entityManager()->getRepository(Role::class);
25        $entity = $this->getEntityById($input['id']);
26
27        $current_user = $this->authUtils()->getCurrentUser();
28        $is_me = (
29            $current_user
30            && $entity->getUsername() === $current_user->getUsername()
31            && $entity->getId() === $current_user->getId()
32        );
33        $can_update = $this->entityUtils()->canUpdateOlzEntity($entity, null, 'users');
34        if (!$is_me && !$can_update) {
35            throw new HttpError(403, "Kein Zugriff!");
36        }
37
38        // Username validation
39        $old_username = $entity->getUsername();
40        $new_username = $input['data']['username'];
41        $is_username_updated = $new_username !== $old_username;
42        if (!$this->authUtils()->isUsernameAllowed($new_username)) {
43            throw new ValidationError(['username' => ["Der Benutzername darf nur Buchstaben, Zahlen, und die Zeichen -_. enthalten."]]);
44        }
45        if ($is_username_updated) {
46            $same_username_user = $user_repo->findOneBy(['username' => $new_username]);
47            $same_old_username_user = $user_repo->findOneBy(['old_username' => $new_username]);
48            $same_username_role = $role_repo->findOneBy(['username' => $new_username]);
49            $same_old_username_role = $role_repo->findOneBy(['old_username' => $new_username]);
50            $is_existing_username = (bool) (
51                $same_username_user || $same_old_username_user
52                || $same_username_role || $same_old_username_role
53            );
54            if ($is_existing_username) {
55                throw new ValidationError(['username' => ["Dieser Benutzername ist bereits vergeben."]]);
56            }
57        }
58
59        // Email validation
60        $new_email = $input['data']['email'] ?? null;
61        $is_email_updated = $new_email !== $entity->getEmail();
62        if (preg_match('/@olzimmerberg\.ch$/i', $new_email ?? '')) {
63            throw new ValidationError(['email' => ["Bitte keine @olzimmerberg.ch E-Mail verwenden."]]);
64        }
65        if ($is_email_updated) {
66            $same_email_user = $user_repo->findOneBy(['email' => $new_email]);
67            if ($same_email_user) {
68                throw new ValidationError(['email' => ["Es existiert bereits eine Person mit dieser E-Mail Adresse."]]);
69            }
70        }
71
72        // TODO Do this more elegantly?
73        $old_data = $this->getEntityData($entity);
74        $this->log()->notice('OLD:', [$old_data]);
75
76        $this->entityUtils()->updateOlzEntity($entity, $input['meta']);
77        if ($is_username_updated) {
78            $entity->setOldUsername($entity->getUsername());
79        }
80        $this->updateEntityWithData($entity, $input['data']);
81        if ($is_email_updated) {
82            $entity->setEmailIsVerified(false);
83            $entity->setEmailVerificationToken(null);
84            $entity->removePermission('verified_email');
85        }
86
87        // TODO Do this more elegantly?
88        $new_data = $this->getEntityData($entity);
89        $this->log()->notice('NEW:', [$new_data]);
90
91        $this->entityManager()->persist($entity);
92        $this->entityManager()->flush();
93        $this->persistUploads($entity, $input['data']);
94
95        if ($is_username_updated && $this->session()->get('user') === $old_username) {
96            $this->session()->set('user', $new_username);
97        }
98
99        if ($is_email_updated) {
100            $this->emailUtils()->setLogger($this->log());
101            try {
102                $this->emailUtils()->sendEmailVerificationEmail($entity);
103            } catch (\Throwable $th) {
104                return [
105                    'custom' => ['status' => 'OK_NO_EMAIL_VERIFICATION'],
106                    'id' => $entity->getId() ?? 0,
107                ];
108            }
109            $this->entityManager()->flush();
110        }
111
112        return [
113            'custom' => ['status' => 'OK'],
114            'id' => $entity->getId() ?? 0,
115        ];
116    }
117}