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

Steven Wittens's avatar
Steven Wittens committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
function poll_allowvotes(&$node) {
  /*
  ** Only accept votes on specific cases to prevent double voting and abuse.
  ** We only need to determine this once for a poll, but we don't do this in
  ** poll_load() (i.e. for every poll that is loaded) for speed reasons.
  */
  global $REMOTE_ADDR, $user;

  if ($node->allowvotes != -1) {
    return $node;
  }

  $node->allowvotes = 0;
  if (user_access("vote on polls")) {
    if ($user->uid) {
      // Pad the UID with underscores to allow a simple strstr() search
      $id = "_". $user->uid ."_";
    }
    else {
      $id = $REMOTE_ADDR;
    }
    if (!strstr($node->voters, $id)) {
      $node->allowvotes = $node->active;
    }

    // Save this for later
    $node->polluserid = $id;
  }
  return $node;
33 34
}

35 36 37
function poll_access($op, $node) {
  if ($op == "view") {
    return $node->status;
38 39
  }

40 41
  if ($op == "create") {
    return 1;
Dries's avatar
 
Dries committed
42
  }
Steven Wittens's avatar
Steven Wittens committed
43 44
}

45
function poll_block() {
46
  $timestamp = db_result(db_query("SELECT MAX(created) FROM node WHERE type='poll' AND status='1' AND moderate='0'"));
47
  if ($timestamp) {
48
    $poll = node_load(array("type" => "poll", "created" => $timestamp, "moderate" => "0", "status" => "1"));
49 50
    if ($poll->nid) {
      // Poll_view dumps the output into $poll->body
Steven Wittens's avatar
Steven Wittens committed
51
      poll_view($poll, 1, 1);
52 53
    }
  }
Dries's avatar
 
Dries committed
54
  $blocks[0][subject] = t("Latest poll: %t", array("%t" => $poll->title));
55
  $blocks[0][content] = $poll->body;
56
  $blocks[0][info] = t("Most recent poll");
57
  return $blocks;
58 59
}

60 61
function poll_cron() {
  // Close polls that have exceeded their allowed runtime
Kjartan's avatar
Kjartan committed
62
  $result = db_query("SELECT p.nid FROM poll p LEFT 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
63
  while ($poll = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
64
    db_query("UPDATE poll SET active='0' WHERE nid='$poll->nid'");
Dries's avatar
 
Dries committed
65
  }
66 67
}

68 69 70
function poll_delete($node) {
  db_query("DELETE FROM poll WHERE nid='$node->nid'");
  db_query("DELETE FROM poll_choices WHERE nid='$node->nid'");
71 72
}

73 74
function poll_form(&$node, &$help, &$error) {
  $admin = user_access("administer nodes");
75

76
  $_duration = array(0 => t("Unlimited"), 86400 => format_interval(86400), 172800 => format_interval(172800), 345600 => format_interval(345600), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200), 4838400 => format_interval(4838400), 9676800 => format_interval(9676800), 31536000 => format_interval(31536000));
Steven Wittens's avatar
Steven Wittens committed
77
  $_active = array(0 => t("Closed"), 1 => t("Active"));
Dries's avatar
 
Dries committed
78

Steven Wittens's avatar
Steven Wittens committed
79
  $node->choices = $node->choices ? $node->choices : max(2, count($node->choice) ? count($node->choice) : 5);
80

81 82 83 84 85 86
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
    for ($i = 0; $i < $node->choices; $i++) {
      if ($node->choice[$i] != "") {
        $actualchoices++;
      }
Dries's avatar
 
Dries committed
87

88
      if ($node->chvotes[$i] < 0) {
Kjartan's avatar
Kjartan committed
89
        $error["chvotes][$i"] = "<span style=\"color: red;\">". t("Negative values are not allowed.") ."</span>";
90
      }
91
    }
Dries's avatar
 
Dries committed
92

93
    if ($actualchoices < 2) {
Kjartan's avatar
Kjartan committed
94
      $error["choice][0"] = "<span style=\"color: red;\">". t("You must fill in at least two choices.") ."</span>";
95 96 97 98 99
    }
  }
  else {
    $help = variable_get("poll_help", "");
  }
Dries's avatar
 
Dries committed
100

101 102 103 104
  if (function_exists("taxonomy_node_form")) {
    $output = implode("", taxonomy_node_form("poll", $node));
  }

105 106 107 108
  for ($c = 2; $c <= 20; $c++) {
    $opts[$c] = $c;
  }
  $output .= form_select(t("Number of choices"), "choices", $node->choices, $opts, t("This item only specifies the number of boxes in this form, but it doesn't have to equal the actual amount of options: you can leave the extra boxes empty."));
Kjartan's avatar
Kjartan committed
109
  $output .= form_submit(t("Preview")) ."<br /><br /><br />";
Dries's avatar
 
Dries committed
110

111
  for ($a = 0; $a < $node->choices; $a++) {
Kjartan's avatar
Kjartan committed
112
    $output .= form_textfield(t("Choice") ." ". ($a + 1), "choice][$a", $node->choice[$a], 50, 127, $error["choice][$a"]);
113
    if ($admin) {
Dries's avatar
 
Dries committed
114
      $output .= form_textfield(t("Votes for choice %n", array("%n" => ($a + 1))), "chvotes][$a", $node->chvotes[$a] ? $node->chvotes[$a] : 0, 7, 7, $error["chvotes][$a"]);
115 116
    }
  }
Dries's avatar
 
Dries committed
117

118 119 120
  if ($admin) {
    $output .= form_select(t("Poll status"), "active", isset($node->active) ? $node->active : 1, $_active);
  }
121

122
  $output .= form_select(t("Poll duration"), "runtime", $node->runtime ? $node->runtime : 0, $_duration, t("After this period, the poll will automatically be closed."));
123

124 125
  return $output;
}
Dries's avatar
 
Dries committed
126

127
function poll_help() {
Steven Wittens's avatar
Steven Wittens committed
128
 ?><p>Drupal's poll module allows users to submit multiple-choice questions that others can vote on.</p>
129 130
 <?php
}
131

132 133 134
function poll_insert($node) {
  if (!user_access("administer nodes")) {
    // Make sure all votes are 0 initially
Kjartan's avatar
Kjartan committed
135
    for ($i = 0; $i < count($node->chvotes); $i++) $node->chvotes[$i] = 0;
136 137
    $node->active = 1;
  }
138

139
  db_query("INSERT INTO poll (nid, runtime, voters, active) VALUES ('$node->nid', '$node->runtime', '', '$node->active')");
Dries's avatar
 
Dries committed
140

141 142 143 144
  for ($i = 0; $i < $node->choices; $i++) {
    $choice->chtext = filter($node->choice[$i]);
    $choice->chvotes = (int)$node->chvotes[$i];
    $choice->chorder = $i;
Dries's avatar
 
Dries committed
145

146 147 148 149
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
  }
150 151
}

Steven Wittens's avatar
Steven Wittens committed
152
function poll_link($type, $node = 0, $main) {
153
  if ($type == "menu.create" && user_access("post content")) {
Dries's avatar
 
Dries committed
154
    $links[] = lm(t("create poll"), array("mod" => "node", "op" => "add", "type" => "poll"), "", array("title" => t("Add a new poll.")));
155
  }
Steven Wittens's avatar
Steven Wittens committed
156 157 158
  else if ($type == "page" && user_access("access content")) {
    $links[] = lm(t("polls"), array("mod" => "poll"), "", array("title" => t("View the list of polls on this site.")));
  }
Steven Wittens's avatar
Steven Wittens committed
159 160 161 162 163 164 165 166
  else if ($type == "node" && $node->type == "poll") {
    /*
    ** Add links to allow the user to switch between the results and the voting
    ** form, if he/she hasn't voted yet.
    */

    // Make sure we have determined the 'allowvotes' flag
    poll_allowvotes($node);
167

Steven Wittens's avatar
Steven Wittens committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    if ($node->allowvotes == 1) {
      global $pollresults;

      // Change the current URL: add/edit the value of pollresults[nid]
      if ($pollresults[$node->nid]) {
        // Disable
        $url = eregi_replace("pollresults\[$node->nid\]=1", "pollresults[$node->nid]=0", request_uri());

        $links[] = "<a href=\"$url\">". t("voting form") . "</a>";
      }
      else {
        // Enable
        if (strstr(request_uri(), "pollresults[$node->nid]=")) {
          $url = eregi_replace("pollresults\[$node->nid\]=0", "pollresults[$node->nid]=1", request_uri());
        }
        else {
          $url = request_uri() . (strstr(request_uri(), "?") ? "&amp;" : "?") ."pollresults[$node->nid]=1";
        }

        $links[] = "<a href=\"$url\">". t("view results") . "</a>";
      }
    }
  }
191 192
  return $links ? $links : array();
}
Dries's avatar
 
Dries committed
193

194 195 196
function poll_load($node) {
  // Load the appropriate choices into the $node object
  $poll = db_fetch_object(db_query("SELECT runtime, voters, active FROM poll WHERE nid = '$node->nid'"));
Dries's avatar
 
Dries committed
197

198 199 200 201 202
  $result = db_query("SELECT chtext, chvotes, chorder FROM poll_choices WHERE nid='$node->nid' ORDER BY chorder");
  while ($choice = db_fetch_object($result)) {
    $poll->choice[$choice->chorder]  = $choice->chtext;
    $poll->chvotes[$choice->chorder] = $choice->chvotes;
  }
Steven Wittens's avatar
Steven Wittens committed
203 204 205

  // Reset allowvotes flag, will be filled in later on when needed.
  $poll->allowvotes = -1;
206 207
  return $poll;
}
Dries's avatar
 
Dries committed
208

209 210 211
function poll_node($field) {
  $info["name"] = t("poll");
  $info["description"] = t("A poll is a multiple-choice question which visitors can vote on.");
Dries's avatar
 
Dries committed
212

213 214
  return $info[$field];
}
215

Steven Wittens's avatar
Steven Wittens committed
216 217
function poll_page() {
  global $theme;
Steven Wittens's avatar
Steven Wittens committed
218

Steven Wittens's avatar
Steven Wittens committed
219
  $theme->header();
Steven Wittens's avatar
Steven Wittens committed
220
  $result = db_query("SELECT n.nid, n.title, p.active, SUM(c.chvotes) AS votes FROM node n LEFT JOIN poll p ON n.nid=p.nid LEFT JOIN poll_choices c ON n.nid=c.nid WHERE type='poll' AND status='1' AND moderate='0' GROUP BY n.nid ORDER BY n.created DESC");
Steven Wittens's avatar
Steven Wittens committed
221 222 223 224 225 226 227
  while ($node = db_fetch_object($result)) {
    $output .= "<li>". l($node->title, array("id" => $node->nid)) ." - ". format_plural($node->votes, "vote", "votes") ." - ". ($node->active ? t("open") : t("closed")) ."</li>";
  }
  $theme->box(t("Polls"), $output);
  $theme->footer();
}

228 229 230
function poll_perm() {
  return array("vote on polls");
}
Dries's avatar
 
Dries committed
231

232 233 234
function poll_save($op, $node) {
  if ($op == "approve") {
    return array("status" => 1, "promote" => 1);
235
  }
Dries's avatar
 
Dries committed
236

237 238 239 240 241 242 243
  if ($op == "create") {
    if (user_access("administer nodes")) {
      return array("runtime", "active", "choice", "choices", "chvotes", "body" => "", "teaser" => poll_teaser($node));
    }
    else {
      return array("runtime", "active", "choice", "choices", "chvotes", "body" => "", "moderate" => 1, "teaser" => poll_teaser($node));
    }
244
  }
Dries's avatar
 
Dries committed
245

246 247
  if ($op == "decline") {
    return array("status" => 0, "promote" => 0);
248 249
  }

250 251 252
  if ($op == "update") {
    return array("runtime", "active", "choice", "choices", "chvotes");
  }
253 254
}

Steven Wittens's avatar
Steven Wittens committed
255
function poll_system($field){
Kjartan's avatar
Kjartan committed
256
  $system["description"] = t("Allows users to submit multiple choice questions for voting.");
Steven Wittens's avatar
Steven Wittens committed
257 258 259
  return $system[$field];
}

260 261 262 263 264 265 266 267 268
function poll_teaser($node) {
  // Create a simple teaser that lists all the choices
  foreach ($node->choice as $k => $v) {
    if ($v != "") {
      $teaser .= "* $v\n";
    }
  }
  return $teaser;
}
269

Steven Wittens's avatar
Steven Wittens committed
270 271 272
function poll_view_voting(&$node, $main, $block, $links) {
  // Display the vote form
  global $theme;
Dries's avatar
 
Dries committed
273

Steven Wittens's avatar
Steven Wittens committed
274 275 276
  $url = request_uri();
  $output .= "<form action=\"$url\" method=\"post\">";
  $output .= "<table border=\"0\" align=\"center\"><tr><td>";
Dries's avatar
 
Dries committed
277

Steven Wittens's avatar
Steven Wittens committed
278 279 280
  foreach ($node->choice as $key => $value) {
    if ($value != "") {
      $output .= "<input type=\"radio\" name=\"pollvote[$node->nid]\" value=\"$key\" /> $value<br />";
281
    }
Dries's avatar
 
Dries committed
282
  }
283

Steven Wittens's avatar
Steven Wittens committed
284 285 286 287 288
  if ($block) {
    $output .= "</td></tr><tr><td><div align=\"center\">". form_submit(t("Vote")) ."</div></td></tr></table>";
  }
  else {
    $output .= "</td><td valign=\"middle\"><div align=\"right\">&nbsp;&nbsp;&nbsp;". form_submit(t("Vote")) ."</div></td></tr></table>";
289
  }
Dries's avatar
 
Dries committed
290

Steven Wittens's avatar
Steven Wittens committed
291 292 293 294 295 296 297 298 299
  $output .= $block ? "<div align=\"center\">". $theme->links($links) ."</div>" : "";
  $output .= "</form>";

  return $output;
}

function poll_view_results(&$node, $main, $block, $links) {
  // Display the results
  global $theme;
300

Steven Wittens's avatar
Steven Wittens committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
  // Count the votes and find the maximum
  foreach ($node->choice as $key => $value) {
    $votestotal += $node->chvotes[$key];
    $votesmax = max($votesmax, $node->chvotes[$key]);
  }
  $votesmax = max($votesmax, 1);

  /*
  ** Define CSS classes for the bars
  ** (note: style is not allowed outside <head>, but the alternative is very
  ** ugly and it seems to work in all browsers)
  */
  $output .= "<style type=\"text/css\">";
  $output .= "td.pollfg { background-color: ". $theme->foreground ."; font-size: 5pt; }";
  $output .= "td.pollbg { background-color: ". $theme->background ."; font-size: 5pt; }";
  $output .= "</style>";

  foreach ($node->choice as $key => $value) {
    if ($value != "") {
      $width = round($node->chvotes[$key] * 100 / $votesmax);
      $percentage = round($node->chvotes[$key] * 100 / max($votestotal, 1));

      $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td>$value</td><td><div align=\"right\"> $percentage%". (!$block ? " (". format_plural($node->chvotes[$key], "vote", "votes") .")" : "") ."</div></td></tr></table>";
      if ($width == 0) {
        $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollbg\" width=\"100%\">&nbsp;</td></tr></table>";
      }
      else if ($width == 100) {
        $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollfg\" width=\"100%\">&nbsp;</td></tr></table>";
      }
      else {
        $output .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"95%\" align=\"center\"><tr><td class=\"pollfg\" width=\"". $width ."%\">&nbsp;</td><td class=\"pollbg\" width=\"". (100 - $width) ."%\">&nbsp;</td></tr></table>";
332 333
      }
    }
334
  }
Steven Wittens's avatar
Steven Wittens committed
335
  $output .= "<br /><div align=\"center\">". t("Total votes") .": $votestotal";
Dries's avatar
 
Dries committed
336

Steven Wittens's avatar
Steven Wittens committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
  $output .= ($block ? "<br />". $theme->links($links) : "") ."</div>";

  return $output;
}

function poll_view_processvote(&$node) {
  global $pollvote;

  if (isset($pollvote[$node->nid]) && ($node->allowvotes == 1)) {
    if (!empty($node->choice[$pollvote[$node->nid]])) {
      $node->voters = $node->voters ? ($node->voters ." ". $node->polluserid) : $node->polluserid;
      db_query("UPDATE poll SET voters='$node->voters' WHERE nid='$node->nid'");
      db_query("UPDATE poll_choices SET chvotes = chvotes + 1 WHERE nid='$node->nid' AND chorder='". $pollvote[$node->nid] ."'");
      $node->allowvotes = 0;
      $node->chvotes[$pollvote[$node->nid]]++;
Steven Wittens's avatar
Steven Wittens committed
352
    }
Steven Wittens's avatar
Steven Wittens committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
  }
}

function poll_view(&$node, $main = 0, $block = 0) {
  global $theme, $user;

  /*
  ** When several polls are displayed on the same page (e.g. on the front page and in the side bar)
  ** we distinguish between them using the nid as index into associative arrays:
  ** $pollvote[nid]    - A user's vote
  ** $pollresults[nid] - When a user hasn't voted, he can choose to see the voting form or the results
  */
  global $pollresults;

  // Make sure we have determined the 'allowvotes' flag
  poll_allowvotes($node);

  // Because the voting form is embedded in the node-display, we process the data here
  poll_view_processvote($node);

  // Add extra link pointing to the list of polls (side-block only)
  if ($block) {
    $node->body = $node->teaser = "";

Steven Wittens's avatar
Steven Wittens committed
377 378
    $links = link_node($node, $main);
    $links[] = lm(t("older polls"), array("mod" => "poll"), "", array("title" => t("View the list of polls on this site.")));
379
  }
Steven Wittens's avatar
Steven Wittens committed
380 381 382 383 384 385 386 387 388

  if (($node->allowvotes == 1) && !$pollresults[$node->nid]) {
    $output = poll_view_voting($node, $main, $block, $links);
  }
  else {
    $output = poll_view_results($node, $main, $block, $links);
  }

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

390
  // We also use poll_view() for the side-block
Steven Wittens's avatar
Steven Wittens committed
391
  if (!$block) {
392
    $theme->node($node, $main);
393 394 395
  }
}

396 397 398 399 400 401 402
function poll_update($node) {
  db_query("UPDATE poll SET runtime='$node->runtime', active='$node->active' WHERE nid='$node->nid'");

  db_query("DELETE FROM poll_choices WHERE nid='$node->nid'");
  for ($i = 0; $i < $node->choices; $i++) {
    $choice->chtext = filter($node->choice[$i]);
    $choice->chvotes = (int)$node->chvotes[$i];
Dries's avatar
 
Dries committed
403
    $choice->chorder = $i;
404

405 406 407
    if ($choice->chtext != "") {
      db_query("INSERT INTO poll_choices (nid, chtext, chvotes, chorder) VALUES ('$node->nid', '$choice->chtext', '$choice->chvotes', '$choice->chorder')");
    }
408 409
  }
}
410

411
?>