/[drupal]/contributions/sandbox/alaa/rankvote.module
ViewVC logotype

Contents of /contributions/sandbox/alaa/rankvote.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Fri May 6 13:43:51 2005 UTC (4 years, 6 months ago) by alaa
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +58 -46 lines
File MIME type: text/x-php
updated to 4.6
1 <?php
2
3 /**
4 * @file
5 * Enables your site members to vote on decisions using a simple ranking voting system
6 */
7
8 /**
9 * Implementation of hook_help().
10 */
11 function rankvote_help($section) {
12 switch($section) {
13 case 'admin/help#rankvote':
14 return t("<p>some text to help admins</p>");
15
16 case 'admin/modules#description':
17 return t("Enables your site members to vote on decisions using a simple ranking vote system");
18
19 case 'node/add#rankvote':
20 return t("A Ranking Vote is a form where visitors can rank each option");
21 }
22 }
23
24 /**
25 * Implementation of hook_access().
26 */
27 function rankvote_access($op, $node) {
28 if ($op == 'create') {
29 return user_access('create ranking votes');
30 }
31 }
32
33 /**
34 * Implementation of hook_block().
35 *
36 * Generates a block containing the latest rankvote.
37 */
38 function rankvote_block($op = 'list', $delta = 0) {
39 if (user_access('access content')) {
40 if ($op == 'list') {
41 $blocks[0]['info'] = t('Most recent Ranking Vote');
42 return $blocks;
43 }
44 elseif ($op == 'view') {
45 // Retrieve the latest rankvote.
46 $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n WHERE n.type = 'rankvote' AND n.status = 1 AND n.moderate = 0");
47 $timestamp = db_result(db_query($sql));
48 if ($timestamp) {
49 $rankvote = node_load(array('type' => 'rankvote', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));
50 if ($rankvote->nid) {
51 // rankvote_view() dumps the output into $rankvote->body.
52 rankvote_view($rankvote, 1, 0, 1);
53 }
54 }
55 $block['subject'] = t('Ranking Vote');
56 $block['content'] = $rankvote->body;
57 return $block;
58 }
59 else {
60 return;
61 }
62 }
63 }
64
65 /**
66 * Implementation of hook_cron().
67 *
68 * Closes rankvotes that ave exceeded their allowed runtime.
69 */
70 function rankvote_cron() {
71 $result = db_query("SELECT p.nid FROM {rankvote} p INNER JOIN {node} n ON p.nid=n.nid WHERE (n.created + p.runtime) < '". time() ."' AND p.active = '1' AND p.runtime != '0'");
72 while ($rankvote = db_fetch_object($result)) {
73 db_query("UPDATE {rankvote} SET active='0' WHERE nid = %d", $rankvote->nid);
74 }
75 }
76
77 /**
78 * Implementation of hook_delete().
79 */
80 function rankvote_delete($node) {
81 db_query("DELETE FROM {rankvote} WHERE nid=%d", $node->nid);
82 db_query("DELETE FROM {rankvote_choices} WHERE nid = %d", $node->nid);
83 }
84
85 /**
86 * Implementation of hook_validate().
87 */
88 function rankvote_validate(&$node) {
89 if (isset($node->title)) {
90 // Check for at least two options and validate amount of votes:
91 $realchoices = 0;
92 foreach($node->choice as $i => $choice) {
93 if ($choice['chtext'] != '') {
94 $realchoices++;
95 }
96
97 if ($choice['chvotes'] < 0) {
98 form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
99 }
100 }
101
102 if ($realchoices < 2) {
103 form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
104 }
105 }
106
107 $node->teaser = rankvote_teaser($node);
108 }
109
110 /**
111 * Implementation of hook_form().
112 */
113 function rankvote_form(&$node) {
114 $admin = user_access('administer nodes');
115
116 if (function_exists('taxonomy_node_form')) {
117 $output = implode('', taxonomy_node_form('rankvote', $node));
118 }
119
120 if (!isset($node->choices)) {
121 $node->choices = max(2, count($node->choice) ? count($node->choice) : 5);
122 }
123
124 // User ticked 'need more choices'.
125 if ($node->morechoices) {
126 $node->choices *= 2;
127 }
128
129 $output .= '<div class="rankvote-form">';
130 // RankVote choices
131 //$opts = drupal_map_assoc(range(2, $node->choices * 2 + 5));
132 for ($a = 0; $a < $node->choices; $a++) {
133 $group1 .= form_textfield(t('Choice %n', array('%n' => ($a + 1))), "choice][$a][chtext", $node->choice[$a]['chtext'], 50, 127);
134 if ($admin) {
135 $group1 .= form_textfield(t('Votes for choice %n', array('%n' => ($a + 1))), "choice][$a][chvotes", (int)$node->choice[$a]['chvotes'], 7, 7);
136 }
137 }
138 $group1 .= form_hidden('choices', $node->choices);
139 $group1 .= form_checkbox(t('Need more choices'), 'morechoices', 1, 0, t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."));
140 $output .= form_group(t('Choices'), $group1);
141
142 // RankVote attributes
143 $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9767800, 31536000), "format_interval");
144 $_active = array(0 => t('Closed'), 1=> t('Active'));
145
146 if ($admin) {
147 $group2 .= form_radios(t('Ranking Vote status'), 'active', isset($node->active) ? $node->active : 1, $_active, t('When a Ranking Vote is closed, visitors can no longer vote for it.'));
148 }
149 $group2 .= form_select(t('Ranking Vote duration'), 'runtime', $node->runtime ? $node->runtime : 0, $_duration, t('After this period, the Ranking Vote will be closed automatically.'));
150
151 $output .= form_group(t('Settings'), $group2);
152 $output .= '</div>';
153
154 return $output;
155 }
156
157 /**
158 * Implementation of hook_insert().
159 */
160 function rankvote_insert($node) {
161 if (!user_access('administer nodes')) {
162 // Make sure all votes are 0 initially
163 foreach ($node->choice as $i => $choice) {
164 $node->choice[$i]['chvotes'] = 0;
165 }
166 $node->active = 1;
167 }
168
169 db_query("INSERT INTO {rankvote} (nid, runtime, voters, active) VALUES (%d, %d, '', %d)", $node->nid, $node->runtime, $node->active);
170
171 $i=0;
172 foreach ($node->choice as $choice) {
173 if ($choice['chtext'] != '') {
174 db_query("INSERT INTO {rankvote_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++);
175 }
176 }
177 }
178
179 /**
180 * Implementation of hook_link().
181 */
182 function rankvote_link($type, $node = 0, $main) {
183 $links = array();
184
185 if ($type == 'page' && user_access('access content')) {
186 $links[] = l(t('votes'), 'rankvote', array('title' => t('View the list of Ranking Votes on this site.')));
187 }
188
189 return $links;
190 }
191
192 /**
193 * Implementation of hook_menu().
194 */
195 function rankvote_menu($may_cache) {
196 $items = array();
197
198 if($may_cache) {
199 $items[] = array('path' => 'node/add/rankvote', 'title' => t('ranking vote'),
200 'access' => user_access('create ranking votes'));
201 $items[] = array('path' => 'rankvote', 'title' => t('ranking votes'),
202 'callback' => 'rankvote_page',
203 'access' => user_access('access content'),
204 'type' => MENU_SUGGESTED_ITEM);
205
206 $items[] = array('path' => 'rankvote/vote',
207 'title' => t('vote'),
208 'callback' => 'rankvote_vote',
209 'access' => user_access('vote on ranking votes'),
210 'type' => MENU_CALLBACK);
211 }
212 else {
213 if (arg(0) == 'node' && is_numeric(arg(1))) {
214 $node = node_load(array('nid' => arg(1)));
215
216 if ($node->type == 'rankvote' && $node->allowvotes) {
217 $items[] = array('path' => 'node/'. arg(1) .'/results',
218 'title' => t('results'),
219 'callback' => 'rankvote_results',
220 'access' => user_access('access content'),
221 'weight' => 3,
222 'type' => MENU_LOCAL_TASK);
223 }
224 }
225 }
226
227 return $items;
228 }
229
230 /**
231 * Determine an adjusted user id, to allow for basic tracking of anonymous
232 * users (IP-based).
233 */
234 function rankvote_uid() {
235 global $user;
236 if ($user->uid) {
237 // Pad the UID with underscores to allow a simple strstr() search
238 $id = '_'. $user->uid .'_';
239 }
240 else {
241 $id = $_SERVER['REMOTE_ADDR'];
242 }
243 return $id;
244 }
245
246 /**
247 * Implementation of hook_load().
248 */
249 function rankvote_load($node) {
250 // Load the appropriate choices into the $node object
251 $rankvote = db_fetch_object(db_query("SELECT runtime, voters, active FROM {rankvote} WHERE nid = %d", $node->nid));
252
253 $result = db_query("SELECT chtext, chvotes, chorder FROM {rankvote_choices} WHERE nid=%d ORDER BY RAND()", $node->nid);
254 while ($choice = db_fetch_array($result)) {
255 $rankvote->choice[$choice['chorder']] = $choice;
256 }
257
258 // Determine whether or not this user is allowed to vote
259 $rankvote->allowvotes = false;
260 if (user_access('vote on ranking votes')) {
261 if(!strstr($rankvote->voters, rankvote_uid())) {
262 $rankvote->allowvotes = $rankvote->active;
263 }
264 }
265 return $rankvote;
266 }
267
268 /**
269 * Implementation of hook_node_name().
270 */
271 function rankvote_node_name($node) {
272 return t("Ranking Vote");
273 }
274
275 function rankvote_page() {
276 // List all Ranking Votes
277 $sql = db_rewrite_sql("SELECT n.nid, n.title, p.active, n.created, SUM(c.chvotes) AS votes FROM {node} n INNER JOIN {rankvote} p ON n.nid=p.nid INNER JOIN {rankvote_choices} c ON n.nid=c.nid WHERE type = 'rankvote' AND status = 1 AND moderate = 0 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC");
278 $result = pager_query($sql, 15);
279 $output = '<ul>';
280 while ($node = db_fetch_object($result)) {
281 $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '%count votes') .' - '. ($node->active ? t('open') : t('closed')) . '</li>';
282 }
283 $output .= '</ul>';
284 $output .= theme("pager", NULL, 15);
285 print theme('page', $output);
286 }
287
288 /**
289 * Implementation of hook_perm().
290 */
291 function rankvote_perm() {
292 return array('create ranking votes', 'vote on ranking votes');
293 }
294
295 /**
296 * Creates a simple teaser that lists all the choices.
297 */
298 function rankvote_teaser($node) {
299 if (is_array($node->choice)) {
300 foreach ($node->choice as $k => $choice) {
301 $teaser .= '* '. $choice['chtext'] .'\n';
302 }
303 }
304 return $teaser;
305 }
306
307 /**
308 * Generates the voting form for a ranking vote.
309 */
310 function rankvote_view_voting(&$node, $main, $page, $block) {
311 $output = '<div class="rankvote">';
312
313 if ($block) {
314 $output .= '<div class="title rankvote_title">'. check_plain($node->title) .'</div>';
315 }
316
317 $form = '<div class="vote-form">';
318 $form .= '<div class="choices">';
319 if ($node->choice) {
320 $options = drupal_map_assoc(range(1, count($node->choice)));
321 foreach ($node->choice as $i => $choice) {
322 $form .= form_select(check_plain($choice['chtext']), "choice][". $choice['chorder'], -1, $options, '', 0, false, true);
323 }
324 }
325 $form .= '</div>';
326 $form .= form_hidden('nid', $node->nid);
327 $form .= form_submit(t('Vote'), 'vote') .'</div>';
328
329 $output .= form($form, 'post', url('rankvote/vote/'. $node->nid));
330 $output .= '</div>';
331
332 return $output;
333 }
334
335 /**
336 * Generates a graphical representation of the results of a ranking vote.
337 */
338 function rankvote_view_results(&$node, $main, $page, $block) {
339 // Display the results
340
341 // Count the votes and find the maximum
342 $temp = array();
343 foreach($node->choice as $i => $choice) {
344 $temp[$i] = $choice['chvotes'];
345 }
346 asort($temp);
347
348 // Output the divs for the text, bars and percentages
349 $output .= '<div class="rankvote">';
350 if ($block) {
351 $output .= '<div class="title rankvote_title">'. check_plain($node->title) .'</div>';
352 }
353
354 $output .= '<ul>';
355 foreach($temp as $i => $score) {
356 $output .='<li>'. check_plain($node->choice[$i]['chtext']) .' <small>score = '. $node->choice[$i]['chvotes'] . '</small></li>';
357 }
358 $output .= '</ul></div>';
359
360 return $output;
361 }
362
363 /**
364 * Callback for the 'results' tab for ranking votes you can vote on
365 */
366 function rankvote_results() {
367 if ($node = node_load(array('nid' => arg(1)))) {
368 drupal_set_title(check_plain($node->title));
369 print theme('page', node_show($node, 0));
370 }
371 else {
372 drupal_not_found();
373 }
374 }
375
376
377
378 function _valid_rankvote($choice) {
379 $temp = array();
380 foreach($choice as $rank) {
381 $temp[] = $rank;
382 }
383
384 sort($temp);
385
386 for ($i=0; $i < count($temp); ++$i) {
387 if ($i != $temp[$i]-1) {
388 return false;
389 }
390 }
391 return true;
392 }
393
394 /**
395 * Callback for processing a vote
396 */
397 function rankvote_vote(&$node) {
398 $nid = arg(2);
399 if ($node = node_load(array('nid' => $nid))) {
400 $edit = $_POST['edit'];
401 $choice = $edit['choice'];
402 $vote = $_POST['vote'];
403
404 if (isset($choice) && count($choice) == count($node->choice)) { //need to check valid vote data here
405 if (_valid_rankvote($choice)) {
406 if ($node->allowvotes) {
407 $id = rankvote_uid();
408 $node->voters = $node->voters ? ($node->voters .' '. $id) : $id;
409 db_query("UPDATE {rankvote} SET voters='%s' WHERE nid = %d", $node->voters, $node->nid);
410 foreach($choice as $i => $rank) {
411 db_query("UPDATE {rankvote_choices} SET chvotes = chvotes + %d WHERE nid = %d AND chorder = %d", $rank, $node->nid, $i);
412 $node->choice[$i]['chvotes'] += $rank;
413 }
414 $node->allowvotes = false;
415 drupal_set_message(t('Your vote was recorded.'));
416 }
417 else {
418 drupal_set_message(t("You're not allowed to vote on this ranking vote."), 'error');
419 }
420 }
421 else {
422 drupal_set_message(t("Each choice should get a unique rank for the vote to be valid."), 'error');
423 }
424 }
425 else {
426 drupal_set_message(t("All choices must be ranked for the vote to be valid."), 'error');
427 }
428
429 drupal_goto('node/'. $nid);
430 }
431 else {
432 drupal_not_found();
433 }
434 }
435
436 /**
437 * Implementation of hook_view().
438 *
439 * @param $block
440 * An extra parameter that adapts the hook to display a block-ready
441 * rendering of the ranking vote.
442 */
443 function rankvote_view(&$node, $teaser = FALSE, $page = FALSE, $block = FALSE) {
444 global $user;
445 $output = '';
446
447 if ($node->allowvotes && ($block || arg(2) != 'results')) {
448 $output .= rankvote_view_voting($node, $main, $page, $block);
449 }
450 else {
451 $output .= rankvote_view_results($node, $main, $page, $block);
452 }
453
454 // Special display for side-block
455 if ($block) {
456 // No 'read more' link
457 $node->body = $node->teaser = '';
458
459 $links = module_invoke_all('link', 'node', $node, $main);
460 $links[] = l(t('older ranking votes'), 'rankvote', array('title' => t('View the list of ranking votes on the site.')));
461 if ($node->allowvotes && $block) {
462 $link[] = l(t('results'), 'node/'. $node->nid .'/results', array('title' => t('View the current ranking vote results.')));
463 }
464
465 $output .= '<div class="links">'. theme("links", $links) .'</div>';
466 }
467
468 $node->body = $node->teaser = $output;
469 }
470
471 /**
472 * Implementation of hook_update().
473 */
474 function rankvote_update($node) {
475 db_query('UPDATE {rankvote} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
476
477 db_query('DELETE FROM {rankvote_choices} WHERE nid = %d', $node->nid);
478 $i=1;
479 foreach ($node->choice as $choice) {
480 $chvotes = (int)$choice['chvotes'];
481 $chtext = $choice['chtext'];
482
483 if ($chtext != '') {
484 db_query("INSERT INTO {rankvote_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);
485 }
486 }
487 }

  ViewVC Help
Powered by ViewVC 1.1.2