]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/WikiPoll.php
enabled require_all check in WikiPoll
[SourceForge/phpwiki.git] / lib / plugin / WikiPoll.php
1 <?php // -*-php-*-
2 rcs_id('$Id: WikiPoll.php,v 1.2 2004-02-24 03:21:46 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  * This plugin provides configurable polls.
24  *
25  * Usage:
26  * <?plugin WikiPoll
27  *          question[1]="Do you like PhpWiki?"
28  *            answer[1][1]="Yes" answer[1][2]="Do not know" answer[1][3]="No"
29  *          question[2]="Did you install other wiki engines before?"
30  *            answer[2][1]="Yes" answer[2][2]="No"
31  *          question[3]="What wiki engine do you like most?"
32  *            answer[3][1]="c2Wiki" answer[3][2]="MoinMoin" answer[3][3]="PhpWiki"
33  *            answer[3][4]="usemod" answer[3][5]="Twiki" answer[3][6]="Other"
34  * ?>
35  *
36  * Administration:
37  * <?plugin WikiPoll page=PhpWikiPoll admin=1 ?>
38  * and protect this page properly (e.g. PhpWikiPoll/Admin)
39  *
40  * TODO:
41  *     admin page (view and reset statistics)
42  *
43  * Author: ReiniUrban
44  */
45
46 class WikiPlugin_WikiPoll
47 extends WikiPlugin
48 {
49     var $_args; 
50     
51     function getName () {
52         return _("WikiPoll");
53     }
54
55     function getDescription () {
56         return _("Enable configurable polls");
57     }
58
59     function getVersion() {
60         return preg_replace("/[Revision: $]/", '',
61                             "\$Revision: 1.2 $");
62     }
63
64     function getDefaultArguments() {
65         return array('page'        => '[pagename]',
66                      'admin'       => false,
67                      'require_all' => 1, // if all questions must be answered
68                     );
69     }
70
71     function getArgs($argstr, $request=false, $defaults = false) {
72         if ($defaults === false)
73             $defaults = $this->getDefaultArguments();
74         //Fixme: on POST argstr is empty
75         $args = array();
76         list ($argstr_args, $argstr_defaults) = $this->parseArgStr($argstr);
77         if (isset($argstr_args["question_1"])) {
78           $args['question'] = $this->str2array("question",$argstr_args);
79           $args['answer'] = array();
80           for ($i = 0; $i <= count($args['question']); $i++) {
81               if ($array = $this->str2array(sprintf("%s_%d","answer",$i),$argstr_args))
82                   $args['answer'][$i] = $array;
83           }
84         }
85         
86         if (!empty($defaults))
87           foreach ($defaults as $arg => $default_val) {
88             if (isset($argstr_args[$arg]))
89                 $args[$arg] = $argstr_args[$arg];
90             elseif ( $request and ($argval = $request->getArg($arg)) !== false )
91                 $args[$arg] = $argval;
92             elseif (isset($argstr_defaults[$arg]))
93                 $args[$arg] = (string) $argstr_defaults[$arg];
94             else
95                 $args[$arg] = $default_val;
96
97             if ($request)
98                 $args[$arg] = $this->expandArg($args[$arg], $request);
99
100             unset($argstr_args[$arg]);
101             unset($argstr_defaults[$arg]);
102         }
103
104         foreach (array_merge($argstr_args, $argstr_defaults) as $arg => $val) {
105             if (!preg_match("/^(answer_|question_)/",$arg))
106                 trigger_error(sprintf(_("argument '%s' not declared by plugin"),
107                                       $arg), E_USER_NOTICE);
108         }
109
110         return $args;
111     }
112     
113     function handle_plugin_args_cruft($argstr, $args) {
114         $argstr = str_replace("\n"," ",$argstr);
115         $argstr = str_replace(array("[","]"),array("_",""),$argstr);
116         $this->_args = $this->getArgs($argstr, $GLOBALS['request']);
117         return;
118     }
119
120     function str2array($var, $obarray=false) {
121         if (!$obarray) $obarray = $GLOBALS;
122         $i = 0; $array = array();
123         $name = sprintf("%s_%d",$var,$i);
124         if (isset($obarray[$name])) $array[$i] = $obarray[$name];
125         do {
126           $i++;
127           $name = sprintf("%s_%d",$var,$i);
128           if (isset($obarray[$name])) $array[$i] = $obarray[$name];
129         } while (isset($obarray[$name]));
130         return $array;
131     }
132     
133     function run($dbi, $argstr, &$request, $basepage) {
134         $args = $this->getArgs($argstr, $request);
135         if (!$args['page'])
136             return $this->error("No page specified");
137         if (!empty($args['admin']) and $request->_user->isAdmin()) {
138             // reset statistics
139             return $this->doPollAdmin($dbi, $request, $page);
140         }
141         extract($this->_args);
142         $page = $dbi->getPage($args['page']);
143         // check ip and last visit
144         $poll = $page->get("poll");
145         $ip = $_SERVER['REMOTE_ADDR'];
146         $disable_submit = false;
147         if (isset($poll['ip'][$ip]) and ((time() - $poll['ip'][$ip]) < 20*60)) {
148             //view at least the result or disable the Go button
149             $html = HTML(HTML::strong(_("Sorry! You must wait at least 20 minutes until you can vote again!")));
150             $html->pushContent($this->doPoll(&$page, &$request, $request->getArg('answer'),true));
151             return $html;
152         }
153             
154         $poll['ip'][$ip] = time();
155         // purge older ip's
156         foreach ($poll['ip'] as $ip => $time) {
157             if ((time() - $time) > 21*60)
158                 unset($poll['ip'][$ip]);
159         }
160         $html = HTML::form(array('action' => $request->getPostURL(),
161                                  'method' => 'POST'));
162
163         if ($request->isPost()) {
164             // checkme: check if all answers are answered
165             if ($request->getArg('answer') and 
166                   ($args['require_all'] and
167                    count($request->getArg('answer')) == count($question))) {
168                 $page->set("poll",$poll);
169                 // update statistics and present them the user
170                 return $this->doPoll(&$page, &$request, $request->getArg('answer'));
171             } else {
172                 $html->pushContent(HTML::p(HTML::strong(_("You must answer all questions!"))));
173             }
174         }
175        
176         $init = isset($question[0]) ? 0 : 1;
177         for ($i = $init; $i <= count($question); $i++) {
178             if (!isset($question[$i])) break;
179             $q = $question[$i]; 
180             if (!isset($answer[$i]))
181                 trigger_error(fmt("missing %s for %s","answer"."[$i]","question"."[$i]"),
182                               E_USER_ERROR);
183             $a = $answer[$i];
184             if (! is_array($a)) {
185                 // a simple checkbox
186                 $html->pushContent(HTML::p(HTML::strong($q)));
187                 $html->pushContent(HTML::div(
188                                        HTML::input(array('type' => 'checkbox',
189                                                          'name' => "answer[$i]",
190                                                          'value' => 1)),
191                                        HTML::raw("&nbsp;"), $a));
192             } else {
193                 $row = HTML();
194                 for ($j=0; $j <= count($a); $j++) {
195                     if (isset($a[$j]))
196                         $row->pushContent(HTML::div(
197                                               HTML::input(array('type' => 'radio',
198                                                                 'name' => "answer[$i]",
199                                                                 'value' => $j)),
200                                               HTML::raw("&nbsp;"), $a[$j]));
201                 }
202                 $html->pushContent(HTML::p(HTML::strong($q)),$row);
203             }
204         }
205         if (!$disable_submit)
206             $html->pushContent(HTML::p(
207                 HTML::input(array('type' => 'submit',
208                                   'name' => "WikiPoll",
209                                   'value' => _("Ok"))),
210                 HTML::input(array('type' => 'reset',
211                                   'name' => "reset",
212                                   'value' => _("Reset")))));
213         else 
214              $html->pushContent(HTML::p(),HTML::strong(_("Sorry! You must wait at least 20 minutes until you can vote again!")));
215         return $html;
216     }
217
218     function doPoll($page, $request, $answers, $readonly = false) {
219         $question = $this->_args['question'];
220         $answer   = $this->_args['answer'];
221         $html = HTML::table(array('cellspacing' => 2));
222         $init = isset($question[0]) ? 0 : 1;
223         for ($i = $init; $i <= count($question); $i++) {
224             if (!isset($question[$i])) break;
225             $poll = $page->get('poll');
226             @$poll['data']['all'][$i]++;
227             $q = $question[$i]; 
228             if (!isset($answer[$i]))
229                 trigger_error(fmt("missing %s for %s","answer"."[$i]","question"."[$i]"),
230                               E_USER_ERROR);
231             if (!$readonly)
232                 $page->set('poll',$poll);
233             $a = $answer[$i];
234             if (! is_array($a) ) {
235                 $checkbox = HTML::input(array('type' => 'checkbox',
236                                               'name' => "answer[$i]",
237                                               'value' => $a));
238                 if ($answers[$i])
239                     $checkbox->setAttr('checked',1);
240                 if (!$readonly)
241                     list($percent,$count,$all) = $this->storeResult(&$page, $i, $answers[$i] ? 1 : 0);
242                 else 
243                     list($percent,$count,$all) = $this->getResult(&$page, $i, 1);
244                 $result = sprintf(_("  %d%% selected this (%d/%d)"),$percent,$count,$all);
245                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 3,'align'=>'left'),$q)));
246                 $html->pushContent(HTML::tr(HTML::td($checkbox),
247                                             HTML::td($a),
248                                             HTML::td($result)));
249             } else {
250                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 3,'align'=>'left'),$q)));
251                 $row = HTML();
252                 if (!$readonly)
253                     $this->storeResult(&$page,$i,$answers[$i]);
254                 for ($j=0; $j <= count($a); $j++) {
255                     if (isset($a[$j])) {
256                         list($percent,$count,$all) = $this->getResult(&$page,$i,$j);
257                         $result = sprintf(_("  %d%% selected this (%d/%d)"),$percent,$count,$all);
258                         $radio = HTML::input(array('type' => 'radio',
259                                                    'name' => "answer[$i]",
260                                                    'value' => $j));
261                         if ($answers[$i] == $j)
262                             $radio->setAttr('checked',1);
263                         $row->pushContent(HTML::tr(HTML::td($radio),
264                                                    HTML::td($a[$j]),
265                                                    HTML::td($result)));
266                     }
267                 }
268                 $html->pushContent($row);
269             }
270         }
271         if (!$readonly)
272             return HTML(HTML::h3(_("The result of this poll so far:")),$html,HTML::p(_("Thanks for participating!")));
273         else  
274             return HTML(HTML::h3(_("The result of this poll so far:")),$html);
275   
276     }
277     
278     function getResult($page,$i,$j) {
279         $poll = $page->get("poll");
280         @$count = $poll['data']['count'][$i][$j];
281         @$all = $poll['data']['all'][$i];
282         $percent = sprintf("%d", $count * 100.0 / $all);
283         return array($percent,$count,$all);
284     }
285     
286     function storeResult($page, $i, $j) {
287         $poll = $page->get("poll");
288         if (!$poll) {
289             $poll = array('data' => array('count' => array(),
290                                           'all'   => array()));
291         }
292         @$poll['data']['count'][$i][$j]++;
293         //@$poll['data']['all'][$i];
294         $page->set("poll",$poll);
295         $percent = sprintf("%d", $poll['data']['count'][$i][$j] * 100.0 / $poll['data']['all'][$i]);
296         return array($percent,$poll['data']['count'][$i][$j],$poll['data']['all'][$i]);
297     }
298
299 };
300
301 // $Log: not supported by cvs2svn $
302 //
303
304 // For emacs users
305 // Local Variables:
306 // mode: php
307 // tab-width: 8
308 // c-basic-offset: 4
309 // c-hanging-comment-ender-p: nil
310 // indent-tabs-mode: nil
311 // End:
312 ?>