Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzICal
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 2
90
0.00% covered (danger)
0.00%
0 / 1
 getHtml
0.00% covered (danger)
0.00%
0 / 100
0.00% covered (danger)
0.00%
0 / 1
56
 escapeText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3// =============================================================================
4// iCal-Datei generieren mit Terminen des aktuellen Jahres.
5// Dieses Script wird immer beim Sichern und beim LΓΆschen eines Termins
6// aufgerufen.
7// =============================================================================
8
9namespace Olz\Termine\Components\OlzICal;
10
11use Olz\Components\Common\OlzComponent;
12use Olz\Entity\Termine\Termin;
13use Olz\Entity\Termine\TerminReaction;
14
15/** @extends OlzComponent<array<string, mixed>> */
16class OlzICal extends OlzComponent {
17    public function getHtml(mixed $args): string {
18        $jahr = $this->dateUtils()->getCurrentDateInFormat('Y');
19        $base_href = $this->envUtils()->getBaseHref();
20        $code_href = $this->envUtils()->getCodeHref();
21        $now_fmt = date('Ymd\THis\Z');
22        $host = $this->envUtils()->getEmailForwardingHost();
23        $user = $this->authUtils()->getTokenUser();
24
25        // Termine abfragen
26        $termin_class = Termin::class;
27        $termin_reaction_class = TerminReaction::class;
28        // TODO: Add `HAVING MIN(tyes.emoji) IS NOT NULL OR MIN(tno.emoji) IS NULL`
29        $dql = <<<ZZZZZZZZZZ
30            SELECT t, MIN(tyes.emoji), MIN(tno.emoji)
31            FROM {$termin_class} t
32                LEFT JOIN {$termin_reaction_class} tyes ON (
33                    tyes.user = :user_id
34                    AND tyes.termin = t.id
35                    AND tyes.emoji IN ('πŸ‘', 'βœ…', 'βœ”οΈ')
36                )
37                LEFT JOIN {$termin_reaction_class} tno ON (
38                    tno.user = :user_id
39                    AND tno.termin = t.id
40                    AND tno.emoji IN ('πŸ‘Ž', '❎', '❌', '😒', '🚫')
41                )
42            WHERE
43                t.start_date >= :start_date
44                AND t.on_off = '1'
45            GROUP BY t.id
46            ORDER BY t.start_date ASC, t.start_time ASC
47            ZZZZZZZZZZ;
48        $termine = $this->entityManager()
49            ->createQuery($dql)
50            ->setParameter('user_id', $user?->getId())
51            ->setParameter('start_date', "{$jahr}-01-01")
52            ->getResult()
53        ;
54
55        // ical-Kalender
56        $ical = "BEGIN:VCALENDAR".
57        "\r\nPRODID:OL Zimmerberg Termine".
58        "\r\nVERSION:2.0".
59        "\r\nMETHOD:PUBLISH".
60        "\r\nCALSCALE:GREGORIAN".
61        "\r\nX-WR-CALNAME:OL Zimmerberg Termine".
62        "\r\nX-WR-TIMEZONE:Europe/Zurich";
63
64        // Termine
65        foreach ($termine as $termin_row) {
66            [$termin, $yes_emoji, $no_emoji] = $termin_row;
67
68            $id = $termin->getId();
69            $start_date = $termin->getStartDate();
70            $end_date = $termin->getEndDate() ?? $start_date;
71            $duration_days = ($end_date->getTimestamp() - $start_date->getTimestamp()) / 86400;
72            $should_split = $duration_days > 8;
73            $solv_id = $termin->getSolvId();
74
75            $olz_url = "{$base_href}{$code_href}termine/{$id}";
76            $solv_url = "https://www.o-l.ch/cgi-bin/fixtures?&mode=show&unique_id={$solv_id}";
77
78            $links = "OLZ-Termin: {$olz_url}";
79            $attach = "\r\nATTACH;FMTTYPE=text/html:{$olz_url}";
80            $links .= $solv_id ? "\nSOLV-Termin: {$solv_url}" : "";
81            $attach .= $solv_id ? "\r\nATTACH;FMTTYPE=text/html:{$solv_url}" : "";
82
83            $plus_one_day = \DateInterval::createFromDateString("+1 days");
84            $end_date_end = (new \DateTime($end_date->format('Y-m-d')))->add($plus_one_day);
85            $start_date_fmt = $this->dateUtils()->olzDate('jjjjmmtt', $start_date);
86            $end_date_fmt = $this->dateUtils()->olzDate('jjjjmmtt', $end_date);
87            $end_date_end_fmt = $this->dateUtils()->olzDate('jjjjmmtt', $end_date_end);
88            $modified_fmt = $termin->getLastModifiedAt()->format('Ymd\THis\Z');
89            $created_fmt = $termin->getCreatedAt()->format('Ymd\THis\Z');
90            $yes_emoji_prefix = $yes_emoji ? "{$yes_emoji} " : '';
91            $no_emoji_prefix = $no_emoji ? "{$no_emoji} " : '';
92            $title_fmt = "{$yes_emoji_prefix}{$no_emoji_prefix}{$termin->getTitle()}";
93            $description_fmt = $this->escapeText("{$termin->getText()}\n{$links}");
94            $label_idents = implode(', ', array_map(
95                fn ($label) => "{$label->getIdent()}",
96                [...$termin->getLabels()],
97            ));
98            if ($should_split) {
99                $ical .=
100                "\r\nBEGIN:VEVENT".
101                "\r\nDTSTART;VALUE=DATE:{$start_date_fmt}".
102                "\r\nDTEND;VALUE=DATE:{$start_date_fmt}".
103                "\r\nDTSTAMP:{$now_fmt}".
104                "\r\nLAST-MODIFIED:{$modified_fmt}".
105                "\r\nCREATED:{$created_fmt}".
106                "\r\nSUMMARY:{$title_fmt} (Beginn)".
107                "\r\nDESCRIPTION:{$description_fmt}".
108                "\r\nCATEGORIES:{$label_idents}".
109                $attach.
110                "\r\nCLASS:PUBLIC".
111                "\r\nUID:olz_termin_{$id}_start@{$host}".
112                "\r\nEND:VEVENT".
113                "\r\nBEGIN:VEVENT".
114                "\r\nDTSTART;VALUE=DATE:{$end_date_fmt}".
115                "\r\nDTEND;VALUE=DATE:{$end_date_fmt}".
116                "\r\nDTSTAMP:{$now_fmt}".
117                "\r\nLAST-MODIFIED:{$modified_fmt}".
118                "\r\nCREATED:{$created_fmt}".
119                "\r\nSUMMARY:{$title_fmt} (Ende)".
120                "\r\nDESCRIPTION:{$description_fmt}".
121                "\r\nCATEGORIES:{$label_idents}".
122                $attach.
123                "\r\nCLASS:PUBLIC".
124                "\r\nUID:olz_termin_{$id}_end@{$host}".
125                "\r\nEND:VEVENT";
126            } else {
127                $ical .=
128                "\r\nBEGIN:VEVENT".
129                "\r\nDTSTART;VALUE=DATE:{$start_date_fmt}".
130                "\r\nDTEND;VALUE=DATE:{$end_date_end_fmt}".
131                "\r\nDTSTAMP:{$now_fmt}".
132                "\r\nLAST-MODIFIED:{$modified_fmt}".
133                "\r\nCREATED:{$created_fmt}".
134                "\r\nSUMMARY:{$title_fmt}".
135                "\r\nDESCRIPTION:{$description_fmt}".
136                "\r\nCATEGORIES:{$label_idents}".
137                $attach.
138                "\r\nCLASS:PUBLIC".
139                "\r\nUID:olz_termin_{$id}@{$host}".
140                "\r\nEND:VEVENT";
141            }
142        }
143
144        $ical .= "\r\nEND:VCALENDAR";
145
146        return $ical;
147    }
148
149    protected function escapeText(string $text): string {
150        return preg_replace("/(\r\n|\n|\r)/", "\\n", $text) ?: '';
151    }
152}