Index: feedback/feedback.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feedback/feedback.admin.inc,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 feedback.admin.inc --- feedback/feedback.admin.inc 20 Feb 2010 22:30:53 -0000 1.1.2.2 +++ feedback/feedback.admin.inc 12 Apr 2010 18:52:03 -0000 @@ -7,116 +7,59 @@ */ /** - * Build a (sortable) form containing a checkbox for each feedback entry. + * Manage feedback module settings. */ -function feedback_admin_view_form() { +function feedback_admin_settings_form() { $form = array(); - $status_headings = array( - 0 => t('Open feedback messages'), - 1 => t('Processed feedback messages'), - ); - $form['#feedback_header'] = array( - array(), - array('data' => t('Location'), 'field' => 'f.location_masked', 'sort' => 'asc'), - array('data' => t('Date'), 'field' => 'f.timestamp'), - array('data' => t('User'), 'field' => 'u.name'), - t('Message'), - ); - // Hack to prevent pager_query() from issuing PHP notices. - if (!isset($_GET['page'])) { - $_GET['page'] = ''; - } - if (count(explode(',', $_GET['page'])) < 2) { - $_GET['page'] .= ',0'; - } - - $form['feedback-messages'] = array('#tree' => TRUE); - foreach (array(0, 1) as $status) { - $sql = "SELECT f.*, u.name FROM {feedback} f INNER JOIN {users} u ON f.uid = u.uid WHERE f.status = %d"; - $count_query = "SELECT COUNT(fid) FROM {feedback} WHERE status = %d"; - $tablesort = tablesort_sql($form['#feedback_header']); - $result = pager_query($sql . $tablesort, 50, $status, $count_query, $status); + $implementations = array(); + $options = array(); + // Get available storage options. + $implementations = module_invoke_all('feedback_info'); - $form['feedback-messages'][$status] = array( - '#type' => 'fieldset', - '#title' => $status_headings[$status], - '#collapsible' => TRUE, - '#collapsed' => $status, - '#attributes' => array('class' => 'feedback-messages'), - ); - while ($entry = db_fetch_object($result)) { - $form['feedback-messages'][$status][$entry->fid] = array( - '#type' => 'checkbox', - '#return_value' => 1, - '#default_value' => FALSE, - ); - $form['feedback-messages'][$status][$entry->fid]['location'] = array('#value' => l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->url)); - $form['feedback-messages'][$status][$entry->fid]['date'] = array('#value' => format_date($entry->timestamp, 'small')); - $form['feedback-messages'][$status][$entry->fid]['user'] = array('#value' => theme('username', $entry)); - $form['feedback-messages'][$status][$entry->fid]['message'] = array('#value' => feedback_format_message($entry)); + // Build options for the storage selector. + if (is_array($implementations['module'])) { + foreach ($implementations['module'] as $key => $module) { + // Check module implements the correct API version. + if ($implementations['api version'][$key] == 2) { + $options[$module] = $implementations['name'][$key]; + } + else { + drupal_set_message(t('Warning: the %module module does not use the correct API for this version of Feedback.', array('%module' => $module)), 'error', FALSE); + } } } - $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); - return $form; -} - -/** - * Output a sortable table containing all feedback entries. - */ -function theme_feedback_admin_view_form($form) { - $output = ''; - foreach (element_children($form['feedback-messages']) as $status) { - $item = &$form['feedback-messages'][$status]; - if (!isset($item['#type']) || $item['#type'] != 'fieldset') { - continue; + // Returned elements are not an array. + else { + // Check module implements the correct API version. + if ($implementations['api version'] == 2) { + $options[$implementations['module']] = $implementations['name']; } - // Build the table. - $rows = array(); - foreach (element_children($item) as $element_entry) { - $entry = &$item[$element_entry]; - // Render the data first. - $rows[] = array( - 0, - drupal_render($entry['location']), - drupal_render($entry['date']), - drupal_render($entry['user']), - drupal_render($entry['message']), - ); - // Render the checkbox. - $rows[count($rows) - 1][0] = drupal_render($entry); - } - if (empty($rows)) { - $rows[] = array(array('data' => t('No feedback entries available.'), 'colspan' => 5)); - } - // Inject the table. - $item['messages'] = array( - '#value' => theme('table', $form['#feedback_header'], $rows) . theme('pager', array(), 50, $status), - '#weight' => -1, - ); - // Render the fieldset. - $output .= drupal_render($item); } - // Render internal FAPI and potential extra form elements. - $output .= drupal_render($form); - return $output; + + // Build the storage type selector. + $form['feedback_storage_settings'] = array( + '#title' => t('Storage settings'), + '#description' => t('Select where the Feedback module should save data.'), + '#type' => 'select', + // Disable by default, enable later if there's more than one option. + '#disabled' => TRUE, + '#options' => $options, + // Value is the module name to be used for storage. + '#default_value' => variable_get('feedback_storage_settings', 'feedback'), + ); + if (count($options) > 1) { + $form['feedback_storage_settings']['#disabled'] = FALSE; + } + // Call the submit function for clearing the menu cache. + $form['#submit'][] = 'feedback_admin_settings_form_submit'; + return system_settings_form($form); } /** - * Form submit callback for admin view form. + * Form submit callback for admin settings form. */ -function feedback_admin_view_form_submit($form, &$form_state) { - $update = array(); - // Determine feedback entries to update. - foreach ($form_state['values']['feedback-messages'] as $status => $entries) { - $entries = array_filter($entries); - foreach ($entries as $fid => $value) { - // Lame for now. :( - $update[$fid] = ($status == 0 ? 1 : 0); - } - } - // Update status of entries in database. - foreach ($update as $fid => $value) { - db_query("UPDATE {feedback} SET status = %d WHERE fid = %d", $value, $fid); - } +function feedback_admin_settings_form_submit($form, &$form_state) { + // Re-build menus after saving settings. + module_invoke('menu', 'rebuild'); + drupal_set_message(t('Menus have been re-built.')); } - Index: feedback/feedback.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/feedback/feedback.module,v retrieving revision 1.75.2.4 diff -u -r1.75.2.4 feedback.module --- feedback/feedback.module 20 Feb 2010 23:59:32 -0000 1.75.2.4 +++ feedback/feedback.module 12 Apr 2010 18:52:04 -0000 @@ -10,7 +10,7 @@ * Implementation of hook_perm(). */ function feedback_perm() { - return array('access feedback form', 'view feedback messages'); + return array('access feedback form', 'view feedback messages', 'administer feedback'); } /** @@ -28,12 +28,36 @@ * Implementation of hook_menu(). */ function feedback_menu() { - $items['admin/reports/feedback'] = array( - 'title' => 'Feedback messages', - 'description' => 'View feedback messages.', + // Check the module being used for storage. + $module = variable_get('feedback_storage_settings', 'feedback'); + // Get module info. + $module_info = module_invoke($module, 'feedback_info'); + // If there are arguments, use them. + if ($module_info['report callback'] && $module_info['report arguments']) { + $items['admin/reports/feedback'] = array( + 'title' => 'Feedback messages', + 'description' => 'View feedback messages.', + 'page callback' => $module_info['report callback'], + 'page arguments' => $module_info['report arguments'], + 'access arguments' => array('view feedback messages'), + ); + } + // If there are no arguments, just call the callback function. + elseif ($module_info['report callback']) { + $items['admin/reports/feedback'] = array( + 'title' => 'Feedback messages', + 'description' => 'View feedback messages.', + 'page callback' => $module_info['report callback'], + 'access arguments' => array('view feedback messages'), + ); + } + + $items['admin/settings/feedback'] = array( + 'title' => 'Feedback settings', + 'description' => 'Administer feedback settings.', 'page callback' => 'drupal_get_form', - 'page arguments' => array('feedback_admin_view_form'), - 'access arguments' => array('view feedback messages'), + 'page arguments' => array('feedback_admin_settings_form'), + 'access arguments' => array('administer feedback'), 'file' => 'feedback.admin.inc', ); return $items; @@ -90,59 +114,15 @@ * Form builder function for a user feedback form. */ function feedback_form() { - $form['#attributes']['class'] = 'feedback-form'; - - // Store the path on which this form is displayed. - $form['location'] = array('#type' => 'value', '#value' => $_GET['q']); - // Allow the form to be submitted via AJAX. - $form['ajax'] = array('#type' => 'hidden', '#default_value' => 0); + $form = array(); - $form['help'] = array( - '#prefix' => '
', - '#value' => t('If you experience a bug or would like to see an addition on the current page, feel free to leave us a message.'), - '#suffix' => '
', - ); - if (user_access('view feedback messages')) { - if (arg(0) != 'node') { - $feedbacks = feedback_load(array('status' => 0, 'location_masked' => feedback_mask_path($_GET['q']))); - } - else { - $feedbacks = feedback_load(array('status' => 0, 'location' => $_GET['q'])); - } - if ($feedbacks) { - $rows = ''; - foreach ($feedbacks as $feedback) { - $rows .= '
'. theme('username', $feedback) .' '. format_date($feedback->timestamp, 'small') .':
'; - $rows .= '
'. feedback_format_message($feedback) .'
'; - } - $form['messages'] = array( - '#prefix' => '
', - '#value' => $rows, - '#suffix' => '
', - ); - } - } - $form['message'] = array( - '#type' => 'textarea', - '#attributes' => array('class' => 'feedback-message'), - '#cols' => 20, - '#title' => t('Message'), - '#required' => TRUE, - '#wysiwyg' => FALSE, - ); - $form['submit'] = array( - '#type' => 'submit', - '#value' => t('Send'), - '#id' => 'feedback-submit', - '#prefix' => '
', - '#suffix' => '
', - ); - - return $form; + // Go fetch the feedback data entry fields. + return feedback_fields($form); } function feedback_form_submit($form, &$form_state) { - feedback_add_entry($form_state['values']['message'], $form_state['values']['location']); + // Pass all the form values because we don't know what they will be. + feedback_add_entry($form_state['values']); $message = t('Thanks for your feedback!'); if ($form_state['values']['ajax']) { echo drupal_to_js(array('message' => $message)); @@ -154,6 +134,17 @@ } /** + * Build the form fields for the feedback form. + */ +function feedback_fields($form) { + // Check the module being used for storage. + $module = variable_get('feedback_storage_settings', 'feedback'); + // Pass building the feedback form to the appropriate module. + $form = module_invoke($module, 'feedback_form', $form); + return $form; +} + +/** * Format a feedback entry. * * @param $entry @@ -181,6 +172,58 @@ * A keyed array of optional where clause conditions. */ function feedback_load($array) { + // Check the module being used for storage. + $module = variable_get('feedback_storage_settings', 'feedback'); + // Pass the act of loading feedback to the appropriate module. + return module_invoke($module, 'feedback_load', $array); +} + +/** + * 'Mask' a path, i.e. replace all numeric arguments in a path with '%' placeholders. + * + * Please note that only numeric arguments with a preceding slash will be + * replaced. + * + * @param $path + * An internal Drupal path, f.e. 'user/123/edit'. + * @return + * A 'masked' path, for above example 'user/%/edit'. + */ +function feedback_mask_path($path) { + return preg_replace('@/\d+@', '/%', $path); +} + +/** + * Store a new feedback entry in the database. + * + * @param string $form_values + * The posted form values from feedback_form. + * In default 'basic storage' mode the main values are: + * $form_values['message'] + * $form_values['location'] + */ +function feedback_add_entry($form_values) { + global $user; + + // Check the module being used for storage. + $module = variable_get('feedback_storage_settings', 'feedback'); + // Pass the act of storage off to the appropriate module. + module_invoke($module, 'feedback_save', $form_values, $user); +} + +/** + * Implementation of hook_feedback_save(). + */ +function feedback_feedback_save($form_values, $user) { + db_query("INSERT INTO {feedback} (uid, message, location, location_masked, url, timestamp, useragent) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $user->uid, trim($form_values['message']), $form_values['location'], feedback_mask_path($form_values['location']), url($form_values['location'], array('absolute' => TRUE)), time(), $_SERVER['HTTP_USER_AGENT']); +} + +/** + * Implementation of hook_feedback_load(). + */ +function feedback_feedback_load($array) { + // Was the feedback_load() function. + // Load feedback for use in the feedback form. $where = $args = array(); if (!empty($array)) { foreach ($array as $column => $value) { @@ -201,32 +244,73 @@ } /** - * 'Mask' a path, i.e. replace all numeric arguments in a path with '%' placeholders. - * - * Please note that only numeric arguments with a preceding slash will be - * replaced. - * - * @param $path - * An internal Drupal path, f.e. 'user/123/edit'. - * @return - * A 'masked' path, for above example 'user/%/edit'. + * Implementation of hook_feedback_form(). */ -function feedback_mask_path($path) { - return preg_replace('@/\d+@', '/%', $path); +function feedback_feedback_form($form) { + // Build the feedback form fields. + $form['#attributes']['class'] = 'feedback-form'; + + // Store the path on which this form is displayed. + $form['location'] = array('#type' => 'value', '#value' => $_GET['q']); + // Allow the form to be submitted via AJAX. + $form['ajax'] = array('#type' => 'hidden', '#default_value' => 0); + + $form['help'] = array( + '#prefix' => '
', + '#value' => t('If you experience a bug or would like to see an addition on the current page, feel free to leave us a message.'), + '#suffix' => '
', + ); + if (user_access('view feedback messages')) { + if (arg(0) != 'node') { + $feedbacks = feedback_load(array('status' => 0, 'location_masked' => feedback_mask_path($_GET['q']))); + } + else { + $feedbacks = feedback_load(array('status' => 0, 'location' => $_GET['q'])); + } + if ($feedbacks) { + $rows = ''; + foreach ($feedbacks as $feedback) { + $rows .= '
'. theme('username', $feedback) .' '. format_date($feedback->timestamp, 'small') .':
'; + $rows .= '
'. feedback_format_message($feedback) .'
'; + } + $form['messages'] = array( + '#prefix' => '
', + '#value' => $rows, + '#suffix' => '
', + ); + } + } + + // The actual message field. + $form['message'] = array( + '#type' => 'textarea', + '#attributes' => array('class' => 'feedback-message'), + '#title' => t('Message'), + '#required' => TRUE, + '#wysiwyg' => FALSE, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Send'), + '#id' => 'feedback-submit', + '#prefix' => '
', + '#suffix' => '
', + ); + return $form; } /** - * Store a new feedback entry in the database. - * - * @param string $message - * A feedback message text entered by an user. - * @param string $location - * The path on which the feedback message was entered. + * Implementation of hook_feedback_info(). */ -function feedback_add_entry($message, $location) { - global $user; - - db_query("INSERT INTO {feedback} (uid, message, location, location_masked, url, timestamp, useragent) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $user->uid, trim($message), $location, feedback_mask_path($location), url($location, array('absolute' => TRUE)), time(), $_SERVER['HTTP_USER_AGENT']); +function feedback_feedback_info() { + // Return information required for Feedback settings. + return array( + 'name' => 'basic storage', + 'module' => 'feedback', + 'api version' => 2, + 'report callback' => 'drupal_get_form', + 'report arguments' => array('feedback_admin_view_form'), + ); } /** @@ -237,3 +321,121 @@ db_query('UPDATE {feedback} SET uid = 0 WHERE uid = %d', $account->uid); } } + +/** + * Build a (sortable) form containing a checkbox for each feedback entry. + */ +function feedback_admin_view_form() { + $form = array(); + $status_headings = array( + 0 => t('Open feedback messages'), + 1 => t('Processed feedback messages'), + ); + $form['#feedback_header'] = array( + array(), + array('data' => t('Location'), 'field' => 'f.location_masked', 'sort' => 'asc'), + array('data' => t('Date'), 'field' => 'f.timestamp'), + array('data' => t('User'), 'field' => 'u.name'), + t('Message'), + ); + // Hack to prevent pager_query() from issuing PHP notices. + if (!isset($_GET['page'])) { + $_GET['page'] = ''; + } + if (count(explode(',', $_GET['page'])) < 2) { + $_GET['page'] .= ',0'; + } + $tablesort = tablesort_sql($form['#feedback_header']); + + // Fetch the actual messages to display. + $messages = array('#tree' => TRUE); + + foreach (array(0, 1) as $status) { + $sql = "SELECT f.*, u.name FROM {feedback} f INNER JOIN {users} u ON f.uid = u.uid WHERE f.status = %d"; + $count_query = "SELECT COUNT(fid) FROM {feedback} WHERE status = %d"; + $result = pager_query($sql . $tablesort, 50, $status, $count_query, $status); + + $messages[$status] = array( + '#type' => 'fieldset', + '#title' => $status_headings[$status], + '#collapsible' => TRUE, + '#collapsed' => $status, + '#attributes' => array('class' => 'feedback-messages'), + ); + while ($entry = db_fetch_object($result)) { + $messages[$status][$entry->fid] = array( + '#type' => 'checkbox', + '#return_value' => 1, + '#default_value' => FALSE, + ); + $messages[$status][$entry->fid]['location'] = array('#value' => l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->url)); + $messages[$status][$entry->fid]['date'] = array('#value' => format_date($entry->timestamp, 'small')); + $messages[$status][$entry->fid]['user'] = array('#value' => theme('username', $entry)); + $messages[$status][$entry->fid]['message'] = array('#value' => feedback_format_message($entry)); + } + } + $form['feedback-messages'] = $messages; + + $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); + return $form; +} + +/** + * Output a sortable table containing all feedback entries. + */ +function theme_feedback_admin_view_form($form) { + $output = ''; + foreach (element_children($form['feedback-messages']) as $status) { + $item = &$form['feedback-messages'][$status]; + if (!isset($item['#type']) || $item['#type'] != 'fieldset') { + continue; + } + // Build the table. + $rows = array(); + foreach (element_children($item) as $element_entry) { + $entry = &$item[$element_entry]; + // Render the data first. + $rows[] = array( + 0, + drupal_render($entry['location']), + drupal_render($entry['date']), + drupal_render($entry['user']), + drupal_render($entry['message']), + ); + // Render the checkbox. + $rows[count($rows) - 1][0] = drupal_render($entry); + } + if (empty($rows)) { + $rows[] = array(array('data' => t('No feedback entries available.'), 'colspan' => 5)); + } + // Inject the table. + $item['messages'] = array( + '#value' => theme('table', $form['#feedback_header'], $rows) . theme('pager', array(), 50, $status), + '#weight' => -1, + ); + // Render the fieldset. + $output .= drupal_render($item); + } + // Render internal FAPI and potential extra form elements. + $output .= drupal_render($form); + return $output; +} + +/** + * Form submit callback for admin view form. + */ +function feedback_admin_view_form_submit($form, &$form_state) { + $update = array(); + // Determine feedback entries to update. + foreach ($form_state['values']['feedback-messages'] as $status => $entries) { + $entries = array_filter($entries); + foreach ($entries as $fid => $value) { + // Lame for now. :( + $update[$fid] = ($status == 0 ? 1 : 0); + } + } + // Update status of entries in database. + foreach ($update as $fid => $value) { + db_query("UPDATE {feedback} SET status = %d WHERE fid = %d", $value, $fid); + } +}