Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 149
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzUserDetail
0.00% covered (danger)
0.00%
0 / 149
0.00% covered (danger)
0.00%
0 / 4
1122
0.00% covered (danger)
0.00%
0 / 1
 hasAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 searchSqlWhenHasAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHtmlWhenHasAccess
0.00% covered (danger)
0.00%
0 / 139
0.00% covered (danger)
0.00%
0 / 1
702
 prettyPrintPermissionMap
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace Olz\Users\Components\OlzUserDetail;
4
5use Doctrine\Common\Collections\Criteria;
6use Olz\Components\Common\OlzRootComponent;
7use Olz\Components\Page\OlzFooter\OlzFooter;
8use Olz\Components\Page\OlzHeader\OlzHeader;
9use Olz\Entity\ForwardedEmail;
10use Olz\Entity\Roles\Role;
11use Olz\Entity\Users\User;
12use Olz\Repository\Roles\PredefinedRole;
13use Olz\Roles\Components\OlzRoleInfoModal\OlzRoleInfoModal;
14
15/** @extends OlzRootComponent<array<string, mixed>> */
16class OlzUserDetail extends OlzRootComponent {
17    public function hasAccess(): bool {
18        return true;
19    }
20
21    public function searchSqlWhenHasAccess(array $terms): string|array|null {
22        return null;
23    }
24
25    public function getHtmlWhenHasAccess(mixed $args): string {
26        $code_href = $this->envUtils()->getCodeHref();
27        $user_repo = $this->entityManager()->getRepository(User::class);
28        $user = $user_repo->findOneBy(['id' => $args['id']]);
29        if (!$user) {
30            $this->httpUtils()->dieWithHttpError(404);
31            throw new \Exception('should already have failed');
32        }
33
34        $user_id = $user->getId() ?? -1;
35        $parent_id = $user->getParentUserId() ?? -1;
36        $auth_user_id = $this->authUtils()->getCurrentAuthUser()?->getId();
37        $is_root = $this->authUtils()->hasPermission('all');
38        if (!$is_root && $user_id !== $auth_user_id && $parent_id !== $auth_user_id) {
39            $this->httpUtils()->dieWithHttpError(403);
40            throw new \Exception('should already have failed');
41        }
42
43        $role_repo = $this->entityManager()->getRepository(Role::class);
44        $sysadmin_role = $role_repo->getPredefinedRole(PredefinedRole::Sysadmin);
45
46        $out = OlzHeader::render([
47            'back_link' => "{$code_href}verein",
48            'title' => $user->getFullName(),
49            'description' => "{$user->getFullName()} - Profil.",
50            'norobots' => true,
51        ]);
52
53        $out .= "<div class='content-full olz-user-detail'>";
54
55        $image_paths = $this->authUtils()->getUserAvatar($user);
56        $image_src_html = $this->htmlUtils()->getImageSrcHtml($image_paths);
57        $img_html = "<img {$image_src_html} alt='' class='image'>";
58
59        $auth_user_id = $this->session()->get('auth_user_id');
60        $is_parent = $auth_user_id && intval($user->getParentUserId()) === intval($auth_user_id);
61        $is_self = $auth_user_id && intval($user->getId()) === intval($auth_user_id);
62        $has_permissions = $this->authUtils()->hasPermission('users');
63        $can_edit = $is_parent || $is_self || $has_permissions;
64        $edit_admin = '';
65        $edit_password = '';
66        if ($can_edit) {
67            $json_id = json_encode($user->getId());
68            $edit_admin = <<<ZZZZZZZZZZ
69                <div>
70                    <button
71                        id='edit-user-button'
72                        class='btn btn-primary'
73                        onclick='return olz.editUser({$json_id})'
74                    >
75                        <img src='{$code_href}assets/icns/edit_white_16.svg' class='noborder' />
76                        Bearbeiten
77                    </button>
78                </div>
79                ZZZZZZZZZZ;
80            $edit_password = <<<'ZZZZZZZZZZ'
81                     <button
82                        class='btn btn-secondary'
83                        onclick='return olz.initOlzChangePasswordModal()'
84                        id='change-password-button'
85                    >
86                        Passwort ändern
87                    </button>
88                ZZZZZZZZZZ;
89        }
90
91        $street = $user->getStreet() ?? '(Keine Adresse)';
92        $postal_code = $user->getPostalCode() ?? '(Keine PLZ)';
93        $city = $user->getCity() ?? '(Kein Ort)';
94        $region = $user->getRegion() ?? 'Keine Region';
95        $country_code = $user->getCountryCode() ?? 'Kein Land';
96        $birthdate = $user->getBirthdate()?->format('d.m.Y') ?? '(Unbekannt)';
97        $phone = $user->getPhone() ?? '(Unbekannt)';
98
99        if (
100            !$user->getParentUserId()
101            && !$user->isEmailVerified()
102            && !$this->authUtils()->hasPermission('verified_email', $user)
103        ) {
104            if ($user->getEmailVerificationToken()) {
105                $out .= <<<'ZZZZZZZZZZ'
106                    <div class='alert alert-danger' role='alert'>
107                        Deine E-Mail-Adresse ist noch nicht bestätigt. Bitte prüfe deine Inbox (und dein Spam-Postfach) auf unsere Bestätigungs-E-Mail (Betreff: "[OLZ] E-Mail bestätigen").
108                        <a
109                            href='#'
110                            onclick='olz.initOlzVerifyUserEmailModal()'
111                            id='verify-user-email-link'
112                        >
113                            Erneut senden
114                        </a>
115                    </div>
116                    ZZZZZZZZZZ;
117            } else {
118                $out .= <<<'ZZZZZZZZZZ'
119                    <div class='alert alert-danger' role='alert'>
120                        Deine E-Mail-Adresse ist noch nicht bestätigt.
121                        <a
122                            href='#'
123                            onclick='olz.initOlzVerifyUserEmailModal()'
124                            id='verify-user-email-link'
125                        >
126                            Jetzt bestätigen
127                        </a>
128                    </div>
129                    ZZZZZZZZZZ;
130            }
131        }
132
133        $out .= <<<ZZZZZZZZZZ
134            <div class='edit-user-container'>{$edit_admin}</div>
135            <div class='image-container'>{$img_html}</div>
136            <h1 class='name-container'>{$user->getFullName()}</h1>
137            <div class='info-container username'>Benutzername: {$user->getUsername()}</div>
138            ZZZZZZZZZZ;
139        if ($can_edit) {
140            $out .= <<<ZZZZZZZZZZ
141                <div class='info-container address'>
142                    <div>{$street}</div>
143                    <div>{$postal_code} {$city} ({$region}{$country_code})</div>
144                </div>
145                <div class='info-container birthdate'>Geburtsdatum: {$birthdate}</div>
146                <div class='info-container phone'>Telephon: {$phone}</div>
147                ZZZZZZZZZZ;
148        }
149
150        $has_official_email = $this->authUtils()->hasPermission('user_email', $user);
151        $email_html = '';
152        if ($has_official_email) {
153            $host = $this->envUtils()->getEmailForwardingHost();
154            $olz_email = "{$user->getUsername()}@{$host}";
155            $email = $user->getEmail() ? $olz_email : null;
156            $email_html = "<div class='info-container'>Du hast eine <b>offizielle</b> OLZ E-Mail-Adresse: <b>{$olz_email}</b></div>";
157            if ($user->getOldUsername()) {
158                $old_olz_email = "{$user->getOldUsername()}@{$host}";
159                $email_html .= "<div class='info-container'>Du hast ausserdem eine <b>alte</b> offizielle OLZ E-Mail-Adresse: <b>{$old_olz_email}</b> <i>(nicht mehr benutzen!)</i></div>";
160            }
161            $email_html .= "<div class='info-container'>Die E-Mails <b>werden weitergeleitet</b> an: <b>{$user->getEmail()}</b></div>";
162            $email_html .= "<h3>Kürzlich weitergeleitete E-Mails</h3>";
163            $email_html .= "<table class='forwarded-emails'><tr><th>Datum</th><th>Absender</th><th>Betreff</th></tr>";
164            $iso_now = $this->dateUtils()->getIsoNow();
165            $minus_one_month = \DateInterval::createFromDateString("-30 days");
166            $one_month_ago = (new \DateTime($iso_now))->add($minus_one_month);
167            $forwarded_email_repo = $this->entityManager()->getRepository(ForwardedEmail::class);
168            $forwarded_emails = $forwarded_email_repo->matching(Criteria::create()
169                ->where(Criteria::expr()->andX(
170                    Criteria::expr()->eq('recipient_user', $user),
171                    Criteria::expr()->gt('forwarded_at', $one_month_ago),
172                ))
173                ->orderBy(['forwarded_at' => 'DESC'])
174                ->setFirstResult(0)
175                ->setMaxResults(1000));
176            foreach ($forwarded_emails as $forwarded_email) {
177                $email_html .= <<<ZZZZZZZZZZ
178                    <tr>
179                        <td class='nowrap'>{$forwarded_email->getForwardedAt()?->format('d.m.Y H:i')}</td>
180                        <td class='nowrap'>{$forwarded_email->getSenderAddress()}</td>
181                        <td>{$forwarded_email->getSubject()}</td>
182                    </tr>
183                    ZZZZZZZZZZ;
184            }
185            $email_html .= "</table>";
186        } else {
187            $email = $user->getEmail();
188            $email_html = "<div class='info-container'>Du hast <b>keine offizielle</b> OLZ E-Mail-Adresse.</div>";
189            $sysadmin_modal = $sysadmin_role ? OlzRoleInfoModal::render(['role' => $sysadmin_role]) : '"Website"';
190            $email_html .= "<div class='info-container'>Bei Fragen: kontaktiere das Ressort {$sysadmin_modal}.</div>";
191        }
192        if ($email) {
193            $email_out = $this->htmlUtils()->replaceEmailAdresses($email);
194            $out .= "<div class='info-container email'>{$email_out}</div>";
195        }
196        $out .= $edit_password;
197
198        $out .= <<<ZZZZZZZZZZ
199            <h2>Berechtigungen</h2>
200            <div class='info-container'>Persönliche Berechtigungen: <b>{$this->prettyPrintPermissionMap($user->getPermissionMap())}</b></div>
201            ZZZZZZZZZZ;
202        foreach ($user->getRoles() as $role) {
203            $role_modal = OlzRoleInfoModal::render(['role' => $role]);
204            $out .= "<div class='info-container'>Berechtigungen im Rahmen von {$role_modal}: <b>{$this->prettyPrintPermissionMap($role->getPermissionMap())}</b></div>";
205        }
206
207        $out .= <<<ZZZZZZZZZZ
208            <h2>E-Mail Weiterleitung</h2>
209            {$email_html}
210            ZZZZZZZZZZ;
211
212        if ($can_edit) {
213            $out .= "<h2>Familie</h2>";
214            $child_users = $user_repo->findBy(['parent_user' => $user->getId()]);
215            $out .= "<ul id='child-users-list' class='info-container'>";
216            foreach ($child_users as $child_user) {
217                $out .= "<li>Familienmitglied <a href='{$code_href}benutzer/{$child_user->getId()}'>{$child_user->getFullName()}</a></li>";
218            }
219            $out .= "</ul>";
220            if ($user->getParentUserId()) {
221                $parent_user = $user_repo->findOneBy(['id' => $user->getParentUserId()]);
222                $out .= "<div class='info-container'>Familienmitglied von <a href='{$code_href}benutzer/{$parent_user?->getId()}'>{$parent_user?->getFullName()}</a></div>";
223                if ($child_users) {
224                    $this->log()->warning("User {$user->getId()} has parent and children.");
225                }
226            } else {
227                $json_id = json_encode($user->getId());
228                $out .= <<<ZZZZZZZZZZ
229                    <div>
230                        <button
231                            id='add-child-user-button'
232                            class='btn btn-secondary'
233                            onclick='return olz.addChildUser({$json_id})'
234                        >
235                            <img src='{$code_href}assets/icns/new_white_16.svg' class='noborder' />
236                            Familienmitglied hinzufügen
237                        </button>
238                    </div>
239                    ZZZZZZZZZZ;
240            }
241        }
242        $out .= "</div>";
243
244        $out .= OlzFooter::render();
245
246        return $out;
247    }
248
249    /** @param array<string, bool> $permissions_map */
250    protected function prettyPrintPermissionMap(array $permissions_map): string {
251        $out = '';
252        foreach ($permissions_map as $permission => $is_given) {
253            if (!$is_given) {
254                continue;
255            }
256            if ($out !== '') {
257                $out .= ', ';
258            }
259            $out .= $permission;
260        }
261        return $out !== '' ? $out : '(keine Berechtigungen)';
262    }
263}