]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/ModeratedPage.php
enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for...
[SourceForge/phpwiki.git] / lib / plugin / ModeratedPage.php
1 <?php // -*-php-*-
2 rcs_id('$Id: ModeratedPage.php,v 1.3 2004-12-06 19:50:05 rurban Exp $');
3 /*
4  Copyright 2004 $ThePhpWikiProgrammingTeam
5  
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24  * This plugin requires an action page (default: ModeratedPage)
25  * and provides delayed execution of restricted actions, 
26  * after a special moderators request. Usually by email.
27  *   http://mywiki/SomeModeratedPage?action=ModeratedPage&id=kdclcr78431zr43uhrn&pass=approve
28  *
29  * See http://phpwiki.org/PageModeration
30  * Author: ReiniUrban
31  */
32
33 require_once("lib/WikiPlugin.php");
34
35 class WikiPlugin_ModeratedPage
36 extends WikiPlugin
37 {
38     function getName () {
39         return _("ModeratedPage");
40     }
41     function getDescription () {
42         return _("Support moderated pages");
43     }
44     function getVersion() {
45         return preg_replace("/[Revision: $]/", '',
46                             "\$Revision: 1.3 $");
47     }
48     function getDefaultArguments() {
49         return array('page'          => '[pagename]',
50                      'moderators'    => false,
51                      'require_level' => false,   // 1=bogo
52                      'require_access' => 'edit,remove,change',
53                      'id'   => '',
54                      'pass' => '',
55                     );
56     }
57
58     function run($dbi, $argstr, &$request, $basepage) {
59         $args = $this->getArgs($argstr, $request);
60
61         // handle moderation request from the email
62         if (!empty($args['id']) and !empty($args['pass'])) {
63             if (!$args['page'])
64                 return $this->error("No page specified");
65             $page = $dbi->getPage($args['page']);
66             $moderation = $page->get("moderation");
67             if ($moderation) {
68                 if (isset($moderation['id']) and $moderation['id'] == $args['id']) {
69                     // handle defaults:
70                     //   approve or reject
71                     if ($args['pass'] == 'approve')
72                         return $this->approve($args, $moderation);
73                     elseif ($args['pass'] == 'reject')
74                         return $this->reject($args, $moderation);
75                     else
76                         return $this->error("Wrong pass ".$args['pass']);
77                 } else {
78                     return $this->error("Wrong id");
79                 }
80             }
81         }
82         return '';
83     }
84
85     /**
86      * resolve moderators and require_access (not yet) from actionpage plugin argstr
87      */
88     function resolve_argstr(&$request, $argstr) {
89         $args = $this->getArgs($argstr);
90         $group = $request->getGroup();
91         if (empty($args['moderators'])) {
92             $admins = $group->getSpecialMembersOf(GROUP_ADMIN);
93             // email or usernames?
94             $args['moderators'] = array_merge($admins, array(ADMIN_USER));
95         } else { 
96             // resolve possible group names
97             $moderators = explode(',', $args['moderators']); 
98             for ($i=0; $i < count($moderators); $i++) {
99                 $members = $group->getMembersOf($moderators[$i]);
100                 if (!empty($members)) {
101                     array_splice($moderators, $i, 1, $members);
102                 }
103             }
104             if (!$moderators) $moderators = array(ADMIN_USER);
105             $args['moderators'] = $moderators;
106         }
107         //resolve email for $args['moderators']
108         $page = $request->getPage();
109         $users = array();
110         foreach ($args['moderators'] as $userid) {
111             $users[$userid] = 0;
112         }
113         list($args['emails'], $args['moderators']) = $page->getPageChangeEmails(array($page->getName() => $users));
114
115         if (!empty($args['require_access'])) {
116             $args['require_access'] = preg_split("/\s*,\s*/", $args['require_access']);
117             if (empty($args['require_access']))
118                 unset($args['require_access']);
119         }
120         if ($args['require_level'] !== false) {
121             $args['require_level'] = (integer) $args['require_level'];
122         }
123         unset($args['id']);
124         unset($args['page']);
125         unset($args['pass']);
126         return $args;
127     }
128     
129     /**
130      * Handle client-side moderation change request.
131      * Hook called on the lock action, if moderation metadata already exists.
132      */
133     function lock_check(&$request, &$page, $moderated) {
134         $action_page = $request->getPage(_("ModeratedPage"));
135         $status = $this->getSiteStatus($request, $action_page);
136         if (is_array($status)) {
137             if (!empty($status['emails'])) {
138                 trigger_error(_("ModeratedPage: No emails for the moderators defined"), E_USER_WARNING);
139                 return false;
140             }
141             $page->set('moderation', array('_status' => $status));
142             return $this->notice(
143                        fmt("ModeratedPage status update:\n  Moderators: '%s'\n  require_access: '%s'", 
144                        join(',', $status['moderators']), $status['require_access']));
145         } else {
146             $page->set('moderation', false);
147             return $this->notice(HTML($status,
148                         fmt("'%s' is no ModeratedPage anymore.", $page->getName()))); 
149         }
150     }
151
152     /**
153      * Handle client-side moderation change request by the user.
154      * Hook called on the lock action, if moderation metadata should be added.
155      * Need to store the the plugin args (who, when) in the page meta-data
156      */
157     function lock_add(&$request, &$page, &$action_page) {
158         $status = $this->getSiteStatus($request, $action_page);
159         if (is_array($status)) {
160             if (!empty($status['emails'])) {
161                 trigger_error(_("ModeratedPage: No emails for the moderators defined"), E_USER_WARNING);
162                 return false;
163             }
164             $page->set('moderation', array('_status' => $status));
165             return $this->notice(
166                        fmt("ModeratedPage status update: '%s' is now a ModeratedPage.\n  Moderators: '%s'\n  require_access: '%s'", 
167                        $page->getName(), join(',', $status['moderators']), $status['require_access']));
168         }
169         else { // error
170             return $status;
171         }
172     }
173     
174     function notice($msg) {
175         return HTML::div(array('class' => 'wiki-edithelp'), $msg);
176     }
177
178     function generateId() {
179         better_srand();
180         $s = "";
181         for ($i = 1; $i <= 16; $i++) {
182             $r = function_exists('mt_rand') ? mt_rand(55, 90) : rand(55, 90);
183             $s .= chr($r < 65 ? $r-17 : $r);
184         }
185         return $s;
186     }
187
188     /** 
189      * Handle client-side POST moderation request on any moderated page.
190      *   if ($page->get('moderation')) WikiPlugin_ModeratedPage::handler(...);
191      * return false if not handled (pass through), true if handled and displayed.
192      */
193     function handler(&$request, &$page) {
194         $action = $request->getArg('action');
195         $moderated = $page->get('moderated');
196         // cached version, need re-lock of each page to update moderators
197         if (!empty($moderated['_status'])) 
198             $status = $moderated['_status'];
199         else {
200             $action_page = $request->getPage(_("ModeratedPage"));
201             $status = $this->getSiteStatus($request, $action_page);
202             $moderated['_status'] = $status;
203         }
204         if (!empty($status['emails'])) {
205             trigger_error(_("ModeratedPage: No emails for the moderators defined"), E_USER_WARNING);
206             return true;
207         }
208         // which action?
209         if (!empty($status['require_access']) and !in_array(action2access($action), $status['require_access']))
210             return false; // allow and fall through, not moderated
211         if (!empty($status['require_level']) and $request->_user->_level >= $status['require_level'])
212             return false; // allow and fall through, not moderated
213         // else all post actions are moderated by default
214         if (1) /* or in_array($action, array('edit','remove','rename')*/ {
215             //$moderated = $page->get('moderated');
216             $id = $this->generateId();
217             while (!empty($moderated[$id])) $id = $this->generateId(); // avoid duplicates
218             $moderated['id'] = $id;             // overwrite current id
219             $moderated['data'][$id] = array(    // add current request
220                                             'timestamp' => time(),
221                                             'userid' => $request->_user->getId(),
222                                             'args' => $request->getArgs(),
223                                             'user'   => serialize($request->_user),
224                                             );
225             $this->_tokens['CONTENT'] = HTML::div(array('class' => 'wikitext'),
226                                                   fmt("%s: action forwarded to moderator %s", 
227                                                       $action, 
228                                                       join(", ", $status['moderators'])
229                                                       ));
230             //send email
231             $pagename = $page->getName();
232             $subject = "[".WIKI_NAME.'] '.$action.': '._("ModeratedPage").' '.$pagename;
233             if (mail(join(",", $status['emails']), 
234                      $subject, 
235                      $action.': '._("ModeratedPage").' '.$pagename."\n"
236                      . serialize($moderated['data'][$id])
237                      ."\n<".WikiURL($pagename, array('action' => _("ModeratedPage"), 
238                                                      'id' => $id, 'pass' => 'approve'), 1).">"
239                      ."\n<".WikiURL($pagename, array('action' => _("ModeratedPage"), 
240                                                      'id' => $id, 'pass' => 'reject'), 1).">\n"
241                      )) {
242                 $page->set('moderated', $moderated);
243                 return false; // pass thru
244             } else {
245                 //FIXME: This will msg get lost on the edit redirect
246                 trigger_error(_("ModeratedPage Notification Error: Couldn't send email"), E_USER_WARNING);
247                 return true;
248             }
249         }
250         return false;
251     }
252
253     /** 
254      * Handle admin-side moderation resolve.
255      * We might have to convert the GET to a POST request to continue with the left-over stored request.
256      */
257     function approve($args, $moderation) {
258         // check id, convert to POST, continue
259         ;
260     }
261     /** 
262      * Handle admin-side moderation resolve.
263      */
264     function reject($args, $moderation) {
265         // check id, delete action
266         ;
267     }
268     
269     /**
270      * Get the side-wide ModeratedPage status, reading the action-page args.
271      * Who are the moderators? What actions should be moderated?
272      */
273     function getSiteStatus(&$request, &$action_page) {
274         $loader = new WikiPluginLoader();
275         $rev = $action_page->getCurrentRevision();
276         $content = $rev->getPackedContent();
277         list($pi) = explode("\n", $content, 2); // plugin ModeratedPage must be first line!
278         if ($parsed = $loader->parsePI($pi)) {
279             $plugin =& $parsed[1];
280             if ($plugin->getName() != _("ModeratedPage"))
281                 return $this->error(sprintf(_("<?plugin ModeratedPage ... ?> not found in first line of %s"),
282                                             $action_page->getName()));
283             if (!$action_page->get('locked'))
284                 return $this->error(sprintf(_("%s is not locked!"),
285                                             $action_page->getName()));
286             return $plugin->resolve_argstr($request, $parsed[2]);
287         } else {
288             return $this->error(sprintf(_("<?plugin ModeratedPage ... ?> not found in first line of %s"),
289                                         $action_page->getName()));
290         }
291     }
292     
293 };
294
295 // $Log: not supported by cvs2svn $
296 // Revision 1.2  2004/11/30 17:46:49  rurban
297 // added ModeratedPage POST action hook (part 2/3)
298 //
299 // Revision 1.1  2004/11/19 19:22:35  rurban
300 // ModeratePage part1: change status
301 //
302
303 // For emacs users
304 // Local Variables:
305 // mode: php
306 // tab-width: 8
307 // c-basic-offset: 4
308 // c-hanging-comment-ender-p: nil
309 // indent-tabs-mode: nil
310 // End:
311 ?>