Skip to content
Snippets Groups Projects
poll.module 14.3 KiB
Newer Older
/**
 * Implementation of hook_help().
 */
function poll_help($section) {
Steven Wittens's avatar
Steven Wittens committed
  switch ($section) {
    case 'admin/help#poll':
Steven Wittens's avatar
Steven Wittens committed
      <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/configure/permission"), "%poll" => url("poll")));
Dries Buytaert's avatar
 
Dries Buytaert committed
    case 'admin/modules#description':
      return t("Enables your site to capture votes on different topics in the form of multiple choice questions.");
Steven Wittens's avatar
Steven Wittens committed
    case 'node/add#poll':
      return t("A poll is a multiple-choice question which visitors can vote on.");
function poll_access($op, $node) {
Steven Wittens's avatar
Steven Wittens committed
  if ($op == 'create') {
    return user_access('create polls');
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
/**
 * Implementation of hook_block().
 *
 * Generates a block containing the latest poll.
 */
Steven Wittens's avatar
Steven Wittens committed
function poll_block($op = 'list', $delta = 0) {
  if (user_access('access content')) {
    if ($op == 'list') {
      $blocks[0]['info'] = t('Most recent poll');
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $blocks;
    }
    else {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $timestamp = db_result(db_query('SELECT MAX(n.created) FROM {node} n '. node_access_join_sql() ." WHERE n.type = 'poll' AND n.status = 1 AND ". node_access_where_sql() .' AND n.moderate = 0'));
Dries Buytaert's avatar
 
Dries Buytaert committed
      if ($timestamp) {
Steven Wittens's avatar
Steven Wittens committed
        $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));

Dries Buytaert's avatar
 
Dries Buytaert committed
        if ($poll->nid) {
          // poll_view() dumps the output into $poll->body.
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
Steven Wittens's avatar
Steven Wittens committed
      $block['subject'] = t('Poll');
      $block['content'] = $poll->body;
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $block;
/**
 * Implementation of hook_cron().
 *
 * Closes polls that have exceeded their allowed runtime.
 */
function poll_cron() {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $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 Buytaert's avatar
 
Dries Buytaert committed
  while ($poll = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    db_query("UPDATE {poll} SET active='0' WHERE nid = %d", $poll->nid);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
function poll_delete($node) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  db_query("DELETE FROM {poll} WHERE nid=%d", $node->nid);
  db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
Steven Wittens's avatar
Steven Wittens committed
    $realchoices = 0;
    foreach ($node->choice as $i => $choice) {
      if ($choice['chtext'] != '') {
        $realchoices++;
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
      if ($choice['chvotes'] < 0) {
Dries Buytaert's avatar
 
Dries Buytaert committed
        form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
    if ($realchoices < 2) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_form(&$node) {
Steven Wittens's avatar
Steven Wittens committed
  $admin = user_access('administer nodes');
Steven Wittens's avatar
Steven Wittens committed
  if (function_exists('taxonomy_node_form')) {
    $output = implode('', taxonomy_node_form('poll', $node));
  }
Steven Wittens's avatar
Steven Wittens committed
  if (!isset($node->choices)) {
    $node->choices = max(2, count($node->choice) ? count($node->choice) : 5);
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  if ($node->morechoices) {
    $node->choices *= 2;
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="poll-form">';
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  // Poll choices
Dries Buytaert's avatar
 
Dries Buytaert committed
  $opts = drupal_map_assoc(range(2, $node->choices * 2 + 5));
  for ($a = 0; $a < $node->choices; $a++) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $group1 .= form_textfield(t('Choice %n', array('%n' => ($a + 1))), "choice][$a][chtext", $node->choice[$a]['chtext'], 50, 127);
    if ($admin) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      $group1 .= form_textfield(t('Votes for choice %n', array('%n' => ($a + 1))), "choice][$a][chvotes", (int)$node->choice[$a]['chvotes'], 7, 7);
Steven Wittens's avatar
Steven Wittens committed
  $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 Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  // Poll attributes
  $_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
  $_active = array(0 => t('Closed'), 1 => t('Active'));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  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 Buytaert's avatar
 
Dries Buytaert committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $group2 .= form_select(t('Poll duration'), 'runtime', $node->runtime ? $node->runtime : 0, $_duration, t('After this period, the poll will be closed automatically.'));
Dries Buytaert's avatar
 
Dries Buytaert committed

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

  return $output;
function poll_insert($node) {
Steven Wittens's avatar
Steven Wittens committed
  if (!user_access('administer nodes')) {
    // Make sure all votes are 0 initially
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $i => $choice) {
      $node->choice[$i]['chvotes'] = 0;
    }
    $node->active = 1;
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
  db_query("INSERT INTO {poll} (nid, runtime, voters, active) VALUES (%d, %d, '', %d)", $node->nid, $node->runtime, $node->active);
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  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++);
Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * Implementation of hook_link().
 */
function poll_link($type, $node = 0, $main) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $links = array();

Dries Buytaert's avatar
 
Dries Buytaert committed
  if ($type == 'page' && user_access('access content')) {
Steven Wittens's avatar
Steven Wittens committed
    $links[] = l(t('polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Steven Wittens's avatar
Steven Wittens committed
  }
Dries Buytaert's avatar
 
Dries Buytaert committed

  return $links;
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * Implementation of hook_menu().
 */
function poll_menu() {
  $items = array();
  $items[] = array('path' => 'node/add/poll', 'title' => t('poll'),
    'access' => user_access('create polls'));
  $items[] = array('path' => 'poll', 'title' => t('polls'),
    'callback' => 'poll_page',
    'access' => user_access('access content'),
    'type' => MENU_SUGGESTED_ITEM);

  $items[] = array('path' => 'poll/vote',
    'title' => t('vote'),
    'callback' => 'poll_vote',
    'access' => user_access('vote on polls'),
    'type' => MENU_CALLBACK);

  if (arg(0) == 'node' && is_numeric(arg(1))) {
    $node = node_load(array('nid' => arg(1)));

    if ($node->type == 'poll' && $node->allowvotes) {
      $items[] = array('path' => 'node/'. arg(1) .'/results',
        'title' => t('results'),
        'callback' => 'poll_results',
        'access' => user_access('access content'),
        'weight' => 3,
        'type' => MENU_LOCAL_TASK);
    }
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
  return $items;
}

Steven Wittens's avatar
Steven Wittens committed
/**
 * 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;
}

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

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

Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_node_name($node) {
  return t("poll");
Steven Wittens's avatar
Steven Wittens committed
function poll_page() {
Steven Wittens's avatar
Steven Wittens committed
  // List all polls
Dries Buytaert's avatar
 
Dries Buytaert committed
  $result = pager_query("SELECT DISTINCT(n.nid), n.title, p.active, SUM(c.chvotes) AS votes FROM {node} n ". node_access_join_sql() ." 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 ". node_access_where_sql() ." AND moderate = 0 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC", 15);
Steven Wittens's avatar
Steven Wittens committed
  $output = '<ul>';
Steven Wittens's avatar
Steven Wittens committed
  while ($node = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $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
  }
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</ul>';
  $output .= theme("pager", NULL, 15);
  print theme('page', $output);
Steven Wittens's avatar
Steven Wittens committed
}

function poll_perm() {
Steven Wittens's avatar
Steven Wittens committed
  return array('create polls', 'vote on polls');
Dries Buytaert's avatar
 
Dries Buytaert committed

/**
 * Creates a simple teaser that lists all the choices.
 */
function poll_teaser($node) {
Dries Buytaert's avatar
Dries Buytaert committed
  if (is_array($node->choice)) {
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $k => $choice) {
      $teaser .= '* '. $choice['chtext'] .'\n';
Steven Wittens's avatar
Steven Wittens committed
/**
Steven Wittens's avatar
Steven Wittens committed
 */
function poll_view_voting(&$node, $main, $page, $block) {
  $url = request_uri();
Dries Buytaert's avatar
 
Dries Buytaert committed
  $output = '<div class="poll">';
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  $form = '<div class="vote-form">';
Steven Wittens's avatar
Steven Wittens committed
  $form .= '<div class="choices">';
Dries Buytaert's avatar
 
Dries Buytaert committed
  if ($node->choice) {
Steven Wittens's avatar
Steven Wittens committed
    $list = array();
    foreach ($node->choice as $i => $choice) {
      $list[$i] = drupal_specialchars($choice['chtext']);
Steven Wittens's avatar
Steven Wittens committed
    $form .= form_radios($page ? '' : $node->title, 'choice', -1, $list);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $form .= '</div>';
  $form .= form_hidden('nid', $node->nid);
  $form .= form_submit(t('Vote'), 'vote') .'</div>';

  $output .= form($form, 'post', url('poll/vote/'. $node->nid));
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';

  return $output;
}

/**
 * Generates a graphical representation of the results of a poll.
 */
Steven Wittens's avatar
Steven Wittens committed
function poll_view_results(&$node, $main, $page, $block) {
  // Display the results
Dries Buytaert's avatar
 
Dries Buytaert committed

  // Count the votes and find the maximum
Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    $votestotal += $choice['chvotes'];
    $votesmax = max($votesmax, $choice['chvotes']);
Dries Buytaert's avatar
 
Dries Buytaert committed
  // Output the divs for the text, bars and percentages
Steven Wittens's avatar
Steven Wittens committed
  $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>';
Steven Wittens's avatar
Steven Wittens committed
  $output .= '<div class="total">'. t('Total votes') .": $votestotal</div>";
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';

  return $output;
}

/**
 * Callback for the 'results' tab for polls you can vote on
 */
function poll_results() {
  if ($node = node_load(array('nid' => arg(1)))) {
    print theme('page', node_show($node, 0), $node->title);
  }
  else {
    drupal_not_found();
  }
}

/**
 * Callback for processing a vote
 */
function poll_vote(&$node) {
  $nid = arg(2);
  if ($node = node_load(array('nid' => $nid))) {
    $edit = $_POST['edit'];
    $choice = $edit['choice'];
    $vote = $_POST['vote'];
Steven Wittens's avatar
Steven Wittens committed

    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']++;
Dries Buytaert's avatar
 
Dries Buytaert committed
        drupal_set_message(t('Your vote was recorded.'));
Steven Wittens's avatar
Steven Wittens committed
      }
      else {
Dries Buytaert's avatar
 
Dries Buytaert committed
        drupal_set_message(t("You're not allowed to vote on this poll."), 'error');
Steven Wittens's avatar
Steven Wittens committed
      }
    }
    else {
Dries Buytaert's avatar
 
Dries Buytaert committed
      drupal_set_message(t("You didn't specify a valid poll choice."), 'error');
Steven Wittens's avatar
Steven Wittens committed
    }

    drupal_goto('node/'. $nid);
  }
  else {
    drupal_not_found();
/**
 * Implementation of hook_view().
 *
 * @param $block
 *   An extra parameter that adapts the hook to display a block-ready
 *   rendering of the poll.
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_view(&$node, $teaser = FALSE, $page = FALSE, $block = FALSE) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  global $user;
Dries Buytaert's avatar
 
Dries Buytaert committed
  $output = '';
  if ($node->allowvotes && ($block || arg(2) != 'results')) {
Steven Wittens's avatar
Steven Wittens committed
    $output .= poll_view_voting($node, $main, $page, $block);
  }
  else {
    $output .= poll_view_results($node, $main, $page, $block);
  }
Steven Wittens's avatar
Steven Wittens committed
  // Special display for side-block
  if ($block) {
Steven Wittens's avatar
Steven Wittens committed
    // No 'read more' link
    $node->body = $node->teaser = '';
Steven Wittens's avatar
Steven Wittens committed
    $links = link_node($node, $main);
Steven Wittens's avatar
Steven Wittens committed
    $links[] = l(t('older polls'), 'poll', array('title' => t('View the list of polls on this site.')));
    if ($node->allowvotes && $block) {
      $links[] = l(t('results'), 'node/'. $node->nid .'/results', array('title' => t('View the current poll results.')));
    }
Steven Wittens's avatar
Steven Wittens committed
    $output .= '<div class="links">'. theme("links", $links) .'</div>';
  }

  $node->body = $node->teaser = $output;
function poll_update($node) {
Steven Wittens's avatar
Steven Wittens committed
  db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
  foreach ($node->choice as $choice) {
    $chvotes = (int)$choice['chvotes'];
    $chtext = $choice['chtext'];
Steven Wittens's avatar
Steven Wittens committed
    if ($chtext != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);