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