1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Esther Brunner <wikidesign@gmail.com> 5 */ 6 7use dokuwiki\plugin\blogtng\entities\Comment; 8 9/** 10 * Class admin_plugin_blogtng 11 */ 12class admin_plugin_blogtng extends DokuWiki_Admin_Plugin { 13 14 /** @var helper_plugin_blogtng_comments */ 15 protected $commenthelper = null; 16 /** @var helper_plugin_blogtng_entry */ 17 protected $entryhelper = null; 18 /** @var helper_plugin_blogtng_sqlite */ 19 protected $sqlitehelper = null; 20 /** @var helper_plugin_blogtng_tags */ 21 protected $taghelper = null; 22 /** 23 * @var string action in admin to perform 24 */ 25 private $admin; 26 /** 27 * @var int number of comments per page of the comment list 28 */ 29 private $commentLimit; 30 /** 31 * @var int number of entries per page of the entry list 32 */ 33 private $entryLimit; 34 35 /** 36 * Determine position in list in admin window 37 * Lower values are sorted up 38 * 39 * @return int 40 */ 41 public function getMenuSort() { return 200; } 42 43 /** 44 * Return true for access only by admins (config:superuser) or false if managers are allowed as well 45 * 46 * @return bool 47 */ 48 public function forAdminOnly() { return false; } 49 50 /** 51 * Constructor 52 */ 53 public function __construct() { 54 $this->commenthelper = plugin_load('helper', 'blogtng_comments'); 55 $this->entryhelper = plugin_load('helper', 'blogtng_entry'); 56 $this->sqlitehelper = plugin_load('helper', 'blogtng_sqlite'); 57 $this->taghelper = plugin_load('helper', 'blogtng_tags'); 58 } 59 60 /** 61 * Handles all actions of the admin component 62 * 63 * @author Michael Klier <chi@chimeric.de> 64 */ 65 public function handle() { 66 global $INPUT; 67 if($INPUT->has('admin')) { 68 $this->admin = $INPUT->extract('admin')->str('admin'); //can be post or get 69 } else { 70 $this->admin = ''; 71 } 72 //skip actions when no valid security token given 73 $noSecTokenNeeded = ['search', 'comment_edit', 'comment_preview', null]; 74 if(!in_array($this->admin, $noSecTokenNeeded) && !checkSecurityToken()) { 75 $this->admin = ''; 76 } 77 78 //get some preferences 79 $this->commentLimit = (int) get_doku_pref('blogtng_comment_limit', 15); 80 $this->entryLimit = (int) get_doku_pref('blogtng_entry_limit', 5); 81 82 83 // handle actions 84 switch($this->admin) { 85 86 case 'comment_save': 87 // FIXME error handling? 88 $comment = $this->getPostedComment(); 89 90 $this->commenthelper->save($comment); 91 msg($this->getLang('msg_comment_save'), 1); 92 break; 93 94 case 'comment_delete': 95 // FIXME error handling 96 $this->commenthelper->delete($INPUT->post->str('comment-cid')); 97 msg($this->getLang('msg_comment_delete'), 1); 98 break; 99 100 case 'comment_batch_edit': 101 $batch = $INPUT->post->str('comment_batch_edit'); 102 $cids = $INPUT->post->arr('comments-cids'); 103 if($cids) { 104 foreach($cids as $cid) { 105 switch($batch) { 106 // FIXME messages 107 case 'delete': 108 $this->commenthelper->delete($cid); 109 msg($this->getLang('msg_comment_delete'), 1); 110 break; 111 case 'status_hidden': 112 $this->commenthelper->moderate($cid, 'hidden'); 113 msg($this->getLang('msg_comment_status_change'), 1); 114 break; 115 case 'status_visible': 116 $this->commenthelper->moderate($cid, 'visible'); 117 msg($this->getLang('msg_comment_status_change'), 1); 118 break; 119 } 120 } 121 } 122 //back to default view 123 $this->admin = ''; 124 break; 125 126 case 'entry_set_blog': 127 // FIXME errors? 128 $pid = $INPUT->post->str('entry-pid'); 129 $blog = $INPUT->post->str('entry-blog'); 130 if($pid) { 131 $blogs = $this->entryhelper->getAllBlogs(); 132 if(in_array($blog, $blogs)) { 133 $this->entryhelper->load_by_pid($pid); 134 $this->entryhelper->entry['blog'] = $blog; 135 $this->entryhelper->save(); 136 } 137 } 138 msg($this->getLang('msg_entry_blog_change'), 1); 139 break; 140 141 case 'entry_set_commentstatus': 142 $pid = $INPUT->post->str('entry-pid'); 143 $status = $INPUT->post->str('entry-commentstatus'); 144 if($pid) { 145 if(in_array($status, ['disabled', 'enabled', 'closed'])) { 146 $this->entryhelper->load_by_pid($pid); 147 $this->entryhelper->entry['commentstatus'] = $status; 148 $this->entryhelper->save(); 149 } 150 } 151 msg($this->getLang('msg_comment_status_change'), 1); 152 break; 153 154 case 'comment_edit': 155 case 'comment_preview': 156 case 'search': 157 default: 158 // do nothing - show dashboard 159 160 //update preferences 161 if ($INPUT->has('comment-limit')) { 162 $this->commentLimit = $INPUT->int('comment-limit'); 163 set_doku_pref('blogtng_comment_limit', $this->commentLimit); 164 } 165 166 if ($INPUT->has('entry-limit')) { 167 $this->entryLimit = $INPUT->int('entry-limit'); 168 set_doku_pref('blogtng_entry_limit', $this->entryLimit); 169 } 170 break; 171 } 172 } 173 174 /** 175 * Handles the XHTML output of the admin component 176 * 177 * @author Michael Klier <chi@chimeric.de> 178 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 179 */ 180 public function html() { 181 global $ID, $INPUT; 182 183 ptln('<h1>'.$this->getLang('menu').'</h1>'); 184 185 ptln('<div id="blogtng__admin">'); 186 187 // display link back to dashboard 188 if($this->admin) { 189 ptln('<div class="level1">'); 190 $params = ['do'=>'admin', 'page'=>'blogtng']; 191 ptln('<p><a href="' . wl($ID, $params) . '" title="' . $this->getLang('dashboard') . '">← ' . $this->getLang('dashboard') . '</a></p>'); 192 ptln('</div>'); 193 194 } 195 196 switch($this->admin) { 197 case 'search': 198 // display search form 199 $this->htmlSearchForm(); 200 201 ptln('<h2>' . $this->getLang('searchresults') . '</h2>'); 202 203 $query = $INPUT->arr('query'); 204 $query['resultset'] = 'query'; 205 $query['limit'] = 20; 206 $query['offset'] = $INPUT->int('query-offset'); 207 $this->htmlSearchResults($query); 208 break; 209 210 case 'comment_edit': 211 case 'comment_preview': 212 if($this->admin == 'comment_edit') { 213 $comment = $this->commenthelper->comment_by_cid($INPUT->get->str('comment-cid')); 214 if($comment !== null) { 215 $this->htmlCommentEditForm($comment); 216 } 217 } 218 if($this->admin == 'comment_preview') { 219 $comment = $this->getPostedComment(); 220 221 $this->htmlCommentEditForm($comment); 222 $this->htmlCommentPreview($comment); 223 } 224 break; 225 226 default: 227 // display search form 228 $this->htmlSearchForm(); 229 230 // print latest 'x' comments/entries 231 $query['limit'] = $this->commentLimit; 232 $query['offset'] = $INPUT->int('comment-offset'); 233 $query['resultset'] = 'comment'; 234 $this->htmlLatestItems($query); 235 236 $query['limit'] = $this->entryLimit; 237 $query['offset'] = $INPUT->int('entry-offset'); 238 $query['resultset'] = 'entry'; 239 $this->htmlLatestItems($query); 240 break; 241 } 242 243 ptln('</div>'); 244 } 245 246 /** 247 * Displays a list of comments or entries for a given search term 248 * 249 * @param array $query url parameters for query 250 */ 251 private function htmlSearchResults($query) { 252 if(!$this->sqlitehelper->ready()) return; 253 254 $db = $this->sqlitehelper->getDB(); 255 256 switch($query['filter']) { 257 case 'entry_title': 258 case 'entry_author': 259 $select = 'SELECT * '; 260 $from = 'FROM entries '; 261 $orderby = 'ORDER BY created DESC '; 262 $itemdisplaycallback = 'htmlEntryList'; 263 break; 264 case 'comment': 265 case 'comment_ip': 266 $select = 'SELECT cid, comments.pid as pid, ip, source, name, comments.mail as mail, web, avatar, comments.created as created, text, status '; 267 $from = 'FROM comments LEFT JOIN entries ON comments.pid = entries.pid '; 268 $orderby = 'ORDER BY comments.created DESC '; 269 $itemdisplaycallback = 'htmlCommentList'; 270 break; 271 case 'tags': 272 $select = 'SELECT DISTINCT entries.pid as pid, page, title, blog, image, created, lastmod, author, login, mail '; 273 $from = 'FROM entries LEFT JOIN tags ON entries.pid = tags.pid '; 274 $orderby = 'ORDER BY created DESC '; 275 $itemdisplaycallback = 'htmlEntryList'; 276 break; 277 default: 278 return; 279 } 280 $count = 'SELECT COUNT(*) as count '; 281 282 if(isset($query['blog']) && $query['blog']) { 283 $where = 'WHERE blog = ' . $db->quote_string($query['blog']) . ' '; 284 } else { 285 $where = 'WHERE blog != "" '; 286 } 287 288 if(isset($query['string']) && $query['string'] != '') { 289 switch($query['filter']) { 290 case 'entry_title': 291 $where .= 'AND ( title LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 292 break; 293 case 'entry_author': 294 $where .= 'AND ( author LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 295 break; 296 case 'comment': 297 $where .= 'AND ( comments.text LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 298 break; 299 case 'comment_ip': 300 $where .= 'AND ( comments.ip LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 301 break; 302 case 'tags': 303 $where .= 'AND ( tags.tag LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 304 break; 305 } 306 } 307 308 //comments: if pid is given limit to give page 309 if(isset($query['pid']) && $query['pid'] != '') { 310 $where .= 'AND ( comments.pid = ' . $db->quote_string($query['pid']) . ' ) '; 311 } 312 313 $sqlcount = $count . $from . $where; 314 $sqlselect = $select . $from . $where . $orderby; 315 316 317 $sqlselect .= ' LIMIT '.$query['limit']; 318 if($query['offset'] > 0) { 319 $sqlselect .= ' OFFSET '.$query['offset']; 320 } 321 322 $res = $db->query($sqlcount); 323 $count = $db->res2single($res); 324 325 $resid = $db->query($sqlselect); 326 if($resid) { 327 $this->htmlShowPaginatedResult($resid, $query, $itemdisplaycallback, $count, $query['limit']); 328 } 329 } 330 331 /** 332 * Display paginated results 333 * 334 * @param object $resid Database resource object 335 * @param array $query Query parameters 336 * @param string $itemdisplaycallback called for each item, to display content of item 337 * @param int $count Number of total items 338 * @param int $limit Number of results to display per page (page size) 339 * 340 * @author Michael Klier <chi@chimeric.de> 341 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 342 */ 343 private function htmlShowPaginatedResult($resid, $query, $itemdisplaycallback, $count, $limit) { 344 global $lang; 345 if(!$resid) return; 346 347 $currentpage = floor($query['offset'] / $limit) + 1; 348 349 $items = $this->sqlitehelper->getDB()->res2arr($resid); 350 351 if($items) { 352 ptln('<div class="level2"><p><strong>' . $this->getLang('numhits') . ':</strong> ' . $count .'</p></div>'); 353 354 // show pagination only when enough items 355 if($count > $limit) { 356 $this->htmlPagination($query, $currentpage, $count, $limit); 357 } 358 // show list of items using callback 359 call_user_func(array($this, $itemdisplaycallback), $items, $query); 360 361 } else { 362 ptln('<div class="level2">'); 363 ptln($lang['nothingfound']); 364 ptln('</div>'); 365 } 366 367 // show pagination only when enough items 368 if($count > $limit) { 369 $this->htmlPagination($query, $currentpage, $count, $limit); 370 } 371 } 372 373 /** 374 * Diplays that pagination links of a query 375 * 376 * @param array $query Query parameters 377 * @param int $currentpage number of current page 378 * @param int $maximum maximum number of items available 379 * @param int $limit number of items per page 380 * 381 * @author Michael Klier <chi@chimeric.de> 382 */ 383 private function htmlPagination($query, $currentpage, $maximum, $limit) { 384 $lastpage = (int) ceil($maximum / $limit); 385 386 $pages[] = 1; // first always 387 $pages[] = $lastpage; // last page always 388 $pages[] = $currentpage; // current page always 389 390 if($lastpage > 1){ // if enough pages 391 $pages[] = 2; // second and .. 392 $pages[] = $lastpage-1; // one before last 393 } 394 395 // three around current 396 if($currentpage-1 > 0) $pages[] = $currentpage-1; 397 if($currentpage-2 > 0) $pages[] = $currentpage-2; 398 if($currentpage-3 > 0) $pages[] = $currentpage-3; 399 if($currentpage+1 < $lastpage) $pages[] = $currentpage+1; 400 if($currentpage+2 < $lastpage) $pages[] = $currentpage+2; 401 if($currentpage+3 < $lastpage) $pages[] = $currentpage+3; 402 403 $pages = array_unique($pages); 404 sort($pages); 405 406 ptln('<div class="level2"><p>'); 407 408 if($currentpage > 1) { 409 $this->htmlPaginationurl($query, ($currentpage - 2) * $limit, '«', $currentpage - 1); 410 } 411 412 $last = 0; 413 foreach($pages as $page) { 414 if($page - $last > 1) { 415 ptln('<span class="sep">...</span>'); 416 } 417 if($page == $currentpage) { 418 ptln('<span class="cur">' . $page . '</span>'); 419 } else { 420 $this->htmlPaginationurl($query, ($page - 1) * $limit, $page, $page); 421 } 422 $last = $page; 423 } 424 425 if($currentpage < $lastpage) { 426 $this->htmlPaginationurl($query, $currentpage * $limit, '»', $currentpage + 1); 427 } 428 429 ptln('</p></div>'); 430 } 431 432 /** 433 * Print a pagination link. 434 * 435 * @param array $query Query parameters 436 * @param int $offset number of previous items 437 * @param string $text text of url 438 * @param string $title title of url 439 * @internal param string $anchor url anchor 440 */ 441 private function htmlPaginationurl($query, $offset, $text, $title) { 442 global $ID; 443 list($params, $anchor) = $this->buildUrlParams($query, $offset); 444 ptln("<a href='".wl($ID, $params).'#'.$anchor."' title='$title'>$text</a>"); 445 } 446 447 /** 448 * Build URL parameters. 449 * 450 * @param array $query Query parameters 451 * @param int $offset number of previous items 452 * @return array($params, $anchor) 453 */ 454 private function buildUrlParams($query, $offset) { 455 $params = [ 456 'do' => 'admin', 457 'page' => 'blogtng', 458 $query['resultset'].'-offset' => $offset 459 ]; 460 $anchor = $query['resultset'] . '_latest'; 461 462 if($query['resultset'] == 'query') { 463 $params = $params + [ 464 'admin' => 'search', 465 'query[filter]' => $query['filter'], 466 'query[blog]' => $query['blog'], 467 'query[string]' => $query['string'], 468 'query[pid]' => $query['pid'] 469 ]; 470 $anchor = ''; 471 } 472 return [$params, $anchor]; 473 } 474 475 /** 476 * Display the latest comments or entries 477 * 478 * @param array $query parameters 479 * 480 * @author Michael Klier <chi@chimeric.de> 481 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 482 */ 483 private function htmlLatestItems($query) { 484 $resultset = $query['resultset']; //query,comment,entry 485 486 printf("<h2 id='{$resultset}_latest'>".$this->getLang($resultset.'_latest').'</h2>', $query['limit']); 487 $this->htmlLimitForm($query); 488 489 if(!$this->sqlitehelper->ready()) return; 490 491 $count = 'SELECT COUNT(pid) as count '; 492 $select = 'SELECT * '; 493 494 if($resultset == 'entry') { 495 $from = 'FROM entries '; 496 $where = 'WHERE blog != "" '; 497 $itemdisplaycallback = 'htmlEntryList'; 498 } else { 499 $from = 'FROM comments '; 500 $where = ''; 501 $itemdisplaycallback = 'htmlCommentList'; 502 } 503 504 $orderby = 'ORDER BY created DESC '; 505 506 $sqlcount = $count . $from . $where; 507 $sqlselect = $select . $from . $where . $orderby; 508 509 $limit = $query['limit']; 510 $sqlselect .= 'LIMIT ' . $limit; 511 if($query['offset']) { 512 $sqlselect .= ' OFFSET ' . $query['offset']; 513 } 514 515 $res = $this->sqlitehelper->getDB()->query($sqlcount); 516 $count = $this->sqlitehelper->getDB()->res2single($res); 517 518 $resid = $this->sqlitehelper->getDB()->query($sqlselect); 519 if(!$resid) { 520 return; 521 } 522 $this->htmlShowPaginatedResult($resid, $query, $itemdisplaycallback, $count, $limit); 523 } 524 525 /** 526 * Displays a list of entries, as callback of htmlSearchResults() 527 * 528 * @param array $entries of entries 529 * @param array $query parameters 530 * 531 * @author Michael Klier <chi@chimeric.de> 532 */ 533 private function htmlEntryList($entries, $query) { 534 ptln('<div class="level2">'); 535 ptln('<table class="inline">'); 536 537 ptln('<th>' . $this->getLang('created') . '</th>'); 538 ptln('<th>' . $this->getLang('author') . '</th>'); 539 ptln('<th>' . $this->getLang('entry') . '</th>'); 540 ptln('<th>' . $this->getLang('blog') . '</th>'); 541 ptln('<th>' . $this->getLang('commentstatus') . '</th>'); 542 ptln('<th>' . $this->getLang('comments') . '</th>'); 543 ptln('<th>' . $this->getLang('tags') . '</th>'); 544 ptln('<th></th>'); 545 foreach($entries as $entry) { 546 $this->htmlEntryItem($entry, $query); 547 } 548 ptln('</table>'); 549 ptln('</div>'); 550 } 551 552 /** 553 * Displays a single entry and related actions 554 * 555 * @param array $entry Single entry 556 * @param array $query Query parameters 557 * 558 * @author Michael Klier <chi@chimeric.de> 559 */ 560 private function htmlEntryItem($entry, $query) { 561 global $lang; 562 global $ID; 563 564 static $class = 'odd'; 565 ptln('<tr class="' . $class . '">'); 566 $class = ($class == 'odd') ? 'even' : 'odd'; 567 568 ptln('<td class="entry_created">' . dformat($entry['created']) . '</td>'); 569 ptln('<td class="entry_author">' . hsc($entry['author']) . '</td>'); 570 ptln('<td class="entry_title">' . html_wikilink(':'.$entry['page'], $entry['title']) . '</td>'); 571 ptln('<td class="entry_set_blog">' . $this->htmlEntryEditForm($entry, $query, 'blog') . '</th>'); 572 ptln('<td class="entry_set_commentstatus">' . $this->htmlEntryEditForm($entry, $query, 'commentstatus') . '</th>'); 573 574 $this->commenthelper->setPid($entry['pid']); 575 576 // search comments of this entry link 577 ptln('<td class="entry_comments">'); 578 $count = $this->commenthelper->get_count(null, true); 579 if($count > 0) { 580 $params = array('do' => 'admin', 581 'page' => 'blogtng', 582 'admin' => 'search', 583 'query[filter]' => 'comment', 584 'query[pid]' => $entry['pid']); 585 ptln('<a href="' . wl($ID, $params) . '" title="' . $this->getLang('comments') . '">' . $count . '</a>'); 586 } else { 587 ptln($count); 588 } 589 ptln('</td>'); 590 591 // tags filter links 592 ptln('<td class="entry_tags">'); 593 $this->taghelper->load($entry['pid']); 594 $tags = $this->taghelper->getTags(); 595 $count = count($tags); 596 for($i = 0; $i < $count; $i++) { 597 $params = array('do' => 'admin', 598 'page' => 'blogtng', 599 'admin' => 'search', 600 'query[filter]' => 'tags', 601 'query[string]' => $tags[$i]); 602 $link = '<a href="' . wl($ID, $params) . '" title="' . $tags[$i] . '">' . $tags[$i] . '</a>'; 603 if($i < ($count - 1)) $link .= ', '; 604 ptln($link); 605 } 606 ptln('</td>'); 607 608 // edit links 609 ptln('<td class="entry_edit">'); 610 $params = array('id' => $entry['page'], 611 'do' => 'edit'); 612 ptln('<a href="' . wl($ID, $params) . '" class="blogtng_btn_edit" title="' . $lang['btn_secedit'] . '">' . $lang['btn_secedit'] . '</a>'); 613 ptln('</td>'); 614 615 ptln('</tr>'); 616 } 617 618 /** 619 * Displays a list of comments, as callback of htmlSearchResults() 620 * 621 * @param array[] $comments List of comments 622 * @param array $query Query parameters 623 * 624 * @author Michael Klier <chi@chimeric.de> 625 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 626 */ 627 private function htmlCommentList($comments, $query) { 628 global $lang; 629 630 ptln('<div class="level2">'); 631 632 ptln('<form action="' . DOKU_SCRIPT . '" method="post" id="blogtng__comment_batch_edit_form">'); 633 ptln('<input type="hidden" name="page" value="blogtng" />'); 634 ptln('<input type="hidden" name="comment-offset" value="' .$query['offset']. '" />'); 635 ptln('<input type="hidden" name="sectok" value="' .getSecurityToken(). '" />'); 636 ptln('<input type="hidden" name="admin" value="comment_batch_edit" />'); 637 638 ptln('<table class="inline">'); 639 640 ptln('<th id="blogtng__admin_checkall_th"></th>'); 641 ptln('<th>' . $this->getLang('comments') . '</th>'); 642 ptln('<th></th>'); 643 644 foreach($comments as $comment) { 645 $this->htmlCommentItem(new Comment($comment)); 646 } 647 648 ptln('</table>'); 649 650 ptln('<select name="comment_batch_edit">'); 651 ptln('<option value="status_visible">Visible</option>'); 652 ptln('<option value="status_hidden">Hidden</option>'); 653 ptln('<option value="delete">'.$lang['btn_delete'].'</option>'); 654 ptln('</select>'); 655 ptln('<input type="submit" class="edit button" name="do[admin]" value="' . $lang['btn_update'] . '" />'); 656 ptln('</form>'); 657 658 ptln('</div>'); 659 } 660 661 /** 662 * Displays a single comment and related actions 663 * 664 * @param Comment $comment A single comment 665 * 666 * @author Michael Klier <chi@chimeric.de> 667 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 668 */ 669 private function htmlCommentItem($comment) { 670 global $lang; 671 global $ID; 672 673 static $class = 'odd'; 674 ptln('<tr class="' . $class . '">'); 675 $class = ($class == 'odd') ? 'even' : 'odd'; 676 677 $cmt = new Comment($comment); 678 ptln('<td class="admin_checkbox">'); 679 ptln('<input type="checkbox" class="comment_cid" name="comments-cids[]" value="' . $comment->getCid() . '" />'); 680 ptln('</td>'); 681 682 ptln('<td class="comment_row">'); 683 ptln('<div class="comment_text" title="'.$this->getLang('comment_text').'">' . hsc($comment->getText()) . '</div>'); 684 ptln('<div class="comment_metadata">'); 685 ptln('<span class="comment_created" title="'.$this->getLang('created').'">' . dformat($comment->getCreated()) . '</span>'); 686 ptln('<span class="comment_ip" title="'.$this->getLang('comment_ip').'">' . hsc($comment->getIp()) . '</span>'); 687 688 ptln('<span class="comment_name" title="'.$this->getLang('comment_name').'">'); 689 $avatar = $cmt->tpl_avatar(16,16,true); 690 if($avatar) ptln('<img src="' . $avatar . '" alt="' . hsc($comment->getName()) . '" class="avatar" /> '); 691 if($comment->getMail()){ 692 ptln('<a href="mailto:' . hsc($comment->getMail()) . '" class="mail" title="' . hsc($comment->getMail()) . '">' . hsc($comment->getName()) . '</a>'); 693 }else{ 694 ptln(hsc($comment->getName())); 695 } 696 ptln('</span>'); 697 698 $weburl = ''; 699 if($comment->getWeb()) { 700 $weburl = '<a href="' . hsc($comment->getWeb()) . '" title="' . hsc($comment->getWeb()) . '">' . hsc($comment->getWeb()) . '</a>'; 701 } 702 ptln('<span class="comment_web" title="'.$this->getLang('comment_web').'">'.$weburl.'</span>'); 703 704 ptln('<span class="comment_status" title="'.$this->getLang('comment_status').'">' . hsc($comment->getStatus()) . '</span>'); 705 ptln('<span class="comment_source" title="'.$this->getLang('comment_source').'">' . hsc($comment->getSource()) . '</span>'); 706 707 $this->entryhelper->load_by_pid($comment->getPid()); 708 $pagelink = html_wikilink(':'.$this->entryhelper->entry['page'], $this->entryhelper->entry['title']); 709 ptln('<span class="comment_entry" title="'.$this->getLang('comment_entry').'">' . $pagelink . '</span>'); 710 ptln('</div>'); 711 ptln('</td>'); 712 713 ptln('<td class="comment_edit">'); 714 $params = array('do'=>'admin', 715 'page'=>'blogtng', 716 'comment-cid'=>$comment->getCid(), 717 'admin'=>'comment_edit'); 718 ptln('<a href="' . wl($ID, $params). '" class="blogtng_btn_edit" title="' . $lang['btn_edit'] . '">' . $lang['btn_secedit'] . '</a>'); 719 ptln('</td>'); 720 721 ptln('</tr>'); 722 } 723 724 /** 725 * Displays a preview of the comment 726 * 727 * @param Comment $comment submitted comment 728 */ 729 private function htmlCommentPreview($comment) { 730 $this->entryhelper->load_by_pid($comment->getPid()); 731 $blogname = $this->entryhelper->get_blog(); 732 733 ptln('<div id="blogtng__comment_preview">'); 734 ptln(p_locale_xhtml('preview')); 735 ptln('<br />'); 736 $comment->output($blogname); 737 ptln('</div>'); 738 } 739 740 /** 741 * Displays the form to change the comment status of a blog entry 742 * 743 * @param array $entry Blog entry 744 * @param array $query Query parameters 745 * @param string $field 'blog' or 'commentstatus' 746 * @return false|string 747 * 748 * @author Michael Klier <chi@chimeric.de> 749 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 750 */ 751 private function htmlEntryEditForm($entry, $query, $field = 'commentstatus') { 752 global $lang; 753 754 $changablefields = ['commentstatus', 'blog']; 755 if(!in_array($field, $changablefields)) return hsc($entry[$field]); 756 757 $form = new Doku_Form(['id'=>"blogtng__entry_set_{$field}_form"]); 758 $form->addHidden('do', 'admin'); 759 $form->addHidden('page', 'blogtng'); 760 $form->addHidden('entry-pid', $entry['pid']); 761 $form->addHidden('entry-offset', $query['offset']); 762 763 if($field == 'commentstatus') { 764 $availableoptions = ['enabled', 'disabled', 'closed']; 765 } else { 766 $availableoptions = $this->entryhelper->getAllBlogs(); 767 } 768 $form->addElement(form_makeListBoxField("entry-$field", $availableoptions, $entry[$field], '')); 769 $form->addElement('<input type="submit" name="admin[entry_set_'.$field.']" class="edit button" value="' . $lang['btn_update'] . '" />'); 770 771 ob_start(); 772 html_form("blotng__btn_entry_set_$field", $form); 773 return ob_get_clean(); 774 } 775 776 /** 777 * Displays the comment edit form 778 * 779 * @param Comment $comment 780 * 781 * @author Michael Klier <chi@chimeric.de> 782 */ 783 private function htmlCommentEditForm($comment) { 784 global $lang; 785 786 ptln('<div class="level1">'); 787 $form = new Doku_Form(['id'=>'blogtng__comment_edit_form']); 788 $form->startFieldset($this->getLang('act_comment_edit')); 789 $form->addHidden('page', 'blogtng'); 790 $form->addHidden('do', 'admin'); 791 $form->addHidden('comment-cid', $comment->getCid()); 792 $form->addHidden('comment-pid', $comment->getPid()); 793 $form->addHidden('comment-created', $comment->getCreated()); 794 $form->addElement(form_makeListBoxField('comment-status', ['visible', 'hidden'], $comment->getStatus(), $this->getLang('comment_status'))); 795 $form->addElement('<br />'); 796 $form->addElement(form_makeListBoxField('comment-source', ['comment', 'trackback', 'pingback'], $comment->getSource(), $this->getLang('comment_source'))); 797 $form->addElement('<br />'); 798 $form->addElement(form_makeTextField('comment-name', $comment->getName(), $this->getLang('comment_name'))); 799 $form->addElement('<br />'); 800 $form->addElement(form_makeTextField('comment-mail', $comment->getMail(), $this->getLang('comment_mail'))); 801 $form->addElement('<br />'); 802 $form->addElement(form_makeTextField('comment-web', $comment->getWeb(), $this->getLang('comment_web'))); 803 $form->addElement('<br />'); 804 $form->addElement(form_makeTextField('comment-avatar', $comment->getAvatar(), $this->getLang('comment_avatar'))); 805 $form->addElement('<br />'); 806 $form->addElement('<textarea class="edit" name="comment-text" rows="10" cols="80">' . $comment->getText() . '</textarea>'); 807 $form->addElement('<input type="submit" name="admin[comment_save]" class="edit button" value="' . $lang['btn_save'] . '" />'); 808 $form->addElement('<input type="submit" name="admin[comment_preview]" class="edit button" value="' . $lang['btn_preview'] . '" />'); 809 $form->addElement('<input type="submit" name="admin[comment_delete]" class="edit button" value="' . $lang['btn_delete'] . '" />'); 810 $form->endFieldset(); 811 html_form('blogtng__edit_comment', $form); 812 ptln('</div>'); 813 } 814 815 /** 816 * Displays the search form 817 * 818 * @author Michael Klier <chi@chimeric.de> 819 */ 820 private function htmlSearchForm() { 821 global $lang, $INPUT; 822 823 ptln('<div class="level1">'); 824 825 $blogs = $this->entryhelper->getAllBlogs(); 826 827 $form = new Doku_Form(array('id'=>'blogtng__search_form')); 828 $form->startFieldset($lang['btn_search']); 829 $form->addHidden('page', 'blogtng'); 830 $form->addHidden('admin', 'search'); 831 832 $query = $INPUT->arr('query'); 833 $form->addElement(form_makeListBoxField('query[blog]', $blogs, $query['blog'], $this->getLang('blog'))); 834 $form->addElement(form_makeListBoxField('query[filter]', ['entry_title', 'entry_author', 'comment', 'comment_ip', 'tags'], $query['filter'], $this->getLang('filter'))); 835 $form->addElement(form_makeTextField('query[string]', $query['string'],'')); 836 837 $form->addElement(form_makeButton('submit', 'admin', $lang['btn_search'])); 838 $form->endFieldset(); 839 html_form('blogtng__search_form', $form); 840 841 ptln('</div>'); 842 } 843 844 /** 845 * Displays the limit selection form 846 * 847 * @param array $query Query parameters 848 * 849 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 850 */ 851 private function htmlLimitForm($query) { 852 global $lang; 853 854 $resultset = $query['resultset']; 855 856 ptln('<div class="level1">'); 857 858 $form = new Doku_Form(['id'=>'blogtng__'.$resultset.'_limit_form']); 859 $form->startFieldset(""); 860 $form->addHidden('page', 'blogtng'); 861 $form->addElement( 862 form_makeListBoxField($resultset . '-limit', 863 [5,10,15,20,25,30,40,50,100], 864 $query['limit'], 865 $this->getLang('numhits'))); 866 $form->addHidden($resultset . '-offset', $query['offset']); 867 $form->addElement(form_makeButton('submit', 'admin', $lang['btn_update'])); 868 $form->endFieldset(); 869 html_form('blogtng__'.$resultset.'_cnt_form', $form); 870 871 ptln('</div>'); 872 } 873 874 /** 875 * Create a comment with the posted from data 876 * 877 * @return Comment 878 */ 879 private function getPostedComment() 880 { 881 global $INPUT; 882 883 $comment = new Comment(); 884 $comment->setCid($INPUT->post->str('comment-cid')); 885 $comment->setPid($INPUT->post->str('comment-pid')); 886 $comment->setCreated($INPUT->post->str('comment-created')); 887 $comment->setStatus($INPUT->post->str('comment-status')); 888 $comment->setSource($INPUT->post->str('comment-source')); 889 $comment->setName($INPUT->post->str('comment-name')); 890 $comment->setMail($INPUT->post->str('comment-mail')); 891 $comment->setWeb($INPUT->post->str('comment-web')); 892 $comment->setAvatar($INPUT->post->str('comment-avatar')); 893 $comment->setText($INPUT->post->str('comment-text')); 894 return $comment; 895 } 896} 897