1<?php 2 3use dokuwiki\Extension\ActionPlugin; 4use dokuwiki\Extension\Event; 5use dokuwiki\Extension\EventHandler; 6use dokuwiki\Form\InputElement; 7use FYKOS\dokuwiki\Extension\PluginFKSHelper\Form\DateTimeInputElement; 8use FYKOS\dokuwiki\Extension\PluginNewsFeed\Model\ModelNews; 9use dokuwiki\Form\Form; 10use dokuwiki\Cache\Cache; 11 12require_once __DIR__ . '/../fkshelper/inc/Form/DateTimeInputElement.php'; 13 14/** 15 * Class action_plugin_newsfeed 16 * @author Michal Červeňák <miso@fykos.cz> 17 */ 18class action_plugin_newsfeed extends ActionPlugin { 19 20 private static array $categories = [ 21 'fykos-blue', 22 'fykos-pink', 23 'fykos-line', 24 'fykos-purple', 25 'fykos-orange', 26 'fykos-green', 27 ]; 28 29 private helper_plugin_newsfeed $helper; 30 31 public function __construct() { 32 $this->helper = $this->loadHelper('newsfeed'); 33 } 34 35 public function register(EventHandler $controller): void { 36 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax'); 37 $controller->register_hook('ACTION_ACT_PREPROCESS', 'AFTER', $this, 'handleMetaData'); 38 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleActPreprocess'); 39 $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'handleActUnknown'); 40 } 41 42 public function handleActUnknown(Event $event): void { 43 global $ACT; 44 global $INPUT; 45 if ($ACT !== helper_plugin_newsfeed::FORM_TARGET) { 46 return; 47 } 48 if (auth_quickaclcheck('start') < AUTH_EDIT) { 49 return; 50 } 51 $event->preventDefault(); 52 $event->stopPropagation(); 53 switch ($INPUT->param('news')['do']) { 54 case'edit': 55 case'create': 56 $this->handleEditForm(); 57 return; 58 case 'preview': 59 $this->handleStreamPreview(); 60 return; 61 } 62 } 63 64 public function handleActPreprocess(Event $event): void { 65 global $INPUT; 66 if ($event->data !== helper_plugin_newsfeed::FORM_TARGET) { 67 return; 68 } 69 if (auth_quickaclcheck('start') < AUTH_EDIT) { 70 return; 71 } 72 $event->preventDefault(); 73 $event->stopPropagation(); 74 switch ($INPUT->param('news')['do']) { 75 case 'create': 76 case 'edit': 77 default: 78 return; 79 case'save': 80 $this->handleNews(); 81 return; 82 case'priority': 83 $this->handlePriority(); 84 return; 85 case'delete': 86 $this->handleDelete(); 87 return; 88 case'purge': 89 $this->handleCache(); 90 return; 91 } 92 } 93 94 public function handleAjax(Event $event): void { 95 $payload = json_decode(file_get_contents('php://input'), true); 96 if ($payload['target'] !== 'feed') { 97 return; 98 } 99 header('Content-Type: application/json'); 100 $event->stopPropagation(); 101 $event->preventDefault(); 102 103 echo json_encode($this->printStream((int)$payload['news']['offset'], (int)$payload['news']['length'], $payload['news']['stream'], $payload['page_id'])); 104 } 105 106 public function handleMetaData(): void { 107 global $ID; 108 global $INPUT; 109 if (!$INPUT->str('news-id')) { 110 return; 111 } 112 113 $newsId = $INPUT->str('news-id'); 114 $news = $this->helper->serviceNews->getById($newsId); 115 116 $this->helper->openGraphData->addMetaData('og', 'title', $news->title); 117 $this->helper->openGraphData->addMetaData('og', 'url', $news->getToken($ID)); 118 $text = $news->renderText(); 119 $this->helper->openGraphData->addMetaData('og', 'description', $text); 120 if ($news->hasImage()) { 121 $this->helper->openGraphData->addMetaData('og', 'image', ml($news->image, null, true, '&', true)); 122 } 123 } 124 125 private function printStream(int $start, int $length, string $streamId, string $pageId): array { 126 127 $stream = $this->helper->serviceStream->findByName($streamId); 128 129 $news = $stream->getNews(); 130 $htmlNews = []; 131 for ($i = $start; $i < min([$start + $length, (count($news))]); $i++) { 132 $e = $i % 2 ? 'even' : 'odd'; 133 $htmlNews[] = $news[$i]->render($e, $streamId, $pageId); 134 } 135 return ['html' => ['news' => $htmlNews]]; 136 } 137 138 139 private function handleNews(): void { 140 global $INPUT; 141 $file = ModelNews::getCacheFileById($INPUT->param('news')['id']); 142 $cache = new Cache($file, ''); 143 $cache->removeCache(); 144 145 $data = []; 146 foreach (helper_plugin_newsfeed::$fields as $field) { 147 if ($field === 'text') { 148 $data[$field] = cleanText($INPUT->str('text')); 149 } else { 150 $data[$field] = $INPUT->param($field); 151 } 152 } 153 $data = [ 154 'title' => $data['title'], 155 'author_name' => $data['authorName'], 156 'author_email' => $data['authorEmail'], 157 'text' => $data['text'], 158 'news_date' => $data['newsDate'], 159 'image' => $data['image'] ?: null, 160 'category' => $data['category'], 161 'link_href' => $data['linkHref'] ?: null, 162 'link_title' => $data['linkTitle'] ?: null, 163 ]; 164 165 if (+$INPUT->param('news')['id'] === 0) { 166 $this->helper->serviceNews->create($data); 167 $this->saveIntoStreams($this->helper->serviceNews->getMaxId(), $INPUT->param('news')['stream']); 168 } else { 169 $news = $this->helper->serviceNews->getById($INPUT->param('news')['id']); 170 $this->helper->serviceNews->update($news, $data); 171 } 172 header('Location: ' . $_SERVER['REQUEST_URI']); 173 exit(); 174 } 175 176 private function saveIntoStreams(int $newsId, string $streamName): void { 177 $stream = $this->helper->serviceStream->findByName($streamName); 178 179 $streams = [$stream->streamId]; 180 $this->helper->fullParentDependence($stream->streamId, $streams); 181 182 foreach ($streams as $stream) { 183 $this->helper->servicePriority->store($newsId, $stream); 184 } 185 } 186 187 private function handlePriority(): void { 188 global $INPUT; 189 $file = ModelNews::getCacheFileById($INPUT->param('news')['id']); 190 191 $cache = new cache($file, ''); 192 $cache->removeCache(); 193 $stream = $this->helper->serviceStream->findByName($INPUT->param('news')['stream']); 194 195 $priority = $this->helper->servicePriority->findByNewsAndStream($INPUT->param('news')['id'], $stream->streamId); 196 $data = $INPUT->param('priority'); 197 $this->helper->servicePriority->update($priority, [ 198 'priority_from' => $data['from'], 199 'priority_to' => $data['to'], 200 'priority' => $data['value'], 201 ]); 202 header('Location: ' . $_SERVER['REQUEST_URI']); 203 exit(); 204 } 205 206 private function handleDelete(): void { 207 global $INPUT; 208 $stream = $this->helper->serviceStream->findByName($INPUT->param('news')['stream']); 209 $priority = $this->helper->servicePriority->findByNewsAndStream($INPUT->param('news')['id'], $stream->streamId); 210 $priority->delete(); 211 header('Location: ' . $_SERVER['REQUEST_URI']); 212 exit(); 213 } 214 215 private function handleCache(): void { 216 global $INPUT; 217 if (!$INPUT->param('news')['id']) { 218 $news = $this->helper->serviceNews->getAll(); 219 foreach ($news as $new) { 220 $f = $new->getCacheFile(); 221 $cache = new Cache($f, ''); 222 $cache->removeCache(); 223 } 224 } else { 225 $f = ModelNews::getCacheFileById($INPUT->param('news')['id']); 226 $cache = new Cache($f, ''); 227 $cache->removeCache(); 228 } 229 header('Location: ' . $_SERVER['REQUEST_URI']); 230 exit(); 231 } 232 233 private function handleStreamPreview(): void { 234 global $INPUT; 235 if ($INPUT->param('news')['stream']) { 236 echo p_render('xhtml', p_get_instructions('{{news-stream>feed="5";stream="' . $INPUT->param('news')['stream'] . '"}}'), $info); 237 } else { 238 msg('Stream is required.', -1); 239 } 240 } 241 242 private function handleEditForm(): void { 243 global $INPUT; 244 global $ID; 245 246 $form = new Form(); 247 248 if ($INPUT->param('news')['id'] !== 0) { 249 $data = $this->helper->serviceNews->getById($INPUT->param('news')['id']); 250 } else { 251 $data = new ModelNews($this->helper->sqlite); 252 $data->loadDefault(); 253 } 254 $form->setHiddenField('page_id', $ID); 255 $form->setHiddenField('do', helper_plugin_newsfeed::FORM_TARGET); 256 $form->setHiddenField('news[id]', $INPUT->param('news')['id']); 257 $form->setHiddenField('news[do]', 'save'); 258 $form->setHiddenField('news[stream]', $INPUT->param('news')['stream']); 259 $form->addFieldsetOpen('Novinky na webu'); 260 261 foreach (helper_plugin_newsfeed::$fields as $field) { 262 $input = null; 263 $form->addTagOpen('div')->addClass('form-group'); 264 265 switch ($field) { 266 case'text': 267 $input = $form->addTextarea('text', $this->getLang($field), -1)->attrs([ 268 'class' => 'form-control', 269 'rows' => 10, 270 ]); 271 $input->val($data->text); 272 break; 273 case 'newsDate': 274 $input = new DateTimeInputElement($field, $this->getLang($field)); 275 $input->attr('class', 'form-control'); 276 $input->setStep(1); 277 $form->addElement($input); 278 $input->val($data->newsDate ?: 'now'); 279 break; 280 case'category': 281 $input = $form->addDropdown('category', static::$categories, $this->getLang($field))->attr('class', 'form-control'); 282 $input->val($data->category); 283 break; 284 case'image': 285 $input = $form->addTextInput($field, $this->getLang($field))->attr('class', 'form-control'); 286 $input->val($data->image); 287 break; 288 case 'linkHref': 289 $input = $form->addTextInput($field, $this->getLang($field))->attrs([ 290 'class' => 'form-control', 291 ]); 292 $input->val($data->linkHref); 293 break; 294 case 'linkTitle': 295 $input = $form->addTextInput($field, $this->getLang($field))->attrs([ 296 'class' => 'form-control', 297 ]); 298 $input->val($data->linkTitle); 299 break; 300 case 'authorName': 301 $input = $form->addTextInput($field, $this->getLang($field))->attrs([ 302 'pattern' => '\S.*', 303 'required' => 'required', 304 'class' => 'form-control', 305 ]); 306 $input->val($data->authorName); 307 break; 308 case 'authorEmail': 309 $input = new InputElement('email', $field, $this->getLang($field)); 310 $input->attr('class', 'form-control'); 311 $form->addElement($input); 312 $input->val($data->authorEmail); 313 break; 314 case 'title': 315 $input = $form->addTextInput($field, $this->getLang($field))->attrs([ 316 'pattern' => '\S.*', 317 'required' => 'required', 318 'class' => 'form-control', 319 ]); 320 $input->val($data->title); 321 break; 322 default: 323 msg('Not implement input field ' . $field, -1); 324 } 325 if ($note = $this->getLang($field . '_note')) { 326 $form->addHTML('<small>' . $note . '</small>'); 327 } 328 $form->addTagClose('div'); 329 } 330 $form->addFieldsetClose(); 331 $form->addButton('submit', $this->getLang('save'))->addClass('btn btn-success'); 332 echo $form->toHTML(); 333 } 334} 335