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 845fc512fbSwikidesign $num = $comments['number']; 85ecbf11fbSGerrit Uitslag if (!$comments['status'] || ($comments['status'] == 2 && !$num)) { 86ecbf11fbSGerrit Uitslag return ''; 87ecbf11fbSGerrit Uitslag } 885fc512fbSwikidesign } 895fc512fbSwikidesign 904cded5e1SGerrit Uitslag if ($num == 0) { 914cded5e1SGerrit Uitslag $comment = '0 ' . $this->getLang('nocomments'); 924cded5e1SGerrit Uitslag } elseif ($num == 1) { 934cded5e1SGerrit Uitslag $comment = '1 ' . $this->getLang('comment'); 944cded5e1SGerrit Uitslag } else { 954cded5e1SGerrit Uitslag $comment = $num . ' ' . $this->getLang('comments'); 964cded5e1SGerrit Uitslag } 975fc512fbSwikidesign 98ecbf11fbSGerrit Uitslag return '<a href="' . wl($id) . $section . '" class="wikilink1" title="' . $id . $section . '">' 99ecbf11fbSGerrit Uitslag . $comment 100ecbf11fbSGerrit Uitslag . '</a>'; 1015fc512fbSwikidesign } 1025fc512fbSwikidesign 1035fc512fbSwikidesign /** 1045fc512fbSwikidesign * Returns an array of pages with discussion sections, sorted by recent comments 1054cded5e1SGerrit Uitslag * Note: also used for content by Feed Plugin 106e7ac9adaSGerrit Uitslag * 107e7ac9adaSGerrit Uitslag * @param string $ns 108e7ac9adaSGerrit Uitslag * @param null|int $num 109e7ac9adaSGerrit Uitslag * @param string|bool $skipEmpty 110e7ac9adaSGerrit Uitslag * @return array 1115fc512fbSwikidesign */ 112ecbf11fbSGerrit Uitslag public function getThreads($ns, $num = null, $skipEmpty = false) 113ecbf11fbSGerrit Uitslag { 1145fc512fbSwikidesign global $conf; 1155fc512fbSwikidesign 1165fc512fbSwikidesign // returns the list of pages in the given namespace and it's subspaces 117*ab18f68dSGerrit Uitslag $dir = utf8_encodeFN(str_replace(':', '/', $ns)); 118*ab18f68dSGerrit Uitslag $opts = [ 119*ab18f68dSGerrit Uitslag 'depth' => 0, // 0=all 120*ab18f68dSGerrit Uitslag 'skipacl' => true // is checked later 121*ab18f68dSGerrit Uitslag ]; 122ecbf11fbSGerrit Uitslag $items = []; 123*ab18f68dSGerrit Uitslag search($items, $conf['datadir'], 'search_allpages', $opts, $dir); 1245fc512fbSwikidesign 1255fc512fbSwikidesign // add pages with comments to result 126ecbf11fbSGerrit Uitslag $result = []; 1275fc512fbSwikidesign foreach ($items as $item) { 128*ab18f68dSGerrit Uitslag $id = $item['id']; 1295fc512fbSwikidesign 1305fc512fbSwikidesign // some checks 1315fc512fbSwikidesign $perm = auth_quickaclcheck($id); 1325fc512fbSwikidesign if ($perm < AUTH_READ) continue; // skip if no permission 1335fc512fbSwikidesign $file = metaFN($id, '.comments'); 1345fc512fbSwikidesign if (!@file_exists($file)) continue; // skip if no comments file 1355fc512fbSwikidesign $data = unserialize(io_readFile($file, false)); 136264b7327Swikidesign $status = $data['status']; 1375644a1afSlupo49 $number = $data['number']; 1385644a1afSlupo49 139ecbf11fbSGerrit Uitslag if (!$status || ($status == 2 && !$number)) continue; // skip if comments are off or closed without comments 140*ab18f68dSGerrit Uitslag if ($skipEmpty && $number == 0) continue; // skip if discussion is empty and flag is set 1415fc512fbSwikidesign 1425fc512fbSwikidesign $date = filemtime($file); 1435fc512fbSwikidesign $meta = p_get_metadata($id); 144ecbf11fbSGerrit Uitslag $result[$date . '_' . $id] = [ 1455fc512fbSwikidesign 'id' => $id, 146264b7327Swikidesign 'file' => $file, 1475fc512fbSwikidesign 'title' => $meta['title'], 1485fc512fbSwikidesign 'date' => $date, 1495fc512fbSwikidesign 'user' => $meta['creator'], 1505fc512fbSwikidesign 'desc' => $meta['description']['abstract'], 151fcb1bc77Swikidesign 'num' => $number, 15206ed893aSGerrit Uitslag 'comments' => $this->td($id, null, $class, $number), 153264b7327Swikidesign 'status' => $status, 1545fc512fbSwikidesign 'perm' => $perm, 1555fc512fbSwikidesign 'exists' => true, 15673f66a3cSwikidesign 'anchor' => 'discussion__section', 157ecbf11fbSGerrit Uitslag ]; 1585fc512fbSwikidesign } 1595fc512fbSwikidesign 1605fc512fbSwikidesign // finally sort by time of last comment 1615fc512fbSwikidesign krsort($result); 1625fc512fbSwikidesign 163ecbf11fbSGerrit Uitslag if (is_numeric($num)) { 164ecbf11fbSGerrit Uitslag $result = array_slice($result, 0, $num); 165ecbf11fbSGerrit Uitslag } 1665fc512fbSwikidesign 1675fc512fbSwikidesign return $result; 1685fc512fbSwikidesign } 1695fc512fbSwikidesign 1705fc512fbSwikidesign /** 1715fc512fbSwikidesign * Returns an array of recently added comments to a given page or namespace 1724cded5e1SGerrit Uitslag * Note: also used for content by Feed Plugin 173e7ac9adaSGerrit Uitslag * 174e7ac9adaSGerrit Uitslag * @param string $ns 1754aaefe28SGerrit Uitslag * @param int|null $num number of comment per page 176e7ac9adaSGerrit Uitslag * @return array 1775fc512fbSwikidesign */ 178ecbf11fbSGerrit Uitslag public function getComments($ns, $num = null) 179ecbf11fbSGerrit Uitslag { 1804aaefe28SGerrit Uitslag global $conf, $INPUT; 1815fc512fbSwikidesign 1824aaefe28SGerrit Uitslag $first = $INPUT->int('first'); 1835fc512fbSwikidesign 1844aaefe28SGerrit Uitslag if (!$num || !is_numeric($num)) { 185ecbf11fbSGerrit Uitslag $num = $conf['recent']; 186ecbf11fbSGerrit Uitslag } 1875fc512fbSwikidesign 188ecbf11fbSGerrit Uitslag $result = []; 1895fc512fbSwikidesign $count = 0; 1905fc512fbSwikidesign 191ecbf11fbSGerrit Uitslag if (!@file_exists($conf['metadir'] . '/_comments.changes')) { 192ecbf11fbSGerrit Uitslag return $result; 193ecbf11fbSGerrit Uitslag } 1945fc512fbSwikidesign 1955fc512fbSwikidesign // read all recent changes. (kept short) 1965fc512fbSwikidesign $lines = file($conf['metadir'] . '/_comments.changes'); 1975fc512fbSwikidesign 198ecbf11fbSGerrit Uitslag $seen = []; //caches seen pages in order to skip them 1995fc512fbSwikidesign // handle lines 20055e1d144SMichael Hamann $line_num = count($lines); 20155e1d144SMichael Hamann for ($i = ($line_num - 1); $i >= 0; $i--) { 202ecbf11fbSGerrit Uitslag $rec = $this->handleRecentComment($lines[$i], $ns, $seen); 2035fc512fbSwikidesign if ($rec !== false) { 2045fc512fbSwikidesign if (--$first >= 0) continue; // skip first entries 205ecbf11fbSGerrit Uitslag 2065fc512fbSwikidesign $result[$rec['date']] = $rec; 2075fc512fbSwikidesign $count++; 2085fc512fbSwikidesign // break when we have enough entries 2095fc512fbSwikidesign if ($count >= $num) break; 2105fc512fbSwikidesign } 2115fc512fbSwikidesign } 2125fc512fbSwikidesign 2135fc512fbSwikidesign // finally sort by time of last comment 2145fc512fbSwikidesign krsort($result); 2155fc512fbSwikidesign 2165fc512fbSwikidesign return $result; 2175fc512fbSwikidesign } 2185fc512fbSwikidesign 2195fc512fbSwikidesign /* ---------- Changelog function adapted for the Discussion Plugin ---------- */ 2205fc512fbSwikidesign 2215fc512fbSwikidesign /** 2225fc512fbSwikidesign * Internal function used by $this->getComments() 2235fc512fbSwikidesign * 2245fc512fbSwikidesign * don't call directly 2255fc512fbSwikidesign * 2264aaefe28SGerrit Uitslag * @param string $line comment changelog line 2274aaefe28SGerrit Uitslag * @param string $ns namespace (or id) to filter 2284aaefe28SGerrit Uitslag * @param array $seen array to cache seen pages 2294aaefe28SGerrit Uitslag * @return array|false with 2304aaefe28SGerrit Uitslag * 'type' => string, 2314aaefe28SGerrit Uitslag * 'extra' => string comment id, 2324aaefe28SGerrit Uitslag * 'id' => string page id, 2334aaefe28SGerrit Uitslag * 'perm' => int ACL permission 2344aaefe28SGerrit Uitslag * 'file' => string file path of wiki page 2354aaefe28SGerrit Uitslag * 'exists' => bool wiki page exists 2364aaefe28SGerrit Uitslag * 'name' => string name of user 2374aaefe28SGerrit Uitslag * 'desc' => string text of comment 2384aaefe28SGerrit Uitslag * 'anchor' => string 2394aaefe28SGerrit Uitslag * 2405fc512fbSwikidesign * @see getRecentComments() 2415fc512fbSwikidesign * @author Andreas Gohr <andi@splitbrain.org> 2425fc512fbSwikidesign * @author Ben Coburn <btcoburn@silicodon.net> 2435fc512fbSwikidesign * @author Esther Brunner <wikidesign@gmail.com> 244e7ac9adaSGerrit Uitslag * 2455fc512fbSwikidesign */ 246ecbf11fbSGerrit Uitslag protected function handleRecentComment($line, $ns, &$seen) 247ecbf11fbSGerrit Uitslag { 2485fc512fbSwikidesign if (empty($line)) return false; //skip empty lines 2495fc512fbSwikidesign 2505fc512fbSwikidesign // split the line into parts 2515fc512fbSwikidesign $recent = parseChangelogLine($line); 2525fc512fbSwikidesign if ($recent === false) return false; 2535fc512fbSwikidesign 2545fc512fbSwikidesign $cid = $recent['extra']; 2555fc512fbSwikidesign $fullcid = $recent['id'] . '#' . $recent['extra']; 2565fc512fbSwikidesign 2575fc512fbSwikidesign // skip seen ones 2585fc512fbSwikidesign if (isset($seen[$fullcid])) return false; 2595fc512fbSwikidesign 2605fc512fbSwikidesign // skip 'show comment' log entries 2615fc512fbSwikidesign if ($recent['type'] === 'sc') return false; 2625fc512fbSwikidesign 2635fc512fbSwikidesign // remember in seen to skip additional sights 2645fc512fbSwikidesign $seen[$fullcid] = 1; 2655fc512fbSwikidesign 2665fc512fbSwikidesign // check if it's a hidden page or comment 2675fc512fbSwikidesign if (isHiddenPage($recent['id'])) return false; 2685fc512fbSwikidesign if ($recent['type'] === 'hc') return false; 2695fc512fbSwikidesign 2705fc512fbSwikidesign // filter namespace or id 271ecbf11fbSGerrit Uitslag if ($ns && strpos($recent['id'] . ':', $ns . ':') !== 0) return false; 2725fc512fbSwikidesign 2735fc512fbSwikidesign // check ACL 2745fc512fbSwikidesign $recent['perm'] = auth_quickaclcheck($recent['id']); 2755fc512fbSwikidesign if ($recent['perm'] < AUTH_READ) return false; 2765fc512fbSwikidesign 2775fc512fbSwikidesign // check existance 2785fc512fbSwikidesign $recent['file'] = wikiFN($recent['id']); 2795fc512fbSwikidesign $recent['exists'] = @file_exists($recent['file']); 2805fc512fbSwikidesign if (!$recent['exists']) return false; 2815fc512fbSwikidesign if ($recent['type'] === 'dc') return false; 2825fc512fbSwikidesign 2835fc512fbSwikidesign // get discussion meta file name 2842cbdac2eSwikidesign $data = unserialize(io_readFile(metaFN($recent['id'], '.comments'), false)); 2855fc512fbSwikidesign 2865fc512fbSwikidesign // check if discussion is turned off 2875fc512fbSwikidesign if ($data['status'] === 0) return false; 2885fc512fbSwikidesign 2894dd9b9e2SMichael Hamann $parent_id = $cid; 2904dd9b9e2SMichael Hamann // Check for the comment and all parents if they exist and are visible. 2914dd9b9e2SMichael Hamann do { 2924dd9b9e2SMichael Hamann $tcid = $parent_id; 2934dd9b9e2SMichael Hamann 29455e1d144SMichael Hamann // check if the comment still exists 2954dd9b9e2SMichael Hamann if (!isset($data['comments'][$tcid])) return false; 2964dd9b9e2SMichael Hamann // check if the comment is visible 2974dd9b9e2SMichael Hamann if ($data['comments'][$tcid]['show'] != 1) return false; 2984dd9b9e2SMichael Hamann 2994dd9b9e2SMichael Hamann $parent_id = $data['comments'][$tcid]['parent']; 3004dd9b9e2SMichael Hamann } while ($parent_id && $parent_id != $tcid); 30155e1d144SMichael Hamann 3025fc512fbSwikidesign // okay, then add some additional info 3034cded5e1SGerrit Uitslag if (is_array($data['comments'][$cid]['user'])) { 3046046f25cSwikidesign $recent['name'] = $data['comments'][$cid]['user']['name']; 3054cded5e1SGerrit Uitslag } else { 3064cded5e1SGerrit Uitslag $recent['name'] = $data['comments'][$cid]['name']; 3074cded5e1SGerrit Uitslag } 3085fc512fbSwikidesign $recent['desc'] = strip_tags($data['comments'][$cid]['xhtml']); 309d8092064SMichael Hamann $recent['anchor'] = 'comment_' . $cid; 3105fc512fbSwikidesign 3115fc512fbSwikidesign return $recent; 3125fc512fbSwikidesign } 313e6b2f142Slupo49 314e7ac9adaSGerrit Uitslag /** 3154aaefe28SGerrit Uitslag * Check if current user is member of the moderator groups 3164aaefe28SGerrit Uitslag * 3174aaefe28SGerrit Uitslag * @return bool is moderator? 318e7ac9adaSGerrit Uitslag */ 319ecbf11fbSGerrit Uitslag public function isDiscussionModerator() 320ecbf11fbSGerrit Uitslag { 3214aaefe28SGerrit Uitslag global $USERINFO, $INPUT; 322e6b2f142Slupo49 $groups = trim($this->getConf('moderatorgroups')); 323e6b2f142Slupo49 324ecbf11fbSGerrit Uitslag if (auth_ismanager()) { 325ecbf11fbSGerrit Uitslag return true; 326ecbf11fbSGerrit Uitslag } 327e6b2f142Slupo49 // Check if user is member of the moderator groups 3284aaefe28SGerrit Uitslag if (!empty($groups) && auth_isMember($groups, $INPUT->server->str('REMOTE_USER'), (array)$USERINFO['grps'])) { 329ecbf11fbSGerrit Uitslag return true; 330ecbf11fbSGerrit Uitslag } 331e6b2f142Slupo49 332e6b2f142Slupo49 return false; 333e6b2f142Slupo49 } 3345fc512fbSwikidesign} 335