' . t("This module is an add-on to the FAQ module that allows users with the 'ask question' permission to create a question which will be queued for an 'expert' to answer.") . '
' . '' . t("The module shows an abbreviated version of the FAQ form without an answer field. The node is created without the 'published' attribute. There is a block that will show the unanswered questions to the 'expert' (generally, this requires a separate role).") . '
' . '' . t("Viewing of the completed question and answer pair is done by the FAQ module.") . '
' . '' . t("Simply adding the 'FAQ' content type to a vocabulary will not make it eligible for experts; you must go to the settings page and add it there.") . '
'; return $output; case 'admin/settings/faq/ask': return theme('box', NULL, '' . t('In order for the Faq_Ask module to operate, you must, at the least,: 1) Define at least one vocabulary for use with the "faq" content type; 2) select one or more roles as experts (and you may have to "Save configuration"); 3) select at least one category and expert combination; 4) click the "Save configuration" button.') . ''); case 'faq_ask/unanswered': $output = '' . filter_xss_admin(variable_get('faq_ask_expert_advice', _faq_ask_advice_default('expert'))) . '
'; if (user_access('administer blocks')) { $output .= '' . t('You may go here to change the block limit.', array('!setting' => url('admin/structure/block/manage/faq_ask/unanswered/configure'))) . '
'; } return $output; case 'faq_ask/%': case 'faq_ask': return filter_xss_admin(variable_get('faq_ask_help_text', _faq_ask_help_default())); } } /** * Implements hook_permission(). * * Define the permissions this module uses * * @return array * permissions defined for the faq_ask module */ function faq_ask_permission() { return array( 'ask question' => array( 'title' => t('Ask a question'), 'description' => t('Ask a question to be submitted to an expert.'), ), 'answer question' => array( 'title' => t('Answer a question'), 'description' => t('Answer a question submitted by someone asking.'), ), ); } /** * Implements hook_node_access(). * * @param string $op * The type of node access we are handling * @param object $node * Node object we are checking the access to * @param obhect $account * Account object of the current user * * @return boolean * TRUE if access is granted, FALSE if not. */ function faq_ask_node_access($op, $node, $account) { // If node is already published, it's not ours any more. if (!is_object($node)) { return NULL; } if ($node->status == 1) { return NULL; } if ($op == 'create') { return user_access('ask question') || user_access('answer question'); } else { // We don't include "edit own" because the intent is they can edit their own until it's published. return user_access('answer question') || $account->uid == $node->uid; } } /** * Determines whether the current user has one of the given permissions. * * @param string $string1 * first permission string * @param string $string2 * second permission string * * @return boolean * TRUE if user has one of the given permissions, FALSE otherwise */ function faq_ask_user_access_or($string1, $string2) { return user_access($string1) || user_access($string2); } /** * Implements hook_menu(). * * @return array * Menu structure for the various menus defined for the faq_ask module * */ function faq_ask_menu() { $items = array(); // Issue #1348430: taecelle: Can't see the settings tab // Changed the path to the correct location $items['admin/config/content/faq/ask'] = array( 'title' => 'Experts', 'page callback' => 'drupal_get_form', 'page arguments' => array('faq_ask_settings_form'), 'access arguments' => array('administer faq'), 'description' => 'Allows the user to configure the Ask_FAQ module.', 'type' => MENU_LOCAL_TASK, 'weight' => -7, ); /* $items['admin/config/content/faq/ask/test'] = array( 'title' => 'Experts', 'page callback' => 'drupal_get_form', 'page arguments' => array('faq_ask_test_form'), 'access arguments' => array('administer faq'), 'description' => 'Just for testing purpouses.', 'type' => MENU_LOCAL_TASK, 'weight' => -7, ); */ $items['faq_ask'] = array( 'title' => 'Ask a question', 'page callback' => 'faq_ask_page', 'access callback' => 'user_access', 'access arguments' => array('ask question'), 'weight' => 1, ); $items['faq_ask/%'] = array( 'page arguments' => array(1), 'access arguments' => array('ask question'), 'type' => MENU_CALLBACK, ); $items['faq_ask/answer/%node'] = array( 'title' => 'Answer a question', 'page callback' => 'faq_ask_answer', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['faq_ask/edit/%node'] = array( 'title' => 'Edit a question', 'page callback' => 'faq_ask_edit', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['faq_ask/unanswered'] = array( 'title' => 'List more unanswered questions', 'page callback' => 'faq_ask_list_more', 'access callback' => 'faq_ask_user_access_or', 'access arguments' => array('answer question', 'ask question'), 'type' => MENU_CALLBACK, ); return $items; } /** * Get the ask question form. * * Obsolete? Doesn not seem to be called anywhere * * @return void */ function faq_ask_page($tid = NULL) { drupal_goto('node/add/faq', array( 'query' => array( 'ask' => 'TRUE' ))); } /** * Get the edit question form. * * Checks for the permissions of the current user and redirects to the appropriate edit form. * * @param object $node * Node object of the node we are editing * * @return void */ function faq_ask_edit($node) { global $user; if ($node->status == 1) { drupal_set_message(t('That question has already been answered.'), 'status'); } else { if (node_access('update', $node)) { drupal_goto('node/' . $node->nid . '/edit', array( 'query' => array( 'ask' => 'TRUE' ))); } else { drupal_set_message(t('You are not allowed to edit that question.'), 'error'); } } drupal_goto('node'); } /** * Implements hook_form_FORM_ID_alter(). * * This is how we build the "ask question" form. * @TODO: Make sure this is called after the taxonomy is added, so that we may delete or modify the taxonomy part of the form if we want to. * * @param array $form * The edit form to modify. * @param array $form_state * Form state information * * @return array $form * Modified form as called by reference */ function faq_ask_form_faq_node_form_alter(&$form, &$form_state) { global $user; // Issue #1280446 by deck7uk // If this form is reached with a user that can ask question but should not answer if (user_access('ask question') && !user_access('answer question')) { $_GET['ask'] = 1; // make sure the ask query is set } if (!isset($_GET['ask']) || ($_GET['ask'] != 1 && $_GET['ask'] != 'TRUE')) { return; // Do not modify form if ask query is not set } $language = $form['body']['#language']; if (!user_access('view own unpublished content') || ($user->uid == 0)) { $form['#redirect'] = 'faq-page'; } drupal_set_title(t('Ask a Question')); // Set the published field off and make sure they can't override it. $form['options']['status']['#default_value'] = FALSE; $form['options']['status']['#disabled'] = TRUE; // Add default text to body field. $form['body']['#default_value'] = variable_get('faq_ask_unanswered', t('Not answered yet.')); // Hide the body elements (we'll dummy one later) and the menu elements. hide($form['body']); hide($form['menu']); hide($form['options']); hide($form['upload']); $form['additional_settings']['#access'] = FALSE; $form['upload']['#access'] = FALSE; // Check if only experts can categorize the question. if (variable_get('faq_ask_categorize', FALSE)) { // Hide all taxonomy fields $fields = field_info_instances('node', 'faq'); foreach ($fields as $name => $properties) { if ($properties['display']['default']['module'] == 'taxonomy' && isset($form[$name])) { hide($form[$name]); // Hide form if it is a taxonomy field $form[$name][$language]['#required'] = FALSE; // If hidden, then do not expect it to be required } } } // if we're supposed to notify asker on answer, add form item for this if (variable_get('faq_ask_notify_asker', FALSE)) { // If asker is anonymous, add an optional e-mail field that may be used for notification when question is answered if ($user->uid == 0) { // Form field for e-mail. $form['faq_email'] = array( '#type' => 'textfield', '#title' => t('Notification E-mail (optional)'), '#default_value' => '', '#weight' => 10, '#description' => t('Write your e-mail here if you would like to be notified when the question is answered.') ); } else { // Checkbox for notification $form['faq_notify'] = array( '#type' => 'checkbox', '#title' => t('Notify by E-mail (optional)'), '#default_value' => FALSE, '#weight' => 10, '#description' => t('Check this box if you would like to be notified when the question is answered.'), ); } } // Add validation of the e-mail field if (!isset($form['#validate'])) { $form['#validate'] = array(); } $form['#validate'][] = 'faq_ask_form_validate'; // Make sure we know we came from here. $form['faq_ask'] = array('#type' => 'value', '#value' => TRUE); //$form['#submit'][] = 'faq_ask_submit'; $form['actions']['submit']['#submit'][] = 'faq_ask_submit'; // Handle special cases if this is a block form if (isset($_GET['block'])) { if ($_GET['block']) { // Shorter description on Qestion field + move it higher $form['title']['#description'] = t('Question to be answered.'); $form['title']['#weight'] = '-5'; $form['title']['#size'] = ''; // Make sure it is not set to 60 as default // Shorter description on detailed question field $form['detailed_question']['#description'] = t('Longer question text.'); $form['detailed_question']['#size'] = ''; // Make sure it is not set to 60 as default // Make sure the category field does not expand too wide $fields = field_info_instances('node', 'faq'); foreach ($fields as $name => $properties) { if (isset($properties['display']['default']['module']) && $properties['display']['default']['module'] != 'taxonomy' && isset($form[$name]) && $properties['field_name'] == 'field_tags') { $form[$name][$form[$name]['#language']]['#cols'] = ''; $form[$name][$form[$name]['#language']]['#size'] = ''; } } // Email field if (isset($form['faq_email'])) { $form['faq_email']['#size'] = ''; // Make sure it is not set to 60 as default } } } } /** * Validation form for the FAQ Ask form * * Verifies that the e-mail entered seems to be a valid e-mail. * Thanks to http://hokuten.net/2010/drupal-creating-an-e-mail-subscription-block/ * * @param array $form * The edit form to validate. * @param array $form_state * Form state information * * @return void * */ function faq_ask_form_validate($form, &$form_state) { if (isset($form_state['values']['faq_email']) && 2 < strlen($form_state['values']['faq_email'])) { $email = $form_state['values']['faq_email']; if (!valid_email_address($email)) { form_set_error('email', t('That is not a valid e-mail address.')); } } else { // Issue #1569684 by jlea9378: Not a valid e-mail address unset($form_state['values']['faq_email']); } } /** * Implements hook_node_update(). * * Checks if the node being updated is a question that has been answered * * @param object $node * Node object to update * */ function faq_ask_node_update($node) { if ($node->type == 'faq') { // Update the faq_ask_term_index table by removing nid/tid pairs when node is published if ($node->status == '1') { db_delete('faq_ask_term_index')->condition('nid', $node->nid)->execute(); } // return if the asker notification should be done by cron if (variable_get('faq_ask_notify_by_cron', TRUE)) { return; } // Check if the node is published and asker notified $email = _faq_ask_get_faq_notification_email($node->nid); if ($node->status == '1' && $email != '') { // Get the asker account $params['account'] = user_load_by_mail($email); $params['question'] = $node->title; $params['nid'] = $node->nid; // Send the e-mail to the asker. Drupal calls hook_mail() via this $mail_sent = drupal_mail('faq_ask', 'notify_asker', $email, user_preferred_language($params['account']), $params); // Handle sending result if ($mail_sent) { watchdog('FAQ_Ask', 'Asker notification email sent to @to for question @quest', array('@to' => $email, '@quest' => check_plain($node->title)), WATCHDOG_NOTICE); // If email sent, remove the notification from the queue _faq_ask_delete_faq_notification($node->nid); } else { watchdog('FAQ_Ask', 'Asker notification email to @to failed for the "@quest" question.', array('@to' => $email, '@quest' => check_plain($node->title)), WATCHDOG_ERROR); drupal_set_message( t( 'Asker notification email to @to failed for the "@quest" question.', array('@to' => $email, '@quest' => check_plain($node->title)) ) ); } } } } /** * Implementation of hook_node_insert() * * Handles the creation of a question node after the node is created. This * ensures that the node ID is available, needed for sending e-mail * notifications * * @param object $node * Node object to handle */ function faq_ask_node_insert($node) { global $user; if ($node->type == 'faq') { // Handle only faq node types $terms = _faq_ask_get_terms($node); // Update the faq_ask_term_index table if node is unpublished if ($node->status == '0') { db_delete('faq_ask_term_index')->condition('nid', $node->nid)->execute(); foreach ($terms as $tid => $term) { if ($tid) { // If term is available db_insert('faq_ask_term_index') ->fields( array('nid' => $node->nid, 'tid' => $tid, 'sticky' => $node->sticky, 'created' => $node->created)) ->execute(); } } } // Are we notifying the expert(s)? if (variable_get('faq_ask_notify', FALSE)) { // Use only the first term entered in the correct vocabulary. $term = taxonomy_term_load(array_shift(array_keys($terms))); // Find out who the experts are. $query = db_select('faq_expert', 'fe')->fields('fe', array('uid'))->condition('fe.tid', array_keys($terms), 'IN'); $experts = $query->execute()->fetchAll(); foreach ($experts as $expert) { $account = user_load($expert->uid); $params = array( 'category' => is_object($term)?$term->tid:-1, 'question' => $node->title, 'question_details' => $node->detailed_question, 'nid' => $node->nid, 'creator' => theme('username', array('account' => user_load($node->uid), 'plain' => TRUE)), 'account' => $account, ); $mail_sent = drupal_mail('faq_ask', 'notify_expert', $account->mail, user_preferred_language($account), $params); if ($mail_sent) { watchdog('FAQ_Ask', 'Expert notification email sent to @to', array('@to' => $account->mail), WATCHDOG_NOTICE); } else { watchdog( 'FAQ_Ask', 'Expert notification email to @to failed for the "@cat" category.', array('@to' => $account->mail, '@cat' => check_plain($term->name)), WATCHDOG_ERROR ); drupal_set_message(t('Expert notification email failed for the "@cat" category.', array('@cat' => check_plain($term->name)))); } } } // Save this is the node to be created $asker_email = ''; // Handle the notification of asker if (isset($node->faq_email) && $node->faq_email) { $asker_email = $node->faq_email; // If this user is not registered as a user before - check if all asking anonymous users should be added to the newsletter list if (module_exists('simplenews') && $tid = variable_get('faq_ask_notify_asker_simplenews_tid', '0')) { // If we have selected a newsletter to add if (function_exists('simplenews_subscribe_user')) { simplenews_subscribe_user($asker_email, $tid, variable_get('faq_ask_notify_asker_simplenews_confirm', 1), 'FAQ-Ask'); } } if (module_exists('mailchimp') && $lid = variable_get('faq_ask_notify_asker_mailchimp_lid', '0') && function_exists('mailchimp_get_list')) { // If we have selected a newsletter to add // dpm($lid, 'list ID'); $list = mailchimp_get_list($lid); // dpm($list, 'list'); if (function_exists('mailchimp_subscribe_user') && !empty($list)) { // Add optional groupings information like terms $merge_vars = array('GROUPINGS' => array('groups' => 'FAQ-Ask')); mailchimp_subscribe_user($list, $asker_email, $merge_vars, $message = TRUE, $mcapi = NULL); } } } elseif (isset($node->faq_notify) && $node->faq_notify) { $asker_email = $user->mail; } else { drupal_set_message(t('Your question has been submitted. It will appear in the FAQ listing as soon as it has been answered.'), 'status'); } if ($asker_email) { _faq_ask_set_faq_notification($node->nid, $asker_email); drupal_set_message(t('Your question has been submitted. An e-mail will be sent to @mail when answered.', array('@mail' => $asker_email)), 'status'); } // Handle the notification of asker } } /** * Handle deletion of questions * Removes any pending answer notifications and * term mappings for unpublished questions * * @param object $node * Node to be deleted. */ function faq_ask_node_delete($node) { // Remove notifications db_delete('faq_ask_notify') ->condition('nid', $node->nid) ->execute(); // Remove term/nid pairs db_delete('faq_ask_term_index') ->condition('nid', $node->nid) ->execute(); } /** * Get the term id's related to a node or a form posting * Returns an array of all term ids of a node if the terms * are part of the vocabularies selected for FAQ-Ask. * If no terms then an array with a single 0 as term id is returned * * Parameters passed as array should be the $form_state['values'] * part of a form submission * * @param (object|array) $data * * @return array of terms ids * */ function _faq_ask_get_terms($data) { $category = array(); $vocabs = variable_get('faq_ask_vocabularies', 0); $language = is_object($data)?$data->language:$data['language']; if (is_object($data)) $data = (array)$data; // Get fields relevant for the faq node and $fields = field_info_instances('node', 'faq'); foreach ($fields as $name => $properties) { if (isset($properties['display']['default']['module']) && $properties['display']['default']['module'] != 'taxonomy') unset($fields[$name]); } // Parse through all tagging fields in use foreach ($fields as $field_name => $field_details) { // If we have terms defined if (isset($data[$field_name][$language])) { // Cycle through terms foreach ($data[$field_name][$language] as $term) { // If there is a term tid defined and it is an int if (isset($term['tid']) && is_int((int)$term['tid'])) { if (!isset($term['vid']) || (in_array($term['vid'], $vocabs))) $category[$term['tid']] = taxonomy_term_load($term['tid']); } // Otherwise it may be a new term created by a tagging feature elseif (isset($term['tid']) && $term['tid'] == 'autocreate') { // We're creating a new term if (!isset($category['autocreate'])) { $category['0'] = new stdClass(); $category['0']['names'] = array(); $category['0']->vid = $term['vid']; } $category['autocreate']['names'][] = $term['name']; } } } } if (empty($category)) $category[] = '0'; return $category; } /** * Handles the ask form submission * * @param array $form * The form being posted * * @param array $form_state * Array containing the posted values * */ function faq_ask_submit($form, &$form_state) { global $user; if ($form_state['values']['op'] != t('Save')) { // If we're not saving then do not do actions return; } // Issue #1554912 by jlea9378: Access Denied for Anonymous if ((!user_access('view own unpublished content')) || ($user->uid == 0)) { $form_state['redirect'] = array('faq-page'); // Redirect to faq-page if the user is not allowed to view content } } /** * Implements hook_cron(). * * Checks the que for asker notifications and sends a notification to the asker when the question is published * */ function faq_ask_cron() { // If the asker notification should be done by cron if (!variable_get('faq_ask_notify_by_cron', TRUE)) { return; } // Get all the waiting notifications $notifications = _faq_ask_get_faq_notifications(); foreach ($notifications as $nid => $notify) { // With the notification record, check if status of the question is published if ($notification = db_select('node', 'n')->fields('n', array('title', 'status'))->condition('nid', $notify->nid)->execute()->fetchAssoc()) { if ($notification['status'] == '1') { $params = array( 'question' => $notification['title'], 'nid' => $notify->nid, 'account' => user_load_by_mail($notify->email), 'category' => -1, ); // Send the e-mail to the asker. Drupal calls hook_mail() via this $mail_sent = drupal_mail('faq_ask', 'notify_asker', $notify->email, user_preferred_language($params['account']), $params); // Handle sending result if ($mail_sent) { watchdog('FAQ_Ask', 'Asker notification email sent to @to for question: "@quest"', array('@to' => $notify->email, '@quest' => check_plain($notification['title'])), WATCHDOG_NOTICE); // If email sent, remove the notification from the queue _faq_ask_delete_faq_notification($nid); } else { watchdog('FAQ_Ask', 'Asker notification email to @to failed for the "@quest" question.', array('@to' => $notify->email, '@quest' => check_plain($notification['title'])), WATCHDOG_ERROR); drupal_set_message(t('Asker notification email to @to failed for the "@quest" question.', array('@to' => $notify->email, '@quest' => check_plain($notification['title'])))); } } } } } /** * Helper function to fetch an email for notification assigned to an faq node * * @param integer $nid * The node Id where the e-mail is assoiciated * * @return string * Email associated with the node given by $nid * */ function _faq_ask_get_faq_notification_email($nid) { return db_select('faq_ask_notify', 'fan') ->fields('fan', array('email')) ->condition('nid', $nid) ->execute() ->fetchField(); } /** * Helper function fetching all notifications * * @TODO: optimise to query for all the relevant notifications = those who have a node that is published * * @return array * Array containing all outstanding notifications */ function _faq_ask_get_faq_notifications() { return db_select('faq_ask_notify', 'fa') ->fields('fa', array('nid', 'email')) ->execute() ->fetchAllAssoc('nid'); } /** * Helper function to set a notification associated with a node * * @param integer $nid * Node Id of the question to associate an e-mail address to * @param string $email * Email address to associate with the question and to send the notification to when answered * */ function _faq_ask_set_faq_notification($nid, $email) { if (!$nid) { drupal_set_message(t('Attempt to insert notification to @email for no node ID. Insert failed.', array('@email' => $email)), 'error'); return; } db_insert('faq_ask_notify') ->fields( array( 'nid' => $nid, 'email' => $email, ) ) ->execute(); // Does not work as the result of the execute() method on the query object is undefined // or untrusted for tables without a AUTO_INCREMENT field. See http://drupal.org/node/310079 // if ($inserted == 0) { // drupal_set_message(t('Attempt to insert email notification failed.'), 'error'); // } } /** * Helper function to remove a notification from a question * * @param integer $nid * The Node Id to remove the notification from * */ function _faq_ask_delete_faq_notification($nid) { $deleted = db_delete('faq_ask_notify')->condition('nid', $nid)->execute(); if ($deleted == 0) { drupal_set_message(t('Attempt to delete email notification failed.'), 'error'); } } /** * Block "Ask a Question" form implementation * * This implements the form displayed in a block where the user may ask a question * * @return array * Block content * */ function faq_ask_a_question_blockform() { // Include page handler for node_add() module_load_include('inc', 'node', 'node.pages'); // If user is allowed to create a faq content type if (node_access('create', 'faq')) { // Fool the hook_form_alter function to think we're in an faq-ask page $saved_get = ''; if (isset($_GET['ask'])) { $saved_get = $_GET['ask']; } $_GET['ask'] = '1'; $_GET['block'] = 'TRUE'; // Note title before rendering of form. $title = drupal_get_title(); // Create the form $form = node_add('faq'); // Restore title, which will have been overridden. drupal_set_title($title, PASS_THROUGH); // Issue #1811600 by TBarina: Giving permission to Ask a Question causes all node titles to display &;#039; instead of apostrophe. // Adding param const PASS_THROUGH tp the drupal_set_title() function to avoid check_plain() // Restore the $_GET['ask'] variable status if ($saved_get != '') { $_GET['ask'] = $saved_get; } else { unset($_GET['ask']); } unset($_GET['block']); return $form; } else { return ''; } } /* function faq_ask_test_form($form, &$form_state, $nid = '10') { $form = array(); // dpm($form_state, 'form_state'); $form['email'] = array( '#type' => 'fieldset', '#title' => t('Testing E-mail formatting'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['email']['nid'] = array( '#type' => 'textfield', '#title' => t('Enter the node ID of a question'), '#description' => t('The node will be fetched and the formatted e-mail generated for notification will be displayed when submitted.'), '#default_value' => $nid, ); $form['email']['submit'] = array( '#type' => 'submit', '#value' => t('Run'), '#submit' => array('faq_ask_test_form_submit'), ); $form['taxonomy'] = array( '#type' => 'fieldset', '#title' => t('Testing Taxonomy field settings'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['taxonomy']['info'] = array( ); $form['taxonomy']['submit'] = array( '#type' => 'submit', '#value' => t('Get fields'), '#submit' => array('faq_ask_test_taxonomy_submit'), ); return $form; } function faq_ask_test_taxonomy_submit($form, &$form_state) { $unpub = db_select('node', 'n')->fields('n', array('nid'))->condition('n.status', '0')->condition('n.type', 'faq')->execute()->fetchCol('nid'); dpm($unpub, 'Unpublished questions'); if (empty($unpub)) return; $node = ''; foreach ($unpub as $nid) { $node = node_load($nid); foreach (_faq_ask_get_term_field_name($node) as $field) { foreach ($node->{$field}[$node->language] as $term) { $result = db_select('faq_ask_term_index', 'ti')->fields('ti')->condition('tid', $term['tid'])->condition('nid', $node->nid)->execute()->fetchAll(); if (empty($result) && $term['tid']) { db_insert('faq_ask_term_index') ->fields( array( 'nid' => $node->nid, 'tid' => $term['tid'], 'sticky' => $node->sticky, 'created' => $node->created, )) ->execute(); } } } } $fields = field_info_instances('node', 'faq'); } function faq_ask_test_form_submit($form, &$form_state) { $form_state['node'] = node_load($form_state['values']['nid']); $category = array(); $vocabs = variable_get('faq_ask_vocabularies', 0); if (isset($form_state['node']->{$faq_cat}) && $form_state['node']->{$faq_cat}) { $categories = $form_state['node']->{$faq_cat}[$form_state['node']->language]; foreach ($categories as $id => $term) { $tid = $term['tid']; $category[$tid] = $tid; } } if (empty($category)) $category[] = '0'; // Save this is the node to be created $form_state['node']->faq_ask_data = array(); $form_state['node']->faq_ask_data['categories'] = $category; // if (variable_get('faq_ask_notify', FALSE)) { // Are we notifying the expert(s)? // Find out who the experts are. $query = db_select('faq_expert', 'fe')->fields('fe', array('uid'))->condition('fe.tid', $category, 'IN'); $experts = $query->execute()->fetchAll(); // Save in node object for use in the hook_insert() implementation $form_state['node']->faq_ask_data['experts'] = $experts; // } $node = $form_state['node']; $params = array(); $account = new stdClass(); $messages = array(); foreach ($node->faq_ask_data['experts'] as $expert) { // Use only the first term entered in the correct vocabulary. $term = taxonomy_term_load(array_shift($node->faq_ask_data['categories'])); // TODO: Make something better in category->expert mapping $account = user_load($node->uid); $params = array( 'category' => is_object($term)?$term->tid:-1, 'question' => $node->title, 'question_details' => $node->detailed_question, 'nid' => $node->nid, 'creator' => theme('username', array('account' => $account, 'plain' => TRUE)), ); $params['account'] = user_load($expert->uid); $language = user_preferred_language($account); $language->language = $form_state['node']->language; $message = array('language' => $language); $mail_sent = faq_ask_mail('notify_expert', $message, $params); unset($message['language']); unset($message['headers']); $messages[] = $message; } $notifications = _faq_ask_get_faq_notifications(); foreach ($notifications as $nid => $notify) { if ($nid == $node->nid) { // With the notification record, check if status of the question is published $notification = db_select('node', 'n')->fields('n', array('title', 'status'))->condition('nid', $notify->nid)->execute()->fetchAssoc(); $params = array( 'question' => $notification['title'], 'nid' => $notify->nid, 'account' => user_load_by_mail($notify->email), 'category' => -1, ); // drupal_set_message('Account:'.print_r($params['account']->name, TRUE).''); // Send the e-mail to the asker. Drupal calls hook_mail() via this $messages[$nid] = array( 'language' => $language ); $mail_sent = faq_ask_mail('notify_asker', $messages[$nid], $params); unset($messages[$nid]['language']); unset($messages[$nid]['headers']); } } // drupal_set_message('E-mails sent:
'.print_r($messages, TRUE).''); $form_state['redirect'] = 'admin/config/content/faq/ask/test/' . $form_state['values']['nid']; } */ /** * Implements hook_mail(). * * This function completes the email, allowing for placeholder substitution. * Done: notify_asker. stenjo * @TODO: define messages & subjects on settings page, with list of tokens. how to handle newlines? * * @param string $key * What type of e-mail are we sending? * @param array $message * The message array to be sendt * @param array $params * Additional parameters for placeholders in e-mail text. * * @return array $message * As passed by reference * */ function faq_ask_mail($key, &$message, $params) { $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed'; $body = array(); $options = array( 'langcode' => $message['language']->language, ); // Initiate text variables $variables = array( '@question' => $params['question'], '@question_details' => isset($params['question_details'])?$params['question_details']:'', '@site-name' => variable_get('site_name', 'Drupal'), ); // Find category name if (isset($params['category']) && $params['category']) { $term = ''; $tid = $params['category']; if (is_array($params['category'])) { $term = taxonomy_term_load(array_shift($params['category'])); } else { $term = taxonomy_term_load($params['category']); } if (is_object($term)) { $variables['!cat'] = $term->name; } else { $params['category'] = -1; } } else { $params['category'] = -1; } // Handle user names if (!isset($variables['!username']) || $variables['!username'] == '') { if (isset($params['account']) && is_object($params['account'])) { $variables['!username'] = $params['account']->name; } else { $variables['!username'] = t('user'); } } switch ($key) { case 'notify_expert': $url_options = array( 'options' => array( 'absolute' => TRUE), 'query' => array('token' => _faq_ask_get_token('faq_ask/answer/' . $params['nid']))); $variables = array_merge( $variables, array( '!answer_uri' => url('faq_ask/answer/' . $params['nid'], $url_options), '!asker' => $params['creator'], '!login_uri' => url('user'), ) ); $subject = t('You have a question waiting on @site-name', $variables, $options); $body[]= t('Dear !username,', $variables, $options); if ($params['category'] == -1) { $body[] = t('The following question has been posted.', array(), $options); } else { $body[] = t('The following question has been posted in the "!cat" category by !asker.', $variables, $options); } $body[] = t('@question', $variables, $options); if ($variables['@question_details']) { $body[] = t('@question_details', $variables, $options); } $body[] = t('In order to answer it you will first need to login to the site.', $variables, $options); $body[] = t('Once logged in, you may proceed directly to the question to answer it.', $variables, $options); $body[] = t('By clicking on the above question link you will be redirected to the login form if you are currently logged out.', $variables, $options); break; case 'notify_asker': $url_options = array( 'absolute' => TRUE, ); $variables = array_merge($variables, array( '!question_uri' => url('node/' . $params['nid'], array('absolute' => TRUE)), )); $subject = t('A question you asked has been answered on @site-name', $variables, $options); $body[] = t('Dear !username,', $variables, $options); $body[] = t('The question: "@question" you asked on @site-name has been answered.', $variables, $options); $body[] = t('To view the answer, please visit the question you created on !question_uri.', $variables, $options); $body[] = t('Thank you for visiting.', $variables, $options); break; } $message['body'] = $body; $message['subject'] = $subject; } /** * Implements hook_form(). * * This form allows the users to select the expert roles and to which categories the users in those roles are assigned. * Note, the expert/category table attempts to use the least horizontal space, * so it can "flip" based on whether there are more categories or experts. * * @param array $form_state * */ function faq_ask_settings_form($form, &$form_state /*, $op = NULL, $aid = NULL*/) { // Set a basic message that will be unset once we pass the error checking. $form['error'] = array('#value' => t('Errors were found, please correct them before proceeding.'), '#weight' => -10); $faq_use_categories = variable_get('faq_use_categories', FALSE); if (!$faq_use_categories) { drupal_set_message(t('The Faq_Ask module requires that FAQ "Categorize questions."') . ' ' . t('Please go to the settings page to configure this module.', array( '@url' => url('admin/config/content/faq/categories') )), 'error'); return $form; } // Get the list of vocabularies that apply to FAQ s. $vocabs = taxonomy_get_vocabularies('faq'); if (count($vocabs) == 0) { drupal_set_message(t('The Faq_Ask module requires that at least one vocabulary apply to the "faq" content type. Please go to the Taxonomy configuration page to do this.', array('@taxo_uri' => url('admin/structure/taxonomy'))), 'error'); return $form; } // Get the admin's name. //$admin = ucwords(db_result(db_query('SELECT name FROM {users} WHERE uid=1'))); $query1 = db_select('users', 'u'); $query1->addField('u', 'name'); $query1->condition('u.uid', '1'); $admin = ucwords($query1->execute()->fetchField()); // --------------------------------------------- // Get the Simplenews newsletters if they exists $sn_newsletters = array('0' => t('No newsletter')); if (module_exists('simplenews')) { if (!function_exists('simplenews_get_newsletters')) { drupal_set_message(t('The Simplenews integration is not compatible with this version of Simplenews. Please download a later version.'), 'error'); } else { $list = simplenews_get_newsletters(variable_get('simplenews_vid', '')); foreach ($list as $key => $object) { $list[$key] = $object->name; } $sn_newsletters += $list; } } // --------------------------------------------- // Get the MailChimp newsletters if they exists // mailchimp_subscribe_user $mc_newsletters = array('0' => t('No newsletter')); if (module_exists('mailchimp_lists')) { if (!function_exists('mailchimp_lists_get_available_lists')) { drupal_set_message(t('The MailChimp integration is not compatible with this version of MailChimp. Please download a later version.'), 'error'); } else { $mc_lists = mailchimp_get_lists(); // dpm($mc_lists); foreach ($mc_lists as $key => $object) { $mc_lists[$object['id']] = $object['name']; } $mc_newsletters += $mc_lists; } } $form['notification'] = array( '#type' => 'fieldset', '#title' => t('Notifications'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['notification']['faq_ask_notify'] = array( '#type' => 'checkbox', '#title' => t('Notify experts'), '#description' => t('If this box is checked, the expert(s) for the question will be notified via email that a question awaits them. If you do not choose this option, the "Unanswered Questions" block will be the only way they will know they have questions to answer.'), '#default_value' => variable_get('faq_ask_notify', 0), ); $form['notification']['notify_asker'] = Array( '#type' => 'fieldset', '#title' => T('Asker notification'), '#collapsible' => FALSE, '#collapsed' => FALSE, ); $form['notification']['notify_asker']['faq_ask_asker_notify'] = array( '#type' => 'checkbox', '#title' => t('Notify askers'), '#description' => t('If this box is checked, the asker creating the question will be notified via email that their question is answered.'), '#default_value' => variable_get('faq_ask_notify_asker', 0), ); $form['notification']['notify_asker']['faq_ask_asker_notify_cron'] = array( '#type' => 'checkbox', '#title' => t('Use cron for asker notification'), '#description' => t('If this box is checked, the asker notifications will be sendt via cron.'), '#default_value' => variable_get('faq_ask_notify_by_cron', TRUE), // '#disabled' => !variable_get('faq_ask_notify_asker', 0), '#states' => array( 'visible' => array(':input[name="faq_ask_asker_notify"]' => array('checked' => TRUE)), ), ); $form['notification']['notify_asker']['simplenews'] = array( '#type' => 'fieldset', '#title' => t('Simplenews newsletter integration'), '#collapsible' => TRUE, '#collapsed' => !module_exists('simplenews'), ); // If the Simplenews module is loaded we can add functionality to add anonymous askers to a newsletter $form['notification']['notify_asker']['simplenews']['faq_ask_notify_asker_simplenews'] = array( '#type' => 'select', '#title' => t('Add anonymous asker to newsletter'), '#default_value' => variable_get('faq_ask_notify_asker_simplenews_tid', '0'), '#options' => $sn_newsletters, '#description' => (module_exists('simplenews') ? t('Select a newsletter you want anonymous askers to be assigned to.') : t('This functionality needs the Simplenews module to be activated.')), '#disabled' => !module_exists('simplenews'), '#states' => array( 'visible' => array(':input[name="faq_ask_asker_notify"]' => array('checked' => TRUE))), ); $form['notification']['notify_asker']['simplenews']['faq_ask_notify_asker_simplenews_confirm'] = array( '#type' => 'checkbox', '#title' => t('Confirm subscription to newsletter'), '#description' => t('If this box is checked, the asker creating the question will be asked to confirm the subscription of the newsletter.'), '#default_value' => variable_get('faq_ask_notify_asker_simplenews_confirm', 1), '#disabled' => !module_exists('simplenews'), '#states' => array( 'visible' => array(':input[name="faq_ask_asker_notify"]' => array('checked' => TRUE))), ); $form['notification']['notify_asker']['mailchimp'] = array( '#type' => 'fieldset', '#title' => t('MailChimp newsletter integration'), '#collapsible' => TRUE, '#collapsed' => !module_exists('mailchimp_lists'), ); //dpm($mc_newsletters); //dpm(variable_get('faq_ask_notify_asker_mailchimp_lid', '0')); // If the MailChimp module is loaded we can add functionality to add anonymous askers to a newsletter $form['notification']['notify_asker']['mailchimp']['faq_ask_notify_asker_mailchimp'] = array( '#type' => 'select', '#title' => t('Add anonymous asker to newsletter'), '#default_value' => variable_get('faq_ask_notify_asker_mailchimp_lid', '0'), '#options' => $mc_newsletters, '#description' => (module_exists('mailchimp_lists') ? t('Select a newsletter you want anonymous askers to be assigned to.') : t('This functionality needs the MailChimp module to be activated.')), '#disabled' => !module_exists('mailchimp_lists'), '#states' => array( 'visible' => array(':input[name="faq_ask_asker_notify"]' => array('checked' => TRUE))), ); $form['notification']['notify_asker']['mailchimp']['faq_ask_notify_asker_mailchimp_confirm'] = array( '#type' => 'checkbox', '#title' => t('Confirm subscription to newsletter'), '#description' => t('If this box is checked, the asker creating the question will be asked to confirm the subscription of the newsletter.'), '#default_value' => variable_get('faq_ask_notify_asker_simplenews_confirm', 1), '#disabled' => !module_exists('mailchimp_lists'), '#states' => array( 'visible' => array(':input[name="faq_ask_asker_notify"]' => array('checked' => TRUE))), ); $form['options'] = array( '#type' => 'fieldset', '#title' => t('Options'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['options']['faq_ask_categorize'] = array( '#type' => 'checkbox', '#title' => t('Only expert can categorize'), '#description' => t('If this box is checked, only an expert answering a question can add a category.'), '#default_value' => variable_get('faq_ask_categorize', FALSE), '#weight' => 1, ); /* // Issue #1482014 by Matthew Slater (matslats): Assumes vocab called tags $options = array(); foreach (field_info_instances('node', 'faq') as $fieldname => $instance) { //could narrow it down to just taxonomy fields //and even derive the vocab name instead of the fieldname if that's more useful. $options[$fieldname] = $instance['label']; } $form['options']['faq_category_field'] = array( '#title' => 'Description field', '#description' => t("Which field API field in the FAQ node bundle should be used for 'categories'"), '#type' => 'select', '#options' => $options, '#default_value' => variable_get('faq_category_field', 0), '#weight' => 2, ); */ $give_options = array( 0 => t('Asker retains ownerhsip'), 1 => t('Anonymous questions reassigned to expert'), 2 => t('All questions reassigned to expert'), ); $form['options']['faq_ask_expert_own'] = array( '#type' => 'radios', '#options' => $give_options, '#title' => t('Give ownership to the expert'), '#description' => t('This determines if questions will be reassigned to the expert when answered.'), '#default_value' => variable_get('faq_ask_expert_own', 0), '#weight' => 3, ); $form['options']['faq_ask_unanswered'] = array( '#type' => 'textarea', '#title' => t('Default unanswered body text'), '#cols' => 60, '#rows' => 1, '#description' => t('This text will be inserted into the body of questions when they are asked. This helps make editing easier'), '#default_value' => variable_get('faq_ask_unanswered', t('Not answered yet.')), '#weight' => 4, ); $form['options']['faq_ask_expert_advice'] = array( '#type' => 'textarea', '#title' => t('Answer advice for the expert'), '#cols' => 60, '#rows' => 1, '#description' => t('This text will be shown at the bottom of the "Unanswered questions" block.'), '#default_value' => variable_get('faq_ask_expert_advice', _faq_ask_advice_default()), '#weight' => 4, ); $form['options']['advice']['faq_ask_admin_advice'] = array( '#type' => 'textarea', '#title' => t('Advice for an administrator/editor'), '#cols' => 60, '#rows' => 1, '#default_value' => variable_get('faq_ask_admin_advice', _faq_ask_advice_default('admin')), '#weight' => 5, ); $form['options']['advice']['faq_ask_asker_advice'] = array( '#type' => 'textarea', '#title' => t('Advice for an asker'), '#cols' => 60, '#rows' => 1, '#default_value' => variable_get('faq_ask_asker_advice', _faq_ask_advice_default('asker')), '#weight' => 6, ); $help_default = variable_get('faq_ask_help_text', _faq_ask_help_default()); $form['options']['faq_ask_help_text'] = array( '#type' => 'textarea', '#title' => t('Help text for the asker'), '#cols' => 60, '#rows' => drupal_strlen($help_default) / 60, '#description' => t('This text will be shown at the top of the "Ask a Question" page.'), '#default_value' => $help_default, '#weight' => 7, ); $form['experts'] = array( '#type' => 'fieldset', '#title' => t('Experts'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); // Use the list of vocabularies from above. if (count($vocabs) == 1) { // Single vocabulary, don't bother with a selection box, just set it. $vid = key($vocabs); $def_vid = array($vid => $vid); variable_set('faq_ask_vocabularies', array($vid => $vid)); $vobj = $vocabs[$vid]; $free = $vobj->name; } else { // Multiple vocabs available. $voc_list = array(); // Clear vocabulary list $def_vid = array(); // Clear default selected list foreach ($vocabs as $vid => $vobj) { $voc_list[$vid] = $vobj->name; // Create selection list if ($vobj->name == 'FAQ') { $def_vid[$vid] = $vid; // Create default selected list } } if (empty($def_vid)) // If no default selected vocabs, then default select all of them $def_vid = array_keys($voc_list); // variable_get('efaq_ask_vocabularies', 0)? /* Issue #161406 by phazer: Categories not included in the FAQ list are showing up on the Expert Grid * Changed default vids to reflect an array rather than a separate vocab. * Also changed the vocab list terms retrieved are based upon */ $form['experts']['faq_ask_vocabularies'] = array( '#type' => 'select', '#options' => $voc_list, '#title' => t('Use these vocabularies'), '#multiple' => TRUE, '#default_value' => variable_get('faq_ask_vocabularies', $def_vid), '#description' => t('Only the terms from the selected vocabularies will be included in the list below.') . ' ' . t("Simply adding the 'FAQ' content type to a vocabulary will not make it eligible for experts; you must return to here to add it.") . '
' . t('Note: Even though the check boxes below are checked, you must still click the "Save configuration" button to save the expert settings.') . '
'; } $top .= '' . implode(' | ', $faq_terms) . ' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
' . t('Note: Even though the check boxes below are checked, you must still click the "Save configuration" button to save the expert settings.') . ' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
' . $name . ' | '; foreach ($faq_terms as $tid => $term_name) { $box_name = 'expert_' . $uid . '_' . $tid; $form['experts'][$box_name] = array( '#type' => 'checkbox', '#default_value' => $only_one_expert, '#prefix' => $top . $left . '', '#suffix' => ' | ', ); $top = NULL; $left = NULL; } $form['experts'][$box_name]['#suffix'] .= '
' . t('Note: Even though the check boxes below are checked, you must still click the "Save configuration" button to save the expert settings.') . '
'; } $top .= '' . implode(' | ', $faq_expert_names) . ' | |
---|---|---|
' . $term_name . ' | '; foreach ($faq_expert_names as $uid => $name) { $box_name = 'expert_' . $uid . '_' . $tid; $form['experts'][$box_name] = array( '#type' => 'checkbox', '#default_value' => $only_one_expert, '#prefix' => $top . $left . '', '#suffix' => ' | ', ); $top = NULL; $left = NULL; } $form['experts'][$box_name]['#suffix'] .= '
' . t("For some strange reason, I couldn't find any categories for you.") . '
'; } else { return NULL; } } // find the nodes that are in our terms or does not have a term $query->condition(db_or()->condition('tid', $terms, 'IN')->isNull('tid')); } elseif (!$can_edit) { // If not expert and cannot edit the node by permission - edit own $query->condition('n.uid', $user->uid); // AND n.uid = $user->uid (the user and the node owner are the same) } // A high limit means we are doing the "unanswered" page. if ($limit < 1000) { $totalcount = $query->countQuery()->execute()->fetchField(); // Find the total number of items w/o limit $query->range(0, $limit); // We are only displaying a block $query->orderBy('n.created'); $nids = $query->execute()->fetchCol(); // Get nids if ($totalcount) return theme('faq_ask_unanswered_block', array('data' => $nids, 'more_link' => $totalcount > $limit, 'mode' => $mode)); else return ''; } $query->orderBy('tid'); // Only need the nid column. $result = $query->execute()->fetchAllKeyed(); // Get fts $data = array(); // Rearrange so that we have an array indexed by tid => array(nids) foreach ($result as $nid => $tid) { if (empty($data[$tid])) $data[$tid]=array(); $data[$tid][] = $nid; } foreach ($data as $tid => $nodes) { // Output via theme each block of nodes $output .= theme('faq_ask_unanswered', array('data' => $nodes, 'term' => $tid, 'mode' => $mode)); } return $output; } /** * This function lists all the unanswered questions the user is allowed to see. * It is used by the "more..." link from the block, but can also be called independently. */ function faq_ask_list_more() { drupal_set_title(t('All Unanswered Questions')); $output = '