You are here

answers.module in Answers 5.2

Enables the creation of question nodes that can be answered by posting answer nodes.

@author Amanuel Tewolde http://ticklespace.com @email myfirstname (at) companydomain above

File

answers.module
View source
<?php

/**
 * @file
 * Enables the creation of question nodes that can be answered by posting answer nodes.
 * 
 * @author Amanuel Tewolde http://ticklespace.com
 * @email myfirstname (at) companydomain above
 * 
 */
define('ANSWERS_TYPE', 'answers_type_');

/**
 * Implementation of hook_help().
 */
function answers_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      return t('Enables the creation of question and answer service.');
    case 'node/add#quest':
      return t('This modules provides a way for users to post questions and get answers from other users.');
  }
}

/**
 * Implementation of hook_node_info().
 */
function answers_node_info() {
  return array(
    'answers' => array(
      'name' => t('Question'),
      'module' => 'answers',
      'description' => t("Post a question."),
      'has_title' => TRUE,
      'title_label' => t('Question'),
      'has_body' => TRUE,
      'body_label' => t('Add details'),
    ),
  );
}

/**
 * Implementation of hook_perm().
 */
function answers_perm() {
  return array(
    'create quests',
    'edit own quests',
  );
}

/**
 * Implementation of hook_access().
 */
function answers_access($op, $node) {
  global $user;
  if ($op == 'create') {
    return user_access('create quests');
  }
  if ($op == 'update' || $op == 'delete') {
    if (user_access('edit own quests') && $user->uid == $node->uid) {
      return TRUE;
    }
  }
}

/**
 * Implementation of hook_menu().
 */
function answers_settings() {
  $form['answermodules'] = array(
    '#type' => 'fieldset',
    '#description' => t('Select content types you wish to use to answer the questions posted.'),
    '#weight' => -3,
    '#title' => t('Answers Modules'),
  );
  $form['answermodules']['formtypes'] = array();
  $form['answermodules']['formtypes'] = array_merge($form['answermodules']['formtypes'], module_invoke_all('answers', 'settings'));
  $form['answers_settings'] = array(
    '#type' => 'fieldset',
    '#weight' => -2,
    '#title' => t('General Settings'),
  );
  $answers_email = "\nHi %name,\n<br />\n%addername has posted a %ansertype on the quest - \" %title \".\n<br />\nView your quest: %url \n<br />\n<hr />\n\nThis is an automatic message from %site.\n<br />\n  ";
  $answers_subject = '@name an new answer was posted to your question: @subject';
  $form['answers_settings']['answernotify'] = array(
    '#type' => 'textarea',
    '#title' => t('Notify email user of a posted answer'),
    '#default_value' => variable_get('answernotify', $answers_email),
    '#description' => t('This is the email that is sent to users. Dynamic vars available: %name, %subject, %addername, %title, %url, %ansertype and %site'),
    '#weight' => 2,
    '#required' => TRUE,
  );
  $form['answers_settings']['answernotifysubject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject of notify email'),
    '#default_value' => variable_get('answernotifysubject', $answers_subject),
    '#description' => t('This is the subject line of the email sent. Dynamic vars available: @name, @subject'),
    '#weight' => 1,
    '#required' => TRUE,
  );
  $form['answers_settings']['allow_answeranon'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow anonimization'),
    '#options' => array(
      '0',
      '1',
    ),
    '#default_value' => variable_get('allow_answeranon', 0),
    '#description' => t('Allow users to post questions anonymously. NOTE: the question still belongs to the user the name is just hidden from normal users'),
    '#required' => FALSE,
  );
  $form['answers_settings']['questlinks'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use Drupal\'s links to show answers totals'),
    '#options' => array(
      '0',
      '1',
    ),
    '#default_value' => variable_get('questlinks', ''),
    '#description' => t('If you plan to layout the total answers in your theme instead uncheck this box.'),
    '#weight' => 3,
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_menu().
 */
function answers_menu($may_cache) {
  $items = array();
  $nid = (int) arg(1);
  global $user;
  if ($may_cache) {
    $items[] = array(
      'path' => 'quest/list',
      'callback' => 'answers_list',
      'title' => t('Browse Quests'),
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );
  }
  $items[] = array(
    'path' => 'admin/settings/answers',
    'callback' => 'drupal_get_form',
    'callback arguments' => array(
      'answers_settings',
    ),
    'title' => t('Answers settings'),
    'description' => t('Configure Answers service settings'),
    'access' => user_access('administer content types'),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/*
 * implement hook_load
 * this loads our stuff and force disables commenting on quest nodes
 * TODO: make the disable comments optional
 * 
 */
function answers_load($node) {
  $questdetails = db_fetch_object(db_query('SELECT * FROM {quests} WHERE vid = %d', $node->vid));
  $questdetails->comment = COMMENT_NODE_DISABLED;
  return $questdetails;
}

/*
 * implement hook_nodeapi
 * this allows us to see when answer nodes are added, deleted or updated.
 * 
 */
function answers_nodeapi(&$node, $op, $teaser, $page) {
  global $user;
  switch ($op) {
    case "insert":
      if (variable_get(ANSWERS_TYPE . $node->type, '0')) {
        if ($node->questid) {
          db_query("INSERT INTO {answers} (qid, nid, uid, Status, relationscore) VALUES ('%d', '{$node->nid}', '{$node->uid}', '%d', '%d')", $node->questid, 0, 0);
          $questnode = node_load($node->questid);
          if ($questnode->notifyme) {
            answers_notify($node->questid, $questnode->title);
          }
        }
      }
      break;
    case "update":
      if (variable_get(ANSWERS_TYPE . $node->type, '0')) {
        if ($node->questid) {
          db_query("UPDATE {answers} SET qid = '%d' WHERE nid = '%d' AND uid = '%d'", $node->questid, $node->nid, $user->uid);
        }
      }
      break;
    case "delete":
      if (variable_get(ANSWERS_TYPE . $node->type, '0')) {
        db_query('DELETE FROM {answers} WHERE nid = %d', $node->nid);
      }
      break;
  }
}
function answers_notify($nid, $title, $style = 'answer') {
  $subj = $title;
  global $user;
  $result = db_query('SELECT u.uid, u.name, u.mail, u.language FROM {users} u INNER JOIN {node} n ON u.uid = n.uid WHERE n.nid = %d', $nid);
  while ($cuser = db_fetch_object($result)) {
    if ($user->uid != $cuser->uid) {
      $subject = t(variable_get('answernotifysubject', '@name an answer has been posted for yoru question: @subject'), array(
        '@name' => $cuser->name,
        '@subject' => $subj,
      ));
      $message = variable_get('answernotify', 'drupal');
      $body = t($message, array(
        '%name' => $cuser->name,
        '%addername' => $user->name,
        '%ansertype' => $style,
        '%title' => $subj,
        '%url' => url('node/' . $nid, NULL, NULL, 1),
        '%site' => variable_get('site_name', 'drupal'),
      ));
      $headers["MIME-Version"] = '1.0';
      $headers["Content-Transfer-Encoding"] = '8bit';
      $headers["Content-Type"] = "text/html; charset='utf-8';";
      $mail_success = drupal_mail('answers_notify_email', $cuser->mail, $subject, $body, variable_get('site_mail', NULL), $headers);
      if (!$mail_success) {
        watchdog('error', t('error mailing quest notification: ') . '"' . $cuser->name . '"  &lt;' . $cuser->mail . '&gt;');
      }
    }
  }
}
function answers_comment($comment, $op) {
  if ($op == 'insert' || $op == 'update' && $comment->status == 1) {
    $nid = $comment['nid'];
    $cid = $comment['cid'];
    $questnode = node_load($nid);
    if ($questnode->notifyme) {
      answers_notify($node->questid, $questnode->title, 'comment');
    }
  }
}
function answers_list() {
  $ansset = 'active';
  if ($_GET['uans'] == 1) {
    $ansset = '';
    $unanset = 'active';
    $filteranswered = TRUE;
  }
  $tabs = '<h1 class="title">Quests list</h1><div class="tabs"><ul class="tabs primary">
              <li ' . $ansset . '>' . l("All Quests", "quest/list", array(
    'class' => $ansset,
  )) . '</li>
              <li ' . $unanset . '>' . l("Show Unanswered Only", "quest/list", array(
    'class' => $unanset,
  ), "&uans=1") . '</li>
             </ul></div>';
  return $o = $tabs . theme('answers_list', $filteranswered);
}

/*
 * TODO: clean this function. 
 * TODO: change so it accepts list of quests to dress up instead of handling the sql etc.
 */
function theme_answers_list($filterunanswered = FALSE) {
  $header[] = array(
    'data' => t('Quests'),
    'field' => 'n.nid',
    'sort' => 'DESC',
  );
  $sql = 'SELECT n.nid, n.vid FROM {node} n WHERE n.type = "answers" ' . tablesort_sql($header);
  $result = pager_query($sql, 30, 0);
  if (!$result) {
    $output = "No quests available.";
  }
  $count1 = 0;
  $count2 = 0;
  while ($qnode = db_fetch_object($result)) {
    $nodedata = node_load($qnode->nid);
    $nodeview = node_view($nodedata, TRUE, FALSE, TRUE);
    $answercount = answers_count_answers($nodedata->nid);
    $odd_or_even1 = $count1 & 1;
    $odd_or_even2 = $count2 & 1;
    if ($filterunanswered) {
      if ($answercount < 1) {
        if ($odd_or_even1 == '0') {
          $output .= "<div class='even'><br>" . $nodeview . "</div>";
        }
        else {
          $output .= "<div class='odd'><br>" . $nodeview . "</div>";
        }
        $count1++;
      }
    }
    else {
      if ($answercount >= 0) {
        if ($odd_or_even2 == '0') {
          $output .= "<div class='even'><br>" . $nodeview . "</div>";
        }
        else {
          $output .= "<div class='odd'><br>" . $nodeview . "</div>";
        }
        $count2++;
      }
    }
  }
  $output = '<div class="quest-list">' . $output . '</div><br /> ';
  $pager = theme('pager', NULL, 30, 0);
  if (!empty($pager)) {
    $output .= $pager;
  }
  return $output;
}
function answers_form_alter($form_id, &$form) {
  $answertypes = module_invoke_all('answers', 'answersinfo');
  foreach ($answertypes as $type => $name) {
    if ($form_id == $type . '_node_form' || $form_id == $type . '_form' || $form_id == 'node_form') {
      if (arg(0) == 'node' && arg(1) == 'add' && arg(3)) {
        $nid = (int) arg(3);
      }
      else {
        $nid = answers_answersapi('question', $form['nid']['#value']);
      }
      $form['questid'] = array(
        '#type' => 'hidden',
        '#value' => $nid,
      );
      $form['#redirect'] = 'node/' . $nid;
    }
  }
}

/**
 * Implementation of hook_form(). 
 */
function answers_form($form_values = NULL) {
  $node = $form_values;
  $type = node_get_types('type', 'answers');
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#required' => TRUE,
    '#default_value' => $node->title,
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
    '#weight' => -5,
  );
  $form['body_filter']['body'] = array(
    '#type' => 'textarea',
    '#title' => check_plain($type->body_label),
    '#default_value' => $node->body,
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
    '#attributes' => array(
      'class' => 'mceNoEditor',
    ),
    '#required' => FALSE,
  );
  $form['body_filter']['filter'] = filter_form($node->format);
  if (variable_get('allow_answeranon', 0)) {
    $form['answeroptions']['answeranon'] = array(
      '#type' => 'checkbox',
      '#title' => t('Make this question anonymous (Hide my Profile)'),
      '#prefix' => '<div class="questpreview answeranon">',
      '#suffix' => '</div>',
      '#default_value' => $node->answeranon,
      '#weight' => 3,
      '#required' => FALSE,
    );
  }
  $form['answeroptions']['notifyme'] = array(
    '#type' => 'checkbox',
    '#title' => t('Notify me by email when I recieve new answers to this question'),
    '#prefix' => '<div class="questpreview notifyme">',
    '#suffix' => '</div>',
    '#default_value' => $node->notifyme,
    '#weight' => 3,
    '#required' => FALSE,
  );
  return $form;
}
function answers_insert($node) {
  db_query("INSERT INTO {quests} (vid, nid, notifyme, answeranon) VALUES (%d, %d, '%d', %d)", $node->vid, $node->nid, $node->notifyme, $node->answeranon);
}
function answers_delete($node) {
  db_query('DELETE FROM {quests} WHERE nid = %d', $node->nid);
  $tresult = db_query('SELECT * FROM {answers} WHERE qid = %d', $node->nid);
  while ($answernode = db_fetch_object($tresult)) {
    node_delete($answernode->nid);
  }
  db_query('DELETE FROM {answers} WHERE nid = %d OR qid= %d', $node->nid, $node->nid);
}
function answers_update($node) {
  if ($node->revision) {
    answers_insert($node);
  }
  else {
    db_query("UPDATE {quests} SET notifyme = '%d', answeranon = %d WHERE vid = %d", $node->notifyme, $node->answeranon, $node->vid);
  }
}
function answers_answersapi($op, $nid) {
  switch ($op) {
    case 'question':
      $tresult = db_query('SELECT a.qid FROM {answers} a WHERE a.nid = "%d"', $nid);
      while ($res = db_fetch_object($tresult)) {
        return $res->qid;
      }
      break;
    case 'answerlink':
      $tresult = db_query('SELECT a.qid FROM {answers} a WHERE a.nid = "%d"', $nid);
      while ($res = db_fetch_object($tresult)) {
        return $res->qid;
      }
      break;
    case 'qtitle':
      $tresult = db_query('SELECT n.title FROM {node} n, {answers} a WHERE a.qid = n.nid AND a.nid = "%d"', $nid);
      while ($res = db_fetch_object($tresult)) {
        return $res->title;
      }
      break;
    case 'theone':
      break;
  }
}
function answers_view($node, $teaser = FALSE, $page = FALSE) {
  $path = drupal_get_path('module', 'answers');
  $node = node_prepare($node, $teaser);
  $node->answerlist = answers_get_answers($node, $teaser, $page);
  $answercount = count($node->answerlist);
  $answerbuttons = module_invoke_all('answers', 'answerbuttons', $node->nid, $answercount);
  $node->answer_buttons = theme('answer_buttons', $answerbuttons, $answercount);
  $node->content['answers'] = array(
    '#value' => theme('answers_content', $node, $teaser),
    '#weight' => 1,
  );
  $node->content['ansposter'] = array(
    '#value' => '<div id="ansposter" style="padding: 0px; margin: 0px;"></div>',
    '#weight' => 2,
  );
  if ($page) {

    // Breadcrumb navigation
    $breadcrumb[] = array(
      'path' => 'quest/list',
      'title' => t('Answers'),
    );
    $breadcrumb[] = array(
      'path' => 'node/' . $node->nid,
    );
    menu_set_location($breadcrumb);

    // TODO: change for 6.x
  }
  return $node;
}
function answers_get_poster($node) {

  // print_r($node);
  if ($node->answeranon) {
    return theme('username', 0);

    //apply a thin veil to hide poster
  }
  else {
    return theme('username', user_load(array(
      'uid' => $node->uid,
    )));
  }
}
function answers_get_answers($node, $teaser = TRUE, $page = FALSE) {
  $answers = array();
  $tresult = db_query('SELECT * FROM {answers} WHERE qid = %d ORDER BY nid DESC ', $node->nid);
  $count = 0;
  while ($answernode = db_fetch_object($tresult)) {
    $odd_or_even = $count & 1;
    $ansnode = node_load($answernode->nid);
    if ($teaser) {
      $rendered = module_invoke($ansnode->type, 'answers', 'embedded', $ansnode->nid);
      if (is_array($rendered)) {
        $rendered = implode(' ', $rendered);
      }
      $answers[$ansnode->type][] = theme('answers_answer', $node, $rendered, '0');
    }
    else {
      $ansnode = node_load($answernode->nid);
      $rendered = node_view($ansnode, $teaser, FALSE, TRUE);
      $answers[$ansnode->type][] = theme('answers_answer', $node, $rendered, $odd_or_even);
    }
    $count++;
  }
  return $answers;
}
function answers_count_answers($nid) {
  return db_result(db_query('SELECT count(nid) FROM {answers} WHERE qid = %d ', $nid));
}
function answers_link_alter(&$node, &$links) {
  if ($node->type == 'answers' || $node->type == 'simpleresp') {
    unset($links['node_read_more']);
  }
}
function theme_answer_buttons($buttons) {
  return '<div class="answerbuttons">' . implode(' | ', $buttons) . '</div>';
}
function theme_answers_answer($node, $rendered, $odd_or_even) {
  if ($odd_or_even == '0') {
    return '<div class="questitem oddans ' . $node->type . '">' . $rendered . '<br></div>';
  }
  else {
    return '<div class="questitem evenans ' . $node->type . '">' . $rendered . '<br></div>';
  }
}
function theme_answers_content($node, $teaser = FALSE) {
  if (!$teaser) {
    foreach ($node->answerlist as $type => $data) {
      $answers .= implode(' ', $data);
    }
    if ($answers) {
      $output = '<h3 class="title">Posted Answers</h3>';
      $output .= '<div class="answers" style="margin: 18px;margin-top: 8px;">' . $answers . '</div>';
    }
    else {
      $output .= '<span class="title">No answers posted yet</span>';
    }
  }
  $output .= $node->answer_buttons;
  return $output;
}
function answers_link($type, $node = 0, $teaser = FALSE) {
  $questlinks = variable_get('questlinks', '');
  if ($questlinks) {
    $links = array();
    global $user;
    if ($user->uid == 0 && $node->type == 'answers') {

      // $links['answerlogin']['title'] = t(' ');
      $links['loganswers'] = array(
        'title' => t('You must be signed in to post <a href="/user/register">Register</a> | <a href="/user/login">Sign In</a>'),
        'html' => 'true',
      );
    }
    if ($node->type == 'answers' && $teaser) {
      $result = db_query_range("SELECT count(distinct(q.nid)) as items FROM {answers} q WHERE q.qid = %d", $node->nid, 0, 100);
      while ($znode = db_fetch_object($result)) {
        if ($znode->items == 1) {
          $links['qitem']['title'] .= $znode->items . " answer";
        }
        else {
          $links['qitem']['title'] .= $znode->items . " answers";
        }
      }
    }
    return $links;
  }
}