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