]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/WikiPoll.php
Update poll
[SourceForge/phpwiki.git] / lib / plugin / WikiPoll.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /*
4  Copyright 2004 $ThePhpWikiProgrammingTeam
5  Copyright 2008 Marc-Etienne Vargenau, Alcatel-lucent
6  
7  This file is part of PhpWiki.
8
9  PhpWiki is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  PhpWiki is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with PhpWiki; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 /**
24  * This plugin provides configurable polls.
25  *
26  * Usage:
27 <?plugin WikiPoll require_all=0 require_least=2
28            question[1]="Do you like PhpWiki?"
29              answer[1][1]="Yes" answer[1][2]="Do not know" answer[1][3]="No"
30            question[2]="Do you have PhpWiki installed by your own?"
31              answer[2][1]="Yes" answer[2][2]="No"
32            question[3]="Did you install any other wiki engine?"
33              answer[3][1]="Yes" answer[3][2]="No"
34            question[4]="What wiki engine do you like most?"
35              answer[4][1]="c2Wiki" answer[4][2]="MoinMoin" answer[4][3]="PhpWiki"
36              answer[4][4]="usemod" answer[4][5]="Twiki" answer[4][5]="guiki"
37              answer[4][6]="Mediawiki" answer[4][7]="Other"
38            question[5]="Which PhpWiki version do you use?"
39              answer[5][1]="1.2.x" answer[5][2]="1.3.1-12" answer[5][3]="1.3.13"
40              answer[5][4]="1.3.14"
41 ?>
42  *
43  * Administration:
44  * <?plugin WikiPoll page=PhpWikiPoll admin=1 ?>
45  * and protect this page properly (e.g. PhpWikiPoll/Admin)
46  *
47  * TODO:
48  *     admin page (view and reset statistics)
49  *     for now only radio, support checkboxes (multiple selections) also?
50  *
51  * Author: ReiniUrban
52  */
53
54 class WikiPlugin_WikiPoll
55 extends WikiPlugin
56 {
57     var $_args; 
58     
59     function getName () {
60         return _("WikiPoll");
61     }
62
63     function getDescription () {
64         return _("Enable configurable polls");
65     }
66
67     function getVersion() {
68         return preg_replace("/[Revision: $]/", '',
69                             "\$Revision$");
70     }
71
72     function getDefaultArguments() {
73         return array('page'        => '[pagename]',
74                      'admin'       => false,
75                      'require_all' => 1,   // 1 if all questions must be answered
76                      'require_least' => 0, // how many at least
77                     );
78     }
79
80     function getArgs($argstr, $request=false, $defaults = false) {
81         if ($defaults === false)
82             $defaults = $this->getDefaultArguments();
83         //Fixme: on POST argstr is empty
84         $args = array();
85         list ($argstr_args, $argstr_defaults) = $this->parseArgStr($argstr);
86         if (isset($argstr_args["question_1"])) {
87           $args['question'] = $this->str2array("question",$argstr_args);
88           $args['answer'] = array();
89           for ($i = 0; $i <= count($args['question']); $i++) {
90               if ($array = $this->str2array(sprintf("%s_%d","answer",$i),$argstr_args))
91                   $args['answer'][$i] = $array;
92           }
93         }
94         
95         if (!empty($defaults))
96           foreach ($defaults as $arg => $default_val) {
97             if (isset($argstr_args[$arg]))
98                 $args[$arg] = $argstr_args[$arg];
99             elseif ( $request and ($argval = $request->getArg($arg)) !== false )
100                 $args[$arg] = $argval;
101             elseif (isset($argstr_defaults[$arg]))
102                 $args[$arg] = (string) $argstr_defaults[$arg];
103             else
104                 $args[$arg] = $default_val;
105
106             if ($request)
107                 $args[$arg] = $this->expandArg($args[$arg], $request);
108
109             unset($argstr_args[$arg]);
110             unset($argstr_defaults[$arg]);
111         }
112
113         foreach (array_merge($argstr_args, $argstr_defaults) as $arg => $val) {
114             if (!preg_match("/^(answer_|question_)/",$arg))
115                 trigger_error(sprintf(_("argument '%s' not declared by plugin"),
116                                       $arg), E_USER_NOTICE);
117         }
118
119         return $args;
120     }
121     
122     function handle_plugin_args_cruft($argstr, $args) {
123         $argstr = str_replace("\n"," ",$argstr);
124         $argstr = str_replace(array("[","]"),array("_",""),$argstr);
125         $this->_args = $this->getArgs($argstr, $GLOBALS['request']);
126         return;
127     }
128
129     function str2array($var, $obarray=false) {
130         if (!$obarray) $obarray = $GLOBALS;
131         $i = 0; $array = array();
132         $name = sprintf("%s_%d",$var,$i);
133         if (isset($obarray[$name])) $array[$i] = $obarray[$name];
134         do {
135           $i++;
136           $name = sprintf("%s_%d",$var,$i);
137           if (isset($obarray[$name])) $array[$i] = $obarray[$name];
138         } while (isset($obarray[$name]));
139         return $array;
140     }
141     
142     function run($dbi, $argstr, &$request, $basepage) {
143         if (!isset($_SERVER))
144             $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
145         $request->setArg('nocache','purge');
146         $args = $this->getArgs($argstr, $request);
147         if (!$args['page'])
148             return $this->error("No page specified");
149         if (!empty($args['admin']) and $request->_user->isAdmin()) {
150             // reset statistics
151             return $this->doPollAdmin($dbi, $request, $page);
152         }
153         extract($this->_args);
154         $page = $dbi->getPage($args['page']);
155         // check ip and last visit
156         $poll = $page->get("poll");
157         $ip = $_SERVER['REMOTE_ADDR'];
158         $disable_submit = false;
159         if (isset($poll['ip'][$ip]) and ((time() - $poll['ip'][$ip]) < 20*60)) {
160             //view at least the result or disable the Go button
161             $html = HTML(HTML::strong(
162                         _("Sorry! You must wait at least 20 minutes until you can vote again!")));
163             $html->pushContent($this->doPoll($page, $request, $request->getArg('answer'),true));
164             return $html;
165         }
166             
167         $poll['ip'][$ip] = time();
168         // purge older ip's
169         foreach ($poll['ip'] as $ip => $time) {
170             if ((time() - $time) > 21*60)
171                 unset($poll['ip'][$ip]);
172         }
173         $html = HTML::form(array('action' => $request->getPostURL(),
174                                  'method' => 'POST'));
175
176         if ($request->isPost()) {
177             // checkme: check if all answers are answered
178             if ($request->getArg('answer') and (
179                  ($args['require_all'] and
180                   count($request->getArg('answer')) == count($question))
181                  or 
182                  ($args['require_least'] and
183                   count($request->getArg('answer')) >= $args['require_least']))) {
184                 $page->set("poll", $poll);
185                 // update statistics and present them the user
186                 return $this->doPoll($page, $request, $request->getArg('answer'));
187             } else {
188                 $html->pushContent(HTML::p(HTML::strong(_("Not enough questions answered!"))));
189             }
190         }
191        
192         $init = isset($question[0]) ? 0 : 1;
193         for ($i = $init; $i <= count($question); $i++) {
194             if (!isset($question[$i])) break;
195             $q = $question[$i]; 
196             if (!isset($answer[$i]))
197                 trigger_error(fmt("Missing %s for %s","answer"."[$i]","question"."[$i]"),
198                               E_USER_ERROR);
199             $a = $answer[$i];
200             if (! is_array($a)) {
201                 // a simple checkbox
202                 $html->pushContent(HTML::p(HTML::strong($q)));
203                 $html->pushContent(HTML::div(
204                                        HTML::input(array('type' => 'checkbox',
205                                                          'name' => "answer[$i]",
206                                                          'value' => 1)),
207                                        HTML::raw("&nbsp;"), $a));
208             } else {
209                 $row = HTML();
210                 for ($j=0; $j <= count($a); $j++) {
211                     if (isset($a[$j]))
212                         $row->pushContent(HTML::div(
213                                               HTML::input(array('type' => 'radio',
214                                                                 'name' => "answer[$i]",
215                                                                 'value' => $j)),
216                                               HTML::raw("&nbsp;"), $a[$j]));
217                 }
218                 $html->pushContent(HTML::p(HTML::strong($q)),$row);
219             }
220         }
221         if (!$disable_submit)
222             $html->pushContent(HTML::p(
223                 HTML::input(array('type' => 'submit',
224                                   'name' => "WikiPoll",
225                                   'value' => _("OK"))),
226                 HTML::input(array('type' => 'reset',
227                                   'name' => "reset",
228                                   'value' => _("Reset")))));
229         else 
230              $html->pushContent(HTML::p(),HTML::strong(
231                  _("Sorry! You must wait at least 20 minutes until you can vote again!")));
232         return $html;
233     }
234
235     function bar($percent) {
236         global $WikiTheme;
237         return HTML(HTML::img(array('src' => $WikiTheme->getImageUrl('leftbar'),
238                                     'alt' => '<')),
239                     HTML::img(array('src' => $WikiTheme->getImageUrl('mainbar'),
240                                     'alt' => '-',
241                                     'width' => sprintf("%02d",$percent),
242                                     'height' => 14)),
243                     HTML::img(array('src' => $WikiTheme->getImageUrl('rightbar'),
244                                     'alt' => '>')));
245     }
246
247     function doPoll($page, $request, $answers, $readonly = false) {
248         $question = $this->_args['question'];
249         $answer   = $this->_args['answer'];
250         $html = HTML::table(array('cellspacing' => 2));
251         $init = isset($question[0]) ? 0 : 1;
252         for ($i = $init; $i <= count($question); $i++) {
253             if (!isset($question[$i])) break;
254             $poll = $page->get('poll');
255             @$poll['data']['all'][$i]++;
256             $q = $question[$i]; 
257             if (!isset($answer[$i]))
258                 trigger_error(fmt("Missing %s for %s","answer"."[$i]","question"."[$i]"),
259                               E_USER_ERROR);
260             if (!$readonly)
261                 $page->set('poll',$poll);
262             $a = $answer[$i];
263             $result = (isset($answers[$i])) ? $answers[$i] : -1;
264             if (! is_array($a) ) {
265                 $checkbox = HTML::input(array('type' => 'checkbox',
266                                               'name' => "answer[$i]",
267                                               'value' => $a));
268                 if ($result >= 0)
269                     $checkbox->setAttr('checked',1);
270                 if (!$readonly)
271                     list($percent,$count,$all) = $this->storeResult($page, $i, $result ? 1 : 0);
272                 else 
273                     list($percent,$count,$all) = $this->getResult($page, $i, 1);
274                 $print = sprintf(_("  %d%% (%d/%d)"), $percent, $count, $all);
275                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4,'align'=>'left'),$q)));
276                 $html->pushContent(HTML::tr(HTML::td($checkbox),
277                                             HTML::td($a),
278                                             HTML::td($this->bar($percent)),
279                                             HTML::td($print)));
280             } else {
281                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4,'align'=>'left'),$q)));
282                 $row = HTML();
283                 if (!$readonly)
284                     $this->storeResult($page, $i, $answers[$i]);
285                 for ($j=0; $j <= count($a); $j++) {
286                     if (isset($a[$j])) {
287                         list($percent,$count,$all) = $this->getResult($page,$i,$j);
288                         $print = sprintf(_("  %d%% (%d/%d)"), $percent, $count, $all);
289                         $radio = HTML::input(array('type' => 'radio',
290                                                    'name' => "answer[$i]",
291                                                    'value' => $j));
292                         if ($result == $j)
293                             $radio->setAttr('checked',1);
294                         $row->pushContent(HTML::tr(HTML::td($radio),
295                                                    HTML::td($a[$j]),
296                                                    HTML::td($this->bar($percent)),
297                                                    HTML::td($print)));
298                     }
299                 }
300                 $html->pushContent($row);
301             }
302         }
303         if (!$readonly)
304             return HTML(HTML::h3(_("The result of this poll so far:")),$html,HTML::p(_("Thanks for participating!")));
305         else  
306             return HTML(HTML::h3(_("The result of this poll so far:")),$html);
307   
308     }
309     
310     function getResult($page,$i,$j) {
311         $poll = $page->get("poll");
312         @$count = $poll['data']['count'][$i][$j];
313         @$all = $poll['data']['all'][$i];
314         $percent = sprintf("%d", $count * 100.0 / $all);
315         return array($percent,$count,$all);
316     }
317     
318     function storeResult($page, $i, $j) {
319         $poll = $page->get("poll");
320         if (!$poll) {
321             $poll = array('data' => array('count' => array(),
322                                           'all'   => array()));
323         }
324         @$poll['data']['count'][$i][$j]++;
325         //@$poll['data']['all'][$i];
326         $page->set("poll",$poll);
327         $percent = sprintf("%d", $poll['data']['count'][$i][$j] * 100.0 / $poll['data']['all'][$i]);
328         return array($percent,$poll['data']['count'][$i][$j],$poll['data']['all'][$i]);
329     }
330
331 };
332
333 // For emacs users
334 // Local Variables:
335 // mode: php
336 // tab-width: 8
337 // c-basic-offset: 4
338 // c-hanging-comment-ender-p: nil
339 // indent-tabs-mode: nil
340 // End:
341 ?>