1f0fda08aSwikidesign<?php 2f0fda08aSwikidesign/** 3f0fda08aSwikidesign * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4f0fda08aSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 5f0fda08aSwikidesign */ 6f0fda08aSwikidesign 7*c3413364SGerrit Uitslaguse dokuwiki\Extension\Event; 8*c3413364SGerrit Uitslaguse dokuwiki\Subscriptions\SubscriberManager; 9*c3413364SGerrit Uitslaguse dokuwiki\Utf8\PhpString; 10*c3413364SGerrit Uitslag 11de7e6f00SGerrit Uitslag/** 12de7e6f00SGerrit Uitslag * Class action_plugin_discussion 13*c3413364SGerrit Uitslag * 14*c3413364SGerrit Uitslag * Data format of file metadir/<id>.comments: 15*c3413364SGerrit Uitslag * array = [ 16*c3413364SGerrit Uitslag * 'status' => int whether comments are 0=disabled/1=open/2=closed, 17*c3413364SGerrit Uitslag * 'number' => int number of visible comments, 18*c3413364SGerrit Uitslag * 'title' => string alternative title for discussion section 19*c3413364SGerrit Uitslag * 'comments' => [ 20*c3413364SGerrit Uitslag * '<cid>'=> [ 21*c3413364SGerrit Uitslag * 'cid' => string comment id - long random string 22*c3413364SGerrit Uitslag * 'raw' => string comment text, 23*c3413364SGerrit Uitslag * 'xhtml' => string rendered html, 24*c3413364SGerrit Uitslag * 'parent' => null|string null or empty string at highest level, otherwise comment id of parent 25*c3413364SGerrit Uitslag * 'replies' => string[] array with comment ids 26*c3413364SGerrit Uitslag * 'user' => [ 27*c3413364SGerrit Uitslag * 'id' => string, 28*c3413364SGerrit Uitslag * 'name' => string, 29*c3413364SGerrit Uitslag * 'mail' => string, 30*c3413364SGerrit Uitslag * 'address' => string, 31*c3413364SGerrit Uitslag * 'url' => string 32*c3413364SGerrit Uitslag * ], 33*c3413364SGerrit Uitslag * 'date' => [ 34*c3413364SGerrit Uitslag * 'created' => int timestamp, 35*c3413364SGerrit Uitslag * 'modified' => int (not defined if not modified) 36*c3413364SGerrit Uitslag * ], 37*c3413364SGerrit Uitslag * 'show' => bool, whether shown (still be moderated, or hidden by moderator or user self) 38*c3413364SGerrit Uitslag * ], 39*c3413364SGerrit Uitslag * ... 40*c3413364SGerrit Uitslag * ] 41*c3413364SGerrit Uitslag * 'subscribers' => [ 42*c3413364SGerrit Uitslag * '<mail>' => [ 43*c3413364SGerrit Uitslag * 'hash' => string unique token, 44*c3413364SGerrit Uitslag * 'active' => bool, true if confirmed 45*c3413364SGerrit Uitslag * 'confirmsent' => bool, true if confirmation mail is sent 46*c3413364SGerrit Uitslag * ], 47*c3413364SGerrit Uitslag * ... 48*c3413364SGerrit Uitslag * ] 49de7e6f00SGerrit Uitslag */ 50f0fda08aSwikidesignclass action_plugin_discussion extends DokuWiki_Action_Plugin{ 51f0fda08aSwikidesign 52de7e6f00SGerrit Uitslag /** @var helper_plugin_avatar */ 53*c3413364SGerrit Uitslag protected $avatar = null; 54*c3413364SGerrit Uitslag /** @var null|string */ 55*c3413364SGerrit Uitslag protected $style = null; 56*c3413364SGerrit Uitslag /** @var null|bool */ 57*c3413364SGerrit Uitslag protected $useAvatar = null; 58de7e6f00SGerrit Uitslag /** @var helper_plugin_discussion */ 59*c3413364SGerrit Uitslag protected $helper = null; 60e6b2f142Slupo49 61de7e6f00SGerrit Uitslag /** 62de7e6f00SGerrit Uitslag * load helper 63de7e6f00SGerrit Uitslag */ 64e6b2f142Slupo49 public function __construct() { 65e6b2f142Slupo49 $this->helper = plugin_load('helper', 'discussion'); 66e6b2f142Slupo49 } 67f1c6610eSpierre.spring 68de7e6f00SGerrit Uitslag /** 69de7e6f00SGerrit Uitslag * Register the handlers 70de7e6f00SGerrit Uitslag * 71*c3413364SGerrit Uitslag * @param Doku_Event_Handler $controller DokuWiki's event controller object. 72de7e6f00SGerrit Uitslag */ 73*c3413364SGerrit Uitslag public function register(Doku_Event_Handler $controller) { 74*c3413364SGerrit Uitslag $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleCommentActions'); 75*c3413364SGerrit Uitslag $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'renderCommentsSection'); 76*c3413364SGerrit Uitslag $controller->register_hook('INDEXER_PAGE_ADD', 'AFTER', $this, 'addCommentsToIndex', ['id' => 'page', 'text' => 'body']); 77*c3413364SGerrit Uitslag $controller->register_hook('FULLTEXT_SNIPPET_CREATE', 'BEFORE', $this, 'addCommentsToIndex', ['id' => 'id', 'text' => 'text']); 78*c3413364SGerrit Uitslag $controller->register_hook('INDEXER_VERSION_GET', 'BEFORE', $this, 'addIndexVersion', []); 79*c3413364SGerrit Uitslag $controller->register_hook('FULLTEXT_PHRASE_MATCH', 'AFTER', $this, 'fulltextPhraseMatchInComments', []); 80*c3413364SGerrit Uitslag $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, 'update_comment_status', []); 81*c3413364SGerrit Uitslag $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'addToolbarToCommentfield', []); 82*c3413364SGerrit Uitslag $controller->register_hook('TOOLBAR_DEFINE', 'AFTER', $this, 'modifyToolbar', []); 83*c3413364SGerrit Uitslag $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajaxPreviewComments', []); 84*c3413364SGerrit Uitslag $controller->register_hook('TPL_TOC_RENDER', 'BEFORE', $this, 'addDiscussionToTOC', []); 85b8fdc796SMichael Klier } 86b8fdc796SMichael Klier 87b8fdc796SMichael Klier /** 88b8fdc796SMichael Klier * Preview Comments 89b8fdc796SMichael Klier * 90b8fdc796SMichael Klier * @author Michael Klier <chi@chimeric.de> 91de7e6f00SGerrit Uitslag * 92de7e6f00SGerrit Uitslag * @param Doku_Event $event 93de7e6f00SGerrit Uitslag * @param $params 94b8fdc796SMichael Klier */ 95*c3413364SGerrit Uitslag public function ajaxPreviewComments(Doku_Event $event, $params) { 96*c3413364SGerrit Uitslag global $INPUT; 97b8fdc796SMichael Klier if($event->data != 'discussion_preview') return; 98*c3413364SGerrit Uitslag 99b8fdc796SMichael Klier $event->preventDefault(); 100b8fdc796SMichael Klier $event->stopPropagation(); 101b8fdc796SMichael Klier print p_locale_xhtml('preview'); 102b8fdc796SMichael Klier print '<div class="comment_preview">'; 103*c3413364SGerrit Uitslag if(!$INPUT->server->str('REMOTE_USER') && !$this->getConf('allowguests')) { 104b8fdc796SMichael Klier print p_locale_xhtml('denied'); 105b8fdc796SMichael Klier } else { 106*c3413364SGerrit Uitslag print $this->renderComment($INPUT->post->str('comment')); 107b8fdc796SMichael Klier } 108b8fdc796SMichael Klier print '</div>'; 1092d4bee9aSMichael Klier } 1102d4bee9aSMichael Klier 1112d4bee9aSMichael Klier /** 1125886c85bSMichael Klier * Adds a TOC item if a discussion exists 1135886c85bSMichael Klier * 1145886c85bSMichael Klier * @author Michael Klier <chi@chimeric.de> 115de7e6f00SGerrit Uitslag * 116de7e6f00SGerrit Uitslag * @param Doku_Event $event 117de7e6f00SGerrit Uitslag * @param $params 1185886c85bSMichael Klier */ 119*c3413364SGerrit Uitslag public function addDiscussionToTOC(Doku_Event $event, $params) { 1208c057533SMichael Klier global $ACT; 121*c3413364SGerrit Uitslag if($this->hasDiscussion($title) && $event->data && $ACT != 'admin') { 122*c3413364SGerrit Uitslag $tocitem = ['hid' => 'discussion__section', 1235886c85bSMichael Klier 'title' => $this->getLang('discussion'), 1245886c85bSMichael Klier 'type' => 'ul', 125*c3413364SGerrit Uitslag 'level' => 1]; 1265886c85bSMichael Klier 127*c3413364SGerrit Uitslag $event->data[] = $tocitem; 1285886c85bSMichael Klier } 1295886c85bSMichael Klier } 1305886c85bSMichael Klier 1315886c85bSMichael Klier /** 132*c3413364SGerrit Uitslag * Modify Toolbar for use with discussion plugin 1332d4bee9aSMichael Klier * 1342d4bee9aSMichael Klier * @author Michael Klier <chi@chimeric.de> 135de7e6f00SGerrit Uitslag * 136de7e6f00SGerrit Uitslag * @param Doku_Event $event 137de7e6f00SGerrit Uitslag * @param $param 1382d4bee9aSMichael Klier */ 139*c3413364SGerrit Uitslag public function modifyToolbar(Doku_Event $event, $param) { 1402d4bee9aSMichael Klier global $ACT; 1412d4bee9aSMichael Klier if($ACT != 'show') return; 1422d4bee9aSMichael Klier 143*c3413364SGerrit Uitslag if($this->hasDiscussion($title) && $this->getConf('wikisyntaxok')) { 144*c3413364SGerrit Uitslag $toolbar = []; 1452d4bee9aSMichael Klier foreach($event->data as $btn) { 1462d4bee9aSMichael Klier if($btn['type'] == 'mediapopup') continue; 1472d4bee9aSMichael Klier if($btn['type'] == 'signature') continue; 148310210d6SGina Haeussge if($btn['type'] == 'linkwiz') continue; 1491dc736fbSGerrit Uitslag if($btn['type'] == 'NewTable') continue; //skip button for Edittable Plugin 150*c3413364SGerrit Uitslag if(isset($btn['open']) && preg_match("/=+?/", $btn['open'])) continue; 151*c3413364SGerrit Uitslag 152*c3413364SGerrit Uitslag $toolbar[] = $btn; 1532d4bee9aSMichael Klier } 1542d4bee9aSMichael Klier $event->data = $toolbar; 1552d4bee9aSMichael Klier } 1562d4bee9aSMichael Klier } 1572d4bee9aSMichael Klier 1582d4bee9aSMichael Klier /** 1592d4bee9aSMichael Klier * Dirty workaround to add a toolbar to the discussion plugin 1602d4bee9aSMichael Klier * 1612d4bee9aSMichael Klier * @author Michael Klier <chi@chimeric.de> 162de7e6f00SGerrit Uitslag * 163de7e6f00SGerrit Uitslag * @param Doku_Event $event 164de7e6f00SGerrit Uitslag * @param $param 1652d4bee9aSMichael Klier */ 166*c3413364SGerrit Uitslag public function addToolbarToCommentfield(Doku_Event $event, $param) { 1672d4bee9aSMichael Klier global $ACT; 1682d4bee9aSMichael Klier global $ID; 1692d4bee9aSMichael Klier if($ACT != 'show') return; 1702d4bee9aSMichael Klier 171*c3413364SGerrit Uitslag if($this->hasDiscussion($title) && $this->getConf('wikisyntaxok')) { 1722d4bee9aSMichael Klier // FIXME ugly workaround, replace this once DW the toolbar code is more flexible 1732d4bee9aSMichael Klier @require_once(DOKU_INC.'inc/toolbar.php'); 1742d4bee9aSMichael Klier ob_start(); 1752d4bee9aSMichael Klier print 'NS = "' . getNS($ID) . '";'; // we have to define NS, otherwise we get get JS errors 1762d4bee9aSMichael Klier toolbar_JSdefines('toolbar'); 1772d4bee9aSMichael Klier $script = ob_get_clean(); 178*c3413364SGerrit Uitslag $event->data['script'][] = ['type' => 'text/javascript', 'charset' => "utf-8", '_data' => $script]; 1792d4bee9aSMichael Klier } 180f0fda08aSwikidesign } 181f0fda08aSwikidesign 182f0fda08aSwikidesign /** 183a1d93126SGina Haeussge * Handles comment actions, dispatches data processing routines 184de7e6f00SGerrit Uitslag * 185de7e6f00SGerrit Uitslag * @param Doku_Event $event 186de7e6f00SGerrit Uitslag * @param $param 187*c3413364SGerrit Uitslag * @return void 188f0fda08aSwikidesign */ 189*c3413364SGerrit Uitslag public function handleCommentActions(Doku_Event $event, $param) { 190*c3413364SGerrit Uitslag global $ID, $INFO, $lang, $INPUT; 191573e23a1Swikidesign 192a1d93126SGina Haeussge // handle newthread ACTs 193a1d93126SGina Haeussge if ($event->data == 'newthread') { 194a1d93126SGina Haeussge // we can handle it -> prevent others 195*c3413364SGerrit Uitslag $event->data = $this->newThread(); 196a1d93126SGina Haeussge } 197a1d93126SGina Haeussge 198a1d93126SGina Haeussge // enable captchas 199*c3413364SGerrit Uitslag if (in_array($INPUT->str('comment'), ['add', 'save'])) { 200*c3413364SGerrit Uitslag $this->captchaCheck(); 201*c3413364SGerrit Uitslag $this->recaptchaCheck(); 202bd6dc08eSAdrian Schlegel } 203a1d93126SGina Haeussge 2043011fb8bSMichael Klier // if we are not in show mode or someone wants to unsubscribe, that was all for now 205*c3413364SGerrit Uitslag if ($event->data != 'show' 206*c3413364SGerrit Uitslag && $event->data != 'discussion_unsubscribe' 207*c3413364SGerrit Uitslag && $event->data != 'discussion_confirmsubscribe') { 208*c3413364SGerrit Uitslag return; 209*c3413364SGerrit Uitslag } 210a1d93126SGina Haeussge 211b2f2e866SMichael Klier if ($event->data == 'discussion_unsubscribe' or $event->data == 'discussion_confirmsubscribe') { 212*c3413364SGerrit Uitslag if ($INPUT->has('hash')) { 2133011fb8bSMichael Klier $file = metaFN($ID, '.comments'); 2143011fb8bSMichael Klier $data = unserialize(io_readFile($file)); 215*c3413364SGerrit Uitslag $matchedMail = ''; 2169881d835SMichael Klier foreach ($data['subscribers'] as $mail => $info) { 2179881d835SMichael Klier // convert old style subscribers just in case 2189881d835SMichael Klier if (!is_array($info)) { 2199881d835SMichael Klier $hash = $data['subscribers'][$mail]; 2209881d835SMichael Klier $data['subscribers'][$mail]['hash'] = $hash; 2219881d835SMichael Klier $data['subscribers'][$mail]['active'] = true; 2229881d835SMichael Klier $data['subscribers'][$mail]['confirmsent'] = true; 2239881d835SMichael Klier } 2249881d835SMichael Klier 225*c3413364SGerrit Uitslag if ($data['subscribers'][$mail]['hash'] == $INPUT->str('hash')) { 226*c3413364SGerrit Uitslag $matchedMail = $mail; 2270c54624fSGina Haeussge } 2280c54624fSGina Haeussge } 2290c54624fSGina Haeussge 230*c3413364SGerrit Uitslag if ($matchedMail != '') { 231b2f2e866SMichael Klier if ($event->data == 'discussion_unsubscribe') { 232*c3413364SGerrit Uitslag unset($data['subscribers'][$matchedMail]); 233*c3413364SGerrit Uitslag msg(sprintf($lang['subscr_unsubscribe_success'], $matchedMail, $ID), 1); 234*c3413364SGerrit Uitslag } else { //$event->data == 'discussion_confirmsubscribe' 235*c3413364SGerrit Uitslag $data['subscribers'][$matchedMail]['active'] = true; 236*c3413364SGerrit Uitslag msg(sprintf($lang['subscr_subscribe_success'], $matchedMail, $ID), 1); 2379881d835SMichael Klier } 2389881d835SMichael Klier io_saveFile($file, serialize($data)); 2393011fb8bSMichael Klier $event->data = 'show'; 2403011fb8bSMichael Klier } 241de7e6f00SGerrit Uitslag 2429881d835SMichael Klier } 243*c3413364SGerrit Uitslag return; 2443011fb8bSMichael Klier } else { 245a1d93126SGina Haeussge // do the data processing for comments 246*c3413364SGerrit Uitslag $cid = $INPUT->str('cid'); 247*c3413364SGerrit Uitslag switch ($INPUT->str('comment')) { 248f0fda08aSwikidesign case 'add': 249*c3413364SGerrit Uitslag if(empty($INPUT->str('text'))) return; // don't add empty comments 250*c3413364SGerrit Uitslag 251*c3413364SGerrit Uitslag if($INPUT->server->has('REMOTE_USER') && !$this->getConf('adminimport')) { 252*c3413364SGerrit Uitslag $comment['user']['id'] = $INPUT->server->str('REMOTE_USER'); 25394c5d164SMichael Klier $comment['user']['name'] = $INFO['userinfo']['name']; 25494c5d164SMichael Klier $comment['user']['mail'] = $INFO['userinfo']['mail']; 255*c3413364SGerrit Uitslag } elseif(($INPUT->server->has('REMOTE_USER') && $this->getConf('adminimport') && $this->helper->isDiscussionMod()) 256*c3413364SGerrit Uitslag || !$INPUT->server->has('REMOTE_USER')) { 257*c3413364SGerrit Uitslag // don't add anonymous comments 258*c3413364SGerrit Uitslag if(empty($INPUT->str('name')) or empty($INPUT->str('mail'))) { 259*c3413364SGerrit Uitslag return; 260*c3413364SGerrit Uitslag } 261*c3413364SGerrit Uitslag 262*c3413364SGerrit Uitslag if(!mail_isvalid($INPUT->str('mail'))) { 263c9d36b5eSMichael Klier msg($lang['regbadmail'], -1); 264c9d36b5eSMichael Klier return; 265c9d36b5eSMichael Klier } else { 266*c3413364SGerrit Uitslag $comment['user']['id'] = 'test'.hsc($INPUT->str('user')); 267*c3413364SGerrit Uitslag $comment['user']['name'] = hsc($INPUT->str('name')); 268*c3413364SGerrit Uitslag $comment['user']['mail'] = hsc($INPUT->str('mail')); 26994c5d164SMichael Klier } 270c9d36b5eSMichael Klier } 271*c3413364SGerrit Uitslag $comment['user']['address'] = ($this->getConf('addressfield')) ? hsc($INPUT->str('address')) : ''; 272*c3413364SGerrit Uitslag $comment['user']['url'] = ($this->getConf('urlfield')) ? $this->checkURL($INPUT->str('url')) : ''; 273*c3413364SGerrit Uitslag $comment['subscribe'] = ($this->getConf('subscribe')) ? $INPUT->has('subscribe') : ''; 274*c3413364SGerrit Uitslag $comment['date'] = ['created' => $INPUT->str('date')]; 275*c3413364SGerrit Uitslag $comment['raw'] = cleanText($INPUT->str('text')); 276*c3413364SGerrit Uitslag $reply = $INPUT->str('reply'); 277e6b2f142Slupo49 if($this->getConf('moderate') && !$this->helper->isDiscussionMod()) { 278a44bc9f7SMichael Klier $comment['show'] = false; 279a44bc9f7SMichael Klier } else { 280a44bc9f7SMichael Klier $comment['show'] = true; 281a44bc9f7SMichael Klier } 282*c3413364SGerrit Uitslag $this->add($comment, $reply); 283f0fda08aSwikidesign break; 284f0fda08aSwikidesign 285f0fda08aSwikidesign case 'save': 286*c3413364SGerrit Uitslag $raw = cleanText($INPUT->str('text')); 287*c3413364SGerrit Uitslag $this->save([$cid], $raw); 288f0fda08aSwikidesign break; 289f0fda08aSwikidesign 2901e46d176Swikidesign case 'delete': 291*c3413364SGerrit Uitslag $this->save([$cid], ''); 2922ee3dca3Swikidesign break; 2931e46d176Swikidesign 294f0fda08aSwikidesign case 'toogle': 295*c3413364SGerrit Uitslag $this->save([$cid], '', 'toogle'); 296f0fda08aSwikidesign break; 297a1d93126SGina Haeussge } 2983011fb8bSMichael Klier } 299a1d93126SGina Haeussge } 300a1d93126SGina Haeussge 301a1d93126SGina Haeussge /** 302a1d93126SGina Haeussge * Main function; dispatches the visual comment actions 303a1d93126SGina Haeussge */ 304*c3413364SGerrit Uitslag public function renderCommentsSection(Doku_Event $event, $param) { 305*c3413364SGerrit Uitslag global $INPUT; 306a1d93126SGina Haeussge if ($event->data != 'show') return; // nothing to do for us 307a1d93126SGina Haeussge 308*c3413364SGerrit Uitslag $cid = $INPUT->str('cid'); 309*c3413364SGerrit Uitslag 310aa0d6cd7SGerrit Uitslag if(!$cid) { 311*c3413364SGerrit Uitslag $cid = $INPUT->str('reply'); 312aa0d6cd7SGerrit Uitslag } 313*c3413364SGerrit Uitslag var_dump($cid); 314*c3413364SGerrit Uitslag var_dump($INPUT->str('comment')); 315*c3413364SGerrit Uitslag switch ($INPUT->str('comment')) { 316a1d93126SGina Haeussge case 'edit': 317*c3413364SGerrit Uitslag $this->showDiscussionSection(null, $cid); 318a1d93126SGina Haeussge break; 319*c3413364SGerrit Uitslag default: //'reply' or no action specifiec 320*c3413364SGerrit Uitslag $this->showDiscussionSection($cid); 3212b18adb9SMichael Klier break; 322f0fda08aSwikidesign } 323f0fda08aSwikidesign } 324f0fda08aSwikidesign 325f0fda08aSwikidesign /** 326a1d93126SGina Haeussge * Redirects browser to given comment anchor 327a1d93126SGina Haeussge */ 328*c3413364SGerrit Uitslag protected function redirect($cid) { 329a1d93126SGina Haeussge global $ID; 330a1d93126SGina Haeussge global $ACT; 331a1d93126SGina Haeussge 332a1d93126SGina Haeussge if ($ACT !== 'show') return; 333a44bc9f7SMichael Klier 334e6b2f142Slupo49 if($this->getConf('moderate') && !$this->helper->isDiscussionMod()) { 335a44bc9f7SMichael Klier msg($this->getLang('moderation'), 1); 336a44bc9f7SMichael Klier @session_start(); 337a44bc9f7SMichael Klier global $MSG; 338a44bc9f7SMichael Klier $_SESSION[DOKU_COOKIE]['msg'] = $MSG; 339a44bc9f7SMichael Klier session_write_close(); 340a44bc9f7SMichael Klier $url = wl($ID); 341a44bc9f7SMichael Klier } else { 342a44bc9f7SMichael Klier $url = wl($ID) . '#comment_' . $cid; 343a44bc9f7SMichael Klier } 344e88de38aSAxel Beckert 345e88de38aSAxel Beckert if (function_exists('send_redirect')) { 346e88de38aSAxel Beckert send_redirect($url); 347e88de38aSAxel Beckert } else { 34869f42a0bSAxel Beckert header('Location: ' . $url); 349e88de38aSAxel Beckert } 3506d1f4f20SGina Haeussge exit(); 351a1d93126SGina Haeussge } 352a1d93126SGina Haeussge 353a1d93126SGina Haeussge /** 354d406a452SGerrit Uitslag * Checks config settings to enable/disable discussions 355f0bcde18SGerrit Uitslag * 356f0bcde18SGerrit Uitslag * @return bool 357f0bcde18SGerrit Uitslag */ 358f0bcde18SGerrit Uitslag public function isDiscussionEnabled() { 359f0bcde18SGerrit Uitslag global $INFO; 360f0bcde18SGerrit Uitslag 361d406a452SGerrit Uitslag if($this->getConf('excluded_ns') == '') { 362d406a452SGerrit Uitslag $isNamespaceExcluded = false; 363d406a452SGerrit Uitslag } else { 364f0bcde18SGerrit Uitslag $isNamespaceExcluded = preg_match($this->getConf('excluded_ns'), $INFO['namespace']); 365d406a452SGerrit Uitslag } 366f0bcde18SGerrit Uitslag 367f0bcde18SGerrit Uitslag if($this->getConf('automatic')) { 368f0bcde18SGerrit Uitslag if($isNamespaceExcluded) { 369f0bcde18SGerrit Uitslag return false; 370f0bcde18SGerrit Uitslag } else { 371f0bcde18SGerrit Uitslag return true; 372f0bcde18SGerrit Uitslag } 373f0bcde18SGerrit Uitslag } else { 374f0bcde18SGerrit Uitslag if($isNamespaceExcluded) { 375f0bcde18SGerrit Uitslag return true; 376f0bcde18SGerrit Uitslag } else { 377f0bcde18SGerrit Uitslag return false; 378f0bcde18SGerrit Uitslag } 379f0bcde18SGerrit Uitslag } 380f0bcde18SGerrit Uitslag } 381f0bcde18SGerrit Uitslag 382f0bcde18SGerrit Uitslag /** 383*c3413364SGerrit Uitslag * Shows all comments of the current page, if no reply or edit requested, then comment form is shown on the end 384*c3413364SGerrit Uitslag * 385*c3413364SGerrit Uitslag * @param null|string $reply comment id on which the user requested a reply 386*c3413364SGerrit Uitslag * @param null|string $edit comment id which the user requested for editing 387f0fda08aSwikidesign */ 388*c3413364SGerrit Uitslag protected function showDiscussionSection($reply = null, $edit = null) { 389*c3413364SGerrit Uitslag global $ID, $INFO, $INPUT; 390573e23a1Swikidesign 391479dd10fSwikidesign // get .comments meta file name 392f0fda08aSwikidesign $file = metaFN($ID, '.comments'); 393f0fda08aSwikidesign 394*c3413364SGerrit Uitslag if (!$INFO['exists']) return; 395*c3413364SGerrit Uitslag if (!@file_exists($file) && !$this->isDiscussionEnabled()) return; 396*c3413364SGerrit Uitslag if (!$INPUT->server->has('REMOTE_USER') && !$this->getConf('showguests')) return; 397f0fda08aSwikidesign 3982b18adb9SMichael Klier // load data 399*c3413364SGerrit Uitslag $data = []; 4002b18adb9SMichael Klier if (@file_exists($file)) { 4012b18adb9SMichael Klier $data = unserialize(io_readFile($file, false)); 402*c3413364SGerrit Uitslag // comments are turned off 403*c3413364SGerrit Uitslag if (!$data['status']) { 404*c3413364SGerrit Uitslag return; 405*c3413364SGerrit Uitslag } 406*c3413364SGerrit Uitslag var_dump($data); 407f0bcde18SGerrit Uitslag } elseif (!@file_exists($file) && $this->isDiscussionEnabled() && $INFO['exists']) { 4082b18adb9SMichael Klier // set status to show the comment form 4092b18adb9SMichael Klier $data['status'] = 1; 4102b18adb9SMichael Klier $data['number'] = 0; 4112b18adb9SMichael Klier } 412f0fda08aSwikidesign 413a1599850SMichael Klier // show discussion wrapper only on certain circumstances 414*c3413364SGerrit Uitslag if(empty($data['comments']) || !is_array($data['comments'])) { 415*c3413364SGerrit Uitslag $cnt = 0; 4163e19949cSMark Prins $keys = []; 417*c3413364SGerrit Uitslag } else { 418*c3413364SGerrit Uitslag $cnt = count($data['comments']); 419*c3413364SGerrit Uitslag $keys = array_keys($data['comments']); 4203e19949cSMark Prins } 421*c3413364SGerrit Uitslag 422de7e6f00SGerrit Uitslag $show = false; 423*c3413364SGerrit Uitslag if($cnt > 1 || ($cnt == 1 && $data['comments'][$keys[0]]['show'] == 1) 424*c3413364SGerrit Uitslag || $this->getConf('allowguests') || $INPUT->server->has('REMOTE_USER')) { 425a1599850SMichael Klier $show = true; 426f0fda08aSwikidesign // section title 42707c376bbSwikidesign $title = ($data['title'] ? hsc($data['title']) : $this->getLang('discussion')); 42846178401Slupo49 ptln('<div class="comment_wrapper" id="comment_wrapper">'); // the id value is used for visibility toggling the section 4294a0a1bd2Swikidesign ptln('<h2><a name="discussion__section" id="discussion__section">', 2); 4304a0a1bd2Swikidesign ptln($title, 4); 4314a0a1bd2Swikidesign ptln('</a></h2>', 2); 4324a0a1bd2Swikidesign ptln('<div class="level2 hfeed">', 2); 433a1599850SMichael Klier } 434a1599850SMichael Klier 435f0fda08aSwikidesign // now display the comments 436f0fda08aSwikidesign if (isset($data['comments'])) { 43731aab30eSGina Haeussge if (!$this->getConf('usethreading')) { 438*c3413364SGerrit Uitslag $data['comments'] = $this->flattenThreads($data['comments']); 439*c3413364SGerrit Uitslag uasort($data['comments'], [$this, 'sortCallback']); 44031aab30eSGina Haeussge } 441dbd9d5cdSMichael Klier if($this->getConf('newestfirst')) { 442dbd9d5cdSMichael Klier $data['comments'] = array_reverse($data['comments']); 443dbd9d5cdSMichael Klier } 444*c3413364SGerrit Uitslag foreach ($data['comments'] as $cid => $value) { 445*c3413364SGerrit Uitslag if ($cid == $edit) { // edit form 446*c3413364SGerrit Uitslag $this->showCommentForm($value['raw'], 'save', $edit); 447*c3413364SGerrit Uitslag } else { 448*c3413364SGerrit Uitslag $this->showCommentWithReplies($cid, $data, '', $reply); 449*c3413364SGerrit Uitslag } 450f0fda08aSwikidesign } 451f0fda08aSwikidesign } 452f0fda08aSwikidesign 453*c3413364SGerrit Uitslag // comment form shown on the end, if no comment form of $reply or $edit is requested before 454*c3413364SGerrit Uitslag if ($data['status'] == 1 && (!$reply || !$this->getConf('usethreading')) && !$edit) { 455*c3413364SGerrit Uitslag $this->showCommentForm(''); 456*c3413364SGerrit Uitslag } 457f0fda08aSwikidesign 458a1599850SMichael Klier if($show) { 4594a0a1bd2Swikidesign ptln('</div>', 2); // level2 hfeed 4604a0a1bd2Swikidesign ptln('</div>'); // comment_wrapper 461a1599850SMichael Klier } 462f0fda08aSwikidesign 46346178401Slupo49 // check for toggle print configuration 46446178401Slupo49 if($this->getConf('visibilityButton')) { 46546178401Slupo49 // print the hide/show discussion section button 466*c3413364SGerrit Uitslag $this->showDiscussionToggleButton(); 46746178401Slupo49 } 468f0fda08aSwikidesign } 469f0fda08aSwikidesign 470de7e6f00SGerrit Uitslag /** 471*c3413364SGerrit Uitslag * Remove the parent-child relation, such that the comment structure becomes flat 472*c3413364SGerrit Uitslag * 473*c3413364SGerrit Uitslag * @param array $comments array with all comments 474*c3413364SGerrit Uitslag * @param null|array $cids comment ids of replies, which should be flatten 475*c3413364SGerrit Uitslag * @return array returned array with flattened comment structure 476de7e6f00SGerrit Uitslag */ 477*c3413364SGerrit Uitslag protected function flattenThreads($comments, $cids = null) { 478*c3413364SGerrit Uitslag if (is_null($cids)) { 479*c3413364SGerrit Uitslag $cids = array_keys($comments); 480*c3413364SGerrit Uitslag } 48131aab30eSGina Haeussge 482*c3413364SGerrit Uitslag foreach($cids as $cid) { 48331aab30eSGina Haeussge if (!empty($comments[$cid]['replies'])) { 48431aab30eSGina Haeussge $rids = $comments[$cid]['replies']; 485*c3413364SGerrit Uitslag $comments = $this->flattenThreads($comments, $rids); 486*c3413364SGerrit Uitslag $comments[$cid]['replies'] = []; 48731aab30eSGina Haeussge } 48831aab30eSGina Haeussge $comments[$cid]['parent'] = ''; 48931aab30eSGina Haeussge } 49031aab30eSGina Haeussge return $comments; 49131aab30eSGina Haeussge } 49231aab30eSGina Haeussge 493f0fda08aSwikidesign /** 494f0fda08aSwikidesign * Adds a new comment and then displays all comments 495de7e6f00SGerrit Uitslag * 496*c3413364SGerrit Uitslag * @param array $comment with 497*c3413364SGerrit Uitslag * 'raw' => string comment text, 498*c3413364SGerrit Uitslag * 'user' => [ 499*c3413364SGerrit Uitslag * 'id' => string, 500*c3413364SGerrit Uitslag * 'name' => string, 501*c3413364SGerrit Uitslag * 'mail' => string 502*c3413364SGerrit Uitslag * ], 503*c3413364SGerrit Uitslag * 'date' => [ 504*c3413364SGerrit Uitslag * 'created' => int timestamp 505*c3413364SGerrit Uitslag * ] 506*c3413364SGerrit Uitslag * 'show' => bool 507*c3413364SGerrit Uitslag * 'subscribe' => bool 508*c3413364SGerrit Uitslag * @param string $parent comment id of parent 509de7e6f00SGerrit Uitslag * @return bool 510f0fda08aSwikidesign */ 511*c3413364SGerrit Uitslag protected function add($comment, $parent) { 512*c3413364SGerrit Uitslag global $ID, $TEXT, $INPUT; 513f0fda08aSwikidesign 514*c3413364SGerrit Uitslag $originalTxt = $TEXT; // set $TEXT to comment text for wordblock check 515f0fda08aSwikidesign $TEXT = $comment['raw']; 516f0fda08aSwikidesign 517f0fda08aSwikidesign // spamcheck against the DokuWiki blacklist 518f0fda08aSwikidesign if (checkwordblock()) { 519f0fda08aSwikidesign msg($this->getLang('wordblock'), -1); 520f0fda08aSwikidesign return false; 521f0fda08aSwikidesign } 522f0fda08aSwikidesign 523*c3413364SGerrit Uitslag if (!$this->getConf('allowguests') 524*c3413364SGerrit Uitslag && $comment['user']['id'] != $INPUT->server->str('REMOTE_USER') 5254cded5e1SGerrit Uitslag ) { 5263011fb8bSMichael Klier return false; // guest comments not allowed 5274cded5e1SGerrit Uitslag } 5283011fb8bSMichael Klier 529*c3413364SGerrit Uitslag $TEXT = $originalTxt; // restore global $TEXT 530f0fda08aSwikidesign 531f0fda08aSwikidesign // get discussion meta file name 532f0fda08aSwikidesign $file = metaFN($ID, '.comments'); 533f0fda08aSwikidesign 5342b18adb9SMichael Klier // create comments file if it doesn't exist yet 5352b18adb9SMichael Klier if(!@file_exists($file)) { 536*c3413364SGerrit Uitslag $data = ['status' => 1, 'number' => 0]; 5372b18adb9SMichael Klier io_saveFile($file, serialize($data)); 5382b18adb9SMichael Klier } else { 539f0fda08aSwikidesign $data = unserialize(io_readFile($file, false)); 540*c3413364SGerrit Uitslag // comments off or closed 541*c3413364SGerrit Uitslag if ($data['status'] != 1) { 542*c3413364SGerrit Uitslag return false; 543*c3413364SGerrit Uitslag } 5442b18adb9SMichael Klier } 5452b18adb9SMichael Klier 5463011fb8bSMichael Klier if ($comment['date']['created']) { 5473011fb8bSMichael Klier $date = strtotime($comment['date']['created']); 5483011fb8bSMichael Klier } else { 5493011fb8bSMichael Klier $date = time(); 5503011fb8bSMichael Klier } 551f0fda08aSwikidesign 5523011fb8bSMichael Klier if ($date == -1) { 5533011fb8bSMichael Klier $date = time(); 5543011fb8bSMichael Klier } 5553011fb8bSMichael Klier 5566046f25cSwikidesign $cid = md5($comment['user']['id'].$date); // create a unique id 557f0fda08aSwikidesign 5583011fb8bSMichael Klier if (!is_array($data['comments'][$parent])) { 559*c3413364SGerrit Uitslag $parent = null; // invalid parent comment 5603011fb8bSMichael Klier } 561f0fda08aSwikidesign 562f0fda08aSwikidesign // render the comment 563*c3413364SGerrit Uitslag $xhtml = $this->renderComment($comment['raw']); 564f0fda08aSwikidesign 565f0fda08aSwikidesign // fill in the new comment 566*c3413364SGerrit Uitslag $data['comments'][$cid] = [ 5676046f25cSwikidesign 'user' => $comment['user'], 568*c3413364SGerrit Uitslag 'date' => ['created' => $date], 5696046f25cSwikidesign 'raw' => $comment['raw'], 570f0fda08aSwikidesign 'xhtml' => $xhtml, 571f0fda08aSwikidesign 'parent' => $parent, 572*c3413364SGerrit Uitslag 'replies' => [], 573a44bc9f7SMichael Klier 'show' => $comment['show'] 574*c3413364SGerrit Uitslag ]; 575f0fda08aSwikidesign 5763011fb8bSMichael Klier if($comment['subscribe']) { 5773011fb8bSMichael Klier $mail = $comment['user']['mail']; 5783011fb8bSMichael Klier if($data['subscribers']) { 5793011fb8bSMichael Klier if(!$data['subscribers'][$mail]) { 5809881d835SMichael Klier $data['subscribers'][$mail]['hash'] = md5($mail . mt_rand()); 5819881d835SMichael Klier $data['subscribers'][$mail]['active'] = false; 5829881d835SMichael Klier $data['subscribers'][$mail]['confirmsent'] = false; 5839881d835SMichael Klier } else { 5849881d835SMichael Klier // convert old style subscribers and set them active 5859881d835SMichael Klier if(!is_array($data['subscribers'][$mail])) { 5869881d835SMichael Klier $hash = $data['subscribers'][$mail]; 5879881d835SMichael Klier $data['subscribers'][$mail]['hash'] = $hash; 5889881d835SMichael Klier $data['subscribers'][$mail]['active'] = true; 5899881d835SMichael Klier $data['subscribers'][$mail]['confirmsent'] = true; 5909881d835SMichael Klier } 5913011fb8bSMichael Klier } 5923011fb8bSMichael Klier } else { 5939881d835SMichael Klier $data['subscribers'][$mail]['hash'] = md5($mail . mt_rand()); 5949881d835SMichael Klier $data['subscribers'][$mail]['active'] = false; 5959881d835SMichael Klier $data['subscribers'][$mail]['confirmsent'] = false; 5963011fb8bSMichael Klier } 5973011fb8bSMichael Klier } 5983011fb8bSMichael Klier 599f0fda08aSwikidesign // update parent comment 6004cded5e1SGerrit Uitslag if ($parent) { 6014cded5e1SGerrit Uitslag $data['comments'][$parent]['replies'][] = $cid; 6024cded5e1SGerrit Uitslag } 603f0fda08aSwikidesign 604f0fda08aSwikidesign // update the number of comments 605f0fda08aSwikidesign $data['number']++; 606f0fda08aSwikidesign 607f0fda08aSwikidesign // notify subscribers of the page 6088b42cefbSMichael Klier $data['comments'][$cid]['cid'] = $cid; 609*c3413364SGerrit Uitslag $this->notify($data['comments'][$cid], $data['subscribers']); 610f0fda08aSwikidesign 6119881d835SMichael Klier // save the comment metadata file 6129881d835SMichael Klier io_saveFile($file, serialize($data)); 613*c3413364SGerrit Uitslag $this->addLogEntry($date, $ID, 'cc', '', $cid); 6149881d835SMichael Klier 615*c3413364SGerrit Uitslag $this->redirect($cid); 616f0fda08aSwikidesign return true; 617f0fda08aSwikidesign } 618f0fda08aSwikidesign 619f0fda08aSwikidesign /** 620f0fda08aSwikidesign * Saves the comment with the given ID and then displays all comments 621de7e6f00SGerrit Uitslag * 622*c3413364SGerrit Uitslag * @param array|string $cids array with comment ids to save, or a single string comment id 623*c3413364SGerrit Uitslag * @param string $raw if empty comment is deleted, otherwise edited text is stored (note: storing is per one cid!) 624*c3413364SGerrit Uitslag * @param string|null $act 'toogle', 'show', 'hide', null. If null, it depends on $raw 625*c3413364SGerrit Uitslag * @return bool succeed? 626f0fda08aSwikidesign */ 627*c3413364SGerrit Uitslag public function save($cids, $raw, $act = null) { 628*c3413364SGerrit Uitslag global $ID, $INPUT; 629f0fda08aSwikidesign 630*c3413364SGerrit Uitslag if(empty($cids)) return false; // do nothing if we get no comment id 631757550e8SMichael Klier 6322ee3dca3Swikidesign if ($raw) { 6332ee3dca3Swikidesign global $TEXT; 6342ee3dca3Swikidesign 635f0fda08aSwikidesign $otxt = $TEXT; // set $TEXT to comment text for wordblock check 636f0fda08aSwikidesign $TEXT = $raw; 637f0fda08aSwikidesign 638f0fda08aSwikidesign // spamcheck against the DokuWiki blacklist 639f0fda08aSwikidesign if (checkwordblock()) { 640f0fda08aSwikidesign msg($this->getLang('wordblock'), -1); 641f0fda08aSwikidesign return false; 642f0fda08aSwikidesign } 643f0fda08aSwikidesign 644f0fda08aSwikidesign $TEXT = $otxt; // restore global $TEXT 6452ee3dca3Swikidesign } 646f0fda08aSwikidesign 647f0fda08aSwikidesign // get discussion meta file name 648f0fda08aSwikidesign $file = metaFN($ID, '.comments'); 649f0fda08aSwikidesign $data = unserialize(io_readFile($file, false)); 650f0fda08aSwikidesign 651*c3413364SGerrit Uitslag if (!is_array($cids)) { 652*c3413364SGerrit Uitslag $cids = [$cids]; 653*c3413364SGerrit Uitslag } 654264b7327Swikidesign foreach ($cids as $cid) { 655264b7327Swikidesign 6566046f25cSwikidesign if (is_array($data['comments'][$cid]['user'])) { 6576046f25cSwikidesign $user = $data['comments'][$cid]['user']['id']; 6586046f25cSwikidesign $convert = false; 6596046f25cSwikidesign } else { 6606046f25cSwikidesign $user = $data['comments'][$cid]['user']; 6616046f25cSwikidesign $convert = true; 6626046f25cSwikidesign } 6636046f25cSwikidesign 664f0fda08aSwikidesign // someone else was trying to edit our comment -> abort 665*c3413364SGerrit Uitslag if ($user != $INPUT->server->str('REMOTE_USER') && !$this->helper->isDiscussionMod()) { 666*c3413364SGerrit Uitslag return false; 667*c3413364SGerrit Uitslag } 668f0fda08aSwikidesign 669f0fda08aSwikidesign $date = time(); 670f0fda08aSwikidesign 6716046f25cSwikidesign // need to convert to new format? 6726046f25cSwikidesign if ($convert) { 673*c3413364SGerrit Uitslag $data['comments'][$cid]['user'] = [ 6746046f25cSwikidesign 'id' => $user, 6756046f25cSwikidesign 'name' => $data['comments'][$cid]['name'], 6766046f25cSwikidesign 'mail' => $data['comments'][$cid]['mail'], 6776046f25cSwikidesign 'url' => $data['comments'][$cid]['url'], 6786046f25cSwikidesign 'address' => $data['comments'][$cid]['address'], 679*c3413364SGerrit Uitslag ]; 680*c3413364SGerrit Uitslag $data['comments'][$cid]['date'] = [ 6816046f25cSwikidesign 'created' => $data['comments'][$cid]['date'] 682*c3413364SGerrit Uitslag ]; 6836046f25cSwikidesign } 6846046f25cSwikidesign 685264b7327Swikidesign if ($act == 'toogle') { // toogle visibility 686f0fda08aSwikidesign $now = $data['comments'][$cid]['show']; 687f0fda08aSwikidesign $data['comments'][$cid]['show'] = !$now; 688*c3413364SGerrit Uitslag $data['number'] = $this->countVisibleComments($data); 689f0fda08aSwikidesign 690f0fda08aSwikidesign $type = ($data['comments'][$cid]['show'] ? 'sc' : 'hc'); 691f0fda08aSwikidesign 692264b7327Swikidesign } elseif ($act == 'show') { // show comment 693264b7327Swikidesign $data['comments'][$cid]['show'] = true; 694*c3413364SGerrit Uitslag $data['number'] = $this->countVisibleComments($data); 695264b7327Swikidesign 696573e23a1Swikidesign $type = 'sc'; // show comment 697264b7327Swikidesign 698264b7327Swikidesign } elseif ($act == 'hide') { // hide comment 699264b7327Swikidesign $data['comments'][$cid]['show'] = false; 700*c3413364SGerrit Uitslag $data['number'] = $this->countVisibleComments($data); 701264b7327Swikidesign 702573e23a1Swikidesign $type = 'hc'; // hide comment 703264b7327Swikidesign 704f0fda08aSwikidesign } elseif (!$raw) { // remove the comment 705*c3413364SGerrit Uitslag $data['comments'] = $this->removeComment($cid, $data['comments']); 706*c3413364SGerrit Uitslag $data['number'] = $this->countVisibleComments($data); 707f0fda08aSwikidesign 708573e23a1Swikidesign $type = 'dc'; // delete comment 709f0fda08aSwikidesign 710f0fda08aSwikidesign } else { // save changed comment 711*c3413364SGerrit Uitslag $xhtml = $this->renderComment($raw); 712f0fda08aSwikidesign 713f0fda08aSwikidesign // now change the comment's content 7146046f25cSwikidesign $data['comments'][$cid]['date']['modified'] = $date; 7156046f25cSwikidesign $data['comments'][$cid]['raw'] = $raw; 716f0fda08aSwikidesign $data['comments'][$cid]['xhtml'] = $xhtml; 717f0fda08aSwikidesign 718573e23a1Swikidesign $type = 'ec'; // edit comment 719f0fda08aSwikidesign } 720264b7327Swikidesign } 721264b7327Swikidesign 722f0fda08aSwikidesign // save the comment metadata file 723f0fda08aSwikidesign io_saveFile($file, serialize($data)); 724*c3413364SGerrit Uitslag $this->addLogEntry($date, $ID, $type, '', $cid); 725f0fda08aSwikidesign 726*c3413364SGerrit Uitslag $this->redirect($cid); 727f0fda08aSwikidesign return true; 728f0fda08aSwikidesign } 729f0fda08aSwikidesign 730f0fda08aSwikidesign /** 731*c3413364SGerrit Uitslag * Recursive function to remove a comment from the data array 732*c3413364SGerrit Uitslag * 733*c3413364SGerrit Uitslag * @param string $cid comment id to be removed 734*c3413364SGerrit Uitslag * @param array $comments array with all comments 735*c3413364SGerrit Uitslag * @return array returns modified array with all remaining comments 736efbe59d0Swikidesign */ 737*c3413364SGerrit Uitslag protected function removeComment($cid, $comments) { 738efbe59d0Swikidesign if (is_array($comments[$cid]['replies'])) { 739efbe59d0Swikidesign foreach ($comments[$cid]['replies'] as $rid) { 740*c3413364SGerrit Uitslag $comments = $this->removeComment($rid, $comments); 741efbe59d0Swikidesign } 742efbe59d0Swikidesign } 743efbe59d0Swikidesign unset($comments[$cid]); 744efbe59d0Swikidesign return $comments; 745efbe59d0Swikidesign } 746efbe59d0Swikidesign 747efbe59d0Swikidesign /** 748f0fda08aSwikidesign * Prints an individual comment 749de7e6f00SGerrit Uitslag * 750*c3413364SGerrit Uitslag * @param string $cid comment id 751*c3413364SGerrit Uitslag * @param array $data array with all comments by reference 752*c3413364SGerrit Uitslag * @param string $parent comment id of parent 753*c3413364SGerrit Uitslag * @param string $reply comment id on which the user requested a reply 754*c3413364SGerrit Uitslag * @param bool $isVisible is marked as visible 755f0fda08aSwikidesign */ 756*c3413364SGerrit Uitslag protected function showCommentWithReplies($cid, &$data, $parent = '', $reply = '', $isVisible = true) { 757*c3413364SGerrit Uitslag // comment was removed 758*c3413364SGerrit Uitslag if (!isset($data['comments'][$cid])) { 759*c3413364SGerrit Uitslag return; 760*c3413364SGerrit Uitslag } 761f0fda08aSwikidesign $comment = $data['comments'][$cid]; 762f0fda08aSwikidesign 763*c3413364SGerrit Uitslag // corrupt datatype 764*c3413364SGerrit Uitslag if (!is_array($comment)) { 765*c3413364SGerrit Uitslag return; 766*c3413364SGerrit Uitslag } 767f0fda08aSwikidesign 768*c3413364SGerrit Uitslag // handle only replies to given parent comment 769*c3413364SGerrit Uitslag if ($comment['parent'] != $parent) { 770*c3413364SGerrit Uitslag return; 771*c3413364SGerrit Uitslag } 772f0fda08aSwikidesign 773*c3413364SGerrit Uitslag // comment hidden 774*c3413364SGerrit Uitslag if (!$comment['show']) { 775*c3413364SGerrit Uitslag if ($this->helper->isDiscussionMod()) { 776*c3413364SGerrit Uitslag $hidden = ' comment_hidden'; 777*c3413364SGerrit Uitslag } else { 778*c3413364SGerrit Uitslag return; 779*c3413364SGerrit Uitslag } 7804a0a1bd2Swikidesign } else { 7814a0a1bd2Swikidesign $hidden = ''; 782f0fda08aSwikidesign } 783f0fda08aSwikidesign 784f1c6610eSpierre.spring // print the actual comment 785*c3413364SGerrit Uitslag $this->showComment($cid, $data, $parent, $reply, $isVisible, $hidden); 786f1c6610eSpierre.spring // replies to this comment entry? 787*c3413364SGerrit Uitslag $this->showReplies($cid, $data, $reply, $isVisible); 788f1c6610eSpierre.spring // reply form 789*c3413364SGerrit Uitslag $this->showReplyForm($cid, $reply); 790f1c6610eSpierre.spring } 791f1c6610eSpierre.spring 792de7e6f00SGerrit Uitslag /** 793*c3413364SGerrit Uitslag * Print the comment 794*c3413364SGerrit Uitslag * 795*c3413364SGerrit Uitslag * @param string $cid comment id 796*c3413364SGerrit Uitslag * @param array $data array with all comments by reference 797*c3413364SGerrit Uitslag * @param string $parent comment id of parent 798*c3413364SGerrit Uitslag * @param string $reply comment id on which the user requested a reply 799*c3413364SGerrit Uitslag * @param bool $isVisible is marked as visible 800*c3413364SGerrit Uitslag * @param string $hidden extra class, for the admin only hidden view 801de7e6f00SGerrit Uitslag */ 802*c3413364SGerrit Uitslag protected function showComment($cid, &$data, $parent, $reply, $isVisible, $hidden) { 803*c3413364SGerrit Uitslag global $conf, $lang, $HIGH, $INPUT; 804f1c6610eSpierre.spring $comment = $data['comments'][$cid]; 805f1c6610eSpierre.spring 806f0fda08aSwikidesign // comment head with date and user data 8074a0a1bd2Swikidesign ptln('<div class="hentry'.$hidden.'">', 4); 8084a0a1bd2Swikidesign ptln('<div class="comment_head">', 6); 8091810ba9cSMichael Klier ptln('<a name="comment_'.$cid.'" id="comment_'.$cid.'"></a>', 8); 8104a0a1bd2Swikidesign $head = '<span class="vcard author">'; 811f0fda08aSwikidesign 8126046f25cSwikidesign // prepare variables 8136046f25cSwikidesign if (is_array($comment['user'])) { // new format 8146046f25cSwikidesign $user = $comment['user']['id']; 8156046f25cSwikidesign $name = $comment['user']['name']; 8166046f25cSwikidesign $mail = $comment['user']['mail']; 8176046f25cSwikidesign $url = $comment['user']['url']; 8186046f25cSwikidesign $address = $comment['user']['address']; 8196046f25cSwikidesign } else { // old format 8206046f25cSwikidesign $user = $comment['user']; 8216046f25cSwikidesign $name = $comment['name']; 8226046f25cSwikidesign $mail = $comment['mail']; 8236046f25cSwikidesign $url = $comment['url']; 8246046f25cSwikidesign $address = $comment['address']; 8256046f25cSwikidesign } 8266046f25cSwikidesign if (is_array($comment['date'])) { // new format 8276046f25cSwikidesign $created = $comment['date']['created']; 828*c3413364SGerrit Uitslag $modified = $comment['date']['modified'] ?: null; 8296046f25cSwikidesign } else { // old format 8306046f25cSwikidesign $created = $comment['date']; 8316046f25cSwikidesign $modified = $comment['edited']; 8326046f25cSwikidesign } 8336046f25cSwikidesign 8340ff5ab97SMichael Klier // show username or real name? 835*c3413364SGerrit Uitslag if (!$this->getConf('userealname') && $user) { 8360ff5ab97SMichael Klier $showname = $user; 8370ff5ab97SMichael Klier } else { 8380ff5ab97SMichael Klier $showname = $name; 8390ff5ab97SMichael Klier } 8400ff5ab97SMichael Klier 841ce7b17cfSwikidesign // show avatar image? 842*c3413364SGerrit Uitslag if ($this->useAvatar()) { 84312ca6034SMichael Klier $user_data['name'] = $name; 84412ca6034SMichael Klier $user_data['user'] = $user; 84512ca6034SMichael Klier $user_data['mail'] = $mail; 84612ca6034SMichael Klier $avatar = $this->avatar->getXHTML($user_data, $name, 'left'); 847*c3413364SGerrit Uitslag if($avatar) { 848*c3413364SGerrit Uitslag $head .= $avatar; 849*c3413364SGerrit Uitslag } 850f0fda08aSwikidesign } 851f0fda08aSwikidesign 8526046f25cSwikidesign if ($this->getConf('linkemail') && $mail) { 8530ff5ab97SMichael Klier $head .= $this->email($mail, $showname, 'email fn'); 8546046f25cSwikidesign } elseif ($url) { 855*c3413364SGerrit Uitslag $head .= $this->external_link($this->checkURL($url), $showname, 'urlextern url fn'); 856f0fda08aSwikidesign } else { 8570ff5ab97SMichael Klier $head .= '<span class="fn">'.$showname.'</span>'; 858f0fda08aSwikidesign } 8596f1f13d6SMatthias Schulte 8604cded5e1SGerrit Uitslag if ($address) { 8614cded5e1SGerrit Uitslag $head .= ', <span class="adr">'.$address.'</span>'; 8624cded5e1SGerrit Uitslag } 8634a0a1bd2Swikidesign $head .= '</span>, '. 864f014bc86SMichael Klier '<abbr class="published" title="'. strftime('%Y-%m-%dT%H:%M:%SZ', $created) .'">'. 8656f1f13d6SMatthias Schulte dformat($created, $conf['dformat']).'</abbr>'; 8669c0e06f3SMoisés Braga Ribeiro if ($modified) { 8679c0e06f3SMoisés Braga Ribeiro $head .= ', <abbr class="updated" title="'. 8686f1f13d6SMatthias Schulte strftime('%Y-%m-%dT%H:%M:%SZ', $modified).'">'.dformat($modified, $conf['dformat']). 8699c0e06f3SMoisés Braga Ribeiro '</abbr>'; 8704cded5e1SGerrit Uitslag } 871f014bc86SMichael Klier ptln($head, 8); 8724a0a1bd2Swikidesign ptln('</div>', 6); // class="comment_head" 873f0fda08aSwikidesign 874f0fda08aSwikidesign // main comment content 8754a0a1bd2Swikidesign ptln('<div class="comment_body entry-content"'. 876*c3413364SGerrit Uitslag ($this->useAvatar() ? $this->getWidthStyle() : '').'>', 6); 87715cdad37Spierre.spring echo ($HIGH?html_hilight($comment['xhtml'],$HIGH):$comment['xhtml']).DOKU_LF; 8784a0a1bd2Swikidesign ptln('</div>', 6); // class="comment_body" 879f0fda08aSwikidesign 880*c3413364SGerrit Uitslag if ($isVisible) { 8811184c36aSwikidesign ptln('<div class="comment_buttons">', 6); 882f0fda08aSwikidesign 883f0fda08aSwikidesign // show reply button? 884*c3413364SGerrit Uitslag if ($data['status'] == 1 && !$reply && $comment['show'] 885*c3413364SGerrit Uitslag && ($this->getConf('allowguests') || $INPUT->server->has('REMOTE_USER')) 886*c3413364SGerrit Uitslag && $this->getConf('usethreading') 8874cded5e1SGerrit Uitslag ) { 888*c3413364SGerrit Uitslag $this->showButton($cid, $this->getLang('btn_reply'), 'reply', true); 8894cded5e1SGerrit Uitslag } 890f0fda08aSwikidesign 8911184c36aSwikidesign // show edit, show/hide and delete button? 892*c3413364SGerrit Uitslag if (($user == $INPUT->server->str('REMOTE_USER') && $user != '') || $this->helper->isDiscussionMod()) { 893*c3413364SGerrit Uitslag $this->showButton($cid, $lang['btn_secedit'], 'edit', true); 8941184c36aSwikidesign $label = ($comment['show'] ? $this->getLang('btn_hide') : $this->getLang('btn_show')); 895*c3413364SGerrit Uitslag $this->showButton($cid, $label, 'toogle'); 896*c3413364SGerrit Uitslag $this->showButton($cid, $lang['btn_delete'], 'delete'); 897f0fda08aSwikidesign } 8981184c36aSwikidesign ptln('</div>', 6); // class="comment_buttons" 8991184c36aSwikidesign } 9001184c36aSwikidesign ptln('</div>', 4); // class="hentry" 901f0fda08aSwikidesign } 902f0fda08aSwikidesign 903de7e6f00SGerrit Uitslag /** 904*c3413364SGerrit Uitslag * If requested by user, show comment form to write a reply 905*c3413364SGerrit Uitslag * 906*c3413364SGerrit Uitslag * @param string $cid current comment id 907*c3413364SGerrit Uitslag * @param string $reply comment id on which the user requested a reply 908de7e6f00SGerrit Uitslag */ 909*c3413364SGerrit Uitslag protected function showReplyForm($cid, $reply) 910f1c6610eSpierre.spring { 91131aab30eSGina Haeussge if ($this->getConf('usethreading') && $reply == $cid) { 9124a0a1bd2Swikidesign ptln('<div class="comment_replies">', 4); 913*c3413364SGerrit Uitslag $this->showCommentForm('', 'add', $cid); 9144a0a1bd2Swikidesign ptln('</div>', 4); // class="comment_replies" 915f0fda08aSwikidesign } 916f0fda08aSwikidesign } 917f0fda08aSwikidesign 918de7e6f00SGerrit Uitslag /** 919*c3413364SGerrit Uitslag * 920*c3413364SGerrit Uitslag * 921*c3413364SGerrit Uitslag * @param string $cid comment id 922*c3413364SGerrit Uitslag * @param array $data array with all comments by reference 923de7e6f00SGerrit Uitslag * @param string $reply 924*c3413364SGerrit Uitslag * @param bool $isVisible 925de7e6f00SGerrit Uitslag */ 926*c3413364SGerrit Uitslag protected function showReplies($cid, &$data, $reply, &$isVisible) 927f1c6610eSpierre.spring { 928f1c6610eSpierre.spring $comment = $data['comments'][$cid]; 929f1c6610eSpierre.spring if (!count($comment['replies'])) { 930f1c6610eSpierre.spring return; 931f1c6610eSpierre.spring } 932*c3413364SGerrit Uitslag ptln('<div class="comment_replies"'.$this->getWidthStyle().'>', 4); 933*c3413364SGerrit Uitslag $isVisible = ($comment['show'] && $isVisible); 934f1c6610eSpierre.spring foreach ($comment['replies'] as $rid) { 935*c3413364SGerrit Uitslag $this->showCommentWithReplies($rid, $data, $cid, $reply, $isVisible); 936f1c6610eSpierre.spring } 937f1c6610eSpierre.spring ptln('</div>', 4); 938f1c6610eSpierre.spring } 939f1c6610eSpierre.spring 940de7e6f00SGerrit Uitslag /** 941de7e6f00SGerrit Uitslag * Is an avatar displayed? 942de7e6f00SGerrit Uitslag * 943de7e6f00SGerrit Uitslag * @return bool 944de7e6f00SGerrit Uitslag */ 945*c3413364SGerrit Uitslag protected function useAvatar() 946f1c6610eSpierre.spring { 947*c3413364SGerrit Uitslag if (is_null($this->useAvatar)) { 948*c3413364SGerrit Uitslag $this->useAvatar = $this->getConf('useavatar') 949*c3413364SGerrit Uitslag && ($this->avatar = $this->loadHelper('avatar', false)); 950f1c6610eSpierre.spring } 951*c3413364SGerrit Uitslag return $this->useAvatar; 952f1c6610eSpierre.spring } 953f1c6610eSpierre.spring 954de7e6f00SGerrit Uitslag /** 955de7e6f00SGerrit Uitslag * Calculate width of indent 956de7e6f00SGerrit Uitslag * 957de7e6f00SGerrit Uitslag * @return string 958de7e6f00SGerrit Uitslag */ 959*c3413364SGerrit Uitslag protected function getWidthStyle() { 960f1c6610eSpierre.spring if (is_null($this->style)){ 961*c3413364SGerrit Uitslag if ($this->useAvatar()) { 962f1c6610eSpierre.spring $this->style = ' style="margin-left: '.($this->avatar->getConf('size') + 14).'px;"'; 963f1c6610eSpierre.spring } else { 964f1c6610eSpierre.spring $this->style = ' style="margin-left: 20px;"'; 965f1c6610eSpierre.spring } 966f1c6610eSpierre.spring } 967f1c6610eSpierre.spring return $this->style; 968f1c6610eSpierre.spring } 969f1c6610eSpierre.spring 970f0fda08aSwikidesign /** 971*c3413364SGerrit Uitslag * Show the button which toggles between show/hide of the entire discussion section 97246178401Slupo49 */ 973*c3413364SGerrit Uitslag protected function showDiscussionToggleButton() { 97446178401Slupo49 ptln('<div id="toggle_button" class="toggle_button" style="text-align: right;">'); 97511711461Shaobug ptln('<input type="submit" id="discussion__btn_toggle_visibility" title="Toggle Visibiliy" class="button" value="'.$this->getLang('toggle_display').'">'); 97646178401Slupo49 ptln('</div>'); 97746178401Slupo49 } 97846178401Slupo49 97946178401Slupo49 /** 980f0fda08aSwikidesign * Outputs the comment form 981f0fda08aSwikidesign */ 982*c3413364SGerrit Uitslag protected function showCommentForm($raw = '', $act = 'add', $cid = null) { 983*c3413364SGerrit Uitslag global $lang, $conf, $ID, $INPUT; 984f0fda08aSwikidesign 985f0fda08aSwikidesign // not for unregistered users when guest comments aren't allowed 986*c3413364SGerrit Uitslag if (!$INPUT->server->has('REMOTE_USER') && !$this->getConf('allowguests')) { 9877c8e18ffSGina Haeussge ?> 9887c8e18ffSGina Haeussge <div class="comment_form"> 9897c8e18ffSGina Haeussge <?php echo $this->getLang('noguests'); ?> 9907c8e18ffSGina Haeussge </div> 9917c8e18ffSGina Haeussge <?php 992de7e6f00SGerrit Uitslag return; 9937c8e18ffSGina Haeussge } 994f0fda08aSwikidesign 995*c3413364SGerrit Uitslag // fill $raw with $INPUT->str('text') if it's empty (for failed CAPTCHA check) 996*c3413364SGerrit Uitslag if (!$raw && $INPUT->str('comment') == 'show') { 997*c3413364SGerrit Uitslag $raw = $INPUT->str('text'); 9984cded5e1SGerrit Uitslag } 999f0fda08aSwikidesign ?> 10005ef1705fSiLoveiDo 1001f0fda08aSwikidesign <div class="comment_form"> 1002bea69264SMichael Klier <form id="discussion__comment_form" method="post" action="<?php echo script() ?>" accept-charset="<?php echo $lang['encoding'] ?>"> 1003f0fda08aSwikidesign <div class="no"> 1004f0fda08aSwikidesign <input type="hidden" name="id" value="<?php echo $ID ?>" /> 100561437513Swikidesign <input type="hidden" name="do" value="show" /> 1006f0fda08aSwikidesign <input type="hidden" name="comment" value="<?php echo $act ?>" /> 1007530693fbSMichael Klier <?php 1008f0fda08aSwikidesign // for adding a comment 1009f0fda08aSwikidesign if ($act == 'add') { 1010f0fda08aSwikidesign ?> 1011f0fda08aSwikidesign <input type="hidden" name="reply" value="<?php echo $cid ?>" /> 1012f0fda08aSwikidesign <?php 101320c152acSMichael Klier // for guest/adminimport: show name, e-mail and subscribe to comments fields 1014*c3413364SGerrit Uitslag if(!$INPUT->server->has('REMOTE_USER') or ($this->getConf('adminimport') && $this->helper->isDiscussionMod())) { 1015f0fda08aSwikidesign ?> 1016f0fda08aSwikidesign <input type="hidden" name="user" value="<?php echo clientIP() ?>" /> 1017f0fda08aSwikidesign <div class="comment_name"> 1018f0fda08aSwikidesign <label class="block" for="discussion__comment_name"> 1019f0fda08aSwikidesign <span><?php echo $lang['fullname'] ?>:</span> 1020*c3413364SGerrit Uitslag <input type="text" class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('name'))) echo ' error'?>" name="name" id="discussion__comment_name" size="50" tabindex="1" value="<?php echo hsc($INPUT->str('name'))?>" /> 1021f0fda08aSwikidesign </label> 1022f0fda08aSwikidesign </div> 1023f0fda08aSwikidesign <div class="comment_mail"> 1024f0fda08aSwikidesign <label class="block" for="discussion__comment_mail"> 1025f0fda08aSwikidesign <span><?php echo $lang['email'] ?>:</span> 1026*c3413364SGerrit Uitslag <input type="text" class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('mail'))) echo ' error'?>" name="mail" id="discussion__comment_mail" size="50" tabindex="2" value="<?php echo hsc($INPUT->str('mail'))?>" /> 1027f0fda08aSwikidesign </label> 1028f0fda08aSwikidesign </div> 1029f0fda08aSwikidesign <?php 1030f0fda08aSwikidesign } 1031f0fda08aSwikidesign 1032f0fda08aSwikidesign // allow entering an URL 1033f0fda08aSwikidesign if ($this->getConf('urlfield')) { 1034f0fda08aSwikidesign ?> 1035f0fda08aSwikidesign <div class="comment_url"> 1036f0fda08aSwikidesign <label class="block" for="discussion__comment_url"> 1037f0fda08aSwikidesign <span><?php echo $this->getLang('url') ?>:</span> 1038*c3413364SGerrit Uitslag <input type="text" class="edit" name="url" id="discussion__comment_url" size="50" tabindex="3" value="<?php echo hsc($INPUT->str('url'))?>" /> 1039f0fda08aSwikidesign </label> 1040f0fda08aSwikidesign </div> 1041f0fda08aSwikidesign <?php 1042f0fda08aSwikidesign } 1043f0fda08aSwikidesign 1044f0fda08aSwikidesign // allow entering an address 1045f0fda08aSwikidesign if ($this->getConf('addressfield')) { 1046f0fda08aSwikidesign ?> 1047f0fda08aSwikidesign <div class="comment_address"> 1048f0fda08aSwikidesign <label class="block" for="discussion__comment_address"> 1049f0fda08aSwikidesign <span><?php echo $this->getLang('address') ?>:</span> 1050*c3413364SGerrit Uitslag <input type="text" class="edit" name="address" id="discussion__comment_address" size="50" tabindex="4" value="<?php echo hsc($INPUT->str('address'))?>" /> 1051f0fda08aSwikidesign </label> 1052f0fda08aSwikidesign </div> 1053f0fda08aSwikidesign <?php 1054f0fda08aSwikidesign } 1055f0fda08aSwikidesign 1056f0fda08aSwikidesign // allow setting the comment date 1057e6b2f142Slupo49 if ($this->getConf('adminimport') && ($this->helper->isDiscussionMod())) { 1058f0fda08aSwikidesign ?> 1059f0fda08aSwikidesign <div class="comment_date"> 1060f0fda08aSwikidesign <label class="block" for="discussion__comment_date"> 1061f0fda08aSwikidesign <span><?php echo $this->getLang('date') ?>:</span> 1062f0fda08aSwikidesign <input type="text" class="edit" name="date" id="discussion__comment_date" size="50" /> 1063f0fda08aSwikidesign </label> 1064f0fda08aSwikidesign </div> 1065f0fda08aSwikidesign <?php 1066f0fda08aSwikidesign } 1067f0fda08aSwikidesign 1068f0fda08aSwikidesign // for saving a comment 1069f0fda08aSwikidesign } else { 1070f0fda08aSwikidesign ?> 1071f0fda08aSwikidesign <input type="hidden" name="cid" value="<?php echo $cid ?>" /> 1072f0fda08aSwikidesign <?php 1073f0fda08aSwikidesign } 1074f0fda08aSwikidesign ?> 1075f0fda08aSwikidesign <div class="comment_text"> 107643ade360Slupo49 <?php echo $this->getLang('entercomment'); echo ($this->getConf('wikisyntaxok') ? "" : ":"); 107743ade360Slupo49 if($this->getConf('wikisyntaxok')) echo '. ' . $this->getLang('wikisyntax') . ':'; ?> 107843ade360Slupo49 107943ade360Slupo49 <!-- Fix for disable the toolbar when wikisyntaxok is set to false. See discussion's script.jss --> 108043ade360Slupo49 <?php if($this->getConf('wikisyntaxok')) { ?> 108164901b8eSGerrit Uitslag <div id="discussion__comment_toolbar" class="toolbar group"> 108243ade360Slupo49 <?php } else { ?> 108343ade360Slupo49 <div id="discussion__comment_toolbar_disabled"> 108443ade360Slupo49 <?php } ?> 10851de52da1SMichael Klier </div> 1086*c3413364SGerrit Uitslag <textarea class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('text'))) echo ' error'?>" name="text" cols="80" rows="10" id="discussion__comment_text" tabindex="5"><?php 108737e3c825SMichael Klier if($raw) { 108837e3c825SMichael Klier echo formText($raw); 108937e3c825SMichael Klier } else { 1090*c3413364SGerrit Uitslag echo hsc($INPUT->str('text')); 109137e3c825SMichael Klier } 109237e3c825SMichael Klier ?></textarea> 1093f0fda08aSwikidesign </div> 10940c613822SMichael Hamann 10950c613822SMichael Hamann <?php 10960c613822SMichael Hamann /** @var helper_plugin_captcha $captcha */ 10970c613822SMichael Hamann $captcha = $this->loadHelper('captcha', false); 10980c613822SMichael Hamann if ($captcha && $captcha->isEnabled()) { 10990c613822SMichael Hamann echo $captcha->getHTML(); 11000c613822SMichael Hamann } 11010c613822SMichael Hamann 11020c613822SMichael Hamann /** @var helper_plugin_recaptcha $recaptcha */ 11030c613822SMichael Hamann $recaptcha = $this->loadHelper('recaptcha', false); 11040c613822SMichael Hamann if ($recaptcha && $recaptcha->isEnabled()) { 11050c613822SMichael Hamann echo $recaptcha->getHTML(); 11060c613822SMichael Hamann } 1107e7c760b3Swikidesign ?> 11080c613822SMichael Hamann 1109bea69264SMichael Klier <input class="button comment_submit" id="discussion__btn_submit" type="submit" name="submit" accesskey="s" value="<?php echo $lang['btn_save'] ?>" title="<?php echo $lang['btn_save']?> [S]" tabindex="7" /> 11100c3df1b0SMichael Klier <input class="button comment_preview_button" id="discussion__btn_preview" type="button" name="preview" accesskey="p" value="<?php echo $lang['btn_preview'] ?>" title="<?php echo $lang['btn_preview']?> [P]" /> 11113011fb8bSMichael Klier 1112*c3413364SGerrit Uitslag <?php if((!$INPUT->server->has('REMOTE_USER') || $INPUT->server->has('REMOTE_USER') && !$conf['subscribers']) && $this->getConf('subscribe')) { ?> 11133011fb8bSMichael Klier <div class="comment_subscribe"> 111411b1339eSGina Haeussge <input type="checkbox" id="discussion__comment_subscribe" name="subscribe" tabindex="6" /> 11153011fb8bSMichael Klier <label class="block" for="discussion__comment_subscribe"> 11163011fb8bSMichael Klier <span><?php echo $this->getLang('subscribe') ?></span> 11173011fb8bSMichael Klier </label> 11183011fb8bSMichael Klier </div> 11193011fb8bSMichael Klier <?php } ?> 11203011fb8bSMichael Klier 11213011fb8bSMichael Klier <div class="clearer"></div> 1122ed4846efSMichael Klier <div id="discussion__comment_preview"> </div> 1123f0fda08aSwikidesign </div> 1124f0fda08aSwikidesign </form> 1125f0fda08aSwikidesign </div> 1126f0fda08aSwikidesign <?php 1127f0fda08aSwikidesign } 1128f0fda08aSwikidesign 1129f0fda08aSwikidesign /** 1130*c3413364SGerrit Uitslag * Action button below a comment 1131de7e6f00SGerrit Uitslag * 1132*c3413364SGerrit Uitslag * @param string $cid comment id 1133*c3413364SGerrit Uitslag * @param string $label translated label 1134*c3413364SGerrit Uitslag * @param string $act action 1135*c3413364SGerrit Uitslag * @param bool $jump whether to scroll to the commentform 1136f0fda08aSwikidesign */ 1137*c3413364SGerrit Uitslag protected function showButton($cid, $label, $act, $jump = false) { 1138f0fda08aSwikidesign global $ID; 11395ef1705fSiLoveiDo 11401e46d176Swikidesign $anchor = ($jump ? '#discussion__comment_form' : '' ); 1141f0fda08aSwikidesign 1142f0fda08aSwikidesign ?> 11436d1f4f20SGina Haeussge <form class="button discussion__<?php echo $act?>" method="get" action="<?php echo script().$anchor ?>"> 1144f0fda08aSwikidesign <div class="no"> 1145f0fda08aSwikidesign <input type="hidden" name="id" value="<?php echo $ID ?>" /> 114661437513Swikidesign <input type="hidden" name="do" value="show" /> 1147f0fda08aSwikidesign <input type="hidden" name="comment" value="<?php echo $act ?>" /> 1148f0fda08aSwikidesign <input type="hidden" name="cid" value="<?php echo $cid ?>" /> 1149f0fda08aSwikidesign <input type="submit" value="<?php echo $label ?>" class="button" title="<?php echo $label ?>" /> 1150f0fda08aSwikidesign </div> 1151f0fda08aSwikidesign </form> 1152f0fda08aSwikidesign <?php 1153f0fda08aSwikidesign } 1154f0fda08aSwikidesign 1155f0fda08aSwikidesign /** 1156f0fda08aSwikidesign * Adds an entry to the comments changelog 1157f0fda08aSwikidesign * 1158f0fda08aSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 1159f0fda08aSwikidesign * @author Ben Coburn <btcoburn@silicodon.net> 1160de7e6f00SGerrit Uitslag * 1161de7e6f00SGerrit Uitslag * @param int $date 1162de7e6f00SGerrit Uitslag * @param string $id page id 1163*c3413364SGerrit Uitslag * @param string $type create/edit/delete/show/hide comment 'cc', 'ec', 'dc', 'sc', 'hc' 1164de7e6f00SGerrit Uitslag * @param string $summary 1165de7e6f00SGerrit Uitslag * @param string $extra 1166f0fda08aSwikidesign */ 1167*c3413364SGerrit Uitslag protected function addLogEntry($date, $id, $type = 'cc', $summary = '', $extra = '') { 1168*c3413364SGerrit Uitslag global $conf, $INPUT; 1169f0fda08aSwikidesign 1170f0fda08aSwikidesign $changelog = $conf['metadir'].'/_comments.changes'; 1171f0fda08aSwikidesign 11724cded5e1SGerrit Uitslag //use current time if none supplied 11734cded5e1SGerrit Uitslag if(!$date) { 11744cded5e1SGerrit Uitslag $date = time(); 11754cded5e1SGerrit Uitslag } 1176*c3413364SGerrit Uitslag $remote = $INPUT->server->str('REMOTE_ADDR'); 1177*c3413364SGerrit Uitslag $user = $INPUT->server->str('REMOTE_USER'); 1178f0fda08aSwikidesign 1179*c3413364SGerrit Uitslag $strip = ["\t", "\n"]; 1180*c3413364SGerrit Uitslag $logline = [ 1181f0fda08aSwikidesign 'date' => $date, 1182f0fda08aSwikidesign 'ip' => $remote, 1183f0fda08aSwikidesign 'type' => str_replace($strip, '', $type), 1184f0fda08aSwikidesign 'id' => $id, 1185f0fda08aSwikidesign 'user' => $user, 1186f0fda08aSwikidesign 'sum' => str_replace($strip, '', $summary), 1187f0fda08aSwikidesign 'extra' => str_replace($strip, '', $extra) 1188*c3413364SGerrit Uitslag ]; 1189f0fda08aSwikidesign 1190f0fda08aSwikidesign // add changelog line 1191f0fda08aSwikidesign $logline = implode("\t", $logline)."\n"; 1192f0fda08aSwikidesign io_saveFile($changelog, $logline, true); //global changelog cache 1193*c3413364SGerrit Uitslag $this->trimRecentCommentsLog($changelog); 119477a22ba2Swikidesign 119577a22ba2Swikidesign // tell the indexer to re-index the page 119677a22ba2Swikidesign @unlink(metaFN($id, '.indexed')); 1197f0fda08aSwikidesign } 1198f0fda08aSwikidesign 1199f0fda08aSwikidesign /** 1200f0fda08aSwikidesign * Trims the recent comments cache to the last $conf['changes_days'] recent 1201f0fda08aSwikidesign * changes or $conf['recent'] items, which ever is larger. 1202f0fda08aSwikidesign * The trimming is only done once a day. 1203f0fda08aSwikidesign * 1204f0fda08aSwikidesign * @author Ben Coburn <btcoburn@silicodon.net> 1205de7e6f00SGerrit Uitslag * 1206de7e6f00SGerrit Uitslag * @param string $changelog file path 1207de7e6f00SGerrit Uitslag * @return bool 1208f0fda08aSwikidesign */ 1209*c3413364SGerrit Uitslag protected function trimRecentCommentsLog($changelog) { 1210f0fda08aSwikidesign global $conf; 1211f0fda08aSwikidesign 1212f0fda08aSwikidesign if (@file_exists($changelog) && 1213f0fda08aSwikidesign (filectime($changelog) + 86400) < time() && 12144cded5e1SGerrit Uitslag !@file_exists($changelog.'_tmp') 12154cded5e1SGerrit Uitslag ) { 1216f0fda08aSwikidesign 1217f0fda08aSwikidesign io_lock($changelog); 1218f0fda08aSwikidesign $lines = file($changelog); 1219f0fda08aSwikidesign if (count($lines)<$conf['recent']) { 1220f0fda08aSwikidesign // nothing to trim 1221f0fda08aSwikidesign io_unlock($changelog); 1222f0fda08aSwikidesign return true; 1223f0fda08aSwikidesign } 1224f0fda08aSwikidesign 1225f0fda08aSwikidesign io_saveFile($changelog.'_tmp', ''); // presave tmp as 2nd lock 1226f0fda08aSwikidesign $trim_time = time() - $conf['recent_days']*86400; 1227*c3413364SGerrit Uitslag $out_lines = []; 1228f0fda08aSwikidesign 1229e49085a2SMichael Klier $num = count($lines); 1230e49085a2SMichael Klier for ($i=0; $i<$num; $i++) { 1231f0fda08aSwikidesign $log = parseChangelogLine($lines[$i]); 1232f0fda08aSwikidesign if ($log === false) continue; // discard junk 1233f0fda08aSwikidesign if ($log['date'] < $trim_time) { 1234f0fda08aSwikidesign $old_lines[$log['date'].".$i"] = $lines[$i]; // keep old lines for now (append .$i to prevent key collisions) 1235f0fda08aSwikidesign } else { 1236f0fda08aSwikidesign $out_lines[$log['date'].".$i"] = $lines[$i]; // definitely keep these lines 1237f0fda08aSwikidesign } 1238f0fda08aSwikidesign } 1239f0fda08aSwikidesign 1240f0fda08aSwikidesign // sort the final result, it shouldn't be necessary, 1241f0fda08aSwikidesign // however the extra robustness in making the changelog cache self-correcting is worth it 1242f0fda08aSwikidesign ksort($out_lines); 1243f0fda08aSwikidesign $extra = $conf['recent'] - count($out_lines); // do we need extra lines do bring us up to minimum 1244f0fda08aSwikidesign if ($extra > 0) { 1245f0fda08aSwikidesign ksort($old_lines); 1246f0fda08aSwikidesign $out_lines = array_merge(array_slice($old_lines,-$extra),$out_lines); 1247f0fda08aSwikidesign } 1248f0fda08aSwikidesign 1249f0fda08aSwikidesign // save trimmed changelog 1250f0fda08aSwikidesign io_saveFile($changelog.'_tmp', implode('', $out_lines)); 1251f0fda08aSwikidesign @unlink($changelog); 1252f0fda08aSwikidesign if (!rename($changelog.'_tmp', $changelog)) { 1253f0fda08aSwikidesign // rename failed so try another way... 1254f0fda08aSwikidesign io_unlock($changelog); 1255f0fda08aSwikidesign io_saveFile($changelog, implode('', $out_lines)); 1256f0fda08aSwikidesign @unlink($changelog.'_tmp'); 1257f0fda08aSwikidesign } else { 1258f0fda08aSwikidesign io_unlock($changelog); 1259f0fda08aSwikidesign } 1260f0fda08aSwikidesign return true; 1261f0fda08aSwikidesign } 1262de7e6f00SGerrit Uitslag return true; 1263f0fda08aSwikidesign } 1264f0fda08aSwikidesign 1265f0fda08aSwikidesign /** 1266f0fda08aSwikidesign * Sends a notify mail on new comment 1267f0fda08aSwikidesign * 1268f0fda08aSwikidesign * @param array $comment data array of the new comment 1269*c3413364SGerrit Uitslag * @param array $subscribers data of the subscribers by reference 1270f0fda08aSwikidesign * 1271f0fda08aSwikidesign * @author Andreas Gohr <andi@splitbrain.org> 1272f0fda08aSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 1273f0fda08aSwikidesign */ 1274*c3413364SGerrit Uitslag protected function notify($comment, &$subscribers) { 1275*c3413364SGerrit Uitslag global $conf, $ID, $INPUT, $auth; 1276f0fda08aSwikidesign 12779881d835SMichael Klier $notify_text = io_readfile($this->localfn('subscribermail')); 12789881d835SMichael Klier $confirm_text = io_readfile($this->localfn('confirmsubscribe')); 12799881d835SMichael Klier $subject_notify = '['.$conf['title'].'] '.$this->getLang('mail_newcomment'); 12809881d835SMichael Klier $subject_subscribe = '['.$conf['title'].'] '.$this->getLang('subscribe'); 1281f0fda08aSwikidesign 1282451c1100SMichael Hamann $mailer = new Mailer(); 1283*c3413364SGerrit Uitslag if (!$INPUT->server->has('REMOTE_USER')) { 1284451c1100SMichael Hamann $mailer->from($conf['mailfromnobody']); 1285f4a5ed1cSMatthias Schulte } 1286f4a5ed1cSMatthias Schulte 1287*c3413364SGerrit Uitslag $replace = [ 12883c4953e9SMichael Hamann 'PAGE' => $ID, 12893c4953e9SMichael Hamann 'TITLE' => $conf['title'], 12903c4953e9SMichael Hamann 'DATE' => dformat($comment['date']['created'], $conf['dformat']), 12913c4953e9SMichael Hamann 'NAME' => $comment['user']['name'], 12923c4953e9SMichael Hamann 'TEXT' => $comment['raw'], 12933c4953e9SMichael Hamann 'COMMENTURL' => wl($ID, '', true) . '#comment_' . $comment['cid'], 129406644a74SMichael Hamann 'UNSUBSCRIBE' => wl($ID, 'do=subscribe', true, '&'), 12953c4953e9SMichael Hamann 'DOKUWIKIURL' => DOKU_URL 1296*c3413364SGerrit Uitslag ]; 1297451c1100SMichael Hamann 1298*c3413364SGerrit Uitslag $confirm_replace = [ 12993c4953e9SMichael Hamann 'PAGE' => $ID, 13003c4953e9SMichael Hamann 'TITLE' => $conf['title'], 13013c4953e9SMichael Hamann 'DOKUWIKIURL' => DOKU_URL 1302*c3413364SGerrit Uitslag ]; 1303451c1100SMichael Hamann 1304451c1100SMichael Hamann 1305451c1100SMichael Hamann $mailer->subject($subject_notify); 1306451c1100SMichael Hamann $mailer->setBody($notify_text, $replace); 1307451c1100SMichael Hamann 1308f4a5ed1cSMatthias Schulte // send mail to notify address 1309f4a5ed1cSMatthias Schulte if ($conf['notify']) { 1310451c1100SMichael Hamann $mailer->bcc($conf['notify']); 1311451c1100SMichael Hamann $mailer->send(); 1312f4a5ed1cSMatthias Schulte } 1313f4a5ed1cSMatthias Schulte 1314ca785d71SMichael Hamann // send email to moderators 1315ca785d71SMichael Hamann if ($this->getConf('moderatorsnotify')) { 1316*c3413364SGerrit Uitslag $moderatorgrpsString = trim($this->getConf('moderatorgroups')); 1317*c3413364SGerrit Uitslag if (!empty($moderatorgrpsString)) { 1318ca785d71SMichael Hamann // create a clean mods list 1319*c3413364SGerrit Uitslag $moderatorgroups = explode(',', $moderatorgrpsString); 1320*c3413364SGerrit Uitslag $moderatorgroups = array_map('trim', $moderatorgroups); 1321*c3413364SGerrit Uitslag $moderatorgroups = array_unique($moderatorgroups); 1322*c3413364SGerrit Uitslag $moderatorgroups = array_filter($moderatorgroups); 1323ca785d71SMichael Hamann // search for moderators users 1324*c3413364SGerrit Uitslag foreach($moderatorgroups as $moderatorgroup) { 1325*c3413364SGerrit Uitslag if(!$auth->isCaseSensitive()) { 1326*c3413364SGerrit Uitslag $moderatorgroup = PhpString::strtolower($moderatorgroup); 1327*c3413364SGerrit Uitslag } 1328ca785d71SMichael Hamann // create a clean mailing list 1329*c3413364SGerrit Uitslag $bccs = []; 1330*c3413364SGerrit Uitslag if($moderatorgroup[0] == '@') { 1331*c3413364SGerrit Uitslag foreach($auth->retrieveUsers(0, 0, ['grps' => $auth->cleanGroup(substr($moderatorgroup, 1))]) as $user) { 1332ca785d71SMichael Hamann if (!empty($user['mail'])) { 1333*c3413364SGerrit Uitslag $bccs[] = $user['mail']; 1334ca785d71SMichael Hamann } 1335ca785d71SMichael Hamann } 1336ca785d71SMichael Hamann } else { 1337*c3413364SGerrit Uitslag //it is an user 1338*c3413364SGerrit Uitslag $userdata = $auth->getUserData($auth->cleanUser($moderatorgroup)); 1339ca785d71SMichael Hamann if (!empty($userdata['mail'])) { 1340*c3413364SGerrit Uitslag $bccs[] = $userdata['mail']; 1341ca785d71SMichael Hamann } 1342ca785d71SMichael Hamann } 1343*c3413364SGerrit Uitslag $bccs = array_unique($bccs); 1344ca785d71SMichael Hamann // notify the users 1345*c3413364SGerrit Uitslag $mailer->bcc(implode(',', $bccs)); 1346ca785d71SMichael Hamann $mailer->send(); 1347ca785d71SMichael Hamann } 1348ca785d71SMichael Hamann } 1349ca785d71SMichael Hamann } 1350ca785d71SMichael Hamann 1351f4a5ed1cSMatthias Schulte // notify page subscribers 1352451c1100SMichael Hamann if (actionOK('subscribe')) { 1353*c3413364SGerrit Uitslag $data = ['id' => $ID, 'addresslist' => '', 'self' => false]; 1354*c3413364SGerrit Uitslag //FIXME default callback, needed to mentioned it again? 1355*c3413364SGerrit Uitslag Event::createAndTrigger( 1356451c1100SMichael Hamann 'COMMON_NOTIFY_ADDRESSLIST', $data, 1357*c3413364SGerrit Uitslag [new SubscriberManager(), 'notifyAddresses'] 1358451c1100SMichael Hamann ); 1359*c3413364SGerrit Uitslag 1360451c1100SMichael Hamann $to = $data['addresslist']; 1361451c1100SMichael Hamann if(!empty($to)) { 1362451c1100SMichael Hamann $mailer->bcc($to); 1363451c1100SMichael Hamann $mailer->send(); 1364451c1100SMichael Hamann } 13653011fb8bSMichael Klier } 1366f0fda08aSwikidesign 13673011fb8bSMichael Klier // notify comment subscribers 13683011fb8bSMichael Klier if (!empty($subscribers)) { 13693011fb8bSMichael Klier 13709881d835SMichael Klier foreach($subscribers as $mail => $data) { 1371451c1100SMichael Hamann $mailer->bcc($mail); 13729881d835SMichael Klier if($data['active']) { 13733c4953e9SMichael Hamann $replace['UNSUBSCRIBE'] = wl($ID, 'do=discussion_unsubscribe&hash=' . $data['hash'], true, '&'); 13743011fb8bSMichael Klier 1375451c1100SMichael Hamann $mailer->subject($subject_notify); 1376451c1100SMichael Hamann $mailer->setBody($notify_text, $replace); 1377451c1100SMichael Hamann $mailer->send(); 1378*c3413364SGerrit Uitslag } elseif(!$data['confirmsent']) { 13793c4953e9SMichael Hamann $confirm_replace['SUBSCRIBE'] = wl($ID, 'do=discussion_confirmsubscribe&hash=' . $data['hash'], true, '&'); 13809881d835SMichael Klier 1381451c1100SMichael Hamann $mailer->subject($subject_subscribe); 1382451c1100SMichael Hamann $mailer->setBody($confirm_text, $confirm_replace); 1383451c1100SMichael Hamann $mailer->send(); 13849881d835SMichael Klier $subscribers[$mail]['confirmsent'] = true; 13859881d835SMichael Klier } 13863011fb8bSMichael Klier } 13873011fb8bSMichael Klier } 1388f0fda08aSwikidesign } 1389f0fda08aSwikidesign 1390f0fda08aSwikidesign /** 1391f0fda08aSwikidesign * Counts the number of visible comments 1392de7e6f00SGerrit Uitslag * 1393*c3413364SGerrit Uitslag * @param array $data array with all comments 1394de7e6f00SGerrit Uitslag * @return int 1395f0fda08aSwikidesign */ 1396*c3413364SGerrit Uitslag protected function countVisibleComments($data) { 1397f0fda08aSwikidesign $number = 0; 1398de7e6f00SGerrit Uitslag foreach ($data['comments'] as $comment) { 1399f0fda08aSwikidesign if ($comment['parent']) continue; 1400f0fda08aSwikidesign if (!$comment['show']) continue; 1401*c3413364SGerrit Uitslag 1402f0fda08aSwikidesign $number++; 1403f0fda08aSwikidesign $rids = $comment['replies']; 14044cded5e1SGerrit Uitslag if (count($rids)) { 1405*c3413364SGerrit Uitslag $number = $number + $this->countVisibleReplies($data, $rids); 14064cded5e1SGerrit Uitslag } 1407f0fda08aSwikidesign } 1408f0fda08aSwikidesign return $number; 1409f0fda08aSwikidesign } 1410f0fda08aSwikidesign 1411de7e6f00SGerrit Uitslag /** 1412*c3413364SGerrit Uitslag * Count visible replies on the comments 1413*c3413364SGerrit Uitslag * 1414de7e6f00SGerrit Uitslag * @param array $data 1415de7e6f00SGerrit Uitslag * @param array $rids 1416*c3413364SGerrit Uitslag * @return int counted replies 1417de7e6f00SGerrit Uitslag */ 1418*c3413364SGerrit Uitslag protected function countVisibleReplies(&$data, $rids) { 1419f0fda08aSwikidesign $number = 0; 1420f0fda08aSwikidesign foreach ($rids as $rid) { 14212ee3dca3Swikidesign if (!isset($data['comments'][$rid])) continue; // reply was removed 1422f0fda08aSwikidesign if (!$data['comments'][$rid]['show']) continue; 1423*c3413364SGerrit Uitslag 1424f0fda08aSwikidesign $number++; 1425f0fda08aSwikidesign $rids = $data['comments'][$rid]['replies']; 14264cded5e1SGerrit Uitslag if (count($rids)) { 1427*c3413364SGerrit Uitslag $number = $number + $this->countVisibleReplies($data, $rids); 14284cded5e1SGerrit Uitslag } 1429f0fda08aSwikidesign } 1430f0fda08aSwikidesign return $number; 1431f0fda08aSwikidesign } 1432f0fda08aSwikidesign 1433f0fda08aSwikidesign /** 1434*c3413364SGerrit Uitslag * Renders the raw comment (wiki)text to html 1435de7e6f00SGerrit Uitslag * 1436*c3413364SGerrit Uitslag * @param string $raw comment text 1437de7e6f00SGerrit Uitslag * @return null|string 1438f0fda08aSwikidesign */ 1439*c3413364SGerrit Uitslag protected function renderComment($raw) { 1440f0fda08aSwikidesign if ($this->getConf('wikisyntaxok')) { 1441efccf6b0SJeffrey Bergamini // Note the warning for render_text: 1442efccf6b0SJeffrey Bergamini // "very ineffecient for small pieces of data - try not to use" 1443efccf6b0SJeffrey Bergamini // in dokuwiki/inc/plugin.php 1444efccf6b0SJeffrey Bergamini $xhtml = $this->render_text($raw); 1445f0fda08aSwikidesign } else { // wiki syntax not allowed -> just encode special chars 144687bb4e97SMichael Klier $xhtml = hsc(trim($raw)); 144787bb4e97SMichael Klier $xhtml = str_replace("\n", '<br />', $xhtml); 1448f0fda08aSwikidesign } 1449f0fda08aSwikidesign return $xhtml; 1450f0fda08aSwikidesign } 1451f0fda08aSwikidesign 1452f0fda08aSwikidesign /** 1453479dd10fSwikidesign * Finds out whether there is a discussion section for the current page 1454de7e6f00SGerrit Uitslag * 1455de7e6f00SGerrit Uitslag * @param string $title 1456de7e6f00SGerrit Uitslag * @return bool 1457479dd10fSwikidesign */ 1458*c3413364SGerrit Uitslag protected function hasDiscussion(&$title) { 1459b2ac3b3bSwikidesign global $ID; 14604a0a1bd2Swikidesign 1461*c3413364SGerrit Uitslag $file = metaFN($ID, '.comments'); 1462479dd10fSwikidesign 1463*c3413364SGerrit Uitslag if (!@file_exists($file)) { 1464f0bcde18SGerrit Uitslag if ($this->isDiscussionEnabled()) { 14652b18adb9SMichael Klier return true; 14662b18adb9SMichael Klier } else { 14672b18adb9SMichael Klier return false; 14682b18adb9SMichael Klier } 1469479dd10fSwikidesign } 1470479dd10fSwikidesign 1471*c3413364SGerrit Uitslag $comments = unserialize(io_readFile($file, false)); 1472479dd10fSwikidesign 14734cded5e1SGerrit Uitslag if ($comments['title']) { 14744cded5e1SGerrit Uitslag $title = hsc($comments['title']); 14754cded5e1SGerrit Uitslag } 1476479dd10fSwikidesign $num = $comments['number']; 1477*c3413364SGerrit Uitslag if (!$comments['status'] || ($comments['status'] == 2 && $num == 0)) { 1478*c3413364SGerrit Uitslag //disabled, or closed and no comments 1479*c3413364SGerrit Uitslag return false; 1480*c3413364SGerrit Uitslag } else { 1481*c3413364SGerrit Uitslag return true; 1482*c3413364SGerrit Uitslag } 1483479dd10fSwikidesign } 1484479dd10fSwikidesign 1485479dd10fSwikidesign /** 1486e7c760b3Swikidesign * Creates a new thread page 1487de7e6f00SGerrit Uitslag * 1488de7e6f00SGerrit Uitslag * @return string 1489e7c760b3Swikidesign */ 1490*c3413364SGerrit Uitslag protected function newThread() { 1491*c3413364SGerrit Uitslag global $ID, $INFO, $INPUT; 1492f0fda08aSwikidesign 1493*c3413364SGerrit Uitslag $ns = cleanID($INPUT->str('ns')); 1494*c3413364SGerrit Uitslag $title = str_replace(':', '', $INPUT->str('title')); 14952e80cd5fSwikidesign $back = $ID; 14962e80cd5fSwikidesign $ID = ($ns ? $ns.':' : '').cleanID($title); 14972e80cd5fSwikidesign $INFO = pageinfo(); 1498f0fda08aSwikidesign 1499f0fda08aSwikidesign // check if we are allowed to create this file 15002e80cd5fSwikidesign if ($INFO['perm'] >= AUTH_CREATE) { 1501f0fda08aSwikidesign 1502f0fda08aSwikidesign //check if locked by anyone - if not lock for my self 15034cded5e1SGerrit Uitslag if ($INFO['locked']) { 15044cded5e1SGerrit Uitslag return 'locked'; 15054cded5e1SGerrit Uitslag } else { 15064cded5e1SGerrit Uitslag lock($ID); 15074cded5e1SGerrit Uitslag } 1508f0fda08aSwikidesign 1509f0fda08aSwikidesign // prepare the new thread file with default stuff 15102e80cd5fSwikidesign if (!@file_exists($INFO['filepath'])) { 1511f0fda08aSwikidesign global $TEXT; 1512f0fda08aSwikidesign 1513*c3413364SGerrit Uitslag $TEXT = pageTemplate(($ns ? $ns.':' : '').$title); 15141433886fSwikidesign if (!$TEXT) { 1515*c3413364SGerrit Uitslag $data = ['id' => $ID, 'ns' => $ns, 'title' => $title, 'back' => $back]; 1516*c3413364SGerrit Uitslag $TEXT = $this->pageTemplate($data); 15172e80cd5fSwikidesign } 15182e80cd5fSwikidesign return 'preview'; 1519f0fda08aSwikidesign } else { 15202e80cd5fSwikidesign return 'edit'; 1521f0fda08aSwikidesign } 1522f0fda08aSwikidesign } else { 15232e80cd5fSwikidesign return 'show'; 1524f0fda08aSwikidesign } 1525f0fda08aSwikidesign } 1526f0fda08aSwikidesign 1527e7c760b3Swikidesign /** 152861437513Swikidesign * Adapted version of pageTemplate() function 1529de7e6f00SGerrit Uitslag * 1530de7e6f00SGerrit Uitslag * @param array $data 1531de7e6f00SGerrit Uitslag * @return string 153261437513Swikidesign */ 1533*c3413364SGerrit Uitslag protected function pageTemplate($data) { 1534*c3413364SGerrit Uitslag global $conf, $INFO, $INPUT; 153561437513Swikidesign 153661437513Swikidesign $id = $data['id']; 1537*c3413364SGerrit Uitslag $user = $INPUT->server->str('REMOTE_USER'); 153861437513Swikidesign $tpl = io_readFile(DOKU_PLUGIN.'discussion/_template.txt'); 153961437513Swikidesign 154061437513Swikidesign // standard replacements 1541*c3413364SGerrit Uitslag $replace = [ 154261437513Swikidesign '@NS@' => $data['ns'], 154361437513Swikidesign '@PAGE@' => strtr(noNS($id),'_',' '), 154461437513Swikidesign '@USER@' => $user, 154561437513Swikidesign '@NAME@' => $INFO['userinfo']['name'], 154661437513Swikidesign '@MAIL@' => $INFO['userinfo']['mail'], 1547d5530824SMichael Hamann '@DATE@' => dformat(time(), $conf['dformat']), 1548*c3413364SGerrit Uitslag ]; 154961437513Swikidesign 155061437513Swikidesign // additional replacements 155161437513Swikidesign $replace['@BACK@'] = $data['back']; 155261437513Swikidesign $replace['@TITLE@'] = $data['title']; 155361437513Swikidesign 155461437513Swikidesign // avatar if useavatar and avatar plugin available 1555*c3413364SGerrit Uitslag if ($this->getConf('useavatar') && !plugin_isdisabled('avatar')) { 155661437513Swikidesign $replace['@AVATAR@'] = '{{avatar>'.$user.' }} '; 155761437513Swikidesign } else { 155861437513Swikidesign $replace['@AVATAR@'] = ''; 155961437513Swikidesign } 156061437513Swikidesign 156161437513Swikidesign // tag if tag plugin is available 1562*c3413364SGerrit Uitslag if (!plugin_isdisabled('tag')){ 156361437513Swikidesign $replace['@TAG@'] = "\n\n{{tag>}}"; 156461437513Swikidesign } else { 156561437513Swikidesign $replace['@TAG@'] = ''; 156661437513Swikidesign } 156761437513Swikidesign 1568*c3413364SGerrit Uitslag // perform the replacements in tpl 1569*c3413364SGerrit Uitslag return str_replace(array_keys($replace), array_values($replace), $tpl); 157061437513Swikidesign } 157161437513Swikidesign 157261437513Swikidesign /** 1573e7c760b3Swikidesign * Checks if the CAPTCHA string submitted is valid 1574e7c760b3Swikidesign */ 1575*c3413364SGerrit Uitslag protected function captchaCheck() { 1576*c3413364SGerrit Uitslag global $INPUT; 157796bc68a7SMichael Hamann /** @var helper_plugin_captcha $captcha */ 1578*c3413364SGerrit Uitslag if (!$captcha = $this->loadHelper('captcha', false)) { 1579*c3413364SGerrit Uitslag // CAPTCHA is disabled or not available 1580*c3413364SGerrit Uitslag return; 1581*c3413364SGerrit Uitslag } 1582e7c760b3Swikidesign 1583d578a059SMichael Hamann if ($captcha->isEnabled() && !$captcha->check()) { 1584*c3413364SGerrit Uitslag if ($INPUT->str('comment') == 'save') { 1585*c3413364SGerrit Uitslag $INPUT->set('comment', 'edit'); 1586*c3413364SGerrit Uitslag } elseif ($INPUT->str('comment') == 'add') { 1587*c3413364SGerrit Uitslag $INPUT->set('comment', 'show'); 15884cded5e1SGerrit Uitslag } 1589e7c760b3Swikidesign } 1590e7c760b3Swikidesign } 1591e7c760b3Swikidesign 1592a1ca9e44Swikidesign /** 1593bd6dc08eSAdrian Schlegel * checks if the submitted reCAPTCHA string is valid 1594bd6dc08eSAdrian Schlegel * 1595bd6dc08eSAdrian Schlegel * @author Adrian Schlegel <adrian@liip.ch> 1596bd6dc08eSAdrian Schlegel */ 1597*c3413364SGerrit Uitslag protected function recaptchaCheck() { 1598*c3413364SGerrit Uitslag global $INPUT; 1599*c3413364SGerrit Uitslag /** @var helper_plugin_recaptcha $recaptcha */ 1600*c3413364SGerrit Uitslag if (!$recaptcha = plugin_load('helper', 'recaptcha')) 1601bd6dc08eSAdrian Schlegel return; // reCAPTCHA is disabled or not available 1602bd6dc08eSAdrian Schlegel 1603bd6dc08eSAdrian Schlegel // do nothing if logged in user and no reCAPTCHA required 1604*c3413364SGerrit Uitslag if (!$recaptcha->getConf('forusers') && $INPUT->server->has('REMOTE_USER')) return; 1605bd6dc08eSAdrian Schlegel 1606*c3413364SGerrit Uitslag $response = $recaptcha->check(); 1607*c3413364SGerrit Uitslag if (!$response->is_valid) { 1608bd6dc08eSAdrian Schlegel msg($recaptcha->getLang('testfailed'),-1); 1609*c3413364SGerrit Uitslag if ($INPUT->str('comment') == 'save') { 1610*c3413364SGerrit Uitslag $INPUT->str('comment', 'edit'); 1611*c3413364SGerrit Uitslag } elseif ($INPUT->str('comment') == 'add') { 1612*c3413364SGerrit Uitslag $INPUT->str('comment', 'show'); 16134cded5e1SGerrit Uitslag } 1614bd6dc08eSAdrian Schlegel } 1615bd6dc08eSAdrian Schlegel } 1616bd6dc08eSAdrian Schlegel 1617bd6dc08eSAdrian Schlegel /** 1618ac818938SMichael Hamann * Add discussion plugin version to the indexer version 1619ac818938SMichael Hamann * This means that all pages will be indexed again in order to add the comments 1620ac818938SMichael Hamann * to the index whenever there has been a change that concerns the index content. 1621de7e6f00SGerrit Uitslag * 1622de7e6f00SGerrit Uitslag * @param Doku_Event $event 1623de7e6f00SGerrit Uitslag * @param $param 1624ac818938SMichael Hamann */ 1625*c3413364SGerrit Uitslag public function addIndexVersion(Doku_Event $event, $param) { 1626ac818938SMichael Hamann $event->data['discussion'] = '0.1'; 1627ac818938SMichael Hamann } 1628ac818938SMichael Hamann 1629ac818938SMichael Hamann /** 1630a1ca9e44Swikidesign * Adds the comments to the index 1631de7e6f00SGerrit Uitslag * 1632de7e6f00SGerrit Uitslag * @param Doku_Event $event 1633*c3413364SGerrit Uitslag * @param array $param with 1634*c3413364SGerrit Uitslag * 'id' => string 'page'/'id' for respectively INDEXER_PAGE_ADD and FULLTEXT_SNIPPET_CREATE event 1635*c3413364SGerrit Uitslag * 'text' => string 'body'/'text' 1636a1ca9e44Swikidesign */ 1637*c3413364SGerrit Uitslag public function addCommentsToIndex(Doku_Event $event, $param) { 1638a1ca9e44Swikidesign // get .comments meta file name 163910b5d61eSMichael Hamann $file = metaFN($event->data[$param['id']], '.comments'); 1640a1ca9e44Swikidesign 164196b3951aSMichael Hamann if (!@file_exists($file)) return; 164296b3951aSMichael Hamann $data = unserialize(io_readFile($file, false)); 1643*c3413364SGerrit Uitslag 1644*c3413364SGerrit Uitslag // comments are turned off or no comments available to index 1645*c3413364SGerrit Uitslag if (!$data['status'] || $data['number'] == 0) return; 1646a1ca9e44Swikidesign 1647a1ca9e44Swikidesign // now add the comments 1648a1ca9e44Swikidesign if (isset($data['comments'])) { 1649a1ca9e44Swikidesign foreach ($data['comments'] as $key => $value) { 1650*c3413364SGerrit Uitslag $event->data[$param['text']] .= DOKU_LF.$this->addCommentWords($key, $data); 1651a1ca9e44Swikidesign } 1652a1ca9e44Swikidesign } 1653a1ca9e44Swikidesign } 1654a1ca9e44Swikidesign 1655*c3413364SGerrit Uitslag /** 1656*c3413364SGerrit Uitslag * Checks if the phrase occurs in the comments and return event result true if matching 1657*c3413364SGerrit Uitslag * 1658*c3413364SGerrit Uitslag * @param Doku_Event $event 1659*c3413364SGerrit Uitslag * @param $param 1660*c3413364SGerrit Uitslag * @return void 1661*c3413364SGerrit Uitslag */ 1662*c3413364SGerrit Uitslag public function fulltextPhraseMatchInComments(Doku_Event $event, $param) { 166310b5d61eSMichael Hamann if ($event->result === true) return; 166410b5d61eSMichael Hamann 166510b5d61eSMichael Hamann // get .comments meta file name 166610b5d61eSMichael Hamann $file = metaFN($event->data['id'], '.comments'); 166710b5d61eSMichael Hamann 166810b5d61eSMichael Hamann if (!@file_exists($file)) return; 166910b5d61eSMichael Hamann $data = unserialize(io_readFile($file, false)); 1670*c3413364SGerrit Uitslag 1671*c3413364SGerrit Uitslag // comments are turned off or no comments available to match 1672*c3413364SGerrit Uitslag if (!$data['status'] || $data['number'] == 0) return; 167310b5d61eSMichael Hamann 167410b5d61eSMichael Hamann $matched = false; 167510b5d61eSMichael Hamann 167610b5d61eSMichael Hamann // now add the comments 167710b5d61eSMichael Hamann if (isset($data['comments'])) { 1678*c3413364SGerrit Uitslag foreach ($data['comments'] as $cid => $value) { 1679*c3413364SGerrit Uitslag $matched = $this->phraseMatchInComment($event->data['phrase'], $cid, $data); 168010b5d61eSMichael Hamann if ($matched) break; 168110b5d61eSMichael Hamann } 168210b5d61eSMichael Hamann } 168310b5d61eSMichael Hamann 1684*c3413364SGerrit Uitslag if ($matched) { 168510b5d61eSMichael Hamann $event->result = true; 168610b5d61eSMichael Hamann } 1687*c3413364SGerrit Uitslag } 168810b5d61eSMichael Hamann 1689*c3413364SGerrit Uitslag /** 1690*c3413364SGerrit Uitslag * Match the phrase in the comment and its replies 1691*c3413364SGerrit Uitslag * 1692*c3413364SGerrit Uitslag * @param string $phrase phrase to search 1693*c3413364SGerrit Uitslag * @param string $cid comment id 1694*c3413364SGerrit Uitslag * @param array $data array with all comments by reference 1695*c3413364SGerrit Uitslag * @param string $parent cid of parent 1696*c3413364SGerrit Uitslag * @return bool if match true, otherwise false 1697*c3413364SGerrit Uitslag */ 1698*c3413364SGerrit Uitslag protected function phraseMatchInComment($phrase, $cid, &$data, $parent = '') { 169910b5d61eSMichael Hamann if (!isset($data['comments'][$cid])) return false; // comment was removed 1700*c3413364SGerrit Uitslag 170110b5d61eSMichael Hamann $comment = $data['comments'][$cid]; 170210b5d61eSMichael Hamann 170310b5d61eSMichael Hamann if (!is_array($comment)) return false; // corrupt datatype 170410b5d61eSMichael Hamann if ($comment['parent'] != $parent) return false; // reply to an other comment 170510b5d61eSMichael Hamann if (!$comment['show']) return false; // hidden comment 170610b5d61eSMichael Hamann 1707*c3413364SGerrit Uitslag $text = PhpString::strtolower($comment['raw']); 170810b5d61eSMichael Hamann if (strpos($text, $phrase) !== false) { 170910b5d61eSMichael Hamann return true; 171010b5d61eSMichael Hamann } 171110b5d61eSMichael Hamann 171210b5d61eSMichael Hamann if (is_array($comment['replies'])) { // and the replies 171310b5d61eSMichael Hamann foreach ($comment['replies'] as $rid) { 1714*c3413364SGerrit Uitslag if ($this->phraseMatchInComment($phrase, $rid, $data, $cid)) { 171510b5d61eSMichael Hamann return true; 171610b5d61eSMichael Hamann } 171710b5d61eSMichael Hamann } 171810b5d61eSMichael Hamann } 171910b5d61eSMichael Hamann return false; 172010b5d61eSMichael Hamann } 172110b5d61eSMichael Hamann 1722a1ca9e44Swikidesign /** 1723*c3413364SGerrit Uitslag * Saves the current comment status and title from metadata into the .comments file 1724de7e6f00SGerrit Uitslag * 1725de7e6f00SGerrit Uitslag * @param Doku_Event $event 1726de7e6f00SGerrit Uitslag * @param $param 1727c1530f74SMichael Hamann */ 1728de7e6f00SGerrit Uitslag public function update_comment_status(Doku_Event $event, $param) { 1729c1530f74SMichael Hamann global $ID; 1730c1530f74SMichael Hamann 1731c1530f74SMichael Hamann $meta = $event->data['current']; 1732c1530f74SMichael Hamann $file = metaFN($ID, '.comments'); 1733f0bcde18SGerrit Uitslag $status = ($this->isDiscussionEnabled() ? 1 : 0); 1734*c3413364SGerrit Uitslag $title = null; 1735c1530f74SMichael Hamann if (isset($meta['plugin_discussion'])) { 1736*c3413364SGerrit Uitslag $status = $meta['plugin_discussion']['status']; // 0, 1 or 2 1737c1530f74SMichael Hamann $title = $meta['plugin_discussion']['title']; 1738c1530f74SMichael Hamann } else if ($status == 1) { 1739c1530f74SMichael Hamann // Don't enable comments when automatic comments are on - this already happens automatically 1740c1530f74SMichael Hamann // and if comments are turned off in the admin this only updates the .comments file 1741c1530f74SMichael Hamann return; 1742c1530f74SMichael Hamann } 1743c1530f74SMichael Hamann 1744c1530f74SMichael Hamann if ($status || @file_exists($file)) { 1745*c3413364SGerrit Uitslag $data = []; 1746c1530f74SMichael Hamann if (@file_exists($file)) { 1747c1530f74SMichael Hamann $data = unserialize(io_readFile($file, false)); 1748c1530f74SMichael Hamann } 1749c1530f74SMichael Hamann 1750c1530f74SMichael Hamann if (!array_key_exists('title', $data) || $data['title'] !== $title || !isset($data['status']) || $data['status'] !== $status) { 1751c1530f74SMichael Hamann $data['title'] = $title; 1752c1530f74SMichael Hamann $data['status'] = $status; 1753*c3413364SGerrit Uitslag if (!isset($data['number'])) { 1754c1530f74SMichael Hamann $data['number'] = 0; 1755*c3413364SGerrit Uitslag } 1756c1530f74SMichael Hamann io_saveFile($file, serialize($data)); 1757c1530f74SMichael Hamann } 1758c1530f74SMichael Hamann } 1759c1530f74SMichael Hamann } 1760c1530f74SMichael Hamann 1761c1530f74SMichael Hamann /** 1762*c3413364SGerrit Uitslag * Return words of a given comment and its replies, suitable to be added to the index 1763de7e6f00SGerrit Uitslag * 1764*c3413364SGerrit Uitslag * @param string $cid comment id 1765*c3413364SGerrit Uitslag * @param array $data array with all comments by reference 1766*c3413364SGerrit Uitslag * @param string $parent cid of parent 1767de7e6f00SGerrit Uitslag * @return string 1768a1ca9e44Swikidesign */ 1769*c3413364SGerrit Uitslag protected function addCommentWords($cid, &$data, $parent = '') { 1770a1ca9e44Swikidesign 1771efbe59d0Swikidesign if (!isset($data['comments'][$cid])) return ''; // comment was removed 1772*c3413364SGerrit Uitslag 1773a1ca9e44Swikidesign $comment = $data['comments'][$cid]; 1774a1ca9e44Swikidesign 1775efbe59d0Swikidesign if (!is_array($comment)) return ''; // corrupt datatype 1776efbe59d0Swikidesign if ($comment['parent'] != $parent) return ''; // reply to an other comment 1777efbe59d0Swikidesign if (!$comment['show']) return ''; // hidden comment 1778a1ca9e44Swikidesign 1779efbe59d0Swikidesign $text = $comment['raw']; // we only add the raw comment text 1780efbe59d0Swikidesign if (is_array($comment['replies'])) { // and the replies 1781efbe59d0Swikidesign foreach ($comment['replies'] as $rid) { 1782*c3413364SGerrit Uitslag $text .= $this->addCommentWords($rid, $data, $cid); 1783a1ca9e44Swikidesign } 1784a1ca9e44Swikidesign } 1785efbe59d0Swikidesign return ' '.$text; 1786efbe59d0Swikidesign } 1787a10b5c98SMichael Klier 1788a10b5c98SMichael Klier /** 1789a10b5c98SMichael Klier * Only allow http(s) URLs and append http:// to URLs if needed 1790de7e6f00SGerrit Uitslag * 1791de7e6f00SGerrit Uitslag * @param string $url 1792de7e6f00SGerrit Uitslag * @return string 1793a10b5c98SMichael Klier */ 1794*c3413364SGerrit Uitslag protected function checkURL($url) { 1795a10b5c98SMichael Klier if(preg_match("#^http://|^https://#", $url)) { 1796a10b5c98SMichael Klier return hsc($url); 1797a10b5c98SMichael Klier } elseif(substr($url, 0, 4) == 'www.') { 1798*c3413364SGerrit Uitslag return hsc('https://' . $url); 1799a10b5c98SMichael Klier } else { 1800a10b5c98SMichael Klier return ''; 1801a10b5c98SMichael Klier } 1802a10b5c98SMichael Klier } 180331aab30eSGina Haeussge 1804de7e6f00SGerrit Uitslag /** 1805de7e6f00SGerrit Uitslag * Sort threads 1806de7e6f00SGerrit Uitslag * 1807de7e6f00SGerrit Uitslag * @param $a 1808de7e6f00SGerrit Uitslag * @param $b 1809de7e6f00SGerrit Uitslag * @return int 1810de7e6f00SGerrit Uitslag */ 1811*c3413364SGerrit Uitslag function sortCallback($a, $b) { 18127e018cb6Slpaulsen93 if (is_array($a['date'])) { 18137e018cb6Slpaulsen93 // new format 181431aab30eSGina Haeussge $createdA = $a['date']['created']; 18157e018cb6Slpaulsen93 } else { 18167e018cb6Slpaulsen93 // old format 181731aab30eSGina Haeussge $createdA = $a['date']; 181831aab30eSGina Haeussge } 181931aab30eSGina Haeussge 18207e018cb6Slpaulsen93 if (is_array($b['date'])) { 18217e018cb6Slpaulsen93 // new format 182231aab30eSGina Haeussge $createdB = $b['date']['created']; 18237e018cb6Slpaulsen93 } else { 18247e018cb6Slpaulsen93 // old format 182531aab30eSGina Haeussge $createdB = $b['date']; 182631aab30eSGina Haeussge } 182731aab30eSGina Haeussge 18284cded5e1SGerrit Uitslag if ($createdA == $createdB) { 182931aab30eSGina Haeussge return 0; 18304cded5e1SGerrit Uitslag } else { 183131aab30eSGina Haeussge return ($createdA < $createdB) ? -1 : 1; 183231aab30eSGina Haeussge } 18334cded5e1SGerrit Uitslag } 183431aab30eSGina Haeussge 1835*c3413364SGerrit Uitslag} 1836*c3413364SGerrit Uitslag 1837*c3413364SGerrit Uitslag 1838