Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 122
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzNewsListParams
n/a
0 / 0
n/a
0 / 0
0
n/a
0 / 0
OlzNewsList
0.00% covered (danger)
0.00%
0 / 122
0.00% covered (danger)
0.00%
0 / 1
756
0.00% covered (danger)
0.00%
0 / 1
 getHtml
0.00% covered (danger)
0.00%
0 / 122
0.00% covered (danger)
0.00%
0 / 1
756
1<?php
2
3namespace Olz\News\Components\OlzNewsList;
4
5use Olz\Apps\OlzApps;
6use Olz\Components\Common\OlzComponent;
7use Olz\Components\Page\OlzFooter\OlzFooter;
8use Olz\Components\Page\OlzHeader\OlzHeader;
9use Olz\Entity\News\NewsEntry;
10use Olz\Entity\Roles\Role;
11use Olz\Entity\Users\User;
12use Olz\News\Components\OlzNewsFilter\OlzNewsFilter;
13use Olz\News\Components\OlzNewsListItem\OlzNewsListItem;
14use Olz\News\Utils\NewsFilterUtils;
15use Olz\Utils\HttpParams;
16
17/** @extends HttpParams<array{
18 *   filter?: ?string,
19 *   seite?: ?numeric-string,
20 *   von?: ?string,
21 * }> */
22class OlzNewsListParams extends HttpParams {
23}
24
25/** @extends OlzComponent<array<string, mixed>> */
26class OlzNewsList extends OlzComponent {
27    public static string $title = "News";
28    public static string $description = "Aktuelle Beiträge, Berichte von Anlässen und weitere Neuigkeiten von der OL Zimmerberg.";
29
30    public static int $page_size = 25;
31
32    public function getHtml(mixed $args): string {
33        $params = $this->httpUtils()->validateGetParams(OlzNewsListParams::class);
34        $db = $this->dbUtils()->getDb();
35        $entityManager = $this->dbUtils()->getEntityManager();
36        $code_href = $this->envUtils()->getCodeHref();
37
38        $news_utils = NewsFilterUtils::fromEnv();
39        $current_filter = json_decode($params['filter'] ?? '{}', true);
40        $page_number = $params['seite'] ?? 1;
41        $page_index = $page_number - 1;
42
43        if (!$news_utils->isValidFilter($current_filter)) {
44            $valid_filter = $news_utils->getValidFilter($current_filter);
45            $enc_json_filter = urlencode(json_encode($valid_filter) ?: '{}');
46            $this->httpUtils()->redirect("{$code_href}news?filter={$enc_json_filter}", 308);
47        }
48
49        $is_not_archived = $news_utils->isFilterNotArchived($current_filter);
50        $allow_robots = $is_not_archived;
51
52        $enc_json_filter = urlencode(json_encode($current_filter) ?: '{}');
53        $page_param = $page_number === 1 ? '' : "&seite={$page_number}";
54        $news_list_title = $news_utils->getTitleFromFilter($current_filter);
55        $out = OlzHeader::render([
56            'title' => $news_list_title,
57            'description' => self::$description, // TODO: Filter-specific description?
58            'norobots' => !$allow_robots,
59            'canonical_url' => "{$code_href}news?filter={$enc_json_filter}{$page_param}",
60        ]);
61
62        $out .= "<div class='content-right'>";
63        $out .= "<h2 class='optional'>Filter</h2>";
64        $out .= OlzNewsFilter::render([]);
65        $out .= "</div>";
66        $out .= "<div class='content-middle olz-news-list-middle'>";
67
68        $is_logged_in = $this->authUtils()->hasPermission('any');
69        $has_blog = $this->authUtils()->hasPermission('kaderblog');
70        $has_roles = !empty($this->authUtils()->getAuthenticatedRoles());
71        $json_mode = htmlentities(json_encode($has_roles ? ($has_blog ? 'account_with_all' : 'account_with_aktuell') : ($has_blog ? 'account_with_blog' : 'account')) ?: '');
72        $class = $is_logged_in ? ' create-news-container' : ' dropdown-toggle';
73        $properties = $is_logged_in
74            ? <<<ZZZZZZZZZZ
75                onclick='return olz.initOlzEditNewsModal({$json_mode})'
76                ZZZZZZZZZZ
77            : <<<'ZZZZZZZZZZ'
78                type='button'
79                data-bs-toggle='dropdown'
80                aria-expanded='false'
81                ZZZZZZZZZZ;
82        if (!$is_logged_in) {
83            $out .= "<div class='dropdown create-news-container'>";
84        }
85        $out .= <<<ZZZZZZZZZZ
86            <button
87                id='create-news-button'
88                class='btn btn-secondary{$class}'
89                {$properties}
90            >
91                <img src='{$code_href}assets/icns/new_white_16.svg' class='noborder' />
92                Neuer Eintrag
93            </button>
94            ZZZZZZZZZZ;
95        if (!$is_logged_in) {
96            $out .= <<<'ZZZZZZZZZZ'
97                <div
98                    class='dropdown-menu dropdown-menu-end'
99                    aria-labelledby='create-news-button'
100                >
101                    <li><button
102                        class='dropdown-item'
103                        onclick='return olz.initOlzLoginModal({})'
104                    >
105                        Login
106                    </button></li>
107                    <li><hr class="dropdown-divider"></li>
108                    <li><div class='dropdown-item disabled should-login'>
109                        <b>Achtung</b>: Bild-Upload und nachträgliches Bearbeiten des Eintrags nur mit Login möglich!
110                    </div></li>
111                    <li><button
112                        id='create-anonymous-button'
113                        class='dropdown-item'
114                        onclick='return olz.initOlzEditNewsModal(&quot;anonymous&quot;)'
115                    >
116                        Forumseintrag ohne Login
117                    </button></li>
118                </div>
119                ZZZZZZZZZZ;
120            $out .= "</div>";
121        }
122
123        $newsletter_link = '';
124        $newsletter_app = OlzApps::getApp('Newsletter');
125        if ($newsletter_app) {
126            $newsletter_link = <<<ZZZZZZZZZZ
127                <a href='{$code_href}{$newsletter_app->getHref()}' class='newsletter-link'>
128                    <img
129                        src='{$newsletter_app->getIcon()}'
130                        alt='newsletter'
131                        class='newsletter-link-icon'
132                        title='Newsletter abonnieren!'
133                    />
134                </a>
135                ZZZZZZZZZZ;
136        } else {
137            $this->log()->error('Newsletter App does not exist!');
138        }
139        $out .= "<h1>{$news_list_title} {$newsletter_link}</h1>";
140
141        $filter_where = $news_utils->getSqlFromFilter($current_filter);
142        $first_index = $page_index * $this::$page_size;
143        $sql = <<<ZZZZZZZZZZ
144            SELECT
145                COUNT(n.id) as count
146            FROM news n
147            WHERE
148                {$filter_where}
149                AND n.on_off='1'
150            ORDER BY published_date DESC, published_time DESC
151            ZZZZZZZZZZ;
152        // @phpstan-ignore-next-line
153        $count = intval($db->query($sql)->fetch_assoc()['count']);
154        $num_pages = intval($count / $this::$page_size) + 1;
155
156        $sql = <<<ZZZZZZZZZZ
157            SELECT
158                id,
159                owner_user_id,
160                owner_role_id,
161                published_date,
162                published_time,
163                format,
164                author_user_id,
165                author_role_id,
166                author_name,
167                author_email,
168                title,
169                teaser,
170                content,
171                image_ids
172            FROM news n
173            WHERE
174                {$filter_where}
175                AND n.on_off='1'
176            ORDER BY published_date DESC, published_time DESC
177            LIMIT {$first_index}{$this::$page_size}
178            ZZZZZZZZZZ;
179        $res = $db->query($sql);
180
181        $user_repo = $entityManager->getRepository(User::class);
182        $role_repo = $entityManager->getRepository(Role::class);
183
184        $has_archive_access = $this->authUtils()->hasPermission('verified_email');
185        if ($is_not_archived || $has_archive_access) {
186            $page_content = '';
187            // @phpstan-ignore-next-line
188            for ($index = 0; $index < $res->num_rows; $index++) {
189                // @phpstan-ignore-next-line
190                $row = $res->fetch_assoc();
191
192                // TODO: Directly use doctrine to run the DB query.
193                // @phpstan-ignore-next-line
194                $owner_user = $row['owner_user_id'] ?
195                    $user_repo->findOneBy(['id' => $row['owner_user_id']]) : null;
196                $owner_role = $row['owner_role_id'] ?
197                    $role_repo->findOneBy(['id' => $row['owner_role_id']]) : null;
198                $author_user = $row['author_user_id'] ?
199                    $user_repo->findOneBy(['id' => $row['author_user_id']]) : null;
200                $author_role = $row['author_role_id'] ?
201                    $role_repo->findOneBy(['id' => $row['author_role_id']]) : null;
202
203                $news_entry = new NewsEntry();
204                $news_entry->setOwnerUser($owner_user);
205                $news_entry->setOwnerRole($owner_role);
206                // @phpstan-ignore-next-line
207                $news_entry->setPublishedDate(new \DateTime($row['published_date']));
208                // @phpstan-ignore-next-line
209                $news_entry->setFormat($row['format']);
210                $news_entry->setAuthorUser($author_user);
211                $news_entry->setAuthorRole($author_role);
212                // @phpstan-ignore-next-line
213                $news_entry->setAuthorName($row['author_name']);
214                // @phpstan-ignore-next-line
215                $news_entry->setAuthorEmail($row['author_email']);
216                // @phpstan-ignore-next-line
217                $news_entry->setTitle($row['title']);
218                // @phpstan-ignore-next-line
219                $news_entry->setTeaser($row['teaser']);
220                // @phpstan-ignore-next-line
221                $news_entry->setContent($row['content']);
222                $news_entry->setId(intval($row['id']));
223                // @phpstan-ignore-next-line
224                $news_entry->setImageIds($row['image_ids'] ? json_decode($row['image_ids'], true) : null);
225
226                $page_content .= OlzNewsListItem::render([
227                    'json_mode' => $json_mode,
228                    'news_entry' => $news_entry,
229                ]);
230            }
231            if ($page_content === '') {
232                $page_content = "<div class='no-entries'>Keine Einträge. Bitte Filter anpassen.</div>";
233            }
234            $out .= $page_content;
235            if ($num_pages > 1) {
236                $pages = '';
237                for ($page_number = 1; $page_number <= $num_pages; $page_number++) {
238                    $is_current_page = $page_number === $page_index + 1;
239                    $page_link_class = $is_current_page ? ' active' : '';
240                    $page_param = $page_number === 1 ? '' : "&seite={$page_number}";
241                    $pages .= <<<ZZZZZZZZZZ
242                        <li class='page-item'>
243                            <a
244                                class='page-link{$page_link_class}'
245                                href='?filter={$enc_json_filter}{$page_param}'
246                            >
247                                {$page_number}
248                            </a>
249                        </li>
250                        ZZZZZZZZZZ;
251                }
252                $out .= "<nav><ul class='no-style pagination justify-content-center'>{$pages}</ul></nav>";
253            }
254        } else {
255            $out .= <<<'ZZZZZZZZZZ'
256                <div class='olz-no-access'>
257                    <div>Das Archiv ist nur für Vereins-Mitglieder verfügbar.</div>
258                    <div class='auth-buttons'>
259                        <a class='btn btn-primary' href='#login-dialog' role='button'>Login</a>
260                    </div>
261                </div>
262                ZZZZZZZZZZ;
263        }
264
265        $out .= "</div>";
266
267        $out .= OlzFooter::render();
268
269        return $out;
270    }
271}