summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlastair Aitchison2010-04-06 19:46:39 (GMT)
committer Alastair Aitchison2010-04-06 19:46:39 (GMT)
commitda36c36152004ecdc6873ca56bbf6b4831efd545 (patch)
tree55ae7b589fd5d40da177f6850b6cd0a7f7a25d8d
parent4f4caf41bf350db11532f6c9695877958f689a15 (diff)
by tanoshimi: Initial upgrade of HEAD to drupal-7.x
-rw-r--r--.project11
-rw-r--r--README.txt2
-rw-r--r--question.info6
-rw-r--r--question.install311
-rw-r--r--question.module898
-rw-r--r--question.test161
6 files changed, 926 insertions, 463 deletions
diff --git a/.project b/.project
new file mode 100644
index 0000000..f782881
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>Question HEAD</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/README.txt b/README.txt
index 8b654de..eb8a4c4 100644
--- a/README.txt
+++ b/README.txt
@@ -1,6 +1,6 @@
------------------------------------------------------------------------------
Question Module for Drupal
- maintained by: Adam Knight | codepoet | adam (att) hopelessgeek (d0t) com
+ maintained by: Alastair Aitchison | tanoshimi | alastair (att) a3uk (d0t) com
created by: Jeff Robbins | jjeff | robbins (att) jjeff (d0t) com
------------------------------------------------------------------------------
diff --git a/question.info b/question.info
index 7f967d9..fd6700d 100644
--- a/question.info
+++ b/question.info
@@ -1,4 +1,8 @@
; $Id$
name = Question
description = Allows users to ask questions to be answered by site authors.
-core = 5.x
+core = 7.x
+package = Question
+files[] = question.module
+files[] = question.install
+files[] = question.test
diff --git a/question.install b/question.install
index 1c5c463..75d3914 100644
--- a/question.install
+++ b/question.install
@@ -1,40 +1,289 @@
<?php
+// $Id$
+/**
+ * @file
+ * install file for Question module.
+ *
+ * Most of the definition of the node type is in this module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+
+function question_schema() {
+ $schema['question_queue'] = array(
+ 'description' => 'Stores items in a question queue.',
+ 'fields' => array(
+ 'qid' => array(
+ 'description' => 'The unique id assigned to this question.',
+ 'type' => 'serial', // auto-increment field
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'question' => array(
+ 'description' => 'The question text.',
+ 'type' => 'text',
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('qid'),
+ );
+
+ return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
function question_install() {
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- case 'pgsql':
- db_query("CREATE TABLE {question_node} (
- nid int(10) NOT NULL default '0',
- questioner varchar(50) NOT NULL default '',
- quid int(10) NOT NULL default '0',
- question text NOT NULL,
- q_format int(4) NOT NULL default '0',
- answer text NOT NULL,
- a_format int(4) NOT NULL default '0',
- PRIMARY KEY (`nid`)
- );");
- db_query("CREATE TABLE {question_queue} (
- qid int(10) NOT NULL default '0',
- questioner varchar(50) NOT NULL default '',
- quid int(10) NOT NULL default '0',
- question text NOT NULL
- );");
- break;
+ // Get the name of our localization function for translation during install
+ $t = get_t();
+
+ // Do not allow Drupal to define the default permissions set for this node type.
+ // We will control the access to question/answers manually using hook_node_access().
+ variable_set('node_permissions_question', 0);
+
+ // Define the Question node type.
+ $question_node = array(
+ 'type' => 'question',
+ 'name' => $t('Question'),
+ 'base' => 'node_content',
+ 'description' => $t('This is the Question node type.'),
+ );
+ // Set any node type defaults not explicitly declared above.
+ $content_type = node_type_set_defaults($question_node);
+
+ // Save the node type
+ node_type_save($content_type);
+
+ // Load the instance of the body field for our content type
+ $body_instance = field_info_instance('node', 'body', 'question');
+
+ // Delete the body field instance
+ field_delete_instance($body_instance);
+
+ // Create all the fields for a Question node
+ foreach (question_fields() as $field) {
+ field_create_field($field);
+ }
+
+ // Attach an instance of each field to the Question node type
+ foreach (question_field_instances() as $instance) {
+ $instance['object_type'] = 'node';
+ $instance['bundle'] = $question_node['type'];
+ field_create_instance($instance);
}
}
-function question_update_1() {
- $items = array();
- $items[] = update_sql("ALTER TABLE {question_node} ADD PRIMARY KEY (`nid`)");
- $items[] = update_sql("ALTER TABLE {question_queue} ADD PRIMARY KEY (`qid`)");
- return $items;
+/**
+ * Returns an array of all fields created by Question module.
+ *
+ * This is inside its own function so that it can be used in both hook_install()
+ * and hook_uninstall().
+ */
+function question_fields() {
+ $t = get_t();
+ return array(
+ 'question_question' => array(
+ 'field_name' => 'question_question',
+ 'type' => 'text_long',
+ ),
+ 'question_answer' => array(
+ 'field_name' => 'question_answer',
+ 'type' => 'text_long',
+ ),
+ );
}
+/**
+ * Returns an array of all instances created by this content type.
+ * The instance tells Drupal which widget to use when entering data into a field
+ * and how to display it in different view modes.
+ *
+ * This is inside its own function so that it can be used in both hook_install()
+ * and hook_uninstall().
+ *
+ * @see http://api.drupal.org/api/group/field_structs/7
+ */
+function question_field_instances() {
+ $t = get_t();
+ return array(
+ 'question' => array(
+ 'field_name' => 'question_question',
+ 'label' => $t('Question'),
+ 'widget' => array(
+ 'type' => 'text_textarea',
+ 'weight' => -4,
+ ),
+ 'display' => array(
+ 'full' => array(
+ 'label' => 'above',
+ 'settings' => array(),
+ 'weight' => -4,
+ ),
+ 'teaser' => array(
+ 'label' => 'inline',
+ 'settings' => array(),
+ 'weight' => -4,
+ ),
+ ),
+ ),
+ 'answer' => array(
+ 'field_name' => 'question_answer',
+ 'label' => $t('Answer'),
+ 'widget' => array(
+ 'type' => 'text_textarea',
+ 'weight' => -3,
+ ),
+ 'display' => array(
+ 'full' => array(
+ 'label' => 'above',
+ 'settings' => array(),
+ 'weight' => -3,
+ ),
+ 'teaser' => array(
+ 'label' => 'hidden',
+ 'type' => 'hidden',
+ 'settings' => array(),
+ 'weight' => -3,
+ ),
+ ),
+ ),
+ );
+}
+
+/**
+ * Implementation of hook_uninstall().
+ *
+ */
function question_uninstall() {
- db_query('DROP TABLE {question_node}');
- db_query('DROP TABLE {question_queue}');
- variable_del('question_require_registered');
- variable_del('question_thanks');
+
+ // Gather all the nodes created with the Question node type
+ $sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
+ $result = db_query($sql, array(':type' => 'question'));
+ $nids = array();
+ foreach ($result as $row) {
+ $nids[] = $row->nid;
+ }
+ node_delete_multiple($nids); // Delete all the nodes at once
+
+ // Loop over and delete all of the field instances attached to the Question node type
+ // These will probably be the same as the fields defined by this module, but may not be
+ $instances = field_info_instances('node', 'question');
+ foreach ($instances as $instance_name => $instance) {
+ field_delete_instance($instance);
+ }
+
+ // Loop over and delete the fields defined by this module
+ // This will remove all instances of the field from any nodetype to which they are attached
+ foreach (array_keys(question_fields()) as $field) {
+ field_delete_field($field);
+ }
+
+ // Delete the Question node type
+ node_type_delete('question');
+
+ // Purge all field information
+ field_purge_batch(1000);
+}
+
+function question_update_1() {
+ $ret = array();
+ db_add_primary_key($ret, 'question_node', array('nid'));
+ db_add_primary_key($ret, 'question_queue', array('qid'));
+ return $ret;
}
-?> \ No newline at end of file
+
+function question_update_6001() {
+ $ret = array();
+ db_drop_primary_key($ret, 'question_queue');
+ return $ret;
+}
+
+function question_update_6002() {
+ $ret = array();
+ db_change_field(
+ $ret, //Results
+ 'question_queue', //Table name
+ 'qid', //Old column name
+ 'qid', //New column name
+ array('type' => 'serial', 'not null' => TRUE), //Field spec
+ array('primary key' => array('qid')) //Index spec
+ );
+ return $ret;
+}
+
+function question_update_7001() {
+
+ // No longer used for access control
+ variable_del('question_require_registered');
+
+ // Rename the question_thanks variable to something more meaningful
+ variable_set('question_ask_form_redirect', variable_get('question_thanks'));
+
+ // This is the function used to upgrade taxonomy terms from D6 taxonomy_term_node table to D7 fields
+ /*
+ * // Since we are upgrading from Drupal 6, we know that only
+ // field_sql_storage.module will be enabled.
+ $field = field_info_field($field['field_name']);
+ $data_table = _field_sql_storage_tablename($field);
+ $revision_table = _field_sql_storage_revision_tablename($field);
+ $etid = _field_sql_storage_etid('node');
+ $value_column = $field['field_name'] . '_value';
+ $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta', $value_column);
+
+ // This is a multi-pass update. On the first call we need to initialize some
+ // variables.
+ if (!isset($sandbox['total'])) {
+ $sandbox['last'] = 0;
+ $sandbox['count'] = 0;
+
+ $query = db_select('taxonomy_term_node', 't');
+ $sandbox['total'] = $query->countQuery()->execute()->fetchField();
+ $found = (bool) $sandbox['total'];
+ }
+ else {
+ // We do each pass in batches of 1000, this should result in a
+ // maximum of 2000 insert queries each operation.
+ $batch = 1000 + $sandbox['last'];
+
+ // Query and save data for the current revision.
+ $result = db_query_range('SELECT td.tid, tn.nid, td.weight, tn.vid, n2.type, n2.created, n2.sticky FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid INNER JOIN {node} n2 ON tn.nid = n2.nid INNER JOIN {node} n ON tn.vid = n.vid AND td.vid = :vocabulary_id ORDER BY td.weight ASC', array(':vocabulary_id' => $vocabulary->vid), $sandbox['last'], $batch);
+ $deltas = array();
+ foreach ($result as $record) {
+ $found = TRUE;
+ $sandbox['count'] += 1;
+ // Start deltas from 0, and increment by one for each
+ // term attached to a node.
+ $deltas[$record->nid] = isset($deltas[$record->nid]) ? ++$deltas[$record->nid] : 0;
+ $values = array($etid, $record->nid, $record->vid, $record->type, $deltas[$record->nid], $record->tid);
+ db_insert($data_table)->fields($columns)->values($values)->execute();
+
+ // Update the {taxonomy_index} table.
+ db_insert('taxonomy_index')
+ ->fields(array('nid', 'tid', 'sticky', 'created',))
+ ->values(array($record->nid, $record->tid, $record->sticky, $record->created))
+ ->execute();
+ }
+
+ // Query and save data for all revisions.
+ $result = db_query('SELECT td.tid, tn.nid, td.weight, tn.vid, n.type FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid AND td.vid = :vocabulary_id INNER JOIN {node} n ON tn.nid = n.nid ORDER BY td.weight ASC', array(':vocabulary_id' => $vocabulary->vid), $sandbox['last'][$batch]);
+ $deltas = array();
+ foreach ($result as $record) {
+ $found = TRUE;
+ $sandbox['count'] += 1;
+ // Start deltas at 0, and increment by one for each term attached to a revision.
+ $deltas[$record->vid] = isset($deltas[$record->vid]) ? ++$deltas[$record->vid] : 0;
+ $values = array($etid, $record->nid, $record->vid, $record->type, $deltas[$record->vid], $record->tid);
+ db_insert($revision_table)->fields($columns)->values($values)->execute();
+ }
+ $sandbox['last'] = $batch;
+ }
+ if (!$found) {
+ db_drop_table('taxonomy_term_node');
+ }
+ */
+
+ // db_drop_table('question_node');
+} \ No newline at end of file
diff --git a/question.module b/question.module
index 6313d8d..24005b8 100644
--- a/question.module
+++ b/question.module
@@ -1,227 +1,187 @@
<?php
// $Id$
-
/**
- * Implementation of hook_help().
- *
+ * @file
+ * Allows users to submit questions to a queue that may be answered by site administrators
+ *
+ * TODO
+ * Create upgrade path in hook_install_N
+ * Theme functions for question form
+ * Update tests
*/
-
-function question_help($section) {
- switch ($section) {
- case 'node/add#question':
- // This description shows up when users click "create content."
- return t('A question/answer node.');
- case 'admin/question':
- return t('Here is a list of the questions that have been submitted to your site. Each question can be answered by selecting "promote". Once submitted, this question becomes a node. Choose "delete" to delete this question without answering.');
- }
-}
-/**
- * Implementation of hook_node_info().
- *
- */
-function question_node_info() {
- return array('question' => array(
- 'name' => t('Question'),
- 'module' => 'question',
- 'description' => 'Users can ask questions and administrators can respond.'));
-}
+/************************************************
+ * *
+ * MENU ITEMS, PERMISSIONS, AND ACCESS CONTROL *
+ * *
+ ***********************************************/
/**
- * Implementation of hook_access().
+ * Implements hook_permission().
*
+ * Defines the permissions that users can have related to this module
*/
-function question_access($op, $node) {
- global $user;
-
- if ($op == 'create') {
- return user_access('ask questions');
- } elseif ($op == 'update' && $node->uid == $user->uid) {
- if (user_access('ask questions')) { return TRUE; }
- else { return NULL; }
- } elseif ($op == 'update') {
- if (user_access('manage questions')) { return TRUE; }
- else { return NULL; }
- }
+function question_permission() {
+ return array(
+ 'ask questions' => array(
+ 'title' => t('Ask questions'),
+ 'description' => t('Submit a question to the site question queue.'),
+ ),
+ 'view questions' => array(
+ 'title' => t('View questions'),
+ 'description' => t('View all questions in the queue.'),
+ ),
+ 'answer questions' => array(
+ 'title' => t('Answer questions'),
+ 'description' => t('Respond to questions in the queue.'),
+ ),
+ 'delete questions' => array(
+ 'title' => t('Delete questions'),
+ 'description' => t('Delete questions from the queue.'),
+ ),
+ 'edit own answers' => array(
+ 'title' => t('Edit own answers'),
+ 'description' => t('Edit own answers.'),
+ ),
+ 'edit any answers' => array(
+ 'title' => t('Edit any answers'),
+ 'description' => t('Edit any answers.'),
+ ),
+ 'delete own answers' => array(
+ 'title' => t('Delete own answers'),
+ 'description' => t('Delete own answers.'),
+ ),
+ 'delete any answers' => array(
+ 'title' => t('Delete any answers'),
+ 'description' => t('Delete any answers.'),
+ ),
+ );
}
/**
- * Implementation of hook_perm().
- *
+ * Implements hook_node_access().
*/
-function question_perm() {
- return array('ask questions', 'manage questions');
-}
+function question_node_access($node, $op, $account) {
+ // Get they type of node being accessed
+ $type = is_string($node) ? $node : $node->type;
+ // Only affect question nodes
+ if ($type != 'question') {
+ return NODE_ACCESS_IGNORE;
+ }
+ if ($op == 'create' && user_access('answer questions', $account)) {
+ return NODE_ACCESS_ALLOW;
+ }
+ if ($op == 'update' && user_access('edit any answers', $account)) {
+ return NODE_ACCESS_ALLOW;
+ }
+ if ($op == 'update' && ($account->uid == $node->uid) && user_access('edit own answers', $account)) {
+ return NODE_ACCESS_ALLOW;
+ }
+ if ($op == 'delete' && user_access('delete any answers', $account)) {
+ return NODE_ACCESS_ALLOW;
+ }
+ if ($op == 'delete' && ($account->uid == $node->uid) && user_access('delete own answers', $account)) {
+ return NODE_ACCESS_ALLOW;
+ }
+ return NODE_ACCESS_IGNORE;
+}
/**
- * Implementation of hook_menu().
+ * Implements hook_menu().
*
+ * Adds all the necessary menu items, and controls access
+ * to those items based on user permissions.
*/
-function question_menu($may_cache) {
+function question_menu() {
$items = array();
-
- if ($may_cache) {
- $items[] = array(
- 'path' => 'node/add/question',
- 'title' => t('Question'),
- 'access' => user_access('manage questions'));
- $items[] = array(
- 'path' => 'admin/content/question',
- 'title' => t('Questions'),
- 'description' => t('Manage the question queue.'),
- 'access' => user_access('manage questions'),
- 'callback' => 'question_list_page');
- $items[] = array(
- 'path' => 'question',
- 'title' => t('Ask a question'),
- 'access' => user_access('ask questions'),
- 'callback' => 'question_add');
- $items[] = array(
- 'path' => 'admin/settings/question',
- 'title' => t('Question'),
- 'description' => t('Edit Question settings.'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'question_settings',
- 'access' => user_access('administer site configuration'),
- 'type' => MENU_NORMAL_ITEM );
- }
-
+ // The page for users to ask a question
+ $items['question'] = array(
+ 'title' => 'Ask a question', // note don't wrap in t() function from 6.x
+ 'description' => 'Post a question to be answered.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('question_ask_form'),
+ 'access callback' => 'user_access',
+ 'access arguments' => array('ask questions'),
+ );
+ // The queue of unanswered questions
+ $items['admin/content/question'] = array(
+ 'title' => 'Questions',
+ 'description' => 'Manage the sites question queue.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('question_queue_admin'),
+ 'access callback' => 'user_access',
+ 'access arguments' => array('view questions'),
+ 'type' => MENU_LOCAL_TASK,
+ );
+ // The settings page
+ $items['admin/config/content/question'] = array(
+ 'title' => 'Question',
+ 'description' => 'Edit Question settings.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('question_settings'),
+ 'access arguments' => array('administer site configuration'),
+ 'type' => MENU_NORMAL_ITEM,
+ );
+
return $items;
}
/**
- * Implementation of hook_form().
+ * Implements hook_menu_alter().
*
+ * Removes the default link to create a question/answer page from the
+ * "Add new content" menu at node/add.
+ * Instead, we only want users to create answers by promoting questions from the queue.
*/
-function question_form(&$node) {
-
- if (arg(2)=='question' && is_numeric(arg(3))) {
- $que = db_fetch_object(db_query('SELECT * FROM {question_queue} WHERE qid = %d', arg(3)));
- $node->questioner = $que->questioner;
- $node->question = $que->question;
- $form['qid'] = array(
- '#type' => 'hidden',
- '#value' => arg(3),
- );
- }
-
- $form['title'] = array('#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => $node->title,
- '#size' => 60,
- '#maxlength' => 128,
- '#weight' => -8,
- '#required' => TRUE);
-
- $form['questioner'] = array(
- '#type' => 'textfield',
- '#title' => t('Questioner'),
- '#default_value' => $node->questioner,
- '#size' => 60,
- '#maxlength' => 128,
- '#weight' => -7,
- '#description' => t("The person asking the question. Can be the user's id (uid), username, or an email address."),
- );
-
- // Now we define the form elements specific to our node type.
- $form['question'] = array('#weight' => -6);
- $form['question']['question'] = array(
- '#type' => 'textarea',
- '#title' => t('Question'),
- '#default_value' => $node->question,
- '#cols' => 60,
- '#rows' => 20
- );
- $form['question']['q_format'] = filter_form($node->q_format, 10, array('q_format'));
-
- $form['answer'] = array('#weight' => -5);
- $form['answer']['answer'] = array(
- '#type' => 'textarea',
- '#title' => t('Answer'),
- '#default_value' => $node->answer,
- '#cols' => 60,
- '#rows' => 20
- );
- $form['answer']['a_format'] = filter_form($node->a_format, 10, array('a_format'));
-
- return $form;
+function question_menu_alter(&$items) {
+ $items['node/add/question']['type'] = MENU_CALLBACK;
}
+/************************************************
+ * *
+ * SETTINGS, HELP, AND INFORMATION *
+ * *
+ ***********************************************/
+
/**
- * Implementation of hook_validate().
- *
+ * Implements hook_help().
*/
-function question_validate(&$node) {
-
- $node->body = '';
-
- // make body for node previews and whatnot
- //$node->body = '<em>'.$node->question."</em><br />\n
- //".$node->answer;
- //$node->format = $node->a_format;
-
- //check validity of questioner
- $req = (variable_get('question_require_registered', FALSE));
- if (is_numeric($node->questioner)) {
- // is it a uid?
- if (!$account = user_load(array('uid'=>$node->questioner))) {
- // it is not a uid
- if ($req) {
- form_set_error('questioner', t('This is not a valid user id.'));
- }
- }
- else {
- // it is a uid
- $node->quid = $account->uid;
- $node->questioner = $account->name;
- }
- }
- else {
- if (valid_email_address($node->questioner)) {
- // it's an email address
- if ($account = user_load(array('mail'=>$node->questioner))) {
- // they're "one of us"
- $node->quid = $account->uid;
- $node->questioner = $account->name;
- }
- }
- elseif ($account = user_load(array('name'=>$node->questioner))) {
- // it's a user
- $node->quid = $account->uid;
- }
- else {
- // it's neither an email nor a user
- if ($req) {
- form_set_error('questioner', t('This is neither an email address nor a valid user name.'));
- }
- }
+function question_help($page, $arg) {
+ switch ($page) {
+ case 'node/add#question': // This description shows up when users click "create content."
+ return t('A question/answer node.');
+ case 'admin/content/questions':
+ return t('Here is a list of the questions that have been submitted to your site. Each question can be answered by selecting "promote". Once submitted, this question becomes a node. Choose "delete" to delete this question without answering.');
+ case 'admin/structure/trigger/question':
+ $explanation = t(
+ "A trigger is a system event. For the question module, you can choose to
+ associate actions when a question is submitted to the queue, or when a
+ question is answered.");
+ return "<p>$explanation</p>";
}
}
-
function question_settings() {
- // require users to be registered in order to ask questions?
- $form['question_require_registered'] = array(
- '#type' => 'checkbox',
- '#weight' => -5,
- '#title' => t('Require registered users?'),
- '#return_value' => 1,
- '#default_value' => variable_get('question_require_registered', FALSE),
- '#description' => t('Require users to be authenticated in order to submit questions?'),
-);
-
- // Thank You node
- $form['question_thanks'] = array(
+ // Redirect path following question submit
+ $form['question_ask_form_redirect'] = array(
'#type' => 'textfield',
'#weight' => -3,
- '#title' => t('Path to "Thank You" node'),
- '#default_value' => variable_get('question_thanks', FALSE),
+ '#title' => t('Path to redirect node'),
+ '#default_value' => variable_get('question_ask_form_redirect', FALSE),
'#size' => 40,
'#maxlength' => 100,
- '#description' => t('This is where users will end up after they submit the question form. Example: "node/454".<br/>Leave blank and user will be returned to the form page with a thank you message.'),
+ '#description' => t('This is where users will end up after they submit the question form. Example: "node/454".<br/>Leave blank and the user will be returned to the front page of the site.'),
+ );
+ // Message to display
+ $form['question_submission_message'] = array(
+ '#type' => 'textarea',
+ '#weight' => -2,
+ '#title' => t('Message to display'),
+ '#default_value' => variable_get('question_submission_message', FALSE),
+ '#size' => 40,
+ '#description' => t('This message will be shown to the user after submitting a question.<br/>Leave blank to display no message.'),
);
-
// Instructions
$form['question_instructions'] = array(
'#type' => 'textarea',
@@ -231,320 +191,398 @@ function question_settings() {
'#size' => 40,
'#description' => t('This message will appear above the question form to provide the user instructions.'),
);
-
- $form['question_instructions_format'] = filter_form(variable_get('question_instructions_format', false), 0, array('question_instructions_format'));
-
+
return system_settings_form($form);
}
+/************************************************
+ * *
+ * USER QUESTION SUBMISSION *
+ * *
+ ************************************************/
-function question_list_page($op = NULL, $qid = NULL) {
- if ($_POST['edit']['confirm']) {
- question_queue_item_delete($_POST['edit']['qid']);
- unset($_POST);
- drupal_goto('admin/content/question');
+/**
+ * Form for users to ask a question
+ */
+function question_ask_form($node, &$form_state) {
+ // Display the instructions (if applicable)
+ $instructions = variable_get('question_instructions', FALSE);
+ if ($instructions) {
+ $form['instructions'] = array(
+ '#type' => 'markup',
+ '#markup' => check_plain($instructions),
+ );
}
- switch ($op) {
- case 'delete':
- return drupal_get_form('question_queue_item_delete');
- break;
- default:
- $headers = array(t('Question'), t('Operations'));
- $sql = 'SELECT * FROM {question_queue} ORDER BY qid DESC';
- $result = pager_query($sql);
- while ($r = db_fetch_object($result)) {
- $rows[$r->qid]['question']['data'] = '<i>'.$r->questioner.'</i><br/>'.check_markup($r->question);
- $rows[$r->qid]['question']['style'] = 'vertical-align:top;border-bottom:solid 1px #666;';
- $rows[$r->qid]['operations']['data'] = l(t('delete'), 'admin/content/question/delete/'.$r->qid).'&nbsp;'.l(t('promote'), 'node/add/question/'.$r->qid, array('title'=>t('create a question node based on this submission')));
- $rows[$r->qid]['operations']['style'] = 'vertical-align:top;border-bottom:solid 1px #666;';
- }
- $output = theme('table', $headers, $rows, array('style'=>'width:100%', 'cellpadding'=>'5'));
- $output .= theme('pager');
+
+ $form['question'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Question'),
+ '#cols' => 50,
+ '#rows' => 5,
+ '#description' => NULL,
+ '#attributes' => NULL,
+ '#default_value' => isset($form_state['storage']['question']) ? $form_state['storage']['question'] : '[please enter a value]',
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit Question'),
+ );
+ $form['#method'] = 'post';
+ $form['#theme'] = 'question_ask_form';
+
+ return $form;
+}
+
+/**
+ * Implements _form_validate.
+ */
+function question_ask_form_validate(&$form, &$form_state) {
+ if ($form_state['values']['question'] == '') {
+ form_set_error('question', t('Please enter a question.'));
}
- return $output;
}
-function question_queue_item_delete() {
- $qid = arg(4);
- $queue_item = db_fetch_object(db_query("SELECT * from {question_queue} WHERE qid = %d", $qid));
+/**
+ * Implements _form_submit.
+ */
+function question_ask_form_submit($form, &$form_state) {
+
+ // Make an array containing all the values to insert
+ $row = array(
+ 'question' => $form_state['values']['question'],
+ );
+ // Write the question to the database
+ drupal_write_record('question_queue', $row);
+ // Retrieve the question id assigned by the database to be used in future form processing
+ $form_state['storage']['qid'] = $row['qid'];
- $form['qid'] = array(
- '#type' => 'hidden',
- '#value' => $qid
- );
- return confirm_form($form, t('Are you sure you want to delete this question?'), 'admin/content/question', $queue_item->question, t('Delete'), t('Cancel'), 'question_queue_item_delete');
+ // Determine where the browser should now go to
+ $path = variable_get('question_ask_form_redirect', '');
+ if (!empty($path)) {
+ // Redirect to the specified path
+ $form_state['redirect'] = $path;
+ }
+ else {
+ // Return to the site frontpage
+ $form_state['redirect'] = '<front>';
+ }
+
+ // Display message to user
+ $message = variable_get('question_submission_message', '');
+ if (!empty($message)) {
+ drupal_set_message(check_plain($message));
+ }
+
+ // Add an entry to the watchdog log
+ watchdog('content', 'Question submitted: %question.', array('%question' => $form_state['values']['question']), WATCHDOG_NOTICE);
}
-function question_queue_item_delete_submit($form_id, $form_values) {
- db_query('DELETE FROM {question_queue} WHERE qid="%d"', $form_values['qid']);
- drupal_set_message(t('Item deleted'));
- drupal_goto('admin/content/question');
-}
+
+/************************************************
+ * *
+ * ASSIGN QUESTIONS *
+ * *
+ ************************************************ /
/**
- * Implementation of hook_insert().
+ * Provide an array of all the possible operations which can be
+ * perfomed on items in the question queue.
*
+ * @see hook_node_operations().
*/
-function question_insert($node) {
- db_query("INSERT INTO {question_node} (nid, questioner, quid, question, q_format, answer, a_format) VALUES (%d, '%s', %d, '%s', %d, '%s', %d)", $node->nid, $node->questioner, $node->quid, $node->question, $node->q_format, $node->answer, $node->a_format);
- // if this node came from the queue, delete the queue item...
- if (isset($node->qid)) {
- db_query("DELETE FROM {question_queue} WHERE qid = %d", $node->qid);
+function question_question_queue_operations() {
+ $operations = array();
+
+ if (user_access('delete questions')) {
+ $operations = array(
+ 'delete' => array(
+ 'label' => t('Delete selected questions'),
+ 'callback' => NULL,
+ ),
+ );
}
+ return $operations;
}
/**
- * Implementation of hook_update().
+ * Admin form for questions in the queue.
*
+ * @see node_admin_content()
*/
-function question_update($node) {
- db_query("UPDATE {question_node} SET questioner='%s', quid=%d, question='%s', q_format=%d, answer='%s', a_format=%d WHERE nid = %d", $node->questioner, $node->quid, $node->question, $node->q_format, $node->answer, $node->a_format, $node->nid);
+function question_queue_admin($form, &$form_state) {
+ if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
+ return question_queue_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['questions']));
+ }
+ $form['admin'] = question_queue_admin_form();
+ return $form;
}
+
/**
- * Implementation of hook_delete().
- *
+ * Return an array of fields to be included in the question queue.
+ * This is implemented as a separate hook so that it can be extended
+ * by other modules that add additional fields to the question queue.
*/
-function question_delete($node) {
- db_query('DELETE FROM {question_node} WHERE nid = %d', $node->nid);
+function question_question_queue_fields() {
+ return array(
+ 'header' => array(
+ 'question' => array('data' => t('Question'), 'field' => 'question', 'sort' => 'desc'),
+ 'operations' => array('data' => t('Operations')),
+ ),
+ 'options' => array(
+ 'question' => array('#markup' => 'check_plain'),
+ )
+ );
}
/**
- * Implementation of hook_load().
+ * List all questions currently in the queue, and allow
+ * bulk operations to be performed against those questions.
*
+ * @see node_admin_nodes()
*/
-function question_load($node) {
- $additions = db_fetch_object(db_query('SELECT questioner, quid, question, q_format, answer, a_format FROM {question_node} WHERE nid = %d', $node->nid));
- return $additions;
+function question_queue_admin_form() {
+ // Build the 'Update options' dropdown.
+ $form['options'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Update options'),
+ '#prefix' => '<div class="container-inline">',
+ '#suffix' => '</div>',
+ );
+ $options = array();
+ $operations = array();
+ foreach (module_invoke_all('question_queue_operations') as $operation => $array) {
+ $options[$operation] = $array['label'];
+ }
+ $form['options']['operation'] = array(
+ '#type' => 'select',
+ '#options' => $options,
+ '#default_value' => 'delete',
+ );
+ $form['options']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Update'),
+ '#submit' => array('question_queue_admin_form_submit'),
+ );
+
+ // Invoke all modules that define fields that should be included
+ // in the question queue page
+ $question_queue_fields = module_invoke_all('question_queue_fields');
+ // Build the table header.
+ $header = $question_queue_fields['header'];
+
+ // Retrieve all questions currently in the queue
+ $query = db_select('question_queue', 'q')->extend('PagerDefault')->extend('TableSort');
+ $query->fields('q'); // Retrieve every field from the queue table
+ $query->addTag('question_queue'); // Add a tag so that other modules can alter this query
+ $query->orderByHeader($header);
+ $result = $query->execute();
+
+ $options = array();
+ // Loop through all the questions
+ foreach ($result as $question) {
+ // Loop through every field on information about this question
+ foreach ($question as $column => $value) {
+ // Determine how the value in this field should be displayed
+ $markup = "";
+ if (!empty($value)) {
+ if (isset($question_queue_fields['options'][$column]['#markup'])) {
+ $markup = call_user_func($question_queue_fields['options'][$column]['#markup'], $value);
+ }
+ else {
+ $markup = check_plain($value);
+ }
+ }
+ // Add this column to the options array
+ $options[$question->qid][$column] = array('data' => array('#markup' => $markup));
+ }
+ if (user_access('answer questions')) {
+ $options[$question->qid]['operations'] = array('data' => array('#markup' => l(t('respond'), 'node/add/question/' . $question->qid, array('title' => t('create a question node based on this submission')))));
+ }
+ }
+ // Create the table
+ $form['questions'] = array(
+ '#type' => 'tableselect',
+ '#header' => $header,
+ '#options' => $options,
+ '#empty' => t('No questions available, sorry!'),
+ );
+
+ return $form;
}
/**
- * Implementation of hook_view().
+ * Perform updates against multiple question queue items.
*
+ * @see node_mass_update
*/
-function question_view($node, $teaser = FALSE, $page = FALSE) {
- $node = node_prepare($node, $teaser);
- if ($teaser) {
- $node->content['teaser']['#value'] = theme('question_teaser', $node);
- } else {
- $node->content['body']['#value'] = theme('question_body', $node);
+function question_queue_mass_update($questions, $updates) {
+ foreach ($questions as $qid) {
+ _question_queue_mass_update_helper($qid, $updates);
}
- return $node;
+ drupal_set_message(t('The update has been performed.'));
}
-function theme_question_body($node) {
- if ($node->quid) {
- $node->questioner = l($node->questioner, 'user/'.$node->quid);
- }
- $output = '<div class="question">';
- if ($node->questioner) {
- $output .= '<div class="question-asks">'.$node->questioner.t(" asks:")."</div>";
+/**
+ * Question Queue Mass Update - helper function.
+ *
+ * @see _node_mass_update_helper
+ */
+function _question_queue_mass_update_helper($qid, $updates) {
+ foreach ($updates as $name => $value) {
+ $query = db_update('question_queue')
+ ->fields(array(
+ $name => $value,
+ ))
+ ->condition('qid', $qid, '=')
+ ->execute();
}
- $output .= '<div class="question-question">'.t('<h3>Question</h3>').check_markup($node->question, $node->q_format, FALSE).'</div>';
- $output .= '<div class="question-answer">'.t('<h3>Answer</h3>').check_markup($node->answer, $node->a_format, FALSE).'</div>';
- $output .= '</div>';
- return $output;
}
-function theme_question_teaser($node) {
- // just the question for the teasers...
- $output = '<div class="question">';
- $output .= '<div class="question-question">'.check_markup($node->question, $node->q_format, FALSE).'</div>';
- $output .= '</div>';
- $output .= l(t('Read the answer...'),'node/'.$node->nid);
- return $output;
-}
-
-function question_add() {
- // initial form...
- drupal_set_title(t("Submit a Question"));
-
- $instructions = check_markup(variable_get('question_instructions', false), variable_get('question_instructions_format', false), false);
- if (strlen($instructions)) {
- $output = '<div class="question instructions">' . t($instructions) . '</div>';
+/**
+ * Validate the question queue bulk update form.
+ *
+ * @see node_admin_nodes_validate
+ */
+function question_queue_admin_form_validate($form, &$form_state) {
+ $questions = array_filter($form_state['values']['questions']);
+ if (count($questions) == 0) {
+ form_set_error('', t('No questions selected.'));
}
-
- $output .= drupal_get_form('question_qform');
- print theme('page', $output);
- return;
}
-function theme_question_qform($form) {
- global $user;
- return drupal_render($form);
-}
+/**
+ * Submit the question queue bulk update form.
+ *
+ * @see node_admin_nodes_submit
+ */
+function question_queue_admin_form_submit($form, &$form_state) {
+ $operations = module_invoke_all('question_queue_operations');
+ $operation = $operations[$form_state['values']['operation']];
+ // Filter out unchecked questions
+ $questions = array_filter($form_state['values']['questions']);
+ if ($function = $operation['callback']) {
+ // Add in callback arguments if present.
+ if (isset($operation['callback arguments'])) {
+ $args = array_merge(array($questions), $operation['callback arguments']);
+ }
+ else {
+ $args = array($questions);
+ }
+ call_user_func_array($function, $args);
-function question_qform() {
- global $user;
-
- // if we are requiring registered users, but user is not logged in
- if (!$user->uid && variable_get('question_require_registered', FALSE)) {
- $form['error'] = array(
- '#type' => 'markup',
- '#value' => t('<p />Please <a href="!login">login or register</a> to submit questions.', array("!login" => url('user/login', drupal_get_destination())))
- );
- return $form;
- }
- // if user is logged in or we're not requiring registered users
- else if (!variable_get('question_require_registered', FALSE)) {
- $form['questioner'] = array(
- '#type' => 'textfield',
- '#title' => t('Your name'),
- '#default_value' => $user->name,
- '#size' => 40,
- '#maxlength' => 60,
- '#description' => t('Your name, username, or email address'),
- );
+ cache_clear_all();
}
else {
- $form['questioner'] = array(
- '#type' => 'hidden',
- '#value' => $user->name,
- );
+ // We need to rebuild the form to go to a second step. For example, to
+ // show the confirmation form for the deletion of questions.
+ $form_state['rebuild'] = TRUE;
}
- $form['question'] = array(
- '#type' => 'textarea',
- '#title' => t('Question'),
- '#default_value' => $_POST['question'],
- '#cols' => 60,
- '#rows' => 10,
- '#description' => NULL,
- '#attributes' => NULL,
- '#required' => TRUE,
- );
- $form[] = array(
- '#type' => 'submit',
- '#value' => t('Submit Question'),
- );
- $form['#method'] = 'post';
- $form['#action'] = url('question', drupal_get_destination());
- return $form;
}
-function question_qform_validate ($form_id, $form_values) {
- if ($form_values['question'] == '') {
- form_set_error('question', t('Please enter a question.'));
+/**
+ * Confirm multiple deletion from the question queue bulk update form.
+ */
+function question_queue_multiple_delete_confirm($form, &$form_state, $questions) {
+ $form['questions'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
+ // array_filter returns only elements with TRUE values
+ foreach ($questions as $qid => $value) {
+ $title = db_query('SELECT question FROM {question_queue} WHERE qid = :qid', array(':qid' => $qid))->fetchField();
+ $form['questions'][$qid] = array(
+ '#type' => 'hidden',
+ '#value' => $qid,
+ '#prefix' => '<li>',
+ '#suffix' => check_plain($title) . "</li>\n",
+ );
}
+ $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
+ $form['#submit'][] = 'question_queue_multiple_delete_confirm_submit';
+ $confirm_question = format_plural(count($questions),
+ 'Are you sure you want to delete this question?',
+ 'Are you sure you want to delete these questions?');
+ return confirm_form($form,
+ $confirm_question,
+ 'admin/content', t('This action cannot be undone.'),
+ t('Delete'), t('Cancel'));
}
-function question_qform_submit ($form_id, $form_values) {
- $qid = db_next_id('question_queue');
- global $user;
- $quid = $user->uid;
- db_query('INSERT INTO {question_queue} (qid, questioner, quid, question) VALUES (%d, "%s", %d, "%s")', $qid, $form_values['questioner'], $quid, $form_values['question']);
- $path = variable_get('question_thanks', '');
- $dest = $_REQUEST['destination'];
- unset($_REQUEST['destination']);
-
- if (strlen(trim($path))) {
- // if the 'question thank you node' variable was set...
- drupal_goto($path);
- }
- else {
- drupal_set_message(t('Your question was submitted.'));
-
- // if not...
- if ($dest) {
- //go back to the original question node...
- drupal_goto($dest);
- }
- else {
- // last resort
- drupal_goto('node');
+/**
+ * Submit confirmation of multiple deletion from the question queue bulk update form.
+ */
+function question_queue_multiple_delete_confirm_submit($form, &$form_state) {
+ if ($form_state['values']['confirm']) {
+ foreach ($form_state['values']['questions'] as $qid => $value) {
+ $num_deleted = db_delete('question_queue')
+ ->condition('qid', $qid)
+ ->execute();
}
+ $count = count($form_state['values']['questions']);
+ watchdog('content', 'Deleted @count questions.', array('@count' => $count));
+ drupal_set_message(format_plural($count, 'Deleted 1 question', 'Deleted @count questions.', array('@count' => $count)));
}
+ $form_state['redirect'] = 'admin/content/question/assign';
}
-/**
- * This function is for those that want to insert a question form into
- * a node to make it easier for people to ask questions. All it does
- * is pull the rendered form and print it out.
- */
-function question_print_form() {
- print drupal_get_form('question_qform');
-}
+/************************************************
+ * *
+ * RESPOND TO QUESTIONS *
+ * *
+ ************************************************/
/**
- * Returns node object for latest question (based on node's creation date)
- *
- */
-
-function question_get_latest() {
- $obj = db_fetch_object(db_query('SELECT n.nid FROM {question_node} q INNER JOIN {node} n ON n.nid = q.nid WHERE n.status = 1 ORDER BY n.created DESC'));
- if ($obj) {
- $node = node_load($obj->nid);
- return $node;
- } else {
- return;
- }
-}
+ * Implements hook_form().
+ *
+ * This is the node form called when a question has been promoted from the queue.
+ * The $qid is passed as arg(3) in the url (node/add/question/3).
+ * This is used to prepopulate the node form with information from the question queue.
+ */
+function question_form_question_node_form_alter(&$form, &$form_state) {
-function question_get_random() {
- $obj = db_fetch_object(db_query('SELECT n.nid FROM {question_node} q INNER JOIN {node} n ON n.nid = q.nid WHERE n.status = 1 ORDER BY RAND()'));
- if ($obj) {
- $node = node_load($obj->nid);
- return $node;
- } else {
- return;
+ // If we've arrived here from the question queue, retrieve and pre-populate the information we already know
+ if (arg(2)=='question' && is_numeric(arg(3))) {
+ $result = db_query('SELECT * FROM {question_queue} WHERE qid = :qid', array(':qid' => arg(3)))->fetchObject();
+ $form['qid'] = array(
+ '#type' => 'hidden',
+ '#value' => arg(3),
+ );
+ $form['question_questioner']['und']['0']['value']['#default_value'] = isset($result->questioner) ? $result->questioner : '';
+ $form['question_question']['und']['0']['value']['#default_value'] = isset($result->question) ? $result->question : '';
+ $form['title']['#default_value'] = isset($result->question) ? truncate_utf8($result->question, 64, $wordsafe = TRUE, $dots = TRUE) : '';
}
+ $form['#validate'][] = 'question_form_validate'; //add additional validation handler for our new fields
+ $form['#submit'][] = 'question_form_submit'; //add additional validation handler for our new fields
}
/**
- * Returns rendered listing of questions
- * $teaser is a true/false indicating whether the teaser version
- * of the node should be displayed
- * $links is a true/false indicating whether links should be displayed
- * $joins is a string containing JOIN arguments for SQL call
- * example: 'INNER JOIN {term_node} t ON t.nid = q.nid'
- * $wheres is a string containing additional WHERE arguments
- * example: 'AND t.tid = 12'
- * $order is a string containing ORDER BY
- *
- * The above example arguments would return the node ids of all question nodes
- * that are tagged with taxonomy term 12
- */
-
-function question_list_questions($teaser = TRUE, $links = FALSE, $joins = '', $wheres = '', $order = 'ORDER BY n.created DESC') {
- $result = db_query("SELECT n.nid FROM {node} n ".$joins." WHERE n.type = 'question' AND n.status = 1 ".$wheres." ".$order);
- while ($row = db_fetch_object($result)) {
- $node = node_load($row->nid);
- $output .= node_view($node, $teaser, FALSE, $links);
+ * Implements _form_validate().
+ *
+ * Validation functions called when a new response is submitted
+ */
+function question_form_validate(&$elements, &$form_state, $form_id = NULL) {
+
+ if ($elements['question_question']['und'][0]['value']['#value'] == '') {
+ form_set_error('question_question', t('Please enter a question.'));
}
- return $output;
+ if ($elements['title']['#value'] == '') {
+ form_set_error('title', t('Please enter a short title for the question.'));
+ }
+ if ($elements['question_answer']['und'][0]['value']['#value'] == '') {
+ form_set_error('question_answer', t('Please enter the answer.'));
+ }
}
/**
- * Implementation of hook_block.
+ * Implements _form_submit().
*
- * Offers 2 blocks: latest question and random question
+ * Submit functions called when a new response is submitted
*/
-function question_block($op, $delta = 0) {
- switch ($op) {
- case 'list':
- $block[0]['info'] = t('Latest question');
- $block[1]['info'] = t('Random question');
-
- return $block;
- case 'view':
- if (user_access('access content')) {
- switch($delta) {
- case 0:
- $question = question_get_latest();
- $block['subject'] = t('Latest question');
- $block['content'] = theme('question_block', $question);
- break;
- case 1:
- $question = question_get_random();
- $block['subject'] = t('Random question');
- $block['content'] = theme('question_block', $question);
- break;
- }
- }
- return $block;
+function question_form_submit(&$elements, &$form_state, $form_id = NULL) {
+ // If this node came from the queue, delete the queue item...
+ if (isset($elements['qid'])) {
+ $num_deleted = db_delete('question_queue')
+ ->condition('qid', $elements['qid']['#value'])
+ ->execute();
}
}
-
-function theme_question_block($node) {
- return theme_question_teaser($node);
-}
diff --git a/question.test b/question.test
new file mode 100644
index 0000000..1041745
--- /dev/null
+++ b/question.test
@@ -0,0 +1,161 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Simpletests for Question module 7.x.
+ *
+ * Verify Question module functionality.
+ */
+
+/**
+ * Functionality tests for question module.
+ */
+class QuestionTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Question',
+ 'description' => 'Verify functionality of the question module.',
+ 'group' => 'Question',
+ );
+ }
+
+ function setUp() {
+ // Enable the module.
+ parent::setUp('question');
+ // Create a user that has the privilege to ask questions
+ $this->question_user = $this->drupalCreateUser(array('ask questions'));
+ // Create a user that has the privilege to manage questions
+ $this->question_admin_user = $this->drupalCreateUser(array('view questions', 'answer questions', 'delete questions'));
+ // Create a site admin user
+ $this->site_admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ }
+
+ /**
+ * Verify the functionality of the example module.
+ */
+ function testQuestionCreation() {
+
+ // Check that unauthorised users cannot ask questions
+ $this->drupalGet('question');
+ $this->assertResponse(403, t('Make sure unauthorised users cannot access question form.'));
+
+ // Grant anonymous users permission to ask questions
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('ask questions'));
+
+ // Ask a question
+ $this->drupalPost(
+ 'question', // The menu item of the form
+ array(
+ 'question' => 'This is a test question'),
+ t('Submit Question')
+ );
+
+ // Check that the question is in the database
+ $count = db_select('question_queue')->countQuery()->execute()->fetchField();
+ $this->assertEqual($count, 1, t("There is one question in the question queue."));
+
+ // Check that an unauthorised user cannot access the question queue
+ $this->drupalGet('admin/content/question');
+ $this->assertResponse(403, t('Make sure unauthorised users cannot access question queue.'));
+
+ // Login as a site admin user
+ $this->drupalLogin($this->site_admin_user);
+
+ // Change question settings
+ $this->drupalPost(
+ 'admin/config/content/question',
+ array(
+ 'question_ask_form_redirect' => 'question',
+ 'question_submission_message' => 'Thanks for submitting a test message!',
+ 'question_instructions' => 'These are test instructions',
+ ),
+ t('Save configuration')
+ );
+ $this->AssertEqual(variable_get('question_ask_form_redirect'), 'question', 'Redirect setting changed');
+ $this->AssertEqual(variable_get('question_submission_message'), 'Thanks for submitting a test message!', 'Submission message changed');
+ $this->AssertEqual(variable_get('question_instructions'), 'These are test instructions', 'Question instructions changed');
+
+ // Log in as a registered question user
+ $this->drupalLogout($this->site_admin_user);
+ $this->drupalLogin($this->question_user);
+
+ // Ask another question
+ $this->drupalPost(
+ 'question', // The menu item of the form
+ array(
+ 'question' => 'This is another test question'),
+ t('Submit Question')
+ );
+
+ // Check that the new settings were applied
+ $this->assertText('Thanks for submitting a test message!', 'Submission message displayed');
+ $this->assertText('These are test instructions', 'Instructions displayed');
+ $this->assertText('Ask a question', 'Form submission redirected correctly');
+
+ // Check that there are two questions in the database
+ $count = db_select('question_queue')->countQuery()->execute()->fetchField();
+ $this->assertEqual($count, 2, t("There are two questions in the question queue."));
+
+ // Login as question admin user
+ $this->drupalLogout($this->question_user);
+ $this->drupalLogin($this->question_admin_user);
+
+ // Check that "manage questions" permission does not enable users to ask questions
+ $this->drupalGet('question');
+ $this->assertResponse(403, t('Make sure users with "manage questions" permission alone cannot access question form.'));
+
+ // Check that the questions appear on the queue page
+ $this->drupalGet('admin/content/question');
+ $this->assertPattern("/This is a test question.*This is another test question/s", t("Submitted questions found on question queue page"));
+
+ // Go to the page to answer the first question
+ $this->drupalGet('node/add/question/1');
+ $this->assertFieldByName('question_question[und][0][value]', "This is a test question", "The question field is correctly populated");
+
+ // Submit an answer to this question
+ $edit = array(
+ 'title' => 'Test Question',
+ 'question_question[und][0][value]' => 'This is a test question',
+ 'question_answer[und][0][value]' => 'This is a response to the test question',
+ );
+ $this->drupalPost('node/add/question/1', $edit, t('Save'));
+
+ // Check that the Question page has been created
+ $this->assertRaw(t('!type %title has been created.', array('!type' => 'Question', '%title' => $edit['title'])), t('Question page created.'));
+
+ // Check that the node exists in the database
+ $node = $this->drupalGetNodeByTitle($edit['title']);
+ $this->assertTrue($node, t('Node found in database.'));
+
+ // Check that the question has been removed from the queue
+ $this->drupalGet('admin/content/question');
+ $this->assertNoText("This is a test question", t("Test question does not appear in the question queue"));
+
+ // Check that the row has been removed from the database
+ $count = db_select('question_queue')->countQuery()->execute()->fetchField();
+ $this->assertEqual($count, 1, t("There is one question in the question queue."));
+
+ // Delete the remaining question
+ $edit = array(
+ 'questions[2]' => TRUE,
+ 'operation' => 'delete',
+ );
+ $this->drupalPost('admin/content/question', $edit, t('Update'));
+
+ // Test whether the confirmation form is displayed
+ $this->assertText(t('Are you sure you want to delete this question?'), t('Question deletion confirmation displayed.'));
+
+ // Confirm the deletion
+ $this->drupalPost(NULL, array(), t('Delete'));
+
+ // Check that the question has been deleted
+ $this->assertRaw(t('Deleted 1 question'), t('Question deleted.'));
+
+ // Check that the question queue is now empty
+ $count = db_select('question_queue')->countQuery()->execute()->fetchField();
+ $this->assertEqual($count, 0, t("The question queue is empty."));
+ }
+}
+