feedback.module 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. <?php
  2. /**
  3. * @file
  4. * Allows site visitors and users to report issues about this site.
  5. */
  6. /**
  7. * Open state (unprocessed) for feedback entries.
  8. */
  9. define('FEEDBACK_OPEN', 0);
  10. /**
  11. * Processed state for feedback entries.
  12. */
  13. define('FEEDBACK_PROCESSED', 1);
  14. /**
  15. * Implements hook_theme().
  16. */
  17. function feedback_theme() {
  18. return array(
  19. 'feedback_admin_view_form' => array(
  20. 'render element' => 'form',
  21. ),
  22. 'feedback_entry' => array(
  23. 'render element' => 'elements',
  24. 'template' => 'feedback-entry',
  25. 'file' => 'feedback.admin.inc',
  26. ),
  27. 'feedback_form_display' => array(
  28. 'template' => 'feedback-form-display',
  29. 'variables' => array('title' => NULL, 'content' => NULL),
  30. ),
  31. );
  32. }
  33. /**
  34. * Implements hook_entity_info().
  35. */
  36. function feedback_entity_info() {
  37. $return = array(
  38. 'feedback' => array(
  39. 'label' => t('Feedback'),
  40. 'controller class' => 'FeedbackController',
  41. 'base table' => 'feedback',
  42. 'uri callback' => 'feedback_uri',
  43. 'fieldable' => TRUE,
  44. 'entity keys' => array(
  45. 'id' => 'fid',
  46. ),
  47. 'bundles' => array(
  48. 'feedback' => array(
  49. 'label' => t('Feedback'),
  50. 'admin' => array(
  51. 'path' => 'admin/config/user-interface/feedback',
  52. 'access arguments' => array('administer feedback'),
  53. ),
  54. ),
  55. ),
  56. 'view modes' => array(
  57. 'full' => array(
  58. 'label' => t('Full feedback entry'),
  59. 'custom settings' => FALSE,
  60. ),
  61. 'teaser' => array(
  62. 'label' => t('Teaser'),
  63. 'custom settings' => FALSE,
  64. ),
  65. 'widget' => array(
  66. 'label' => t('Widget'),
  67. 'custom settings' => FALSE,
  68. ),
  69. ),
  70. // Disable Metatags (metatag) module's entity form additions.
  71. 'metatags' => FALSE,
  72. ),
  73. );
  74. return $return;
  75. }
  76. /**
  77. * Implements hook_field_extra_fields().
  78. */
  79. function feedback_field_extra_fields() {
  80. $extras['feedback']['feedback']['form']['help'] = array(
  81. 'label' => t('Help'),
  82. 'description' => t('Feedback submission guidelines'),
  83. 'weight' => -10,
  84. );
  85. $extras['feedback']['feedback']['form']['messages'] = array(
  86. 'label' => t('Entries'),
  87. 'description' => t('Existing feedback entries for the current page'),
  88. 'weight' => -5,
  89. );
  90. $extras['feedback']['feedback']['form']['message'] = array(
  91. 'label' => t('Message'),
  92. 'description' => t('Feedback message form text field'),
  93. 'weight' => 0,
  94. );
  95. $extras['feedback']['feedback']['display']['location'] = array(
  96. 'label' => t('Location'),
  97. 'description' => t('The URL of the page the message was submitted on'),
  98. 'weight' => -15,
  99. );
  100. $extras['feedback']['feedback']['display']['date'] = array(
  101. 'label' => t('Date'),
  102. 'description' => t('The submission date of the message'),
  103. 'weight' => -10,
  104. );
  105. $extras['feedback']['feedback']['display']['user'] = array(
  106. 'label' => t('User'),
  107. 'description' => t('The name of the user who submitted the message'),
  108. 'weight' => -5,
  109. );
  110. $extras['feedback']['feedback']['display']['message'] = array(
  111. 'label' => t('Message'),
  112. 'description' => t('The main feedback message'),
  113. 'weight' => 0,
  114. );
  115. return $extras;
  116. }
  117. /**
  118. * Entity uri callback.
  119. */
  120. function feedback_uri($entry) {
  121. return array(
  122. 'path' => 'admin/reports/feedback/' . $entry->fid,
  123. );
  124. }
  125. /**
  126. * Implements hook_permission().
  127. */
  128. function feedback_permission() {
  129. return array(
  130. 'access feedback form' => array(
  131. 'title' => t('Access feedback form'),
  132. 'description' => t('Submit feedback messages.'),
  133. ),
  134. 'view feedback messages' => array(
  135. 'title' => t('View feedback messages'),
  136. 'description' => t('View, process, and delete submitted feedback messages.'),
  137. ),
  138. 'administer feedback' => array(
  139. 'title' => t('Administer feedback settings'),
  140. ),
  141. );
  142. }
  143. /**
  144. * Implements hook_menu().
  145. */
  146. function feedback_menu() {
  147. $items['admin/reports/feedback'] = array(
  148. 'title' => 'Feedback messages',
  149. 'description' => 'View feedback messages.',
  150. 'page callback' => 'drupal_get_form',
  151. 'page arguments' => array('feedback_admin_view_form'),
  152. 'access arguments' => array('view feedback messages'),
  153. 'file' => 'feedback.admin.inc',
  154. );
  155. $items['admin/reports/feedback/%feedback'] = array(
  156. 'title' => 'Feedback entry',
  157. 'page callback' => 'feedback_view',
  158. 'page arguments' => array(3),
  159. 'access arguments' => array('view feedback messages'),
  160. 'file' => 'feedback.admin.inc',
  161. );
  162. $items['admin/reports/feedback/%feedback/view'] = array(
  163. 'title' => 'View',
  164. 'type' => MENU_DEFAULT_LOCAL_TASK,
  165. 'weight' => -10,
  166. );
  167. $items['admin/reports/feedback/%feedback/edit'] = array(
  168. 'title' => 'Edit',
  169. 'page callback' => 'drupal_get_form',
  170. 'page arguments' => array('feedback_entry_form', 3),
  171. 'access arguments' => array('view feedback messages'),
  172. 'type' => MENU_LOCAL_TASK,
  173. 'file' => 'feedback.admin.inc',
  174. );
  175. $items['admin/reports/feedback/%feedback/delete'] = array(
  176. 'title' => 'Delete feedback entry',
  177. 'page callback' => 'drupal_get_form',
  178. 'page arguments' => array('feedback_delete_confirm', 3),
  179. 'access arguments' => array('view feedback messages'),
  180. 'type' => MENU_CALLBACK,
  181. 'file' => 'feedback.admin.inc',
  182. );
  183. $items['admin/config/user-interface/feedback'] = array(
  184. 'title' => 'Feedback',
  185. 'description' => 'Administer feedback settings.',
  186. 'page callback' => 'drupal_get_form',
  187. 'page arguments' => array('feedback_admin_settings_form'),
  188. 'access arguments' => array('administer feedback'),
  189. 'file' => 'feedback.admin.inc',
  190. );
  191. $items['admin/config/user-interface/feedback/settings'] = array(
  192. 'title' => 'Settings',
  193. 'type' => MENU_DEFAULT_LOCAL_TASK,
  194. 'weight' => -10,
  195. );
  196. return $items;
  197. }
  198. /**
  199. * Implements hook_page_build().
  200. */
  201. function feedback_page_build(&$page) {
  202. if (user_access('access feedback form') && !feedback_match_path(variable_get('feedback_excluded_paths', 'admin/reports/feedback'))) {
  203. $page['page_bottom']['feedback'] = array(
  204. '#theme' => 'feedback_form_display',
  205. '#title' => t('Feedback'),
  206. '#content' => drupal_get_form('feedback_form'),
  207. );
  208. $path = drupal_get_path('module', 'feedback');
  209. $page['page_bottom']['feedback']['#attached']['css'][] = $path . '/feedback.css';
  210. $page['page_bottom']['feedback']['#attached']['js'][] = $path . '/feedback.js';
  211. }
  212. }
  213. /**
  214. * Check if the current path matches any pattern in a set of patterns.
  215. *
  216. * @param $patterns
  217. * String containing a set of patterns separated by \n, \r or \r\n.
  218. *
  219. * @return
  220. * Boolean value: TRUE if the current path or alias matches a pattern.
  221. */
  222. function feedback_match_path($patterns) {
  223. // Convert path to lowercase. This allows comparison of the same path
  224. // with different case. Ex: /Page, /page, /PAGE.
  225. $patterns = drupal_strtolower($patterns);
  226. // Convert the current path to lowercase.
  227. $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
  228. // Compare the lowercase internal and lowercase path alias (if any).
  229. $page_match = drupal_match_path($path, $patterns);
  230. if ($path != $_GET['q']) {
  231. $page_match = $page_match || drupal_match_path($_GET['q'], $patterns);
  232. }
  233. return $page_match;
  234. }
  235. /**
  236. * Form constructor for the feedback form.
  237. *
  238. * @see feedback_form_submit()
  239. * @ingroup forms
  240. */
  241. function feedback_form($form, &$form_state) {
  242. $form['#attributes']['class'] = array('feedback-form');
  243. // Store the path on which this form is displayed.
  244. if (!isset($form_state['inline']['location'])) {
  245. $form_state['inline']['location'] = $_GET['q'];
  246. }
  247. $form['location'] = array(
  248. '#type' => 'value',
  249. '#value' => $form_state['inline']['location'],
  250. );
  251. $form['help'] = array(
  252. '#prefix' => '<div class="feedback-help">',
  253. '#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.'),
  254. '#suffix' => '</div>',
  255. );
  256. if (user_access('view feedback messages')) {
  257. if (arg(0) != 'node') {
  258. $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location_masked' => feedback_mask_path($_GET['q'])));
  259. }
  260. else {
  261. $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location' => $_GET['q']));
  262. }
  263. if ($feedbacks) {
  264. form_load_include($form_state, 'inc', 'feedback', 'feedback.admin');
  265. $form['messages'] = array(
  266. '#prefix' => '<div class="feedback-messages">',
  267. '#suffix' => '</div>',
  268. );
  269. foreach ($feedbacks as $fid => $feedback) {
  270. $form['messages'][$fid]['#feedback'] = $feedback;
  271. $form['messages'][$fid]['submitted'] = array('#markup' => t('@feedback-author !feedback-date:', array('@feedback-author' => format_username($feedback), '!feedback-date' => format_date($feedback->timestamp, 'small'))));
  272. $form['messages'][$fid]['submitted']['#prefix'] = '<div class="feedback-submitted">';
  273. $form['messages'][$fid]['submitted']['#suffix'] = '</div>';
  274. $form['messages'][$fid]['body'] = feedback_build_content($feedback, 'widget');
  275. $form['messages'][$fid]['body']['#prefix'] = '<div class="feedback-body">';
  276. $form['messages'][$fid]['body']['#suffix'] = '</div>';
  277. }
  278. }
  279. }
  280. $form['message'] = array(
  281. '#type' => 'textarea',
  282. '#attributes' => array('class' => array('feedback-message')),
  283. '#cols' => 20,
  284. '#title' => t('Message'),
  285. '#required' => TRUE,
  286. '#wysiwyg' => FALSE,
  287. );
  288. $entry = new stdClass();
  289. field_attach_form('feedback', $entry, $form, $form_state);
  290. $form['actions'] = array(
  291. '#type' => 'actions',
  292. // Without clearfix, the AJAX throbber wraps in an ugly way.
  293. // @todo Patch #type actions in core?
  294. '#attributes' => array('class' => array('clearfix')),
  295. );
  296. $form['actions']['submit'] = array(
  297. '#type' => 'submit',
  298. '#value' => t('Send feedback'),
  299. '#id' => 'feedback-submit',
  300. '#ajax' => array(
  301. 'wrapper' => 'feedback-form',
  302. 'callback' => 'feedback_form_ajax_callback',
  303. 'progress' => array(
  304. 'type' => 'throbber',
  305. 'message' => '',
  306. ),
  307. ),
  308. );
  309. return $form;
  310. }
  311. /**
  312. * Form submission handler for feedback_form().
  313. */
  314. function feedback_form_submit($form, &$form_state) {
  315. $entry = new stdClass();
  316. entity_form_submit_build_entity('feedback', $entry, $form, $form_state);
  317. $entry->message = $form_state['values']['message'];
  318. $entry->location = $form_state['values']['location'];
  319. feedback_save($entry);
  320. drupal_set_message(t('Thanks for your feedback!'));
  321. }
  322. /**
  323. * AJAX callback for feedback_form() submissions.
  324. */
  325. function feedback_form_ajax_callback($form, &$form_state) {
  326. // If there was a form validation error, re-render the entire form.
  327. if (!$form_state['executed']) {
  328. return $form;
  329. }
  330. // Otherwise, return a fresh copy of the form, so the user may post additional
  331. // feedback.
  332. // Reset the static cache of drupal_html_id().
  333. // @see drupal_process_form()
  334. // @see drupal_html_id()
  335. $seen_ids = &drupal_static('drupal_html_id');
  336. $seen_ids = array();
  337. // Prevent the form from being processed again.
  338. // @see drupal_build_form()
  339. list($form, $new_form_state) = ajax_get_form();
  340. $new_form_state['input'] = array();
  341. drupal_process_form($form['#form_id'], $form, $new_form_state);
  342. // Return AJAX commands in order to output the special success message.
  343. // @see ajax_deliver()
  344. $build = array('#type' => 'ajax');
  345. $html = drupal_render($form);
  346. $build['#commands'][] = ajax_command_insert(NULL, $html);
  347. // A successful form submission normally means that there were no errors, so
  348. // we only render status messages.
  349. $messages = drupal_get_messages();
  350. $messages += array('status' => array());
  351. $messages = implode('<br />', $messages['status']);
  352. $html = '<div id="feedback-status-message">' . $messages . '</div>';
  353. $build['#commands'][] = ajax_command_append('#block-feedback-form', $html);
  354. return $build;
  355. }
  356. /**
  357. * Loads a feedback entry from the database.
  358. *
  359. * @param $fid
  360. * Integer specifying the feedback ID to load.
  361. *
  362. * @return
  363. * A loaded feedback entry object upon successful load, or FALSE if the entry
  364. * cannot be loaded.
  365. *
  366. * @see feedback_load_multiple()
  367. */
  368. function feedback_load($fid) {
  369. $entries = feedback_load_multiple(array($fid));
  370. return (isset($entries[$fid]) ? $entries[$fid] : FALSE);
  371. }
  372. /**
  373. * Loads feedback entries from the database.
  374. *
  375. * @param $fids
  376. * An array of feedback entry IDs.
  377. * @param $conditions
  378. * An associative array of conditions on the {feedback} table, where the keys
  379. * are the database fields and the values are the values those fields
  380. * must have.
  381. *
  382. * @return
  383. * An array of feedback entry objects indexed by fid.
  384. *
  385. * @see hook_feedback_load()
  386. * @see feedback_load()
  387. * @see entity_load()
  388. * @see EntityFieldQuery
  389. */
  390. function feedback_load_multiple($fids = array(), $conditions = array()) {
  391. return entity_load('feedback', $fids, $conditions);
  392. }
  393. /**
  394. * Saves changes to a feedback entry or adds a new feedback entry.
  395. *
  396. * @param $entry
  397. * The feedback entry object to modify or add. If $entry->fid is omitted, a
  398. * new entry will be added.
  399. *
  400. * @see hook_feedback_insert()
  401. * @see hook_feedback_update()
  402. */
  403. function feedback_save($entry) {
  404. global $user;
  405. // Load the stored entity, if any.
  406. if (!empty($entry->fid) && !isset($entry->original)) {
  407. $entry->original = entity_load_unchanged('feedback', $entry->fid);
  408. }
  409. field_attach_presave('feedback', $entry);
  410. // Allow modules to alter the feedback entry before saving.
  411. module_invoke_all('feedback_presave', $entry);
  412. module_invoke_all('entity_presave', $entry, 'feedback');
  413. if (empty($entry->fid)) {
  414. $entry->message = trim($entry->message);
  415. $defaults = array(
  416. 'uid' => $user->uid,
  417. 'location_masked' => feedback_mask_path($entry->location),
  418. 'url' => url($entry->location, array('absolute' => TRUE)),
  419. 'timestamp' => REQUEST_TIME,
  420. 'useragent' => $_SERVER['HTTP_USER_AGENT'],
  421. );
  422. foreach ($defaults as $key => $default) {
  423. if (!isset($entry->$key)) {
  424. $entry->$key = $default;
  425. }
  426. }
  427. $status = drupal_write_record('feedback', $entry);
  428. field_attach_insert('feedback', $entry);
  429. module_invoke_all('feedback_insert', $entry);
  430. module_invoke_all('entity_insert', $entry, 'feedback');
  431. }
  432. else {
  433. $status = drupal_write_record('feedback', $entry, 'fid');
  434. field_attach_update('feedback', $entry);
  435. module_invoke_all('feedback_update', $entry);
  436. module_invoke_all('entity_update', $entry, 'feedback');
  437. }
  438. unset($entry->original);
  439. return $status;
  440. }
  441. /**
  442. * Deletes a feedback entry.
  443. *
  444. * @param $fid
  445. * A feedback entry ID.
  446. */
  447. function feedback_delete($fid) {
  448. feedback_delete_multiple(array($fid));
  449. }
  450. /**
  451. * Deletes multiple feedback entries.
  452. *
  453. * @param $fids
  454. * An array of feedback entry IDs.
  455. */
  456. function feedback_delete_multiple($fids) {
  457. if (!empty($fids)) {
  458. $entries = feedback_load_multiple($fids);
  459. foreach ($entries as $fid => $entry) {
  460. field_attach_delete('feedback', $entry);
  461. module_invoke_all('feedback_delete', $entry);
  462. module_invoke_all('entity_delete', $entry, 'feedback');
  463. }
  464. db_delete('feedback')
  465. ->condition('fid', $fids, 'IN')
  466. ->execute();
  467. }
  468. }
  469. /**
  470. * 'Mask' a path, i.e. replace all numeric arguments in a path with '%' placeholders.
  471. *
  472. * Please note that only numeric arguments with a preceding slash will be
  473. * replaced.
  474. *
  475. * @param $path
  476. * An internal Drupal path, f.e. 'user/123/edit'.
  477. * @return
  478. * A 'masked' path, for above example 'user/%/edit'.
  479. *
  480. * @todo Use the untranslated patch of menu_get_item() instead.
  481. */
  482. function feedback_mask_path($path) {
  483. return preg_replace('@/\d+@', '/%', $path);
  484. }
  485. /**
  486. * Implements hook_user_cancel().
  487. */
  488. function feedback_user_cancel($edit, $account, $method) {
  489. switch ($method) {
  490. case 'user_cancel_reassign':
  491. db_update('feedback')
  492. ->fields(array('uid' => 0))
  493. ->condition('uid', $account->uid)
  494. ->execute();
  495. break;
  496. }
  497. }
  498. /**
  499. * Implements hook_user_delete().
  500. */
  501. function feedback_user_delete($account) {
  502. $fids = db_query('SELECT fid FROM {feedback} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
  503. feedback_delete_multiple($fids);
  504. }
  505. /**
  506. * Implements hook_action_info().
  507. */
  508. function feedback_action_info() {
  509. return array(
  510. 'feedback_process_action' => array(
  511. 'label' => t('Process entry'),
  512. 'type' => 'feedback',
  513. 'configurable' => FALSE,
  514. 'behavior' => array('changes_property'),
  515. 'triggers' => array('feedback_insert', 'feedback_update'),
  516. ),
  517. 'feedback_open_action' => array(
  518. 'label' => t('Open entry'),
  519. 'type' => 'feedback',
  520. 'configurable' => FALSE,
  521. 'behavior' => array('changes_property'),
  522. 'triggers' => array('feedback_insert', 'feedback_update'),
  523. ),
  524. 'feedback_delete_action' => array(
  525. 'label' => t('Delete entry'),
  526. 'type' => 'feedback',
  527. 'configurable' => FALSE,
  528. 'triggers' => array('feedback_insert', 'feedback_update'),
  529. ),
  530. 'feedback_send_email_action' => array(
  531. 'label' => t('Send e-mail of feedback'),
  532. 'type' => 'feedback',
  533. 'configurable' => TRUE,
  534. 'triggers' => array('feedback_insert', 'feedback_update'),
  535. ),
  536. );
  537. }
  538. /**
  539. * Implements hook_trigger_info().
  540. */
  541. function feedback_trigger_info() {
  542. return array(
  543. 'feedback' => array(
  544. 'feedback_insert' => array(
  545. 'label' => t('New feedback is added.'),
  546. ),
  547. 'feedback_update' => array(
  548. 'label' => t('Feedback is marked processed or open.'),
  549. ),
  550. ),
  551. );
  552. }
  553. /**
  554. * Implements hook_feedback_insert().
  555. */
  556. function feedback_feedback_insert($entry) {
  557. $aids = trigger_get_assigned_actions('feedback_insert');
  558. if (!$aids) {
  559. return;
  560. }
  561. $context = array(
  562. 'group' => 'feedback',
  563. 'hook' => 'feedback_insert',
  564. );
  565. foreach ($aids as $aid => $info) {
  566. actions_do($aid, $entry, $context);
  567. }
  568. }
  569. /**
  570. * Implements hook_feedback_update().
  571. */
  572. function feedback_feedback_update($entry) {
  573. $aids = trigger_get_assigned_actions('feedback_update');
  574. if (!$aids) {
  575. return;
  576. }
  577. $context = array(
  578. 'group' => 'feedback',
  579. 'hook' => 'feedback_update',
  580. );
  581. foreach ($aids as $aid => $info) {
  582. actions_do($aid, $entry, $context);
  583. }
  584. }
  585. /**
  586. * Sets the status of an entry to processed.
  587. *
  588. * @ingroup actions
  589. */
  590. function feedback_process_action($entry, $context) {
  591. $entry->status = FEEDBACK_PROCESSED;
  592. drupal_write_record('feedback', $entry, 'fid');
  593. }
  594. /**
  595. * Sets the status of an entry to open.
  596. *
  597. * @ingroup actions
  598. */
  599. function feedback_open_action($entry, $context) {
  600. $entry->status = FEEDBACK_OPEN;
  601. drupal_write_record('feedback', $entry, 'fid');
  602. }
  603. /**
  604. * Deletes a feedback entry.
  605. *
  606. * @ingroup actions
  607. */
  608. function feedback_delete_action($entry, $context) {
  609. feedback_delete($entry->fid);
  610. }
  611. /**
  612. * Return a form definition so the Feedback send email action can be configured.
  613. *
  614. * @param $context
  615. * Default values (if we are editing an existing action instance).
  616. * @return
  617. * Form definition.
  618. */
  619. function feedback_send_email_action_form($context = array()) {
  620. // Set default values for form.
  621. $context += array(
  622. 'recipients' => '',
  623. 'subject' => '',
  624. 'message' => '',
  625. );
  626. $form['recipients'] = array(
  627. '#type' => 'textarea',
  628. '#title' => t('Recipients'),
  629. '#default_value' => $context['recipients'],
  630. '#description' => t("Example: 'webmaster@example.com' or 'dev@example.com,support@example.com'. To specify multiple recipients, separate each e-mail address with a comma."),
  631. '#required' => TRUE,
  632. );
  633. $form['subject'] = array(
  634. '#type' => 'textfield',
  635. '#title' => t('Subject'),
  636. '#default_value' => $context['subject'],
  637. '#maxlength' => '254',
  638. '#description' => t('The subject of the message.'),
  639. '#required' => TRUE,
  640. );
  641. $form['message'] = array(
  642. '#type' => 'textarea',
  643. '#title' => t('Message'),
  644. '#default_value' => $context['message'],
  645. '#cols' => '80',
  646. '#rows' => '20',
  647. '#description' => t('The message that should be sent. You may include the following variables: !uid, !username, !usermail, !useragent (of the user who gave the feedback), !site_name, !status, !message, !url, !date.'),
  648. '#required' => TRUE,
  649. );
  650. return $form;
  651. }
  652. /**
  653. * Validate the send e-mail action form submission.
  654. */
  655. function feedback_send_email_action_validate($form, &$form_state) {
  656. if (empty($form_state['values']['recipients'])) {
  657. form_set_error('recipients', t('You must enter one or more recipients.'));
  658. }
  659. else {
  660. $recipients = explode(',', $form_state['values']['recipients']);
  661. foreach ($recipients as $recipient) {
  662. if (!valid_email_address(trim($recipient))) {
  663. form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
  664. }
  665. }
  666. }
  667. }
  668. /**
  669. * Process the send e-mail action form submission.
  670. */
  671. function feedback_send_email_action_submit($form, $form_state) {
  672. // Process the HTML form to store configuration. The keyed array that
  673. // we return will be serialized to the database.
  674. $params = array(
  675. 'recipients' => $form_state['values']['recipients'],
  676. 'subject' => $form_state['values']['subject'],
  677. 'message' => $form_state['values']['message'],
  678. );
  679. return $params;
  680. }
  681. /**
  682. * Implements the feedback send e-mail action.
  683. */
  684. function feedback_send_email_action($entry, $context) {
  685. $account = user_load($entry->uid);
  686. $from = variable_get('site_name', 'Drupal') . ' <' . variable_get('site_mail', '') . '>';
  687. $params = array('entry' => $entry, 'account' => $account, 'context' => $context);
  688. // Send the e-mail to the recipients using the site default language.
  689. drupal_mail('feedback', 'send_email_action', $context['recipients'], language_default(), $params, $from);
  690. watchdog('feedback', 'Feedback information sent to %recipients', array('%recipients' => $context['recipients']));
  691. }
  692. /**
  693. * Implements hook_mail().
  694. */
  695. function feedback_mail($key, &$message, $params) {
  696. $language = $message['language'];
  697. $entry = $params['entry'];
  698. $account = $params['account'];
  699. $context = $params['context'];
  700. $variables = array(
  701. '!site_name' => variable_get('site_name', 'Drupal'),
  702. '!uid' => $account->uid,
  703. '!username' => $account->name ? $account->name : t('Anonymous'),
  704. '!usermail' => $account->mail ? $account->mail : t('unknown'),
  705. '!status' => $entry->status ? t('Processed') : t('Open'),
  706. '!message' => $entry->message,
  707. '!url' => url($entry->location, array('absolute' => TRUE, 'language' => $language)),
  708. '!useragent' => $entry->useragent,
  709. '!date' => format_date($entry->timestamp, 'small', '', NULL, $language->language),
  710. );
  711. $subject = strtr($context['subject'], $variables);
  712. $body = strtr($context['message'], $variables);
  713. $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
  714. $message['body'][] = drupal_html_to_text($body);
  715. }
  716. /**
  717. * Implements hook_mollom_form_list().
  718. */
  719. function feedback_mollom_form_list() {
  720. $forms['feedback_form'] = array(
  721. 'title' => t('Feedback form'),
  722. 'entity' => 'feedback',
  723. 'bundle' => 'feedback',
  724. 'entity delete multiple callback' => 'feedback_delete_multiple',
  725. 'delete form' => 'feedback_delete_confirm',
  726. 'delete form file' => array(
  727. 'name' => 'feedback.admin',
  728. ),
  729. 'report access' => array('view feedback messages'),
  730. );
  731. return $forms;
  732. }
  733. /**
  734. * Implements hook_mollom_form_info().
  735. */
  736. function feedback_mollom_form_info($form_id) {
  737. $form_info = array(
  738. 'mode' => MOLLOM_MODE_ANALYSIS,
  739. 'bypass access' => array('administer feedback'),
  740. 'elements' => array(
  741. 'message' => t('Message'),
  742. ),
  743. );
  744. mollom_form_info_add_fields($form_info, 'feedback', 'feedback');
  745. return $form_info;
  746. }
  747. /**
  748. * Implements hook_views_api();
  749. */
  750. function feedback_views_api() {
  751. return array(
  752. 'api' => 3.0,
  753. 'path' => drupal_get_path('module', 'feedback') . '/views',
  754. );
  755. }