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

Steven Wittens's avatar
Steven Wittens committed
4 5
function poll_help($section = 'admin/help#poll') {
  $output = '';
Steven Wittens's avatar
Steven Wittens committed
6

Steven Wittens's avatar
Steven Wittens committed
7
  switch ($section) {
Steven Wittens's avatar
Steven Wittens committed
8

Steven Wittens's avatar
Steven Wittens committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
    case 'admin/help#poll':
      $output .= t("
      <p>Users with the correct <a href=\"%permissions\">permissions</a> can create and/or vote on polls.</p>
      <ul>
      <li>To create a poll a user needs the \"create polls\" permission.</li>
      <li>To vote on a poll question a user must have the \"vote on polls\" permission.</li>
      <li>To view the results one needs the \"access content\" permission.</li>
      <li>To administer polls you need the \"administer nodes\" permission.</li>
      </ul>
      <p>Creating a poll is much like creating any other node. Click \"create poll\" in your user box. 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.</p><p>The <a href=\"%poll\">Poll</a> item in the navigation links 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.</p>", array("%permissions" => url("admin/user/permission"), "%poll" => url("poll")));
      break;
    case 'admin/system/modules#description':
      $output = t("Enables your site to capture votes on different topics in the form of multiple choice questions.");
      break;
    case 'node/add#poll':
      $output = t("A poll is a multiple-choice question which visitors can vote on.");
      break;
Steven Wittens's avatar
Steven Wittens committed
26
  }
Steven Wittens's avatar
Steven Wittens committed
27 28

  return $output;
29 30
}

31
function poll_access($op, $node) {
Steven Wittens's avatar
Steven Wittens committed
32
  if ($op == 'view') {
33
    return $node->status;
34 35
  }

Steven Wittens's avatar
Steven Wittens committed
36 37
  if ($op == 'create') {
    return user_access('create polls');
Dries's avatar
 
Dries committed
38
  }
Steven Wittens's avatar
Steven Wittens committed
39 40
}

Steven Wittens's avatar
Steven Wittens committed
41 42 43 44
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
45 46 47
      return $blocks;
    }
    else {
Steven Wittens's avatar
Steven Wittens committed
48
      // Retrieve latest poll
Dries's avatar
 
Dries committed
49
      $timestamp = db_result(db_query("SELECT MAX(created) FROM {node} WHERE type = 'poll' AND status = '1' AND moderate = '0'"));
Dries's avatar
 
Dries committed
50
      if ($timestamp) {
Steven Wittens's avatar
Steven Wittens committed
51 52
        $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));

Dries's avatar
 
Dries committed
53 54
        if ($poll->nid) {
          // Poll_view dumps the output into $poll->body
55
          poll_view($poll, 1, 0, 1);
Dries's avatar
 
Dries committed
56
        }
Dries's avatar
 
Dries committed
57
      }
Steven Wittens's avatar
Steven Wittens committed
58 59
      $block['subject'] = t('Poll');
      $block['content'] = $poll->body;
Dries's avatar
 
Dries committed
60
      return $block;
61 62 63 64
    }
  }
}

65 66
function poll_cron() {
  // Close polls that have exceeded their allowed runtime
Dries's avatar
 
Dries committed
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)) {
Dries's avatar
 
Dries committed
69
    db_query("UPDATE {poll} SET active='0' WHERE nid = %d", $poll->nid);
Dries's avatar
 
Dries committed
70
  }
71 72
}

73
function poll_delete($node) {
Dries's avatar
 
Dries committed
74 75
  db_query("DELETE FROM {poll} WHERE nid=%d", $node->nid);
  db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
76 77
}

78
function poll_validate(&$node) {
79 80
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
Steven Wittens's avatar
Steven Wittens committed
81 82 83 84
    $realchoices = 0;
    foreach ($node->choice as $i => $choice) {
      if ($choice['chtext'] != '') {
        $realchoices++;
85
      }
Dries's avatar
 
Dries committed
86

Steven Wittens's avatar
Steven Wittens committed
87 88
      if ($choice['chvotes'] < 0) {
        $error["choice][$i][chvotes"] = theme('error', t("Negative values are not allowed."));
89
      }
90
    }
Dries's avatar
 
Dries committed
91

Steven Wittens's avatar
Steven Wittens committed
92 93
    if ($realchoices < 2) {
      $error["choice][0][chtext"] = theme('error', t("You must fill in at least two choices."));
94 95
    }
  }
96 97 98 99 100 101

  $node->teaser = poll_teaser($node);

  return $error;
}

Steven Wittens's avatar
Steven Wittens committed
102 103
function poll_form(&$node, &$error) {
  $admin = user_access('administer nodes');
104

Steven Wittens's avatar
Steven Wittens committed
105 106 107
  if (function_exists('taxonomy_node_form')) {
    $output = implode('', taxonomy_node_form('poll', $node));
  }
108

Steven Wittens's avatar
Steven Wittens committed
109 110 111
  if (!isset($node->choices)) {
    $node->choices = max(2, count($node->choice) ? count($node->choice) : 5);
  }
Dries's avatar
 
Dries committed
112

Steven Wittens's avatar
Steven Wittens committed
113 114 115
  // User ticked 'need more choices'
  if ($node->morechoices) {
    $node->choices *= 2;
116 117
  }

Steven Wittens's avatar
Steven Wittens committed
118
  $output .= '<div class="poll-form">';
Dries's avatar
 
Dries committed
119

Steven Wittens's avatar
Steven Wittens committed
120
  // Poll choices
Dries's avatar
 
Dries committed
121
  $opts = drupal_map_assoc(range(2, $node->choices * 2 + 5));
122
  for ($a = 0; $a < $node->choices; $a++) {
Steven Wittens's avatar
Steven Wittens committed
123
    $group1 .= form_textfield(t('Choice %n', array('%n' => ($a + 1))), "choice][$a][chtext", $node->choice[$a]['chtext'], 50, 127, $error["choice][$a][chtext"]);
124
    if ($admin) {
Steven Wittens's avatar
Steven Wittens committed
125
      $group1 .= form_textfield(t('Votes for choice %n', array('%n' => ($a + 1))), "choice][$a][chvotes", (int)$node->choice[$a]['chvotes'], 7, 7, $error["choice][$a][chvotes"]);
126 127
    }
  }
Steven Wittens's avatar
Steven Wittens committed
128 129 130
  $group1 .= form_hidden('choices', $node->choices);
  $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."));
  $output .= form_group(t('Choices'), $group1);
Dries's avatar
 
Dries committed
131

Dries's avatar
 
Dries committed
132

Steven Wittens's avatar
Steven Wittens committed
133 134 135
  // Poll attributes
  $_duration = array_merge(array(0 => t('Unlimited')), drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval"));
  $_active = array(0 => t('Closed'), 1 => t('Active'));
Dries's avatar
 
Dries committed
136

Steven Wittens's avatar
Steven Wittens committed
137 138
  if ($admin) {
    $group2 .= form_radios(t('Poll status'), 'active', isset($node->active) ? $node->active : 1, $_active, t('When a poll is closed, visitors can no longer vote for it.'));
Dries's avatar
 
Dries committed
139
  }
Steven Wittens's avatar
Steven Wittens committed
140
  $group2 .= form_select(t('Poll duration'), 'runtime', $node->runtime ? $node->runtime : 0, $_duration, t('After this period, the poll will be closed automatically.'));
Dries's avatar
 
Dries committed
141 142

  $output .= form_group(t('Settings'), $group2);
Steven Wittens's avatar
Steven Wittens committed
143
  $output .= '</div>';
Dries's avatar
 
Dries committed
144 145

  return $output;
146
}
147

148
function poll_insert($node) {
Steven Wittens's avatar
Steven Wittens committed
149
  if (!user_access('administer nodes')) {
150
    // Make sure all votes are 0 initially
Steven Wittens's avatar
Steven Wittens committed
151 152 153
    foreach ($node->choice as $i => $choice) {
      $node->choice[$i]['chvotes'] = 0;
    }
154 155
    $node->active = 1;
  }
156

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

Steven Wittens's avatar
Steven Wittens committed
159 160 161
  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++);
162 163
    }
  }
164 165
}

Steven Wittens's avatar
Steven Wittens committed
166
function poll_link($type, $node = 0, $main) {
Dries's avatar
 
Dries committed
167 168
  $links = array();

Steven Wittens's avatar
Steven Wittens committed
169
  if ($type == 'system') {
Dries's avatar
 
Dries committed
170
    if (user_access("create polls")) {
Steven Wittens's avatar
Steven Wittens committed
171
      menu('node/add/poll', t('poll'), 'node_page', 0);
Dries's avatar
 
Dries committed
172
    }
Steven Wittens's avatar
Steven Wittens committed
173 174
    if (user_access('access content')) {
      menu('poll', t('polls'), 'poll_page', 0, MENU_HIDE);
Dries's avatar
 
Dries committed
175
    }
176
  }
Steven Wittens's avatar
Steven Wittens committed
177 178
  else if ($type == 'page' && user_access('access content')) {
    $links[] = l(t('polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
179
  }
Steven Wittens's avatar
Steven Wittens committed
180
  else if ($type == 'node' && $node->type == 'poll') {
Steven Wittens's avatar
Steven Wittens committed
181 182 183 184 185
    /*
    ** Add links to allow the user to switch between the results and the voting
    ** form, if he/she hasn't voted yet.
    */

Steven Wittens's avatar
Steven Wittens committed
186 187 188
    if ($node->allowvotes) {
      if (arg(3) == 'results') {
        $links[] = l(t('voting form'), 'node/view/'. $node->nid);
Steven Wittens's avatar
Steven Wittens committed
189 190
      }
      else {
Steven Wittens's avatar
Steven Wittens committed
191
        $links[] = l(t('view results'), 'node/view/'. $node->nid .'/results');
Steven Wittens's avatar
Steven Wittens committed
192 193 194
      }
    }
  }
Dries's avatar
 
Dries committed
195 196

  return $links;
197
}
Dries's avatar
 
Dries committed
198

Steven Wittens's avatar
Steven Wittens committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
/**
 * Determine an adjusted user id, to allow for basic tracking of anonymous
 * users (IP-based).
 */
function poll_uid() {
  global $user;
  if ($user->uid) {
     // Pad the UID with underscores to allow a simple strstr() search
    $id = '_'. $user->uid .'_';
  }
  else {
    $id = $_SERVER['REMOTE_ADDR'];
  }
  return $id;
}

215 216
function poll_load($node) {
  // Load the appropriate choices into the $node object
Dries's avatar
 
Dries committed
217
  $poll = db_fetch_object(db_query("SELECT runtime, voters, active FROM {poll} WHERE nid = %d", $node->nid));
Dries's avatar
 
Dries committed
218

Dries's avatar
 
Dries committed
219
  $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
220 221
  while ($choice = db_fetch_array($result)) {
    $poll->choice[$choice['chorder']] = $choice;
222
  }
Steven Wittens's avatar
Steven Wittens committed
223

Steven Wittens's avatar
Steven Wittens committed
224 225 226 227 228 229 230
  // Determine whether or not this user is allowed to vote
  $poll->allowvotes = false;
  if (user_access('vote on polls')) {
    if (!strstr($poll->voters, poll_uid())) {
      $poll->allowvotes = $poll->active;
    }
  }
231 232
  return $poll;
}
Dries's avatar
 
Dries committed
233

Dries's avatar
 
Dries committed
234 235
function poll_node_name($node) {
  return t("poll");
236
}
237

Steven Wittens's avatar
Steven Wittens committed
238
function poll_page() {
Steven Wittens's avatar
Steven Wittens committed
239 240 241
  // List all polls
  $result = pager_query("SELECT n.nid, n.title, p.active, 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 type = 'poll' AND status = '1' AND moderate = '0' GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC", 15);
  $output = '<ul>';
Steven Wittens's avatar
Steven Wittens committed
242
  while ($node = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
243
    $output .= '<li>'. l($node->title, "node/view/$node->nid") .' - '. format_plural($node->votes, '1 vote', '%count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>';
Steven Wittens's avatar
Steven Wittens committed
244
  }
Steven Wittens's avatar
Steven Wittens committed
245 246 247
  $output .= '</ul>';
  $output .= theme("pager", NULL, 15);
  print theme('page', $output);
Steven Wittens's avatar
Steven Wittens committed
248 249
}

250
function poll_perm() {
Steven Wittens's avatar
Steven Wittens committed
251
  return array('create polls', 'vote on polls');
252
}
Dries's avatar
 
Dries committed
253

254 255
function poll_teaser($node) {
  // Create a simple teaser that lists all the choices
Dries's avatar
Dries committed
256
  if (is_array($node->choice)) {
Steven Wittens's avatar
Steven Wittens committed
257 258
    foreach ($node->choice as $k => $choice) {
      $teaser .= '* '. $choice['chtext'] .'\n';
259 260 261 262
    }
  }
  return $teaser;
}
263

Steven Wittens's avatar
Steven Wittens committed
264 265 266 267
/**
 * Display the vote form
 */
function poll_view_voting(&$node, $main, $page, $block) {
Steven Wittens's avatar
Steven Wittens committed
268
  $url = request_uri();
Steven Wittens's avatar
Steven Wittens committed
269
  $output .= '<div class="poll">';
Dries's avatar
 
Dries committed
270

Steven Wittens's avatar
Steven Wittens committed
271 272
  $form .= '<div class="vote-form">';
  $form .= '<div class="choices">';
Dries's avatar
 
Dries committed
273
  if ($node->choice) {
Steven Wittens's avatar
Steven Wittens committed
274 275 276
    $list = array();
    foreach ($node->choice as $i => $choice) {
      $list[$i] = drupal_specialchars($choice['chtext']);
277
    }
Steven Wittens's avatar
Steven Wittens committed
278
    $form .= form_radios($page ? '' : $node->title, 'choice', -1, $list);
Dries's avatar
 
Dries committed
279
  }
Steven Wittens's avatar
Steven Wittens committed
280 281 282 283 284 285
  $form .= '</div>';
  $form .= form_hidden('nid', $node->nid);
  $form .= form_submit(t('Vote'), 'vote') .'</div>';

  $output .= form($form, 'post', url('node/view/'. $node->nid));
  $output .= '</div>';
Steven Wittens's avatar
Steven Wittens committed
286 287 288 289

  return $output;
}

Steven Wittens's avatar
Steven Wittens committed
290
function poll_view_results(&$node, $main, $page, $block) {
Steven Wittens's avatar
Steven Wittens committed
291
  // Display the results
Dries's avatar
 
Dries committed
292

Steven Wittens's avatar
Steven Wittens committed
293
  // Count the votes and find the maximum
Steven Wittens's avatar
Steven Wittens committed
294 295 296
  foreach ($node->choice as $choice) {
    $votestotal += $choice['chvotes'];
    $votesmax = max($votesmax, $choice['chvotes']);
Steven Wittens's avatar
Steven Wittens committed
297 298
  }

Dries's avatar
 
Dries committed
299
  // Output the divs for the text, bars and percentages
Steven Wittens's avatar
Steven Wittens committed
300 301 302 303 304 305 306 307 308 309 310 311
  $output .= '<div class="poll">';
  if ($block) {
    $output .= '<div class="title">'. $node->title .'</div>';
  }
  foreach ($node->choice as $i => $choice) {
    if ($choice['chtext'] != '') {
      $percentage = round($choice['chvotes'] * 100 / max($votestotal, 1));
      $output .= '<div class="text">'. drupal_specialchars($choice['chtext']) .'</div>';
      $output .= '<div class="bar">';
      $output .= '<div style="width: '. $percentage .'%;" class="foreground"></div>';
      $output .= '</div>';
      $output .= '<div class="percent">'. $percentage .'%'. (!$block ? ' ('. format_plural($choice['chvotes'], '1 vote', '%count votes') .')' : '') .'</div>';
312
    }
313
  }
Steven Wittens's avatar
Steven Wittens committed
314
  $output .= '<div class="total">'. t('Total votes') .": $votestotal</div>";
Dries's avatar
 
Dries committed
315

Steven Wittens's avatar
Steven Wittens committed
316
  $output .= '</div>';
Steven Wittens's avatar
Steven Wittens committed
317 318 319 320 321

  return $output;
}

function poll_view_processvote(&$node) {
Steven Wittens's avatar
Steven Wittens committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
  $edit = $_POST['edit'];
  $choice = $edit['choice'];
  $vote = $_POST['vote'];

  if ($vote == t('Vote')) {
    if (isset($choice) && isset($node->choice[$choice])) {
      if ($node->allowvotes) {
        $id = poll_uid();
        $node->voters = $node->voters ? ($node->voters .' '. $id) : $id;
        db_query("UPDATE {poll} SET voters='%s' WHERE nid = %d", $node->voters, $node->nid);
        db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
        $node->allowvotes = false;
        $node->choice[$choice]['chvotes']++;
        drupal_set_message(t('Your vote was recorded.'));
      }
      else {
        drupal_set_message(t("You're not allowed to vote on this poll."), 'error');
      }
    }
    else {
      drupal_set_message(t("You didn't specify a valid poll choice."), 'error');
Steven Wittens's avatar
Steven Wittens committed
343
    }
Steven Wittens's avatar
Steven Wittens committed
344 345 346
  }
}

347
function poll_view(&$node, $main = 0, $page = 0, $block = 0) {
Dries's avatar
 
Dries committed
348
  global $user;
Steven Wittens's avatar
Steven Wittens committed
349

Steven Wittens's avatar
Steven Wittens committed
350 351 352 353
  if (!$block) {
    // Because the voting form is embedded in the node-display, we process the data here
    poll_view_processvote($node);
  }
Steven Wittens's avatar
Steven Wittens committed
354

Steven Wittens's avatar
Steven Wittens committed
355 356 357 358 359 360
  if ($node->allowvotes && (arg(2) != $node->nid || arg(3) != 'results')) {
    $output .= poll_view_voting($node, $main, $page, $block);
  }
  else {
    $output .= poll_view_results($node, $main, $page, $block);
  }
Steven Wittens's avatar
Steven Wittens committed
361

Steven Wittens's avatar
Steven Wittens committed
362
  // Special display for side-block
Steven Wittens's avatar
Steven Wittens committed
363
  if ($block) {
Steven Wittens's avatar
Steven Wittens committed
364 365
    // No 'read more' link
    $node->body = $node->teaser = '';
Steven Wittens's avatar
Steven Wittens committed
366

Steven Wittens's avatar
Steven Wittens committed
367
    $links = link_node($node, $main);
Steven Wittens's avatar
Steven Wittens committed
368
    $links[] = l(t('older polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
369

Steven Wittens's avatar
Steven Wittens committed
370
    $output .= '<div class="links">'. theme("links", $links) .'</div>';
Steven Wittens's avatar
Steven Wittens committed
371 372 373
  }

  $node->body = $node->teaser = $output;
374

375
  // We also use poll_view() for the side-block
Steven Wittens's avatar
Steven Wittens committed
376
  if (!$block) {
Steven Wittens's avatar
Steven Wittens committed
377
    return theme('node', $node, $main, $page);
378 379 380
  }
}

381
function poll_update($node) {
Steven Wittens's avatar
Steven Wittens committed
382
  db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
383

Steven Wittens's avatar
Steven Wittens committed
384 385 386 387
  db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
  foreach ($node->choice as $choice) {
    $chvotes = (int)$choice['chvotes'];
    $chtext = $choice['chtext'];
388

Steven Wittens's avatar
Steven Wittens committed
389 390
    if ($chtext != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);
391
    }
392 393
  }
}
394

395
?>