15fc512fbSwikidesign<?php 25fc512fbSwikidesign/** 35fc512fbSwikidesign * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 45fc512fbSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 55fc512fbSwikidesign */ 65fc512fbSwikidesign 7e7ac9adaSGerrit Uitslag/** 8e7ac9adaSGerrit Uitslag * Class helper_plugin_discussion 9e7ac9adaSGerrit Uitslag */ 10ecbf11fbSGerrit Uitslagclass helper_plugin_discussion extends DokuWiki_Plugin 11ecbf11fbSGerrit Uitslag{ 125fc512fbSwikidesign 13e7ac9adaSGerrit Uitslag /** 14e7ac9adaSGerrit Uitslag * @return array 15e7ac9adaSGerrit Uitslag */ 16ecbf11fbSGerrit Uitslag public function getMethods() 17ecbf11fbSGerrit Uitslag { 18ecbf11fbSGerrit Uitslag $result = []; 19ecbf11fbSGerrit Uitslag $result[] = [ 205fc512fbSwikidesign 'name' => 'th', 215fc512fbSwikidesign 'desc' => 'returns the header of the comments column for pagelist', 22ecbf11fbSGerrit Uitslag 'return' => ['header' => 'string'], 23ecbf11fbSGerrit Uitslag ]; 24ecbf11fbSGerrit Uitslag $result[] = [ 255fc512fbSwikidesign 'name' => 'td', 265fc512fbSwikidesign 'desc' => 'returns the link to the discussion section with number of comments', 27ecbf11fbSGerrit Uitslag 'params' => [ 285fc512fbSwikidesign 'id' => 'string', 29ecbf11fbSGerrit Uitslag 'number of comments (optional)' => 'integer'], 30ecbf11fbSGerrit Uitslag 'return' => ['link' => 'string'], 31ecbf11fbSGerrit Uitslag ]; 32ecbf11fbSGerrit Uitslag $result[] = [ 335fc512fbSwikidesign 'name' => 'getThreads', 345fc512fbSwikidesign 'desc' => 'returns pages with discussion sections, sorted by recent comments', 35ecbf11fbSGerrit Uitslag 'params' => [ 365fc512fbSwikidesign 'namespace' => 'string', 37ecbf11fbSGerrit Uitslag 'number (optional)' => 'integer'], 38ecbf11fbSGerrit Uitslag 'return' => ['pages' => 'array'], 39ecbf11fbSGerrit Uitslag ]; 40ecbf11fbSGerrit Uitslag $result[] = [ 415fc512fbSwikidesign 'name' => 'getComments', 425fc512fbSwikidesign 'desc' => 'returns recently added or edited comments individually', 43ecbf11fbSGerrit Uitslag 'params' => [ 445fc512fbSwikidesign 'namespace' => 'string', 45ecbf11fbSGerrit Uitslag 'number (optional)' => 'integer'], 46ecbf11fbSGerrit Uitslag 'return' => ['pages' => 'array'], 47ecbf11fbSGerrit Uitslag ]; 48ecbf11fbSGerrit Uitslag $result[] = [ 49f3535bedSGerrit Uitslag 'name' => 'isDiscussionModerator', 50f3535bedSGerrit Uitslag 'desc' => 'check if current user is member of moderator groups', 51ecbf11fbSGerrit Uitslag 'params' => [], 52ecbf11fbSGerrit Uitslag 'return' => ['isModerator' => 'boolean'] 53ecbf11fbSGerrit Uitslag ]; 545fc512fbSwikidesign return $result; 555fc512fbSwikidesign } 565fc512fbSwikidesign 575fc512fbSwikidesign /** 585fc512fbSwikidesign * Returns the column header for the Pagelist Plugin 59e7ac9adaSGerrit Uitslag * 60e7ac9adaSGerrit Uitslag * @return string 615fc512fbSwikidesign */ 62ecbf11fbSGerrit Uitslag public function th() 63ecbf11fbSGerrit Uitslag { 645fc512fbSwikidesign return $this->getLang('discussion'); 655fc512fbSwikidesign } 665fc512fbSwikidesign 675fc512fbSwikidesign /** 685fc512fbSwikidesign * Returns the link to the discussion section of a page 69e7ac9adaSGerrit Uitslag * 7006ed893aSGerrit Uitslag * @param string $id page id 7106ed893aSGerrit Uitslag * @param string $col column name, used if more columns needed per plugin 7206ed893aSGerrit Uitslag * @param string $class class name per cell set by reference 7306ed893aSGerrit Uitslag * @param null|int $num number of visible comments -- internally used, not by pagelist plugin 74e7ac9adaSGerrit Uitslag * @return string 755fc512fbSwikidesign */ 76ecbf11fbSGerrit Uitslag public function td($id, $col = null, &$class = null, $num = null) 77ecbf11fbSGerrit Uitslag { 78479dd10fSwikidesign $section = '#discussion__section'; 795fc512fbSwikidesign 805fc512fbSwikidesign if (!isset($num)) { 815fc512fbSwikidesign $cfile = metaFN($id, '.comments'); 825fc512fbSwikidesign $comments = unserialize(io_readFile($cfile, false)); 835fc512fbSwikidesign 84*b189aa83Satisne if ($comments) { 855fc512fbSwikidesign $num = $comments['number']; 86ecbf11fbSGerrit Uitslag if (!$comments['status'] || ($comments['status'] == 2 && !$num)) { 87ecbf11fbSGerrit Uitslag return ''; 88ecbf11fbSGerrit Uitslag } 89*b189aa83Satisne } else { 90*b189aa83Satisne $num = 0; 91*b189aa83Satisne } 925fc512fbSwikidesign } 935fc512fbSwikidesign 944cded5e1SGerrit Uitslag if ($num == 0) { 954cded5e1SGerrit Uitslag $comment = '0 ' . $this->getLang('nocomments'); 964cded5e1SGerrit Uitslag } elseif ($num == 1) { 974cded5e1SGerrit Uitslag $comment = '1 ' . $this->getLang('comment'); 984cded5e1SGerrit Uitslag } else { 994cded5e1SGerrit Uitslag $comment = $num . ' ' . $this->getLang('comments'); 1004cded5e1SGerrit Uitslag } 1015fc512fbSwikidesign 102ecbf11fbSGerrit Uitslag return '<a href="' . wl($id) . $section . '" class="wikilink1" title="' . $id . $section . '">' 103ecbf11fbSGerrit Uitslag . $comment 104ecbf11fbSGerrit Uitslag . '</a>'; 1055fc512fbSwikidesign } 1065fc512fbSwikidesign 1075fc512fbSwikidesign /** 1085fc512fbSwikidesign * Returns an array of pages with discussion sections, sorted by recent comments 1094cded5e1SGerrit Uitslag * Note: also used for content by Feed Plugin 110e7ac9adaSGerrit Uitslag * 111e7ac9adaSGerrit Uitslag * @param string $ns 112e7ac9adaSGerrit Uitslag * @param null|int $num 113e7ac9adaSGerrit Uitslag * @param string|bool $skipEmpty 114e7ac9adaSGerrit Uitslag * @return array 1155fc512fbSwikidesign */ 116ecbf11fbSGerrit Uitslag public function getThreads($ns, $num = null, $skipEmpty = false) 117ecbf11fbSGerrit Uitslag { 1185fc512fbSwikidesign global $conf; 1195fc512fbSwikidesign 1205fc512fbSwikidesign // returns the list of pages in the given namespace and it's subspaces 121ab18f68dSGerrit Uitslag $dir = utf8_encodeFN(str_replace(':', '/', $ns)); 122ab18f68dSGerrit Uitslag $opts = [ 123ab18f68dSGerrit Uitslag 'depth' => 0, // 0=all 124ab18f68dSGerrit Uitslag 'skipacl' => true // is checked later 125ab18f68dSGerrit Uitslag ]; 126ecbf11fbSGerrit Uitslag $items = []; 127ab18f68dSGerrit Uitslag search($items, $conf['datadir'], 'search_allpages', $opts, $dir); 1285fc512fbSwikidesign 1295fc512fbSwikidesign // add pages with comments to result 130ecbf11fbSGerrit Uitslag $result = []; 1315fc512fbSwikidesign foreach ($items as $item) { 132ab18f68dSGerrit Uitslag $id = $item['id']; 1335fc512fbSwikidesign 1345fc512fbSwikidesign // some checks 1355fc512fbSwikidesign $perm = auth_quickaclcheck($id); 1365fc512fbSwikidesign if ($perm < AUTH_READ) continue; // skip if no permission 1375fc512fbSwikidesign $file = metaFN($id, '.comments'); 1385fc512fbSwikidesign if (!@file_exists($file)) continue; // skip if no comments file 1395fc512fbSwikidesign $data = unserialize(io_readFile($file, false)); 140264b7327Swikidesign $status = $data['status']; 1415644a1afSlupo49 $number = $data['number']; 1425644a1afSlupo49 143ecbf11fbSGerrit Uitslag if (!$status || ($status == 2 && !$number)) continue; // skip if comments are off or closed without comments 144ab18f68dSGerrit Uitslag if ($skipEmpty && $number == 0) continue; // skip if discussion is empty and flag is set 1455fc512fbSwikidesign 146328362adSGerrit Uitslag //new comments are added to the end of array 147328362adSGerrit Uitslag $date = false; 148328362adSGerrit Uitslag if(isset($data['comments'])) { 149328362adSGerrit Uitslag $latestcomment = end($data['comments']); 150328362adSGerrit Uitslag $date = $latestcomment['date']['created'] ?? false; 151328362adSGerrit Uitslag } 152328362adSGerrit Uitslag //e.g. if no comments 153328362adSGerrit Uitslag if(!$date) { 1545fc512fbSwikidesign $date = filemtime($file); 155328362adSGerrit Uitslag } 156328362adSGerrit Uitslag 1575fc512fbSwikidesign $meta = p_get_metadata($id); 158ecbf11fbSGerrit Uitslag $result[$date . '_' . $id] = [ 1595fc512fbSwikidesign 'id' => $id, 160264b7327Swikidesign 'file' => $file, 16104b83c99SGerrit Uitslag 'title' => $meta['title'] ?? '', 1625fc512fbSwikidesign 'date' => $date, 1635fc512fbSwikidesign 'user' => $meta['creator'], 1645fc512fbSwikidesign 'desc' => $meta['description']['abstract'], 165fcb1bc77Swikidesign 'num' => $number, 16606ed893aSGerrit Uitslag 'comments' => $this->td($id, null, $class, $number), 167264b7327Swikidesign 'status' => $status, 1685fc512fbSwikidesign 'perm' => $perm, 1695fc512fbSwikidesign 'exists' => true, 17073f66a3cSwikidesign 'anchor' => 'discussion__section', 171ecbf11fbSGerrit Uitslag ]; 1725fc512fbSwikidesign } 1735fc512fbSwikidesign 1745fc512fbSwikidesign // finally sort by time of last comment 1755fc512fbSwikidesign krsort($result); 1765fc512fbSwikidesign 177ecbf11fbSGerrit Uitslag if (is_numeric($num)) { 178ecbf11fbSGerrit Uitslag $result = array_slice($result, 0, $num); 179ecbf11fbSGerrit Uitslag } 1805fc512fbSwikidesign 1815fc512fbSwikidesign return $result; 1825fc512fbSwikidesign } 1835fc512fbSwikidesign 1845fc512fbSwikidesign /** 1855fc512fbSwikidesign * Returns an array of recently added comments to a given page or namespace 1864cded5e1SGerrit Uitslag * Note: also used for content by Feed Plugin 187e7ac9adaSGerrit Uitslag * 188e7ac9adaSGerrit Uitslag * @param string $ns 1894aaefe28SGerrit Uitslag * @param int|null $num number of comment per page 190e7ac9adaSGerrit Uitslag * @return array 1915fc512fbSwikidesign */ 192ecbf11fbSGerrit Uitslag public function getComments($ns, $num = null) 193ecbf11fbSGerrit Uitslag { 1944aaefe28SGerrit Uitslag global $conf, $INPUT; 1955fc512fbSwikidesign 1964aaefe28SGerrit Uitslag $first = $INPUT->int('first'); 1975fc512fbSwikidesign 1984aaefe28SGerrit Uitslag if (!$num || !is_numeric($num)) { 199ecbf11fbSGerrit Uitslag $num = $conf['recent']; 200ecbf11fbSGerrit Uitslag } 2015fc512fbSwikidesign 202ecbf11fbSGerrit Uitslag $result = []; 2035fc512fbSwikidesign $count = 0; 2045fc512fbSwikidesign 205ecbf11fbSGerrit Uitslag if (!@file_exists($conf['metadir'] . '/_comments.changes')) { 206ecbf11fbSGerrit Uitslag return $result; 207ecbf11fbSGerrit Uitslag } 2085fc512fbSwikidesign 2095fc512fbSwikidesign // read all recent changes. (kept short) 2105fc512fbSwikidesign $lines = file($conf['metadir'] . '/_comments.changes'); 2115fc512fbSwikidesign 212ecbf11fbSGerrit Uitslag $seen = []; //caches seen pages in order to skip them 2135fc512fbSwikidesign // handle lines 21455e1d144SMichael Hamann $line_num = count($lines); 21555e1d144SMichael Hamann for ($i = ($line_num - 1); $i >= 0; $i--) { 216ecbf11fbSGerrit Uitslag $rec = $this->handleRecentComment($lines[$i], $ns, $seen); 2175fc512fbSwikidesign if ($rec !== false) { 2185fc512fbSwikidesign if (--$first >= 0) continue; // skip first entries 219ecbf11fbSGerrit Uitslag 2205fc512fbSwikidesign $result[$rec['date']] = $rec; 2215fc512fbSwikidesign $count++; 2225fc512fbSwikidesign // break when we have enough entries 2235fc512fbSwikidesign if ($count >= $num) break; 2245fc512fbSwikidesign } 2255fc512fbSwikidesign } 2265fc512fbSwikidesign 2275fc512fbSwikidesign // finally sort by time of last comment 2285fc512fbSwikidesign krsort($result); 2295fc512fbSwikidesign 2305fc512fbSwikidesign return $result; 2315fc512fbSwikidesign } 2325fc512fbSwikidesign 2335fc512fbSwikidesign /* ---------- Changelog function adapted for the Discussion Plugin ---------- */ 2345fc512fbSwikidesign 2355fc512fbSwikidesign /** 2365fc512fbSwikidesign * Internal function used by $this->getComments() 2375fc512fbSwikidesign * 2385fc512fbSwikidesign * don't call directly 2395fc512fbSwikidesign * 2404aaefe28SGerrit Uitslag * @param string $line comment changelog line 2414aaefe28SGerrit Uitslag * @param string $ns namespace (or id) to filter 2424aaefe28SGerrit Uitslag * @param array $seen array to cache seen pages 2434aaefe28SGerrit Uitslag * @return array|false with 2444aaefe28SGerrit Uitslag * 'type' => string, 2454aaefe28SGerrit Uitslag * 'extra' => string comment id, 2464aaefe28SGerrit Uitslag * 'id' => string page id, 2474aaefe28SGerrit Uitslag * 'perm' => int ACL permission 2484aaefe28SGerrit Uitslag * 'file' => string file path of wiki page 2494aaefe28SGerrit Uitslag * 'exists' => bool wiki page exists 2504aaefe28SGerrit Uitslag * 'name' => string name of user 2514aaefe28SGerrit Uitslag * 'desc' => string text of comment 2524aaefe28SGerrit Uitslag * 'anchor' => string 2534aaefe28SGerrit Uitslag * 2545fc512fbSwikidesign * @see getRecentComments() 2555fc512fbSwikidesign * @author Andreas Gohr <andi@splitbrain.org> 2565fc512fbSwikidesign * @author Ben Coburn <btcoburn@silicodon.net> 2575fc512fbSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 258e7ac9adaSGerrit Uitslag * 2595fc512fbSwikidesign */ 260ecbf11fbSGerrit Uitslag protected function handleRecentComment($line, $ns, &$seen) 261ecbf11fbSGerrit Uitslag { 2625fc512fbSwikidesign if (empty($line)) return false; //skip empty lines 2635fc512fbSwikidesign 2645fc512fbSwikidesign // split the line into parts 2655fc512fbSwikidesign $recent = parseChangelogLine($line); 2665fc512fbSwikidesign if ($recent === false) return false; 2675fc512fbSwikidesign 2685fc512fbSwikidesign $cid = $recent['extra']; 2695fc512fbSwikidesign $fullcid = $recent['id'] . '#' . $recent['extra']; 2705fc512fbSwikidesign 2715fc512fbSwikidesign // skip seen ones 2725fc512fbSwikidesign if (isset($seen[$fullcid])) return false; 2735fc512fbSwikidesign 2745fc512fbSwikidesign // skip 'show comment' log entries 2755fc512fbSwikidesign if ($recent['type'] === 'sc') return false; 2765fc512fbSwikidesign 2775fc512fbSwikidesign // remember in seen to skip additional sights 2785fc512fbSwikidesign $seen[$fullcid] = 1; 2795fc512fbSwikidesign 2805fc512fbSwikidesign // check if it's a hidden page or comment 2815fc512fbSwikidesign if (isHiddenPage($recent['id'])) return false; 2825fc512fbSwikidesign if ($recent['type'] === 'hc') return false; 2835fc512fbSwikidesign 2845fc512fbSwikidesign // filter namespace or id 285ecbf11fbSGerrit Uitslag if ($ns && strpos($recent['id'] . ':', $ns . ':') !== 0) return false; 2865fc512fbSwikidesign 2875fc512fbSwikidesign // check ACL 2885fc512fbSwikidesign $recent['perm'] = auth_quickaclcheck($recent['id']); 2895fc512fbSwikidesign if ($recent['perm'] < AUTH_READ) return false; 2905fc512fbSwikidesign 2915fc512fbSwikidesign // check existance 2925fc512fbSwikidesign $recent['file'] = wikiFN($recent['id']); 2935fc512fbSwikidesign $recent['exists'] = @file_exists($recent['file']); 2945fc512fbSwikidesign if (!$recent['exists']) return false; 2955fc512fbSwikidesign if ($recent['type'] === 'dc') return false; 2965fc512fbSwikidesign 2975fc512fbSwikidesign // get discussion meta file name 2982cbdac2eSwikidesign $data = unserialize(io_readFile(metaFN($recent['id'], '.comments'), false)); 2995fc512fbSwikidesign 3005fc512fbSwikidesign // check if discussion is turned off 3015fc512fbSwikidesign if ($data['status'] === 0) return false; 3025fc512fbSwikidesign 3034dd9b9e2SMichael Hamann $parent_id = $cid; 3044dd9b9e2SMichael Hamann // Check for the comment and all parents if they exist and are visible. 3054dd9b9e2SMichael Hamann do { 3064dd9b9e2SMichael Hamann $tcid = $parent_id; 3074dd9b9e2SMichael Hamann 30855e1d144SMichael Hamann // check if the comment still exists 3094dd9b9e2SMichael Hamann if (!isset($data['comments'][$tcid])) return false; 3104dd9b9e2SMichael Hamann // check if the comment is visible 3114dd9b9e2SMichael Hamann if ($data['comments'][$tcid]['show'] != 1) return false; 3124dd9b9e2SMichael Hamann 3134dd9b9e2SMichael Hamann $parent_id = $data['comments'][$tcid]['parent']; 3144dd9b9e2SMichael Hamann } while ($parent_id && $parent_id != $tcid); 31555e1d144SMichael Hamann 3165fc512fbSwikidesign // okay, then add some additional info 3174cded5e1SGerrit Uitslag if (is_array($data['comments'][$cid]['user'])) { 3186046f25cSwikidesign $recent['name'] = $data['comments'][$cid]['user']['name']; 3194cded5e1SGerrit Uitslag } else { 3204cded5e1SGerrit Uitslag $recent['name'] = $data['comments'][$cid]['name']; 3214cded5e1SGerrit Uitslag } 3225fc512fbSwikidesign $recent['desc'] = strip_tags($data['comments'][$cid]['xhtml']); 323d8092064SMichael Hamann $recent['anchor'] = 'comment_' . $cid; 3245fc512fbSwikidesign 3255fc512fbSwikidesign return $recent; 3265fc512fbSwikidesign } 327e6b2f142Slupo49 328e7ac9adaSGerrit Uitslag /** 3294aaefe28SGerrit Uitslag * Check if current user is member of the moderator groups 3304aaefe28SGerrit Uitslag * 3314aaefe28SGerrit Uitslag * @return bool is moderator? 332e7ac9adaSGerrit Uitslag */ 333ecbf11fbSGerrit Uitslag public function isDiscussionModerator() 334ecbf11fbSGerrit Uitslag { 3354aaefe28SGerrit Uitslag global $USERINFO, $INPUT; 336e6b2f142Slupo49 $groups = trim($this->getConf('moderatorgroups')); 337e6b2f142Slupo49 338ecbf11fbSGerrit Uitslag if (auth_ismanager()) { 339ecbf11fbSGerrit Uitslag return true; 340ecbf11fbSGerrit Uitslag } 341e6b2f142Slupo49 // Check if user is member of the moderator groups 3424aaefe28SGerrit Uitslag if (!empty($groups) && auth_isMember($groups, $INPUT->server->str('REMOTE_USER'), (array)$USERINFO['grps'])) { 343ecbf11fbSGerrit Uitslag return true; 344ecbf11fbSGerrit Uitslag } 345e6b2f142Slupo49 346e6b2f142Slupo49 return false; 347e6b2f142Slupo49 } 3485fc512fbSwikidesign} 349