### Eclipse Workspace Patch 1.0 #P faq_ask Index: faq_ask.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/faq_ask/faq_ask.module,v retrieving revision 1.17.2.23.2.14 diff -u -r1.17.2.23.2.14 faq_ask.module --- faq_ask.module 22 Oct 2009 04:11:46 -0000 1.17.2.23.2.14 +++ faq_ask.module 25 Feb 2010 11:51:42 -0000 @@ -61,7 +61,7 @@ else { // return user_access('answer question') || user_access('edit_own_faq'); // 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; + return user_access('answer question') || $account->uid == $node->uid; } } @@ -158,11 +158,11 @@ } /** - * Implementation of hook_form_alter(). + * Implementation of hook_form_FORM_ID_alter(). * This is how we build the "ask question" form. */ -function faq_ask_form_alter(&$form, $form_state, $form_id) { - if ($form_id != 'faq_node_form' || !isset($_GET['ask'])) { +function faq_ask_form_faq_node_form_alter(&$form, $form_state) { + if (!isset($_GET['ask'])) { return; } if ($_GET['ask'] != 1 && $_GET['ask'] != 'true') { @@ -183,9 +183,140 @@ } $form['body'] = array('#type' => 'value', '#value' => variable_get('faq_ask_unanswered', t('Not answered yet.'))); + // if we're supposed to notify asker on answer, add form item for this + if (variable_get('faq_ask_notify_asker', FALSE)) { + + global $user; + + // 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' => 0, + '#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' => 0, + '#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'])) { + $temp_val = $form['#validate']; + $form['#validate'] = array($temp_val); + } + else { + $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['buttons']['submit']['#submit'][] = 'faq_ask_submit'; + + // Sean Corales: Redirect to faq page if user is anonymous or cannot edit own faq nodes + global $user; + if ((!user_access('edit own faq') && !user_access('edit faq')) || ($user->uid == 0)) { + $form['#redirect'] = 'faq'; + } + + // Handle special cases if this is a block form + if (isset($_GET['block'])) { + if($_GET['block']) { + + // Shorten the description text on taxonomy field + if (!variable_get('faq_ask_categorize', FALSE) && isset($form['taxonomy']['tags'])) { + $tags = array_keys($form['taxonomy']['tags']); + $form['taxonomy']['tags'][$tags[0]]['#description'] = t('A comma-separated list of terms.'); + } + + // Shorter description on Qestion field + move it higher + $form['title']['#description'] = t('Question to be answered.'); + $form['title']['#weight'] = '-5'; + + // Shorter description on detailed question field + $form['detailed_question']['#description'] = t('Longer question text.'); + + } + } +} + +/** + * Validation form for the FAQ Ask form + * Thanks to http://hokuten.net/2010/drupal-creating-an-e-mail-subscription-block/ + */ +function faq_ask_form_validate($form, &$form_state) { + + if (isset($form_state['values']['faq-email'])) { + $email = $form_state['values']['faq-email']; + if (strlen($email) > 1 && !eregi('^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.([a-zA-Z]{2,4})$', $email)) { + form_set_error('email', t('That is not a valid e-mail address.')); + } + } +} + +/** + * Implementation of hook_nodeapi() + * Checks if the node being updated is a question that has been answered + */ +function faq_ask_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { + if($node->type == 'faq') { + switch ($op) { + case 'update': + + // 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 + $email = _faq_ask_get_faq_notification($node->nid); + if ($node->status == '1') { + + // Get the asker account + $account = user_load(array('mail' => $email)); + // If the account is not anonymous + if ($account) { + $params['account'] = $account; + } + else { + $params['account'] = null; + } + + // 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)) + ) + ); + } + } + break; + default: + break; + } + } } function faq_ask_submit($form, &$form_state) { @@ -202,12 +333,13 @@ else { $category = 0; // 0 is default expert. } + // Are we notifying the expert(s)? if (variable_get('faq_ask_notify', FALSE)) { $params = array( 'category' => $category ? $category : -1, - 'question' => $node->title, - 'nid' => $node->nid, + 'question' => $form_state['title'], + 'nid' => $form_state['nid'], 'creator' => theme('username', $node, array('plain' => TRUE)), ); // Find out who the experts are. @@ -228,10 +360,157 @@ } } - drupal_set_message(t('Your question has been submitted. It will appear in the FAQ listing as soon as it has been answered.'), 'status'); + // Handle the notification of asker + if (isset($form_state['values']['faq-email'])) { + _faq_ask_set_faq_notification($form_state['nid'], $form_state['values']['faq-email']); + drupal_set_message(t('Your question has been submitted. An e-mail will be sent to @mail when answered.', array('@mail' => $form_state['values']['faq-email'])), 'status'); + } + else if (isset($form_state['values']['faq-notify'])) { + if ($form_state['values']['faq-notify']) { + global $user; + $email = $user->mail; + _faq_ask_set_faq_notification($form_state['nid'], $email); + drupal_set_message(t('Your question has been submitted. An e-mail will be sent to @mail when answered.', array('@mail' => $email)), 'status'); + } + } + 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'); + } } /** + * Implementation of 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 => $email) { + // With the notification record, check if status of the question is published + if ($result = db_query('SELECT title,status FROM {node} WHERE nid=%d', $nid)) { + $notification = db_fetch_array($result); + if ($notification['status'] == '1') { + + $params = array( + 'question' => $notification['title'], + 'nid' => $nid, + 'account' => user_load(array('mail' => $email)), + ); + + // 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($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' => $email, '@quest' => check_plain($notification['title'])), WATCHDOG_ERROR); + drupal_set_message(t('Asker notification email to @to failed for the "@quest" question.', array('@to' => $email, '@quest' => check_plain($notification['title'])))); + } + } + } + + } +} +/** + * Helper function to fetch an email for notification assigned to an faq node + * + */ +function _faq_ask_get_faq_notification_email($nid) { + $result = db_query('SELECT email FROM {faq_ask_notify} WHERE nid=%d', $nid); + return db_fetch_array($result); +} + +/** + * Helper function fetching all notifications + * returns: Array containing all outstanding notifications + */ +function _faq_ask_get_faq_notifications() { + $notifications = array(); + + $result = db_query('SELECT nid, email FROM {faq_ask_notify}'); + while ($row = db_fetch_array($result)) { + $notifications[$row['nid']] = $row['email']; + } + return $notifications; + +} +function _faq_ask_set_faq_notification($nid, $email) { + + $data = array( + 'nid' => $nid, + 'email' => $email + ); + drupal_write_record('faq_ask_notify', $data); +} + +function _faq_ask_delete_faq_notification($nid) { + $delete = db_query("DELETE FROM {faq_ask_notify} WHERE nid=%d", $nid); + if ($delete === FALSE) { + 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 + * + */ +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); + + // Restore the $_GET['ask'] variable status + if ($saved_get != '') { + $_GET['ask'] = $saved_get; + } + else { + unset($_GET['ask']); + } + unset($_GET['block']); + + return $form; + } + else { + return ''; + } + +} + + +/** * Implementation of hook_mail(). * This function completes the email, allowing for placeholder substitution. * @TODO: notify_asker. @@ -264,6 +543,24 @@ $body[] = t('In order to answer it you will first need to login to the site.', $variables, $language->language); $body[] = t('Once logged in, you may proceed directly to the question to answer it.', $variables, $language->language); break; + + case 'notify_asker': + $variables = array_merge($variables, array( + '!cat' => $params['category'], + '@question' => $params['question'], + '!question_uri' => url('node/'. $params['nid'], array('absolute' => TRUE)), + )); + + if ($variables['!username'] == '') { + $variables['!username'] = t('user'); + } + + $subject = t('A question you asked has been answered on !site', $variables, $language->language); + $body[] = t('Dear !username,', $variables, $language->language); + $body[] = t('The question: "@question" you asked on !site has been answered. ', $variables, $language->language); + $body[] = t('To view the answer, please visit the question you created on !question_uri.', $variables, $language->language); + $body[] = t('Thank you for visiting.', $variables, $language->language); + break; } $message['body'] = drupal_wrap_mail(implode($newline, $body)); $message['subject'] = $subject; @@ -276,6 +573,7 @@ * so it can "flip" based on whether there are more categories or experts. */ function faq_ask_settings_form(&$form_state, $op = NULL, $aid = NULL) { + $form = array(); // 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); @@ -296,9 +594,9 @@ // Get the admin's name. $admin = ucwords(db_result(db_query('SELECT name FROM {users} WHERE uid=1'))); - $form['notification'] = array( + $form['notification'] = Array( '#type' => 'fieldset', - '#title' => t('Notifications'), + '#title' => T('Notifications'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); @@ -310,6 +608,28 @@ '#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), + ); + $form['options'] = array( '#type' => 'fieldset', '#title' => t('Options'), @@ -345,7 +665,7 @@ '#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.')), ); - + $form['options']['faq_ask_expert_advice'] = array( '#type' => 'textarea', '#title' => t('Answer advice for the expert'), @@ -434,7 +754,7 @@ //$vocabs = variable_get('faq_ask_vocabularies', $def_vid); $vocabs_array = array(); foreach ($vocabs as $vocab) { - $vocabs_array[$vocab->vid] = $vocab->vid; + $vocabs_array[$vocab->vid] = $vocab->vid; } $result = db_query('SELECT td.tid, td.name, td.description FROM {term_data} td WHERE td.vid IN ('. db_placeholders($vocabs_array) .') ORDER BY td.weight ASC, td.name ASC', $vocabs_array); @@ -566,7 +886,7 @@ else { // Expert 0 means default expert; overlook it. if ($expert['tid'] != 0) { - drupal_set_message(t("!name doesn't exist. If you have just changed your role selections this may be okay.", array('!name' => $box_name)), 'warning'); + drupal_set_message(t("!name doesn't exist. If you have just changed your role selections this may be okay.", array('!name' => $box_name)), 'warning'); } } } @@ -590,7 +910,7 @@ } // Get rid of error element. - unset($form['error']); + unset($form['error']); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save configuration'), @@ -615,6 +935,8 @@ variable_set('faq_ask_categorize', $form_state['values']['faq_ask_categorize']); variable_set('faq_ask_expert_own', $form_state['values']['faq_ask_expert_own']); variable_set('faq_ask_notify', $form_state['values']['faq_ask_notify']); + variable_set('faq_ask_notify_asker', $form_state['values']['faq_ask_asker_notify']); + variable_set('faq_ask_notify_by_cron', $form_state['values']['faq_ask_asker_notify_cron']); variable_set('faq_ask_unanswered', $form_state['values']['faq_ask_unanswered']); variable_set('faq_ask_default_expert', $form_state['values']['faq_ask_default_expert']); variable_set('faq_ask_expert_advice', $form_state['values']['faq_ask_expert_advice']); @@ -652,7 +974,7 @@ global $user; // Validate the request. if (!isset($_REQUEST['token']) || !drupal_valid_token($_REQUEST['token'], "faq_ask/answer/$node->nid")) { - watchdog('Faq_Ask', + watchdog('Faq_Ask', 'Received an invalid answer request (@query_string) from @user_ip.', array('@query_string' => $_SERVER['QUERY_STRING'], '@user_ip' => $_SERVER['REMOTE_ADDR']), WATCHDOG_ALERT); @@ -849,6 +1171,7 @@ */ function faq_ask_block($op = 'list', $delta = 0, $edit = array()) { global $user; + $block = array(); switch ($op) { case 'list': $blocks[0]['info'] = t('Unanswered Questions'); @@ -865,7 +1188,8 @@ case 1: // Ask a question block. if (user_access('ask question')) { - $block['content'] = faq_ask_page(NULL); + $block['title']= t('Ask a Question'); + $block['content'] = faq_ask_a_question_blockform(); } } // end switch($delta). @@ -912,7 +1236,7 @@ // What permissions does this user have? $can_edit = user_access('administer faq') || user_access('administer nodes'); $is_expert = user_access('answer question'); - + $mode = 'edit'; $output = $extra_msg = NULL; // A high limit means we are doing the "unanswered" page. Index: faq_ask.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/faq_ask/faq_ask.install,v retrieving revision 1.4.2.7 diff -u -r1.4.2.7 faq_ask.install --- faq_ask.install 24 Nov 2008 20:13:07 -0000 1.4.2.7 +++ faq_ask.install 25 Feb 2010 11:51:41 -0000 @@ -32,6 +32,28 @@ 'tid' => array('tid', 'uid'), ), ); + + $schema['faq_ask_notify'] = array( + 'description' => t('FAQ node to asker mapping.'), + 'fields' => array( + 'nid' => array( + 'description' => t('Node identifier for notification'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'email' => array( + 'description' => t('Node identifier for notification'), + 'type' => 'varchar', + 'length' => '128', + 'not null' => TRUE, + ), + ), + 'primary key' => array('nid', 'email'), + 'indexes' => array( + 'nid' => array('nid', 'email'), + ), + ); return $schema; } @@ -55,11 +77,22 @@ function faq_ask_update_6100() { $ret = array(); - $ret[] = update_sql('INSERT INTO {faq_expert} (uid, tid) VALUES ('. variable_get('faq_ask_default_expert', 1) .', 0)'); + $ret[] = update_sql('INSERT INTO {faq_expert} (uid, tid) VALUES ('. variable_get('faq_ask_default_expert', 1) .', 0)'); + + return $ret; +} + +function faq_ask_update_6101() { + + $ret = array(); + $schema = faq_ask_schema(); + db_create_table($ret, 'faq_ask_notify', $schema['faq_ask_notify']); return $ret; + } + /** * Implementation of hook_uninstall(). */ @@ -77,6 +110,6 @@ variable_del('faq_ask_help_text'); variable_del('faq_ask_categorize'); variable_del('faq_ask_expert_own'); - + drupal_set_message(t('faq_ask module uninstalled.')); }