poll.module 20.1 KB
Newer Older
1
<?php
2
// $Id$
3

Dries's avatar
   
Dries committed
4
5
6
7
8
9
/**
 * @file
 * Enables your site to capture votes on different topics in the form of multiple
 * choice questions.
 */

10
11
12
13
/**
 * Implementation of hook_help().
 */
function poll_help($section) {
Steven Wittens's avatar
Steven Wittens committed
14
15
  switch ($section) {
    case 'admin/help#poll':
16
      $output = '<p>'. t('The poll module can be used to create simple polls for site users. A poll is a simple multiple choice questionnaire which displays the cumulative results of the answers to the poll. Having polls on the site is a good way to get instant feedback from community members.') .'</p>';
17
18
      $output .= '<p>'. t('Users can create a poll. The title of the poll should be the question, then enter the answers and the "base" vote counts. You can also choose the time period over which the vote will run.The <a href="@poll">poll</a> item in the navigation menu will take you to a page where you can see all the current polls, vote on them (if you haven\'t already) and view the results.', array('@poll' => url('poll'))) .'</p>';
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@poll">Poll page</a>.', array('@poll' => 'http://drupal.org/handbook/modules/poll/')) .'</p>';
19
      return $output;
Steven Wittens's avatar
Steven Wittens committed
20
  }
21
22
}

23
24
25
/**
 * Implementation of hook_access().
 */
26
function poll_access($op, $node) {
Steven Wittens's avatar
Steven Wittens committed
27
28
  if ($op == 'create') {
    return user_access('create polls');
Dries's avatar
   
Dries committed
29
  }
Steven Wittens's avatar
Steven Wittens committed
30
31
}

32
33
34
35
36
/**
 * Implementation of hook_block().
 *
 * Generates a block containing the latest poll.
 */
Steven Wittens's avatar
Steven Wittens committed
37
38
39
40
function poll_block($op = 'list', $delta = 0) {
  if (user_access('access content')) {
    if ($op == 'list') {
      $blocks[0]['info'] = t('Most recent poll');
Dries's avatar
   
Dries committed
41
42
      return $blocks;
    }
43
    else if ($op == 'view') {
44
      // Retrieve the latest poll.
45
      $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = 1 AND p.active = 1");
Dries's avatar
   
Dries committed
46
      $timestamp = db_result(db_query($sql));
Dries's avatar
   
Dries committed
47
      if ($timestamp) {
48
        $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'status' => 1));
Steven Wittens's avatar
Steven Wittens committed
49

Dries's avatar
   
Dries committed
50
        if ($poll->nid) {
51
          $poll = poll_view($poll, TRUE, FALSE, TRUE);
Dries's avatar
   
Dries committed
52
        }
Dries's avatar
   
Dries committed
53
      }
Steven Wittens's avatar
Steven Wittens committed
54
      $block['subject'] = t('Poll');
55
      $block['content'] = drupal_render($poll->content);
Dries's avatar
   
Dries committed
56
      return $block;
57
58
59
60
    }
  }
}

61
62
63
64
65
/**
 * Implementation of hook_cron().
 *
 * Closes polls that have exceeded their allowed runtime.
 */
66
function poll_cron() {
67
  $result = db_query('SELECT p.nid FROM {poll} p INNER JOIN {node} n ON p.nid = n.nid WHERE (n.created + p.runtime) < '. time() .' AND p.active = 1 AND p.runtime != 0');
Dries's avatar
   
Dries committed
68
  while ($poll = db_fetch_object($result)) {
69
    db_query("UPDATE {poll} SET active = 0 WHERE nid = %d", $poll->nid);
Dries's avatar
   
Dries committed
70
  }
71
72
}

73
74
75
76
77
78
79
/**
 * Implementation of hook_delete().
 */
function poll_delete($node) {
  db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid);
  db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
  db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid);
80
81
}

82
/**
83
 * Implementation of hook_submit().
84
 */
85
function poll_submit(&$node) {
86
87
88
89
  // Renumber fields
  $node->choice = array_values($node->choice);
  $node->teaser = poll_teaser($node);
}
Dries's avatar
Dries committed
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
 * Implementation of hook_validate().
 */
function poll_validate($node) {
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
    $realchoices = 0;
    // Renumber fields
    $node->choice = array_values($node->choice);
    foreach ($node->choice as $i => $choice) {
      if ($choice['chtext'] != '') {
        $realchoices++;
      }
      if ($choice['chvotes'] < 0) {
        form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
      }
107
    }
108

109
110
111
    if ($realchoices < 2) {
      form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
    }
112
  }
113
114
}

115
116
117
/**
 * Implementation of hook_form().
 */
118
function poll_form($node, $form_values = NULL) {
Steven Wittens's avatar
Steven Wittens committed
119
  $admin = user_access('administer nodes');
120
  $type = node_get_types('type', $node);
121
122
123
124
125
126
127
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#required' => TRUE,
    '#default_value' => $node->title,
    '#weight' => -1
  );
128

129
130
131
132
133
134
135
136
  if (isset($form_values)) {
    $choices = $form_values['choices'];
    if ($form_values['morechoices']) {
      $choices *= 2;
    }
  }
  else {
    $choices = max(2, count($node->choice) ? count($node->choice) : 5);
137
138
  }

139
140
  $form['choices'] = array(
    '#type' => 'hidden',
141
    '#value' => $choices,
142
  );
143

Steven Wittens's avatar
Steven Wittens committed
144
  // Poll choices
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  $form['choice'] = array(
    '#type' => 'fieldset',
    '#title' => t('Choices'),
    '#prefix' => '<div class="poll-form">',
    '#suffix' => '</div>',
    '#tree' => TRUE
  );

  // We'll manually set the #parents property of this checkbox so that
  // it appears in the fieldset visually, but its value won't pollute
  // the $form_values['choice'] array.
  $form['choice']['morechoices'] = array(
    '#type' => 'checkbox',
    '#parents' => array('morechoices'),
    '#title' => t('Need more choices'),
160
    '#value' => 0,
161
162
163
164
165
166
167
168
169
170
171
    '#description' => t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."),
    '#weight' => 1,
  );

  for ($a = 0; $a < $choices; $a++) {
    $form['choice'][$a]['chtext'] = array(
      '#type' => 'textfield',
      '#title' => t('Choice @n', array('@n' => ($a + 1))),
      '#default_value' => $node->choice[$a]['chtext'],
    );

172
    if ($admin) {
173
174
175
176
177
178
      $form['choice'][$a]['chvotes'] = array(
        '#type' => 'textfield',
        '#title' => t('Votes for choice @n', array('@n' => ($a + 1))),
        '#default_value' => (int)$node->choice[$a]['chvotes'],
        '#size' => 5, '#maxlength' => 7
      );
179
180
    }
  }
Dries's avatar
   
Dries committed
181

Steven Wittens's avatar
Steven Wittens committed
182
  // Poll attributes
183
  $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval");
Steven Wittens's avatar
Steven Wittens committed
184
  $_active = array(0 => t('Closed'), 1 => t('Active'));
Dries's avatar
   
Dries committed
185

Steven Wittens's avatar
Steven Wittens committed
186
  if ($admin) {
187
    $form['settings'] = array('#type' => 'fieldset', '#title' => t('Settings'));
188
189
190
191
192
193
194
195

    $form['settings']['active'] = array(
      '#type' => 'radios',
      '#title' => t('Poll status'),
      '#default_value' => isset($node->active) ? $node->active : 1,
      '#options' => $_active,
      '#description' => t('When a poll is closed, visitors can no longer vote for it.')
    );
Dries's avatar
   
Dries committed
196
  }
197
198
199
200
201
202
203
  $form['settings']['runtime'] = array(
    '#type' => 'select',
    '#title' => t('Poll duration'),
    '#default_value' => $node->runtime,
    '#options' => $_duration,
    '#description' => t('After this period, the poll will be closed automatically.'),
  );
Dries's avatar
   
Dries committed
204

205
  $form['#multistep'] = TRUE;
206
  return $form;
207
}
208

209
function poll_insert($node) {
Steven Wittens's avatar
Steven Wittens committed
210
  if (!user_access('administer nodes')) {
211
    // Make sure all votes are 0 initially
Steven Wittens's avatar
Steven Wittens committed
212
213
214
    foreach ($node->choice as $i => $choice) {
      $node->choice[$i]['chvotes'] = 0;
    }
215
216
    $node->active = 1;
  }
217

218
  db_query("INSERT INTO {poll} (nid, runtime, active) VALUES (%d, %d, %d)", $node->nid, $node->runtime, $node->active);
Dries's avatar
   
Dries committed
219

Steven Wittens's avatar
Steven Wittens committed
220
221
222
  foreach ($node->choice as $choice) {
    if ($choice['chtext'] != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++);
223
224
    }
  }
225
226
}

Dries's avatar
   
Dries committed
227
228
229
/**
 * Implementation of hook_menu().
 */
Dries's avatar
   
Dries committed
230
function poll_menu($may_cache) {
Dries's avatar
   
Dries committed
231
  $items = array();
Dries's avatar
   
Dries committed
232
233

  if ($may_cache) {
234
    $items[] = array('path' => 'poll', 'title' => t('Polls'),
Dries's avatar
   
Dries committed
235
236
237
238
239
      'callback' => 'poll_page',
      'access' => user_access('access content'),
      'type' => MENU_SUGGESTED_ITEM);

    $items[] = array('path' => 'poll/vote',
240
      'title' => t('Vote'),
Dries's avatar
   
Dries committed
241
242
243
      'callback' => 'poll_vote',
      'access' => user_access('vote on polls'),
      'type' => MENU_CALLBACK);
244
245

    $items[] = array('path' => 'poll/cancel',
246
      'title' => t('Cancel'),
247
248
249
      'callback' => 'poll_cancel',
      'access' => user_access('cancel own vote'),
      'type' => MENU_CALLBACK);
Dries's avatar
   
Dries committed
250
251
  }
  else {
252
253
254
255
    // Add the CSS for this module
    // We put this in !$may_cache so it's only added once per request
    drupal_add_css(drupal_get_path('module', 'poll') .'/poll.css');

Dries's avatar
   
Dries committed
256
    if (arg(0) == 'node' && is_numeric(arg(1))) {
257
      $node = node_load(arg(1));
258
259
      if ($node->type == 'poll') {
        $items[] = array('path' => 'node/'. arg(1) .'/votes',
260
          'title' => t('Votes'),
261
262
263
264
265
          'callback' => 'poll_votes',
          'access' => user_access('inspect all votes'),
          'weight' => 3,
          'type' => MENU_LOCAL_TASK);
      }
Dries's avatar
   
Dries committed
266
267
      if ($node->type == 'poll' && $node->allowvotes) {
        $items[] = array('path' => 'node/'. arg(1) .'/results',
268
          'title' => t('Results'),
Dries's avatar
   
Dries committed
269
270
271
272
273
          'callback' => 'poll_results',
          'access' => user_access('access content'),
          'weight' => 3,
          'type' => MENU_LOCAL_TASK);
      }
Steven Wittens's avatar
Steven Wittens committed
274
275
    }
  }
Dries's avatar
   
Dries committed
276

Dries's avatar
   
Dries committed
277
278
279
  return $items;
}

280
281
282
/**
 * Implementation of hook_load().
 */
283
function poll_load($node) {
284
285
  global $user;

286
  // Load the appropriate choices into the $node object
287
  $poll = db_fetch_object(db_query("SELECT runtime, active FROM {poll} WHERE nid = %d", $node->nid));
Dries's avatar
   
Dries committed
288

289
  $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid);
Steven Wittens's avatar
Steven Wittens committed
290
291
  while ($choice = db_fetch_array($result)) {
    $poll->choice[$choice['chorder']] = $choice;
292
  }
Steven Wittens's avatar
Steven Wittens committed
293

Steven Wittens's avatar
Steven Wittens committed
294
  // Determine whether or not this user is allowed to vote
295
296
  $poll->allowvotes = FALSE;
  if (user_access('vote on polls') && $poll->active) {
297
298
299
300
301
    if ($user->uid) {
      $result = db_fetch_object(db_query('SELECT chorder FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid));
    }
    else {
      $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']));
302
    }
303
304
305
306
307
    if (isset($result->chorder)) {
      $poll->vote = $result->chorder;
    }
    else {
      $poll->vote = -1;
308
      $poll->allowvotes = TRUE;
Steven Wittens's avatar
Steven Wittens committed
309
310
    }
  }
311
312
  return $poll;
}
Dries's avatar
   
Dries committed
313

314
/**
315
 * Implementation of hook_node_info().
316
 */
317
function poll_node_info() {
318
319
  return array(
    'poll' => array(
320
      'name' => t('Poll'),
321
322
323
324
325
326
      'module' => 'poll',
      'description' => t("A poll is a multiple-choice question which visitors can vote on."),
      'title_label' => t('Question'),
      'has_body' => FALSE,
    )
  );
327
}
328

Steven Wittens's avatar
Steven Wittens committed
329
function poll_page() {
Steven Wittens's avatar
Steven Wittens committed
330
  // List all polls
331
  $sql = "SELECT n.nid, n.title, p.active, n.created, SUM(c.chvotes) AS votes FROM {node} n INNER JOIN {poll} p ON n.nid = p.nid INNER JOIN {poll_choices} c ON n.nid = c.nid WHERE n.status = 1 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC";
332
  $sql = db_rewrite_sql($sql);
Dries's avatar
   
Dries committed
333
  $result = pager_query($sql, 15);
Steven Wittens's avatar
Steven Wittens committed
334
  $output = '<ul>';
Steven Wittens's avatar
Steven Wittens committed
335
  while ($node = db_fetch_object($result)) {
336
    $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '@count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>';
Steven Wittens's avatar
Steven Wittens committed
337
  }
Steven Wittens's avatar
Steven Wittens committed
338
339
  $output .= '</ul>';
  $output .= theme("pager", NULL, 15);
Dries's avatar
   
Dries committed
340
  return $output;
Steven Wittens's avatar
Steven Wittens committed
341
342
}

343
344
345
/**
 * Implementation of hook_perm().
 */
346
function poll_perm() {
347
  return array('create polls', 'vote on polls', 'cancel own vote', 'inspect all votes');
348
}
Dries's avatar
   
Dries committed
349

350
351
352
/**
 * Creates a simple teaser that lists all the choices.
 */
353
function poll_teaser($node) {
354
  $teaser = NULL;
Dries's avatar
Dries committed
355
  if (is_array($node->choice)) {
Steven Wittens's avatar
Steven Wittens committed
356
357
    foreach ($node->choice as $k => $choice) {
      $teaser .= '* '. $choice['chtext'] .'\n';
358
359
360
361
    }
  }
  return $teaser;
}
362

Steven Wittens's avatar
Steven Wittens committed
363
/**
364
 * Generates the voting form for a poll.
Steven Wittens's avatar
Steven Wittens committed
365
 */
366
function poll_view_voting($node, $block) {
Dries's avatar
   
Dries committed
367
  if ($node->choice) {
Steven Wittens's avatar
Steven Wittens committed
368
369
    $list = array();
    foreach ($node->choice as $i => $choice) {
370
      $list[$i] = check_plain($choice['chtext']);
371
    }
372
373
374
375
376
377
    $form['choice'] = array(
      '#type' => 'radios',
      '#title' => $block ? check_plain($node->title) : '',
      '#default_value' => -1,
      '#options' => $list,
    );
Dries's avatar
   
Dries committed
378
  }
379
380
  $form['nid'] = array('#type' => 'hidden', '#value' => $node->nid);
  $form['vote'] = array('#type' => 'submit', '#value' => t('Vote'));
381
  $form['#action'] = url('node/'. $node->nid);
382
  return $form;
383
}
Steven Wittens's avatar
Steven Wittens committed
384

385
386
387
388
389
390
391
/**
 * Themes the voting form for a poll.
 */
function theme_poll_view_voting($form) {
  $output .= '<div class="poll">';
  $output .= '  <div class="vote-form">';
  $output .= '    <div class="choices">';
392
  $output .= drupal_render($form['choice']);
393
  $output .= '    </div>';
394
395
  $output .= drupal_render($form['nid']);
  $output .= drupal_render($form['vote']);
396
  $output .= '  </div>';
397
  $output .= drupal_render($form);
Steven Wittens's avatar
Steven Wittens committed
398
  $output .= '</div>';
Steven Wittens's avatar
Steven Wittens committed
399
400
401
  return $output;
}

402
403
404
/**
 * Generates a graphical representation of the results of a poll.
 */
Dries's avatar
Dries committed
405
function poll_view_results(&$node, $teaser, $page, $block) {
Steven Wittens's avatar
Steven Wittens committed
406
  // Count the votes and find the maximum
Steven Wittens's avatar
Steven Wittens committed
407
  foreach ($node->choice as $choice) {
408
409
    $total_votes += $choice['chvotes'];
    $max_votes = max($max_votes, $choice['chvotes']);
Steven Wittens's avatar
Steven Wittens committed
410
411
  }

Steven Wittens's avatar
Steven Wittens committed
412
413
  foreach ($node->choice as $i => $choice) {
    if ($choice['chtext'] != '') {
414
      $poll_results .= theme('poll_bar', check_plain($choice['chtext']), round($choice['chvotes'] * 100 / max($total_votes, 1)), format_plural($choice['chvotes'], '1 vote', '@count votes'), $block);
415
    }
416
  }
Dries's avatar
   
Dries committed
417

418
  $output .= theme('poll_results', check_plain($node->title), $poll_results, $total_votes, $node->links, $block, $node->nid, $node->vote);
419
420
421
422

  return $output;
}

423
function theme_poll_results($title, $results, $votes, $links, $block, $nid, $vote) {
424
425
426
427
428
429
430
431
432
433
434
435
  if ($block) {
    $output .= '<div class="poll">';
    $output .= '<div class="title">'. $title .'</div>';
    $output .= $results;
    $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>';
    $output .= '</div>';
    $output .= '<div class="links">'. theme('links', $links) .'</div>';
  }
  else {
    $output .= '<div class="poll">';
    $output .= $results;
    $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>';
436
    if (isset($vote) && $vote > -1 && user_access('cancel own vote')) {
437
      $output .= drupal_get_form('poll_cancel_form', $nid);
438
    }
439
440
441
442
443
444
    $output .= '</div>';
  }

  return $output;
}

445
function poll_cancel_form($nid) {
446
447
448
449
450
  $form['#action'] = url("poll/cancel/$nid");
  $form['submit'] = array('#type' => 'submit', '#value' => t('Cancel your vote'));
  return $form;
}

451
452
453
454
455
456
457
458
459
460
461
function theme_poll_bar($title, $percentage, $votes, $block) {
  if ($block) {
    $output  = '<div class="text">'. $title .'</div>';
    $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>';
    $output .= '<div class="percent">'. $percentage .'%</div>';
  }
  else {
    $output  = '<div class="text">'. $title .'</div>';
    $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>';
    $output .= '<div class="percent">'. $percentage .'% ('. $votes .')</div>';
  }
Steven Wittens's avatar
Steven Wittens committed
462
463
464
465

  return $output;
}

Steven Wittens's avatar
Steven Wittens committed
466
467
468
469
/**
 * Callback for the 'results' tab for polls you can vote on
 */
function poll_results() {
470
  if ($node = node_load(arg(1))) {
471
    drupal_set_title(check_plain($node->title));
Dries's avatar
   
Dries committed
472
    return node_show($node, 0);
Steven Wittens's avatar
Steven Wittens committed
473
474
475
476
477
478
  }
  else {
    drupal_not_found();
  }
}

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
/**
 * Callback for the 'votes' tab for polls you can see other votes on
 */
function poll_votes() {
  if ($node = node_load(arg(1))) {
    drupal_set_title(check_plain($node->title));
    $output = t('This table lists all the recorded votes for this poll.  If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted.');

    $header[] = array('data' => t('Visitor'), 'field' => 'u.name');
    $header[] = array('data' => t('Vote'), 'field' => 'pv.chorder');

    $result = pager_query("SELECT pv.chorder, pv.uid, pv.hostname, u.name FROM {poll_votes} pv LEFT JOIN {users} u ON pv.uid = u.uid WHERE pv.nid = %d" . tablesort_sql($header), 20, 0, NULL, $node->nid);
    $rows = array();
    while ($vote = db_fetch_object($result)) {
      $rows[] = array(
        $vote->name ? theme('username', $vote) : check_plain($vote->hostname),
        check_plain($node->choice[$vote->chorder]['chtext']));
    }
    $output .= theme('table', $header, $rows);
    $output .= theme('pager', NULL, 20, 0);
    print theme('page', $output);
  }
  else {
    drupal_not_found();
  }
}

Steven Wittens's avatar
Steven Wittens committed
506
507
508
509
/**
 * Callback for processing a vote
 */
function poll_vote(&$node) {
510
  global $user;
511
  $nid = arg(1);
512

513
  if ($node = node_load($nid)) {
514
    $edit = $_POST;
Steven Wittens's avatar
Steven Wittens committed
515
516
    $choice = $edit['choice'];
    $vote = $_POST['vote'];
Steven Wittens's avatar
Steven Wittens committed
517
518
519

    if (isset($choice) && isset($node->choice[$choice])) {
      if ($node->allowvotes) {
520
        // Record the vote by this user or host.
521
        if ($user->uid) {
522
          db_query('INSERT INTO {poll_votes} (nid, chorder, uid) VALUES (%d, %d, %d)', $node->nid, $choice, $user->uid);
523
524
        }
        else {
525
          db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, $_SERVER['REMOTE_ADDR']);
526
527
528
        }

        // Add one to the votes.
Steven Wittens's avatar
Steven Wittens committed
529
        db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
530
531

        $node->allowvotes = FALSE;
Steven Wittens's avatar
Steven Wittens committed
532
        $node->choice[$choice]['chvotes']++;
533
        cache_clear_all();
Dries's avatar
   
Dries committed
534
        drupal_set_message(t('Your vote was recorded.'));
Steven Wittens's avatar
Steven Wittens committed
535
536
      }
      else {
537
        drupal_set_message(t("You are not allowed to vote on this poll."), 'error');
Steven Wittens's avatar
Steven Wittens committed
538
539
540
      }
    }
    else {
541
      drupal_set_message(t("You did not specify a valid poll choice."), 'error');
Steven Wittens's avatar
Steven Wittens committed
542
    }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    drupal_goto('node/'. $nid);
  }
  else {
    drupal_not_found();
  }
}


/**
 * Callback for canceling a vote
 */
function poll_cancel(&$node) {
  global $user;

  $nid = arg(2);
558
  if ($node = node_load($nid)) {
559
    if ($node->type == 'poll' && $node->allowvotes == FALSE) {
560
561
562
563
564
565
      if ($user->uid) {
        db_query('DELETE FROM {poll_votes} WHERE nid = %d and uid = %d', $node->nid, $user->uid);
      }
      else {
        db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']);
      }
Steven Wittens's avatar
Steven Wittens committed
566

567
      // Subtract from the votes.
568
      db_query("UPDATE {poll_choices} SET chvotes = chvotes - 1 WHERE nid = %d AND chorder = %d", $node->nid, $node->vote);
569
      $node->allowvotes = TRUE;
570
      $node->choice[$node->vote]['chvotes']--;
571
572
573
574
575
      drupal_set_message(t('Your vote was canceled.'));
    }
    else {
      drupal_set_message(t("You are not allowed to cancel an invalid poll choice."), 'error');
    }
Steven Wittens's avatar
Steven Wittens committed
576
577
578
579
    drupal_goto('node/'. $nid);
  }
  else {
    drupal_not_found();
Steven Wittens's avatar
Steven Wittens committed
580
581
582
  }
}

583
584
585
586
587
588
589
/**
 * Implementation of hook_view().
 *
 * @param $block
 *   An extra parameter that adapts the hook to display a block-ready
 *   rendering of the poll.
 */
590
function poll_view($node, $teaser = FALSE, $page = FALSE, $block = FALSE) {
Dries's avatar
   
Dries committed
591
  global $user;
Dries's avatar
   
Dries committed
592
  $output = '';
Steven Wittens's avatar
Steven Wittens committed
593

Steven Wittens's avatar
Steven Wittens committed
594
  // Special display for side-block
Steven Wittens's avatar
Steven Wittens committed
595
  if ($block) {
Steven Wittens's avatar
Steven Wittens committed
596
    // No 'read more' link
597
    $node->readmore = FALSE;
Steven Wittens's avatar
Steven Wittens committed
598

Dries's avatar
Dries committed
599
    $links = module_invoke_all('link', 'node', $node, 1);
600
    $links[] = array('title' => t('Older polls'), 'href' => 'poll', 'attributes' => array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
601
    if ($node->allowvotes && $block) {
602
      $links[] = array('title' => t('Results'), 'href' => 'node/'. $node->nid .'/results', 'attributes' => array('title' => t('View the current poll results.')));
Steven Wittens's avatar
Steven Wittens committed
603
    }
Steven Wittens's avatar
Steven Wittens committed
604

605
606
607
608
    $node->links = $links;
  }

  if ($node->allowvotes && ($block || arg(2) != 'results')) {
609
610
611
    if ($_POST['op'] == t('Vote')) {
      poll_vote($node);
    }
612
    $node->content['body'] = array(
613
      '#value' => drupal_get_form('poll_view_voting', $node, $block),
614
    );
615
616
  }
  else {
617
618
619
    $node->content['body'] = array(
      '#value' => poll_view_results($node, $teaser, $page, $block),
    );
Steven Wittens's avatar
Steven Wittens committed
620
  }
621
  return $node;
622
623
}

624
625
626
/**
 * Implementation of hook_update().
 */
627
function poll_update($node) {
Steven Wittens's avatar
Steven Wittens committed
628
  db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
629

Steven Wittens's avatar
Steven Wittens committed
630
  db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
Dries's avatar
Dries committed
631
  db_query('DELETE FROM {poll_votes} WHERE nid = %d', $node->nid);
632
633

  $i = 0;
Steven Wittens's avatar
Steven Wittens committed
634
635
636
  foreach ($node->choice as $choice) {
    $chvotes = (int)$choice['chvotes'];
    $chtext = $choice['chtext'];
637

Steven Wittens's avatar
Steven Wittens committed
638
639
    if ($chtext != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);
640
    }
641
  }
642
}
643
644
645
646
647
648
649
650
651

/**
 * Implementation of hook_user().
 */
function poll_user($op, &$edit, &$user) {
  if ($op == 'delete') {
    db_query('UPDATE {poll_votes} SET uid = 0 WHERE uid = %d', $user->uid);
  }
}