/[drupal]/contributions/modules/feedback/feedback.module
ViewVC logotype

Contents of /contributions/modules/feedback/feedback.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.76 - (show annotations) (download) (as text)
Thu Oct 1 03:20:33 2009 UTC (8 weeks, 1 day ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.75: +122 -77 lines
File MIME type: text/x-php
by sun: Ported to Drupal 7.
1 <?php
2 // $Id: feedback.module,v 1.75 2009/03/21 20:22:14 sun Exp $
3
4 /**
5 * @file
6 * Allows site visitors and users to report issues about this site.
7 */
8
9 /**
10 * Implementation of hook_perm().
11 */
12 function feedback_permission() {
13 return array(
14 'access feedback form' => array(
15 'title' => t('Access feedback form'),
16 'description' => t('Submit feedback messages.'),
17 ),
18 'view feedback messages' => array(
19 'title' => t('View feedback messages'),
20 'description' => t('View, process, and delete submitted feedback messages.'),
21 ),
22 );
23 }
24
25 /**
26 * Implementation of hook_theme().
27 */
28 function feedback_theme() {
29 return array(
30 'feedback_admin_view_form' => array(
31 'arguments' => array('form' => array()),
32 ),
33 );
34 }
35
36 /**
37 * Implementation of hook_menu().
38 */
39 function feedback_menu() {
40 $items['admin/reports/feedback'] = array(
41 'title' => 'Feedback messages',
42 'description' => 'View feedback messages.',
43 'page callback' => 'drupal_get_form',
44 'page arguments' => array('feedback_admin_view_form'),
45 'access arguments' => array('view feedback messages'),
46 );
47 return $items;
48 }
49
50 /**
51 * Implementation of hook_init().
52 */
53 function feedback_init() {
54 if (user_access('access feedback form')) {
55 $path = drupal_get_path('module', 'feedback');
56 drupal_add_css($path . '/feedback.css');
57 drupal_add_js($path . '/feedback.js');
58 }
59 }
60
61 /**
62 * Implementation of hook_block_list().
63 */
64 function feedback_block_list() {
65 $blocks['form'] = array(
66 'info' => t('Feedback form'),
67 );
68 return $blocks;
69 }
70
71 /**
72 * Implementation of hook_block_view().
73 */
74 function feedback_block_view($delta = '') {
75 $block = array();
76 switch($delta) {
77 case 'form':
78 if (!user_access('access feedback form') || $_GET['q'] == 'admin/reports/feedback') {
79 break;
80 }
81 $block['subject'] = '<span class="feedback-link">' . t('Feedback') . '</span>';
82 $block['content'] = drupal_get_form('feedback_form');
83 break;
84 }
85 return $block;
86 }
87
88 /**
89 * Implementation of hook_page_build().
90 */
91 function feedback_page_build(&$page) {
92 if (user_access('access feedback form') && $_GET['q'] != 'admin/reports/feedback') {
93 $block = (object) feedback_block_view('form');
94 $block->module = 'feedback';
95 $block->delta = 'form';
96 $block->region = 'footer';
97 $build = $block->content;
98 unset($block->content);
99 $build += array(
100 '#block' => $block,
101 '#weight' => 0,
102 '#sorted' => TRUE,
103 );
104 $build['#theme_wrappers'][] ='block';
105
106 $page['page_bottom']['feedback'] = $build;
107 }
108 }
109
110 /**
111 * Form builder function for a user feedback form.
112 */
113 function feedback_form($form, &$form_state) {
114 $form['#attributes']['class'] = array('feedback-form');
115
116 // Store the path on which this form is displayed.
117 $form['location'] = array('#type' => 'value', '#value' => $_GET['q']);
118 // Allow the form to be submitted via AJAX.
119 $form['ajax'] = array('#type' => 'hidden', '#default_value' => 0);
120
121 $form['help'] = array(
122 '#prefix' => '<div class="feedback-help">',
123 '#markup' => t('If you experience a bug or would like to see an addition on the current page, feel free to leave us a message.'),
124 '#suffix' => '</div>',
125 );
126 if (user_access('view feedback messages')) {
127 if (arg(0) != 'node') {
128 $feedbacks = feedback_load(array('f.status' => 0, 'f.location_masked' => feedback_mask_path($_GET['q'])));
129 }
130 else {
131 $feedbacks = feedback_load(array('f.status' => 0, 'f.location' => $_GET['q']));
132 }
133 if ($feedbacks) {
134 $rows = '';
135 foreach ($feedbacks as $feedback) {
136 $rows .= '<div class="feedback-submitted">'. theme('username', $feedback) .' '. format_date($feedback->timestamp, 'small') .':</div>';
137 $rows .= '<div class="feedback-body">'. feedback_format_message($feedback) .'</div>';
138 }
139 $form['messages'] = array(
140 '#prefix' => '<div class="feedback-messages">',
141 '#markup' => $rows,
142 '#suffix' => '</div>',
143 );
144 }
145 }
146 $form['message'] = array(
147 '#type' => 'textarea',
148 '#attributes' => array('class' => array('feedback-message')),
149 '#title' => t('Message'),
150 '#required' => TRUE,
151 '#wysiwyg' => FALSE,
152 );
153 $form['submit'] = array(
154 '#type' => 'submit',
155 '#value' => t('Send'),
156 '#id' => 'feedback-submit',
157 '#prefix' => '<div id="feedback-throbber">',
158 '#suffix' => '</div>',
159 );
160
161 return $form;
162 }
163
164 function feedback_form_submit($form, &$form_state) {
165 feedback_add_entry($form_state['values']['message'], $form_state['values']['location']);
166 $message = t('Thanks for your feedback!');
167 if ($form_state['values']['ajax']) {
168 drupal_json_output(array('message' => $message));
169 exit;
170 }
171 else {
172 drupal_set_message($message);
173 }
174 }
175
176 /**
177 * Format a feedback entry.
178 *
179 * @param $entry
180 * A feedback object.
181 */
182 function feedback_format_message($entry) {
183 $message = check_plain($entry->message);
184 if (!empty($entry->useragent)) {
185 if (module_exists('browscap')) {
186 $browserinfo = browscap_get_browser($entry->useragent);
187 $browser = ($browserinfo['parent'] ? $browserinfo['parent'] .' / '. $browserinfo['platform'] : $browserinfo['useragent']);
188 $message .= '<div class="browserinfo">(' . $browser . ')</div>';
189 }
190 else {
191 $message .= '<div class="browserinfo">(' . $entry->useragent . ')</div>';
192 }
193 }
194 return $message;
195 }
196
197 /**
198 * Load feedback entries from the database.
199 *
200 * @param $conditions
201 * A keyed array of optional query conditions.
202 */
203 function feedback_load($conditions) {
204 $query = db_select('feedback', 'f')->fields('f');
205 $query->join('users', 'u', 'f.uid = u.uid');
206 $query->fields('u', array('name'));
207
208 if (!empty($conditions)) {
209 foreach ($conditions as $key => $value) {
210 $query->condition($key, $value);
211 }
212 }
213 $entries = $query->execute()->fetchAllAssoc('fid');
214 return $entries;
215 }
216
217 /**
218 * 'Mask' a path, i.e. replace all numeric arguments in a path with '%' placeholders.
219 *
220 * Please note that only numeric arguments with a preceding slash will be
221 * replaced.
222 *
223 * @param $path
224 * An internal Drupal path, f.e. 'user/123/edit'.
225 * @return
226 * A 'masked' path, for above example 'user/%/edit'.
227 */
228 function feedback_mask_path($path) {
229 return preg_replace('@/\d+@', '/%', $path);
230 }
231
232 /**
233 * Store a new feedback entry in the database.
234 *
235 * @param string $message
236 * A feedback message text entered by an user.
237 * @param string $location
238 * The path on which the feedback message was entered.
239 */
240 function feedback_add_entry($message, $location) {
241 global $user;
242
243 return db_insert('feedback')
244 ->fields(array(
245 'uid' => $user->uid,
246 'message' => trim($message),
247 'location' => $location,
248 'location_masked' => feedback_mask_path($location),
249 'url' => url($location, array('absolute' => TRUE)),
250 'timestamp' => REQUEST_TIME,
251 'useragent' => $_SERVER['HTTP_USER_AGENT'],
252 ))
253 ->execute();
254 }
255
256 /**
257 * Implementation of hook_user_cancel().
258 */
259 function feedback_user_cancel($edit, $account, $method) {
260 switch ($method) {
261 case 'user_cancel_reassign':
262 db_update('feedback')
263 ->fields(array('uid' => 0))
264 ->condition('uid', $account->uid)
265 ->execute();
266 break;
267
268 case 'user_cancel_delete':
269 db_delete('feedback')
270 ->condition('uid', $account->uid)
271 ->execute();
272 break;
273 }
274 }
275
276 /**
277 * Build a (sortable) form containing a checkbox for each feedback entry.
278 */
279 function feedback_admin_view_form($form, &$form_state) {
280 $status_headings = array(
281 0 => t('Open feedback messages'),
282 1 => t('Processed feedback messages'),
283 );
284 $form['#feedback_header'] = array(
285 array(),
286 array('data' => t('Location'), 'field' => 'f.location_masked', 'sort' => 'asc'),
287 array('data' => t('Date'), 'field' => 'f.timestamp'),
288 array('data' => t('User'), 'field' => 'u.name'),
289 t('Message'),
290 );
291 // Hack to prevent pager_query() from issuing PHP notices.
292 if (!isset($_GET['page'])) {
293 $_GET['page'] = '';
294 }
295 if (count(explode(',', $_GET['page'])) < 2) {
296 $_GET['page'] .= ',0';
297 }
298
299 $form['feedback-messages'] = array('#tree' => TRUE);
300 $query = db_select('feedback', 'f')->extend('PagerDefault')->extend('TableSort');
301 $query->join('users', 'u', 'f.uid = u.uid');
302 $query->fields('f')
303 ->fields('u', array('name'))
304 ->limit(50);
305 foreach (array(0, 1) as $status) {
306 $status_query = clone $query;
307 $result = $status_query->element($status)
308 ->condition('f.status', $status)
309 ->execute()->fetchAllAssoc('fid');
310
311 $form['feedback-messages'][$status] = array(
312 '#type' => 'fieldset',
313 '#title' => $status_headings[$status],
314 '#collapsible' => TRUE,
315 '#collapsed' => $status,
316 '#attributes' => array('class' => array('feedback-messages')),
317 );
318 foreach ($result as $fid => $entry) {
319 $form['feedback-messages'][$status][$fid] = array(
320 '#type' => 'checkbox',
321 '#return_value' => 1,
322 '#default_value' => FALSE,
323 );
324 $form['feedback-messages'][$status][$fid]['location'] = array('#markup' => l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->url));
325 $form['feedback-messages'][$status][$fid]['date'] = array('#markup' => format_date($entry->timestamp, 'small'));
326 $form['feedback-messages'][$status][$fid]['user'] = array('#markup' => theme('username', $entry));
327 $form['feedback-messages'][$status][$fid]['message'] = array('#markup' => feedback_format_message($entry));
328 }
329 }
330 $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
331 return $form;
332 }
333
334 /**
335 * Output a sortable table containing all feedback entries.
336 */
337 function theme_feedback_admin_view_form($form) {
338 $output = '';
339 foreach (element_children($form['feedback-messages']) as $status) {
340 $item = &$form['feedback-messages'][$status];
341 if (!isset($item['#type']) || $item['#type'] != 'fieldset') {
342 continue;
343 }
344 // Build the table.
345 $rows = array();
346 foreach (element_children($item) as $element_entry) {
347 $entry = &$item[$element_entry];
348 // Render the data first.
349 $rows[] = array(
350 0,
351 drupal_render($entry['location']),
352 drupal_render($entry['date']),
353 drupal_render($entry['user']),
354 drupal_render($entry['message']),
355 );
356 // Render the checkbox.
357 $rows[count($rows) - 1][0] = drupal_render($entry);
358 }
359 if (empty($rows)) {
360 $rows[] = array(array('data' => t('No feedback entries available.'), 'colspan' => 5));
361 }
362 // Inject the table.
363 $item['messages'] = array(
364 '#markup' => theme('table', $form['#feedback_header'], $rows) . theme('pager', array(), $status),
365 '#weight' => -1,
366 );
367 // Render the fieldset.
368 $output .= drupal_render($item);
369 }
370 // Render internal FAPI and potential extra form elements.
371 $output .= drupal_render_children($form);
372 return $output;
373 }
374
375 /**
376 * Form submit callback for admin view form.
377 */
378 function feedback_admin_view_form_submit($form, &$form_state) {
379 $update = array();
380 // Determine feedback entries to update.
381 foreach ($form_state['values']['feedback-messages'] as $status => $entries) {
382 $entries = array_filter($entries);
383 foreach ($entries as $fid => $value) {
384 // Lame for now. :(
385 $update[$fid] = ($status == 0 ? 1 : 0);
386 }
387 }
388 // Update status of entries in database.
389 foreach ($update as $fid => $value) {
390 db_update('feedback')
391 ->fields(array(
392 'status' => $value,
393 ))
394 ->condition('fid', $fid)
395 ->execute();
396 }
397 }
398

  ViewVC Help
Powered by ViewVC 1.1.2