feedback.module in Feedback 5.2
Same filename and directory in other branches
Allows site visitors and users to report issues about this site.
File
feedback.moduleView source
<?php
/**
* @file
* Allows site visitors and users to report issues about this site.
*/
/**
* Implementation of hook_perm().
*/
function feedback_perm() {
return array(
'access feedback form',
'view feedback messages',
);
}
/**
* Implementation of hook_menu().
*/
function feedback_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/logs/feedback',
'title' => t('Feedback messages'),
'description' => t('View feedback messages.'),
'callback' => 'drupal_get_form',
'callback arguments' => 'feedback_admin_view_form',
'access' => user_access('view feedback messages'),
);
}
else {
if (user_access('access feedback form')) {
drupal_add_css(drupal_get_path('module', 'feedback') . '/feedback.css');
drupal_add_js(drupal_get_path('module', 'feedback') . '/feedback.js');
}
}
return $items;
}
/**
* Implementation of hook_block().
*/
function feedback_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$blocks['form'] = array(
'info' => t('Feedback form'),
);
return $blocks;
}
else {
if ($op == 'view') {
$block = array();
switch ($delta) {
case 'form':
if (!user_access('access feedback form') || $_GET['q'] == 'admin/logs/feedback') {
break;
}
$block['subject'] = '<span class="feedback-link">' . t('Feedback') . '</span>';
$block['content'] = drupal_get_form('feedback_form');
break;
}
return $block;
}
}
}
/**
* Implementation of hook_footer().
*/
function feedback_footer($main = 0) {
if (user_access('access feedback form') && $_GET['q'] != 'admin/logs/feedback') {
$block = (object) module_invoke('feedback', 'block', 'view', 'form');
$block->module = 'feedback';
$block->delta = 'form';
$block->region = 'footer';
return theme('block', $block);
}
}
/**
* Form builder function for a user feedback form.
*/
function feedback_form() {
$form = array();
$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' => '<div class="feedback-help">',
'#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' => '</div>',
);
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 .= '<div class="feedback-submitted">' . theme('username', $feedback) . ' ' . format_date($feedback->timestamp, 'small') . ':</div>';
$rows .= '<div class="feedback-body">' . feedback_format_message($feedback) . '</div>';
}
$form['messages'] = array(
'#prefix' => '<div class="feedback-messages">',
'#value' => $rows,
'#suffix' => '</div>',
);
}
}
$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' => '<div id="feedback-throbber">',
'#suffix' => '</div>',
);
return $form;
}
function feedback_form_submit($form_id, $form_values) {
feedback_add_entry($form_values['message'], $form_values['location']);
$message = t('Thanks for your feedback!');
if ($form_values['ajax']) {
echo drupal_to_js(array(
'message' => $message,
));
exit;
}
else {
drupal_set_message($message);
}
}
/**
* Format a feedback entry.
*
* @param $entry
* A feedback object.
*/
function feedback_format_message($entry) {
$message = check_plain($entry->message);
if (!empty($entry->useragent)) {
if (module_exists('browscap')) {
$browserinfo = browscap_get_browser($entry->useragent);
$browser = $browserinfo['parent'] ? $browserinfo['parent'] . ' / ' . $browserinfo['platform'] : $browserinfo['useragent'];
$message .= '<div class="browserinfo">(' . check_plain($browser) . ')</div>';
}
else {
$message .= '<div class="browserinfo">(' . check_plain($entry->useragent) . ')</div>';
}
}
return $message;
}
/**
* Load feedback entries from the database.
*
* @param $array
* A keyed array of optional where clause conditions.
*/
function feedback_load($array) {
$where = $args = array();
if (!empty($array)) {
foreach ($array as $column => $value) {
$where[] = 'f.' . $column . ' = ' . (is_numeric($value) ? '%d' : "'%s'");
$args[] = $value;
}
}
$sql = "SELECT f.*, u.name FROM {feedback} f INNER JOIN {users} u ON f.uid = u.uid";
if (!empty($where)) {
$sql .= ' WHERE ' . implode(' AND ', $where);
}
$result = db_query($sql, $args);
$entries = array();
while ($entry = db_fetch_object($result)) {
$entries[$entry->fid] = $entry;
}
return $entries;
}
/**
* '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 $message
* A feedback message text entered by an user.
* @param string $location
* The path on which the feedback message was entered.
*/
function feedback_add_entry($message, $location) {
global $user;
$fid = db_next_id("{feedback}_fid");
db_query("INSERT INTO {feedback} (fid, uid, message, location, location_masked, url, timestamp, useragent) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d, '%s')", $fid, $user->uid, trim($message), $location, feedback_mask_path($location), url($location, NULL, NULL, TRUE), time(), $_SERVER['HTTP_USER_AGENT']);
}
/**
* Implementation of hook_user().
*/
function feedback_user($op, &$edit, &$account) {
if ($op == 'delete') {
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';
}
$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);
$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),
);
}
}
$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_id, $form_values) {
$update = array();
// Determine feedback entries to update.
foreach ($form_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);
}
}
Functions
Name | Description |
---|---|
feedback_add_entry | Store a new feedback entry in the database. |
feedback_admin_view_form | Build a (sortable) form containing a checkbox for each feedback entry. |
feedback_admin_view_form_submit | Form submit callback for admin view form. |
feedback_block | Implementation of hook_block(). |
feedback_footer | Implementation of hook_footer(). |
feedback_form | Form builder function for a user feedback form. |
feedback_format_message | Format a feedback entry. |
feedback_form_submit | |
feedback_load | Load feedback entries from the database. |
feedback_mask_path | 'Mask' a path, i.e. replace all numeric arguments in a path with '%' placeholders. |
feedback_menu | Implementation of hook_menu(). |
feedback_perm | Implementation of hook_perm(). |
feedback_user | Implementation of hook_user(). |
theme_feedback_admin_view_form | Output a sortable table containing all feedback entries. |