1<?php
2
3/**
4 * DokuWiki Plugin firenews (Syntax Component)
5 *
6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
7 * @author  NilsSchucka <nils@schucka.de>
8 */
9class syntax_plugin_firenews extends \dokuwiki\Extension\SyntaxPlugin
10{
11
12    /** @inheritDoc */
13    public function getType(){ return 'substition'; }
14
15    /** @inheritDoc */
16    public function getSort() { return 32; }
17
18    /** @inheritDoc */
19    public function connectTo($mode)
20    {
21        $this->Lexer->addSpecialPattern('\{\{firenews>[^}]*\}\}', $mode, 'plugin_firenews');
22    }
23
24    /** @inheritDoc */
25    public function handle($match, $state, $pos, Doku_Handler $handler)
26    {
27        // gets the string after the >
28        $match = explode(">", substr($match, 0, -2));
29
30        // saves the string into $params
31        $params = $match[1];
32
33        // add the found string into an array with the key 'param'
34        $datatest_conf              = array();
35        $datatest_conf['param']     = $params;
36
37        // I think this is useless
38        if (!$params) {
39            msg('Syntax detected but unknown parameter was attached.', -1);
40        } else {
41            // returns the array. This array can be used in the render() function as $data
42            return $datatest_conf;
43        }
44    }
45
46    /** @inheritDoc */
47    public function render($mode, Doku_Renderer $renderer, $data)
48    {
49        // Variables
50        global $USERINFO, $conf;
51
52        $pluginname = "firenews";
53        $tablename = $pluginname;
54
55        // Connect to database with sqlite plugin
56        $sqlite = $this->sqlConnection($pluginname);
57
58        // Create table if not exists
59        $sqlite->query("CREATE TABLE IF NOT EXISTS $tablename
60                (
61                    'news_id' INTEGER PRIMARY KEY AUTOINCREMENT,
62                    'header' TEXT NOT NULL,
63                    'subtitle' TEXT NOT NULL,
64                    'targetpage' TEXT NOT NULL,
65                    'startdate' DATE NOT NULL,
66                    'enddate' DATE NOT NULL,
67                    'news' TEXT NOT NULL,
68                    'group' TEXT NOT NULL,
69                    'author' TEXT
70                )");
71
72
73        // Checks if mode is xhtml
74        if ($mode === 'xhtml') {
75            // When param matches creates the Author template on the page
76            if ($data['param'] === "author") {
77
78                // Gets the html file that will get added to the page
79                $formView = file_get_contents(__DIR__ . "/HTMLTemplates/author/author.html");
80                // Applies the correct language from the lang/language
81                $formView = $this->setLanguage($formView, "/\{\{firenews\_(\w+)\}\}/");
82
83                // replaces the {{author}} tag with the current user name
84                $formView = str_replace("{{author}}", "{$USERINFO['name']}", $formView);
85
86                // if the form is submitted
87                if (isset($_POST["submitted"])) {
88
89                    /**
90                     * Adds a {{firenews>}} tag to the targetpage if not exists
91                     * And adds the submitted information in the database
92                     */
93
94                    // Explodes the string to get the targetpage Path
95                    $pagelocation = explode(':', $_POST['ltargetpage']);
96                    $pagepath = __DIR__ . "\..\..\..\data\pages";
97                    foreach ($pagelocation as $value) {
98                        $pagepath .= "\\" . $value;
99                    }
100                    $pagepath .= ".txt";
101
102                    // If file don't exists return false and add a error message
103                    if (!file_exists($pagepath)) {
104                        $formView = str_replace("{{ script_placeholder }}",
105                        <<<HTML
106                        <script>
107                            // This will trigger the error message see HTMLTempalte/author/author.js
108                            window.location = window.location.href + "&fileexists=false";
109                        </script>
110                        HTML, $formView);
111
112                        // This adds the html to the page
113                        $renderer->doc .= $formView;
114                        return false;
115                    }
116
117                    // NOCACHE needed so everyting gets updates correctly
118                    // ToDo find a way to line break
119                    $nocacheTag = "~~NOCACHE~~";
120                    $insertAnchor = "{{firenews>{$_POST['ltargetpage']}}}";
121
122                    // Writes the tag into the targetpage
123                    $fileStream = fopen($pagepath, 'a');
124                    if (!strpos(file_get_contents($pagepath), $insertAnchor)) {
125                        fwrite($fileStream, $nocacheTag.$insertAnchor);
126                    }
127
128                    // Send form to database
129                    $sqlite->query("INSERT INTO $tablename ('header', 'subtitle', 'targetpage', 'startdate', 'enddate', 'news', 'group', 'author')
130                        VALUES ('{$_POST['fheader']}', '{$_POST['lsubtitle']}', '{$_POST['ltargetpage']}', '{$_POST['lstartdate']}', '{$_POST['lenddate']}', '{$_POST['lnews']}', '{$_POST['lgroup']}', '{$_POST['lauthor']}')");
131
132                    /**
133                     * Send emails to group members if selected
134                     * You also need to setup the smtp plugin
135                     */
136                    if ($_POST['lsendEmails']) {
137                        //Find emails of the users that are in the groups given by the POST
138                        $emails = $this->getUsersEmailsOfaGroup($_POST['lgroup']);
139
140                        $this->sendMailToUsers($emails);
141                    }
142
143                    // Form has been submitted -> reset request from POST back to GET
144                    $formView = str_replace("{{ script_placeholder }}",
145                    <<<HTML
146                    <script>
147                        // This will trigger a info message for the user see author.js
148                        window.location = window.location.href + "&submitted=true";
149                    </script>
150                    HTML, $formView);
151
152                }
153
154                // In case the form hasnt been sent
155                $formView = str_replace("{{ script_placeholder }}", "", $formView);
156
157                // this will add the html to the page
158                $renderer->doc .= $formView;
159                return true;
160
161            } else if ($data['param'] === "editnews") {
162
163                // Creating the edit news Page
164                $editnewsTemplate = file_get_contents(__DIR__ . "/HTMLTemplates/editnews/editnewsTemplate.html");
165                // Applies the correct language from the lang/language
166                $editnewsTemplate = $this->setLanguage($editnewsTemplate, "/\{\{firenews\_(\w+)\}\}/");
167
168                $editnews = file_get_contents(__DIR__ . "/HTMLTemplates/editnews/editnews.html");
169                // Applies the correct language from the lang/language
170                $editnews = $this->setLanguage($editnews, "/\{\{firenews\_(\w+)\}\}/");
171
172                $outputRender = "";
173                // if the form is submitted on save
174                if (isset($_POST['savesubmit'])) {
175                    // Update database
176                    $sqlite->query("UPDATE {$tablename}
177                                        SET header = '{$_POST['eheader']}',
178                                            subtitle = '{$_POST['esubtitle']}',
179                                            targetpage = '{$_POST['etargetpage']}',
180                                            startdate = '{$_POST['estartdate']}',
181                                            enddate = '{$_POST['eenddate']}',
182                                            'news' = '{$_POST['enews']}',
183                                            'group' = '{$_POST['egroup']}',
184                                            author = '{$_POST['eauthor']}'
185                                            WHERE news_id = {$_POST['enewsid']}"
186                                    );
187                    // Resets the POST request to GET
188                    $editnewsTemplate = str_replace("{{ script_placeholder }}",
189                    <<<HTML
190                    <script>
191                        // This will trigger a info message for the user see author.js
192                        window.location = window.location.href + "&submitted=saved";
193                    </script>
194                    HTML, $editnewsTemplate);
195                }
196                // if the from is submitted on delete
197                if (isset($_POST["deletesubmit"])) {
198                    $sqlite->query("DELETE FROM {$tablename}
199                                        WHERE news_id = {$_POST['enewsid']}"
200                                    );
201                    // Resets the POST request to GET
202                    $editnewsTemplate = str_replace("{{ script_placeholder }}",
203                    <<<HTML
204                    <script>
205                        // This will trigger a info message for the user see author.js
206                        window.location = window.location.href + "&submitted=deleted";
207                    </script>
208                    HTML, $editnewsTemplate);
209                }
210
211                // Gets the news with the right page
212                $result = $sqlite->query("SELECT * FROM {$tablename} ORDER BY news_id DESC");
213
214
215                if ($result != NULL || $result != false) {
216                    // Goes through the results and adds them to $outputRender
217                    foreach ($result as $value) {
218                        $outputRender .= str_replace(
219                            array("{{HEADER}}", "{{SUBTITLE}}", "{{TARGETPAGE}}", "{{STARTDATE}}", "{{ENDDATE}}", "{{NEWS}}", "{{GROUP}}", "{{AUTHOR}}", "{{NEWSID}}"),
220                            array("{$value['header']}", "{$value['subtitle']}", "{$value['targetpage']}", "{$value['startdate']}", "{$value['enddate']}", "{$value['news']}", "{$value['group']}", "{$value['author']}", "{$value['news_id']}"),
221                            $editnews
222                        );
223                    }
224                }
225                // Replaces the news tag with the outputRender
226                $formView = str_replace("{{NEWS}}", $outputRender, $editnewsTemplate);
227
228                // Appens the html to the page
229                $renderer->doc .= $formView;
230                return true;
231            }
232
233            /**
234             * This part adds the news to the right page
235             */
236
237            // Gets the news with the right page
238            $result = $sqlite->query("SELECT * FROM {$tablename}
239                                        WHERE
240                                            targetpage = '{$data['param']}' AND
241                                            startdate <= strftime('%Y-%m-%d','now') AND
242                                            enddate >= strftime('%Y-%m-%d','now')
243                                            ORDER BY news_id DESC
244                                            LIMIT 5
245                                    ");
246
247            // If the page is found create the news
248            if ($result != NULL || $result != false) {
249                // Gets the news template
250                $newsTemplate = file_get_contents(__DIR__ . "/HTMLTemplates/news/news.html");
251
252                $outputRender = "";
253                // adds news to the page that was returned by the database
254                foreach ($result as $value) {
255
256                    // Check if group is set
257                    if(strlen($value['group']) > 0) {
258
259                        //Check if only a group can see the message
260                        if ($this->isInGroup($value['group']) === false) { continue; }
261
262                        // Replaces the placeholders with the right values
263                        $outputRender .= str_replace(
264                            array("{{HEADER}}", "{{SUBTITLE}}", "{{DATE-AUTHOR}}", "{{NEWS}}"),
265                            array("{$value['header']}", "{$value['subtitle']}", "{$value['startdate']}, {$value['author']}", "{$value['news']}"),
266                            $newsTemplate
267                        );
268
269                        continue;
270                    }
271
272                    // Replaces the placeholders with the right values
273                    $outputRender .= str_replace(
274                        array("{{HEADER}}", "{{SUBTITLE}}", "{{DATE-AUTHOR}}", "{{NEWS}}"),
275                        array("{$value['header']}", "{$value['subtitle']}", "{$value['startdate']}, {$value['author']}", "{$value['news']}"),
276                        $newsTemplate
277                    );
278                }
279                // Puts the html to the page
280                $renderer->doc .= $outputRender;
281
282                return true;
283            }
284        }
285        return false;
286    }
287
288
289    /**
290     * Gets the sqlite connection
291     *
292     * @param string $pluginname name of the current plugin
293     *
294     * @return [type]
295     */
296    private function sqlConnection(string $pluginname)
297    {
298        /** @var helper_plugin_sqlite $sqlite */
299        $sqlite = plugin_load('helper', 'sqlite');
300        if (!$sqlite) {
301            msg('This plugin requires the sqlite plugin. Please install it', -1);
302            return;
303        }
304        // initialize the database connection
305        $dbname = $pluginname;
306        $updatedir = DOKU_PLUGIN . "$pluginname/db/";
307
308        if (!$sqlite->init($dbname, $updatedir)) {
309            die('error init db');
310        }
311
312        return $sqlite;
313    }
314
315    /**
316     * Gets user from groups
317     * @param string $groups Groups from $_POST['lgroup']
318     *
319     * @return [array] array of emails
320     */
321    private function getUsersEmailsOfaGroup(string $groups): array
322    {
323        // Explodes the group string
324        $groupArr = explode(",", $groups);
325        // Gets the user.auth.php where all groups are in (maybe there is a better way)
326        $filestream = fopen(__DIR__ . "\..\..\..\conf\users.auth.php", 'r');
327        $listOfEmails = [];
328
329        // Goes through the file
330        while (feof($filestream)) {
331
332            $currentLine = fgets($filestream);
333            // We want to ignore comments
334            if (str_starts_with($currentLine, "# ")) {
335                continue;
336            }
337            // We want to ignore empty lines
338            if (strlen($currentLine) < 20) {
339                continue;
340            }
341            // Maybe here are more possible errors that could happen
342
343            $explodeFile = explode(":", $currentLine);
344            $emailOfUser = $explodeFile[3];
345            $groupsOfUser = array_slice($explodeFile, 3);
346
347            foreach ($groupsOfUser as $group) {
348                foreach ($groupArr as $neededGroup) {
349                    if ($group === $neededGroup) {
350                        array_push($listOfEmails, $emailOfUser);
351                    }
352                }
353            }
354        }
355        return $listOfEmails;
356    }
357
358    /**
359     * Sends an email to the users
360     * @param array $emails array of emails
361     *
362     * @return [void]
363     */
364    private function sendMailToUsers(array $emails) {
365        /** @var helper_plugin_smtp $sqlite */
366        $mail = new Mailer();
367        $mail->setHeader("nice Header","value", true);
368        $mail->setBody("nice body");
369        $mail->to($emails);
370
371        $mail->send();
372    }
373
374    /**
375     * Checks if the user is in one of those groups
376     * @param string $groups
377     *
378     * @return [bool]
379     */
380    private function isInGroup(string $groups): bool {
381        global $INFO;
382        $groupArr = explode(",", $groups);
383
384        // Ignores everything if the user is a admin or manager
385        if($INFO['isadmin'] || $INFO['ismanager'] ) { return true; }
386
387        foreach($groupArr as $value) {
388            if(in_array($value, $INFO['userinfo']['grps'])) { return true; }
389        }
390
391        return false;
392    }
393
394
395    /**
396     * This function will search through the given file
397     * and replaces found language tags with the language in the file
398     *
399     * @param string $file string that should get the replacements
400     * @param string $pattern regex pattern to search for
401     *
402     * @return string with the right language
403     */
404    private function setLanguage(string $file, string $pattern): string {
405
406        $result = preg_replace_callback($pattern,
407                function($matches) {
408                    $langTag = str_replace(["{{", "}}"], "", $matches[0]);
409                    $lang = $this->getLang($langTag);
410                    return $lang;
411                },
412                $file );
413        return $result;
414    }
415}
416