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