1a768ba62Swikidesign<?php 2264b7327Swikidesign/** 3264b7327Swikidesign * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4264b7327Swikidesign * @author Esther Brunner <wikidesign@gmail.com> 5264b7327Swikidesign */ 6264b7327Swikidesign 7264b7327Swikidesign// must be run within Dokuwiki 8264b7327Swikidesignif (!defined('DOKU_INC')) die(); 9264b7327Swikidesign 10a768ba62Swikidesignif (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 11264b7327Swikidesign 12a768ba62Swikidesignrequire_once(DOKU_PLUGIN.'admin.php'); 13a768ba62Swikidesign 14a768ba62Swikidesignclass admin_plugin_discussion extends DokuWiki_Admin_Plugin { 15a768ba62Swikidesign 16a768ba62Swikidesign function getInfo(){ 17a768ba62Swikidesign return array( 184c4d91c6SGina Haeussge 'author' => 'Gina Häußge, Michael Klier, Esther Brunner', 194c4d91c6SGina Haeussge 'email' => 'dokuwiki@chimeric.de', 203e02b3ffSwikidesign 'date' => '2007-08-22', 21264b7327Swikidesign 'name' => 'Discussion Plugin (admin component)', 22573e23a1Swikidesign 'desc' => 'Moderate discussions', 234c4d91c6SGina Haeussge 'url' => 'http://wiki.splitbrain.org/plugin:discussion', 24a768ba62Swikidesign ); 25a768ba62Swikidesign } 26a768ba62Swikidesign 27264b7327Swikidesign function getMenuSort(){ return 200; } 28264b7327Swikidesign function forAdminOnly(){ return false; } 29a768ba62Swikidesign 30573e23a1Swikidesign function handle(){ 31573e23a1Swikidesign global $lang; 32573e23a1Swikidesign 33573e23a1Swikidesign $cid = $_REQUEST['cid']; 34573e23a1Swikidesign if (is_array($cid)) $cid = array_keys($cid); 35573e23a1Swikidesign 36573e23a1Swikidesign $action =& plugin_load('action', 'discussion'); 37573e23a1Swikidesign if (!$action) return; // couldn't load action plugin component 38573e23a1Swikidesign 39573e23a1Swikidesign switch ($_REQUEST['comment']){ 40573e23a1Swikidesign case $lang['btn_delete']: 41573e23a1Swikidesign $action->_save($cid, ''); 42573e23a1Swikidesign break; 43573e23a1Swikidesign 44573e23a1Swikidesign case $this->getLang('btn_show'): 45573e23a1Swikidesign $action->_save($cid, '', 'show'); 46573e23a1Swikidesign break; 47573e23a1Swikidesign 48573e23a1Swikidesign case $this->getLang('btn_hide'): 49573e23a1Swikidesign $action->_save($cid, '', 'hide'); 50573e23a1Swikidesign break; 51573e23a1Swikidesign 52573e23a1Swikidesign case $this->getLang('btn_change'): 536fd05bf5Swikidesign $this->_changeStatus($_REQUEST['status']); 54573e23a1Swikidesign break; 55573e23a1Swikidesign } 56573e23a1Swikidesign } 57573e23a1Swikidesign 58a768ba62Swikidesign function html(){ 59264b7327Swikidesign global $conf; 60264b7327Swikidesign 61573e23a1Swikidesign $first = $_REQUEST['first']; 62573e23a1Swikidesign if (!is_numeric($first)) $first = 0; 63573e23a1Swikidesign $num = $conf['recent']; 64264b7327Swikidesign 65573e23a1Swikidesign ptln('<h1>'.$this->getLang('menu').'</h1>'); 66264b7327Swikidesign 67573e23a1Swikidesign $threads = $this->_getThreads(); 68573e23a1Swikidesign 69573e23a1Swikidesign // slice the needed chunk of discussion pages 70573e23a1Swikidesign $more = ((count($threads) > ($first + $num)) ? true : false); 71573e23a1Swikidesign $threads = array_slice($threads, $first, $num); 72573e23a1Swikidesign 73264b7327Swikidesign foreach ($threads as $thread){ 74573e23a1Swikidesign $comments = $this->_getComments($thread); 75573e23a1Swikidesign $this->_threadHead($thread); 76573e23a1Swikidesign if ($comments === false){ 776fd05bf5Swikidesign ptln('</div>', 6); // class="level2" 78264b7327Swikidesign continue; 79264b7327Swikidesign } 80264b7327Swikidesign 816fd05bf5Swikidesign ptln('<form method="post" action="'.wl($thread['id']).'">', 8); 826fd05bf5Swikidesign ptln('<div class="no">', 10); 836fd05bf5Swikidesign ptln('<input type="hidden" name="do" value="admin" />', 10); 846fd05bf5Swikidesign ptln('<input type="hidden" name="page" value="discussion" />', 10); 85264b7327Swikidesign echo html_buildlist($comments, 'admin_discussion', array($this, '_commentItem'), array($this, '_li_comment')); 86573e23a1Swikidesign $this->_actionButtons($thread['id']); 87264b7327Swikidesign } 88573e23a1Swikidesign $this->_browseDiscussionLinks($more, $first, $num); 896fd05bf5Swikidesign 90264b7327Swikidesign } 91264b7327Swikidesign 92264b7327Swikidesign /** 93573e23a1Swikidesign * Returns an array of pages with discussion sections, sorted by recent comments 94573e23a1Swikidesign */ 95573e23a1Swikidesign function _getThreads(){ 96573e23a1Swikidesign global $conf; 97573e23a1Swikidesign 98573e23a1Swikidesign require_once(DOKU_INC.'inc/search.php'); 99573e23a1Swikidesign 100573e23a1Swikidesign // returns the list of pages in the given namespace and it's subspaces 101573e23a1Swikidesign $items = array(); 102573e23a1Swikidesign search($items, $conf['datadir'], 'search_allpages', ''); 103573e23a1Swikidesign 104573e23a1Swikidesign // add pages with comments to result 105573e23a1Swikidesign $result = array(); 106573e23a1Swikidesign foreach ($items as $item){ 107573e23a1Swikidesign $id = $item['id']; 108573e23a1Swikidesign 109573e23a1Swikidesign // some checks 110573e23a1Swikidesign $file = metaFN($id, '.comments'); 111573e23a1Swikidesign if (!@file_exists($file)) continue; // skip if no comments file 112573e23a1Swikidesign 113573e23a1Swikidesign $date = filemtime($file); 114573e23a1Swikidesign $result[$date] = array( 115573e23a1Swikidesign 'id' => $id, 116573e23a1Swikidesign 'file' => $file, 117573e23a1Swikidesign 'date' => $date, 118573e23a1Swikidesign ); 119573e23a1Swikidesign } 120573e23a1Swikidesign 121573e23a1Swikidesign // finally sort by time of last comment 122573e23a1Swikidesign krsort($result); 123573e23a1Swikidesign 124573e23a1Swikidesign return $result; 125573e23a1Swikidesign } 126573e23a1Swikidesign 127573e23a1Swikidesign /** 128573e23a1Swikidesign * Outputs header, page ID and status of a discussion thread 129264b7327Swikidesign */ 130264b7327Swikidesign function _threadHead($thread){ 131573e23a1Swikidesign $id = $thread['id']; 132573e23a1Swikidesign 133573e23a1Swikidesign $labels = array( 134573e23a1Swikidesign 0 => $this->getLang('off'), 135573e23a1Swikidesign 1 => $this->getLang('open'), 136573e23a1Swikidesign 2 => $this->getLang('closed') 137264b7327Swikidesign ); 1386fd05bf5Swikidesign $title = p_get_metadata($id, 'title'); 1396fd05bf5Swikidesign if (!$title) $title = $id; 1406fd05bf5Swikidesign ptln('<h2 name="'.$id.'" id="'.$id.'">'.hsc($title).'</h2>', 6); 1416fd05bf5Swikidesign ptln('<form method="post" action="'.wl($id).'">', 6); 1426fd05bf5Swikidesign ptln('<div class="mediaright">', 8); 1436fd05bf5Swikidesign ptln('<input type="hidden" name="do" value="admin" />', 10); 1446fd05bf5Swikidesign ptln('<input type="hidden" name="page" value="discussion" />', 10); 1456fd05bf5Swikidesign ptln($this->getLang('status').': <select name="status" size="1">', 10); 146573e23a1Swikidesign foreach ($labels as $key => $label){ 147573e23a1Swikidesign $selected = (($key == $thread['status']) ? ' selected="selected"' : ''); 1486fd05bf5Swikidesign ptln('<option value="'.$key.'"'.$selected.'>'.$label.'</option>', 12); 149573e23a1Swikidesign } 1506fd05bf5Swikidesign ptln('</select> ', 10); 1516fd05bf5Swikidesign ptln('<input type="submit" name="comment" value="'.$this->getLang('btn_change').'" class"button" title="'.$this->getLang('btn_change').'" />', 10); 1526fd05bf5Swikidesign ptln('</div>', 8); 1536fd05bf5Swikidesign ptln('</form>', 6); 1546fd05bf5Swikidesign ptln('<div class="level2">', 6); 1556fd05bf5Swikidesign ptln('<a href="'.wl($id).'" class="wikilink1">'.$id.'</a> ', 8); 156573e23a1Swikidesign return true; 157573e23a1Swikidesign } 158573e23a1Swikidesign 159573e23a1Swikidesign /** 160573e23a1Swikidesign * Returns the full comments data for a given wiki page 161573e23a1Swikidesign */ 162573e23a1Swikidesign function _getComments(&$thread){ 163573e23a1Swikidesign $id = $thread['id']; 164573e23a1Swikidesign 165573e23a1Swikidesign if (!$thread['file']) $thread['file'] = metaFN($id, '.comments'); 166573e23a1Swikidesign if (!@file_exists($thread['file'])) return false; // no discussion thread at all 167573e23a1Swikidesign 168573e23a1Swikidesign $data = unserialize(io_readFile($thread['file'], false)); 169573e23a1Swikidesign 170573e23a1Swikidesign $thread['status'] = $data['status']; 171573e23a1Swikidesign $thread['number'] = $data['number']; 172573e23a1Swikidesign if (!$data['status']) return false; // comments are turned off 1736fd05bf5Swikidesign if (!$data['comments']) return false; // no comments 174573e23a1Swikidesign 175573e23a1Swikidesign $result = array(); 176573e23a1Swikidesign foreach ($data['comments'] as $cid => $comment){ 177573e23a1Swikidesign $this->_addComment($cid, $data, $result); 178573e23a1Swikidesign } 179573e23a1Swikidesign 1806fd05bf5Swikidesign if (empty($result)) return false; 1816fd05bf5Swikidesign else return $result; 182573e23a1Swikidesign } 183573e23a1Swikidesign 184573e23a1Swikidesign /** 185573e23a1Swikidesign * Recursive function to add the comment hierarchy to the result 186573e23a1Swikidesign */ 187573e23a1Swikidesign function _addComment($cid, &$data, &$result, $parent = '', $level = 1){ 188573e23a1Swikidesign if (!is_array($data['comments'][$cid])) return; // corrupt datatype 189573e23a1Swikidesign $comment = $data['comments'][$cid]; 190573e23a1Swikidesign if ($comment['parent'] != $parent) return; // answer to another comment 191573e23a1Swikidesign 192573e23a1Swikidesign // okay, add the comment to the result 193573e23a1Swikidesign $comment['id'] = $cid; 194573e23a1Swikidesign $comment['level'] = $level; 195573e23a1Swikidesign $result[] = $comment; 196573e23a1Swikidesign 197573e23a1Swikidesign // check answers to this comment 198573e23a1Swikidesign if (count($comment['replies'])){ 199573e23a1Swikidesign foreach ($comment['replies'] as $rid){ 200573e23a1Swikidesign $this->_addComment($rid, $data, $result, $cid, $level + 1); 201573e23a1Swikidesign } 202573e23a1Swikidesign } 203264b7327Swikidesign } 204264b7327Swikidesign 205264b7327Swikidesign /** 206264b7327Swikidesign * Checkbox and info about a comment item 207264b7327Swikidesign */ 208264b7327Swikidesign function _commentItem($comment){ 209264b7327Swikidesign global $conf; 210264b7327Swikidesign 211264b7327Swikidesign // prepare variables 212264b7327Swikidesign if (is_array($comment['user'])){ // new format 213264b7327Swikidesign $name = $comment['user']['name']; 214264b7327Swikidesign $mail = $comment['user']['mail']; 215264b7327Swikidesign } else { // old format 216264b7327Swikidesign $name = $comment['name']; 217264b7327Swikidesign $mail = $comment['mail']; 218264b7327Swikidesign } 219264b7327Swikidesign if (is_array($comment['date'])){ // new format 220264b7327Swikidesign $created = $comment['date']['created']; 221264b7327Swikidesign } else { // old format 222264b7327Swikidesign $created = $comment['date']; 223264b7327Swikidesign } 224573e23a1Swikidesign $abstract = preg_replace('/\s+?/', ' ', strip_tags($comment['xhtml'])); 225264b7327Swikidesign if (utf8_strlen($abstract) > 160) $abstract = utf8_substr($abstract, 0, 160).'...'; 226264b7327Swikidesign 227573e23a1Swikidesign return '<input type="checkbox" name="cid['.$comment['id'].']" value="1" /> '. 228*f014bc86SMichael Klier $this->email($mail, $name, 'email').', '.strftime($conf['dformat'], $created).': '. 229573e23a1Swikidesign '<span class="abstract">'.$abstract.'</span>'; 230264b7327Swikidesign } 231264b7327Swikidesign 232264b7327Swikidesign /** 233264b7327Swikidesign * list item tag 234264b7327Swikidesign */ 235264b7327Swikidesign function _li_comment($comment){ 236264b7327Swikidesign $show = ($comment['show'] ? '' : ' hidden'); 237264b7327Swikidesign return '<li class="level'.$comment['level'].$show.'">'; 238264b7327Swikidesign } 239264b7327Swikidesign 240264b7327Swikidesign /** 241264b7327Swikidesign * Show buttons to bulk remove, hide or show comments 242264b7327Swikidesign */ 243264b7327Swikidesign function _actionButtons($id){ 244264b7327Swikidesign global $lang; 245264b7327Swikidesign 2466fd05bf5Swikidesign ptln('<div class="comment_buttons">', 12); 2476fd05bf5Swikidesign ptln('<input type="submit" name="comment" value="'.$this->getLang('btn_show').'" class="button" title="'.$this->getLang('btn_show').'" />', 14); 2486fd05bf5Swikidesign ptln('<input type="submit" name="comment" value="'.$this->getLang('btn_hide').'" class="button" title="'.$this->getLang('btn_hide').'" />', 14); 2496fd05bf5Swikidesign ptln('<input type="submit" name="comment" value="'.$lang['btn_delete'].'" class="button" title="'.$lang['btn_delete'].'" />', 14); 2506fd05bf5Swikidesign ptln('</div>', 12); // class="comment_buttons" 2516fd05bf5Swikidesign ptln('</div>', 10); // class="no" 2526fd05bf5Swikidesign ptln('</form>', 8); 2536fd05bf5Swikidesign ptln('</div>', 6); // class="level2" 254573e23a1Swikidesign return true; 255573e23a1Swikidesign } 256573e23a1Swikidesign 257573e23a1Swikidesign /** 258573e23a1Swikidesign * Displays links to older newer discussions 259573e23a1Swikidesign */ 260573e23a1Swikidesign function _browseDiscussionLinks($more, $first, $num){ 261573e23a1Swikidesign global $ID; 262573e23a1Swikidesign 2633e02b3ffSwikidesign if (($first == 0) && (!$more)) return true; 2643e02b3ffSwikidesign 265573e23a1Swikidesign $params = array('do' => 'admin', 'page' => 'discussion'); 266573e23a1Swikidesign $last = $first+$num; 2676fd05bf5Swikidesign ptln('<div class="level1">', 8); 268573e23a1Swikidesign if ($first > 0){ 269573e23a1Swikidesign $first -= $num; 270573e23a1Swikidesign if ($first < 0) $first = 0; 271573e23a1Swikidesign $params['first'] = $first; 2726fd05bf5Swikidesign ptln('<p class="centeralign">', 8); 273573e23a1Swikidesign $ret = '<a href="'.wl($ID, $params).'" class="wikilink1"><< '.$this->getLang('newer').'</a>'; 274573e23a1Swikidesign if ($more){ 275573e23a1Swikidesign $ret .= ' | '; 276573e23a1Swikidesign } else { 2776fd05bf5Swikidesign ptln($ret, 10); 2786fd05bf5Swikidesign ptln('</p>', 8); 279573e23a1Swikidesign } 280573e23a1Swikidesign } else if ($more){ 2816fd05bf5Swikidesign ptln('<p class="centeralign">', 8); 282573e23a1Swikidesign } 283573e23a1Swikidesign if ($more){ 284573e23a1Swikidesign $params['first'] = $last; 285573e23a1Swikidesign $ret .= '<a href="'.wl($ID, $params).'" class="wikilink1">'.$this->getLang('older').' >></a>'; 2866fd05bf5Swikidesign ptln($ret, 10); 2876fd05bf5Swikidesign ptln('</p>', 8); 288573e23a1Swikidesign } 2896fd05bf5Swikidesign ptln('</div>', 6); // class="level1" 290573e23a1Swikidesign return true; 291573e23a1Swikidesign } 292573e23a1Swikidesign 293573e23a1Swikidesign /** 294573e23a1Swikidesign * Changes the status of a comment 295573e23a1Swikidesign */ 296573e23a1Swikidesign function _changeStatus($new){ 297573e23a1Swikidesign global $ID; 298573e23a1Swikidesign 299573e23a1Swikidesign // get discussion meta file name 300573e23a1Swikidesign $file = metaFN($ID, '.comments'); 301573e23a1Swikidesign $data = unserialize(io_readFile($file, false)); 302573e23a1Swikidesign 303573e23a1Swikidesign $old = $data['status']; 304573e23a1Swikidesign if ($old == $new) return true; 305573e23a1Swikidesign 306573e23a1Swikidesign // save the comment metadata file 307573e23a1Swikidesign $data['status'] = $new; 308573e23a1Swikidesign io_saveFile($file, serialize($data)); 309573e23a1Swikidesign 310573e23a1Swikidesign // look for ~~DISCUSSION~~ command in page file and change it accordingly 3113e02b3ffSwikidesign $patterns = array('~~DISCUSSION:off\2~~', '~~DISCUSSION\2~~', '~~DISCUSSION:closed\2~~'); 312573e23a1Swikidesign $replace = $patterns[$new]; 3133e02b3ffSwikidesign $wiki = preg_replace('/~~DISCUSSION([\w:]*)(\|?.*?)~~/', $replace, rawWiki($ID)); 314573e23a1Swikidesign saveWikiText($ID, $wiki, $this->getLang('statuschanged'), true); 315573e23a1Swikidesign 316573e23a1Swikidesign return true; 317264b7327Swikidesign } 318264b7327Swikidesign 3195ef1705fSiLoveiDo} 320264b7327Swikidesign 321264b7327Swikidesign//Setup VIM: ex: et ts=4 enc=utf-8 : 322