Explorar el Código

upadted feedback module
didn't repatched it for email notification since rules hooks semmes to be added to the module
added the old patch for memory

Bachir Soussi Chiadmi hace 9 años
padre
commit
0cd6215a32

+ 1305 - 0
sites/all/modules/contrib/users/feedback/0001-patched-for-email-sending-on-each-feedback-creation-.patch

@@ -0,0 +1,1305 @@
+From 235e57d8e944175ddfd7907598ada29c5c2ebb3d Mon Sep 17 00:00:00 2001
+From: Bachir Soussi Chiadmi <bachir@g-u-i.net>
+Date: Sat, 12 Oct 2013 13:27:26 +0200
+Subject: [PATCH] patched for email sending on each feedback creation
+ https://drupal.org/node/353548#comment-7130746
+
+---
+ feedback-353548-45.patch | 338 +++++++++++++++++++++++++++
+ feedback.module          | 229 ++++++++++++++++++
+ feedback.module.orig     | 593 +++++++++++++++++++++++++++++++++++++++++++++++
+ tests/feedback.test      |  75 +++++-
+ 4 files changed, 1231 insertions(+), 4 deletions(-)
+ create mode 100644 feedback-353548-45.patch
+ mode change 100755 => 100644 feedback.module
+ create mode 100755 feedback.module.orig
+ mode change 100755 => 100644 tests/feedback.test
+
+diff --git a/feedback-353548-45.patch b/feedback-353548-45.patch
+new file mode 100644
+index 0000000..999e88a
+--- /dev/null
++++ b/feedback-353548-45.patch
+@@ -0,0 +1,338 @@
++diff --git a/feedback.module b/feedback.module
++index 9763575..ef5b24a 100644
++--- a/feedback.module
+++++ b/feedback.module
++@@ -534,6 +534,235 @@ function feedback_user_delete($account) {
++ }
++ 
++ /**
+++ * Implements hook_action_info().
+++ */
+++function feedback_action_info() {
+++  return array(
+++    'feedback_process_action' => array(
+++      'label' => t('Process entry'),
+++      'type' => 'feedback',
+++      'configurable' => FALSE,
+++      'behavior' => array('changes_property'),
+++      'triggers' => array('feedback_insert', 'feedback_update'),
+++    ),
+++    'feedback_open_action' => array(
+++      'label' => t('Open entry'),
+++      'type' => 'feedback',
+++      'configurable' => FALSE,
+++      'behavior' => array('changes_property'),
+++      'triggers' => array('feedback_insert', 'feedback_update'),
+++    ),
+++    'feedback_delete_action' => array(
+++      'label' => t('Delete entry'),
+++      'type' => 'feedback',
+++      'configurable' => FALSE,
+++      'triggers' => array('feedback_insert', 'feedback_update'),
+++    ),
+++    'feedback_send_email_action' => array(
+++      'label' => t('Send e-mail of feedback'),
+++      'type' => 'feedback',
+++      'configurable' => TRUE,
+++      'triggers' => array('feedback_insert', 'feedback_update'),
+++    ),
+++  );
+++}
+++
+++/**
+++* Implements hook_trigger_info().
+++*/
+++function feedback_trigger_info() {
+++  return array(
+++    'feedback' => array(
+++      'feedback_insert' => array(
+++        'label' => t('New feedback is added.'),
+++      ),
+++      'feedback_update' => array(
+++        'label' => t('Feedback is marked processed or open.'),
+++      ),
+++    ),
+++  );
+++}
+++
+++/**
+++ * Implements hook_feedback_insert().
+++ */
+++function feedback_feedback_insert($entry) {
+++  $aids = trigger_get_assigned_actions('feedback_insert');
+++  if (!$aids) {
+++    return;
+++  }
+++
+++  $context = array(
+++    'group' => 'feedback',
+++    'hook' => 'feedback_insert',
+++  );
+++
+++  foreach ($aids as $aid => $info) {
+++    actions_do($aid, $entry, $context);
+++  }
+++}
+++
+++/**
+++ * Implements hook_feedback_update().
+++ */
+++function feedback_feedback_update($entry) {
+++  $aids = trigger_get_assigned_actions('feedback_update');
+++  if (!$aids) {
+++    return;
+++  }
+++
+++  $context = array(
+++    'group' => 'feedback',
+++    'hook' => 'feedback_update',
+++  );
+++
+++  foreach ($aids as $aid => $info) {
+++    actions_do($aid, $entry, $context);
+++  }
+++}
+++
+++/**
+++ * Sets the status of an entry to processed.
+++ *
+++ * @ingroup actions
+++ */
+++function feedback_process_action($entry, $context) {
+++  $entry->status = FEEDBACK_PROCESSED;
+++  drupal_write_record('feedback', $entry, 'fid');
+++}
+++
+++/**
+++ * Sets the status of an entry to open.
+++ *
+++ * @ingroup actions
+++ */
+++function feedback_open_action($entry, $context) {
+++  $entry->status = FEEDBACK_OPEN;
+++  drupal_write_record('feedback', $entry, 'fid');
+++}
+++
+++/**
+++ * Deletes a feedback entry.
+++ *
+++ * @ingroup actions
+++ */
+++function feedback_delete_action($entry, $context) {
+++  feedback_delete($entry->fid);
+++}
+++
+++/**
+++ * Return a form definition so the Feedback send email action can be configured.
+++ *
+++ * @param $context
+++ *   Default values (if we are editing an existing action instance).
+++ * @return
+++ *   Form definition.
+++ */
+++function feedback_send_email_action_form($context = array()) {
+++  // Set default values for form.
+++  $context += array(
+++   'recipients' => '',
+++   'subject' => '',
+++   'message' => '',
+++  );
+++
+++  $form['recipients'] = array(
+++    '#type' => 'textarea',
+++    '#title' => t('Recipients'),
+++    '#default_value' => $context['recipients'],
+++    '#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."),
+++    '#required' => TRUE,
+++  );
+++  $form['subject'] = array(
+++    '#type' => 'textfield',
+++    '#title' => t('Subject'),
+++    '#default_value' => $context['subject'],
+++    '#maxlength' => '254',
+++    '#description' => t('The subject of the message.'),
+++    '#required' => TRUE,
+++  );
+++  $form['message'] = array(
+++    '#type' => 'textarea',
+++    '#title' => t('Message'),
+++    '#default_value' => $context['message'],
+++    '#cols' => '80',
+++    '#rows' => '20',
+++    '#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.'),
+++    '#required' => TRUE,
+++  );
+++  return $form;
+++}
+++
+++/**
+++ * Validate the send e-mail action form submission.
+++ */
+++function feedback_send_email_action_validate($form, &$form_state) {
+++  if (empty($form_state['values']['recipients'])) {
+++    form_set_error('recipients', t('You must enter one or more recipients.'));
+++  }
+++  else {
+++    $recipients = explode(',', $form_state['values']['recipients']);
+++    foreach ($recipients as $recipient) {
+++      if (!valid_email_address(trim($recipient))) {
+++        form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
+++      }
+++    }
+++  }
+++}
+++
+++/**
+++ * Process the send e-mail action form submission.
+++ */
+++function feedback_send_email_action_submit($form, $form_state) {
+++  // Process the HTML form to store configuration. The keyed array that
+++  // we return will be serialized to the database.
+++  $params = array(
+++    'recipients' => $form_state['values']['recipients'],
+++    'subject'    => $form_state['values']['subject'],
+++    'message'    => $form_state['values']['message'],
+++  );
+++  return $params;
+++}
+++
+++/**
+++ * Implements the feedback send e-mail action.
+++ */
+++function feedback_send_email_action($entry, $context) {
+++  $account = user_load($entry->uid);
+++  $from = variable_get('site_name', 'Drupal') . ' <' . variable_get('site_mail', '') . '>';
+++  $params = array('entry' => $entry, 'account' => $account, 'context' => $context);
+++  // Send the e-mail to the recipients using the site default language.
+++  drupal_mail('feedback', 'send_email_action', $context['recipients'], language_default(), $params, $from);
+++  watchdog('feedback', 'Feedback information sent to %recipients', array('%recipients' => $context['recipients']));
+++}
+++
+++/**
+++ * Implements hook_mail().
+++ */
+++function feedback_mail($key, &$message, $params) {
+++  $language = $message['language'];
+++  $entry = $params['entry'];
+++  $account = $params['account'];
+++  $context = $params['context'];
+++  $variables = array(
+++    '!site_name' => variable_get('site_name', 'Drupal'),
+++    '!uid' => $account->uid,
+++    '!username' => $account->name ? $account->name : t('Anonymous'),
+++    '!usermail' => $account->mail ? $account->mail : t('unknown'),
+++    '!status' => $entry->status ? t('Processed') : t('Open'),
+++    '!message' => $entry->message,
+++    '!url' => url($entry->location, array('absolute' => TRUE, 'language' => $language)),
+++    '!useragent' => $entry->useragent,
+++    '!date' => format_date($entry->timestamp, 'small', '', NULL, $language->language),
+++  );
+++  $subject = strtr($context['subject'], $variables);
+++  $body = strtr($context['message'], $variables);
+++  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
+++  $message['body'][] = drupal_html_to_text($body);
+++}
+++
+++
+++/**
++  * Implements hook_mollom_form_list().
++  */
++ function feedback_mollom_form_list() {
++diff --git a/tests/feedback.test b/tests/feedback.test
++index 4d4244c..09ce922 100644
++--- a/tests/feedback.test
+++++ b/tests/feedback.test
++@@ -20,8 +20,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
++   }
++ 
++   function setUp() {
++-    // @todo Remove soft-dependency on Block.
++-    parent::setUp(array('block', 'feedback'));
+++    parent::setUp(array('feedback', 'trigger'));
++ 
++     $this->admin_user = $this->drupalCreateUser(array('access feedback form', 'view feedback messages', 'administer feedback'));
++     $this->web_user = $this->drupalCreateUser(array('access feedback form'));
++@@ -49,7 +48,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
++     $edit = array(
++       'feedback-messages[0][1]' => TRUE,
++     );
++-    $this->drupalPost(NULL, $edit, t('Submit'));
+++    $this->drupalPost(NULL, $edit, t('Update'));
++     $this->assertFieldByName('feedback-messages[1][1]', 1, t('Processed message found.'));
++   }
++ 
++@@ -89,4 +88,72 @@ class FeedbackTestCase extends DrupalWebTestCase {
++     $this->assertNoLinkByHref('admin/reports/feedback/1/delete');
++     $this->assertNoRaw(check_plain($message), t('Message not found.'));
++   }
++-}
+++
+++  /**
+++   * Test the feedback triggers and actions.
+++   */
+++  function testFeedbackEmailAction() {
+++    $test_user = $this->drupalCreateUser(array('administer actions', 'administer feedback', 'access feedback form'));
+++    $this->drupalLogin($test_user);
+++    $this->assignFeedbackEmailAction('feedback_insert', $test_user->mail);
+++
+++    // Insert a feedback entry.
+++    $message = $this->randomString();
+++    $edit = array(
+++      'message' => $message,
+++    );
+++    $this->drupalPost('node', $edit, t('Send feedback'));
+++    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $message);
+++
+++    $this->assignFeedbackEmailAction('feedback_update', $test_user->mail);
+++
+++    // Update a feedback entry.
+++    $fid = db_query("SELECT fid FROM {feedback} LIMIT 0,1")->fetchField();
+++    $entry = feedback_load($fid);
+++    feedback_save($entry);
+++    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $entry->message);
+++  }
+++
+++  /**
+++   * Assigns a system_send_email_action to the passed-in trigger.
+++   *
+++   * @param $trigger
+++   *   For example, 'user_login'
+++   */
+++  function assignFeedbackEmailAction($trigger, $mail) {
+++    $form_name = "trigger_{$trigger}_assign_form";
+++    $form_html_id = strtr($form_name, '_', '-');
+++
+++    $edit = array(
+++      'actions_label' => $trigger . "_feedback_send_email_action",
+++      'recipients' => $mail,
+++      'subject' => $this->randomName(),
+++      'message' => '!message',
+++    );
+++
+++    $hash = drupal_hash_base64('feedback_send_email_action');
+++    $this->drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
+++    $this->assertText(t('The action has been successfully saved.'));
+++
+++    // Now we have to find out the action ID of what we created.
+++    $aid = db_query('SELECT aid FROM {actions} WHERE callback = :callback AND label = :label', array(':callback' => 'feedback_send_email_action', ':label' => $edit['actions_label']))->fetchField();
+++
+++    $edit = array('aid' => drupal_hash_base64($aid));
+++    $this->drupalPost('admin/structure/trigger/feedback', $edit, t('Assign'), array(), array(), $form_html_id);
+++  }
+++
+++
+++  /**
+++   * Asserts correct token replacement for the given trigger and account.
+++   *
+++   * @param $account
+++   *   The user account which triggered the action.
+++   * @param $email_depth
+++   *   Number of emails to scan, starting with most recent.
+++   */
+++  function assertFeedbackEmailTokenReplacement($mail, $message, $email_depth = 1) {
+++    $this->verboseEmail($email_depth);
+++    $this->assertMailString('body', $message, $email_depth);
+++    $this->assertMail('to', $mail, t('Mail sent to correct destination'));
+++  }
+++}
++\ No newline at end of file
+diff --git a/feedback.module b/feedback.module
+old mode 100755
+new mode 100644
+index a4acfc0..fef1eda
+--- a/feedback.module
++++ b/feedback.module
+@@ -550,6 +550,235 @@ function feedback_user_delete($account) {
+ }
+ 
+ /**
++ * Implements hook_action_info().
++ */
++function feedback_action_info() {
++  return array(
++    'feedback_process_action' => array(
++      'label' => t('Process entry'),
++      'type' => 'feedback',
++      'configurable' => FALSE,
++      'behavior' => array('changes_property'),
++      'triggers' => array('feedback_insert', 'feedback_update'),
++    ),
++    'feedback_open_action' => array(
++      'label' => t('Open entry'),
++      'type' => 'feedback',
++      'configurable' => FALSE,
++      'behavior' => array('changes_property'),
++      'triggers' => array('feedback_insert', 'feedback_update'),
++    ),
++    'feedback_delete_action' => array(
++      'label' => t('Delete entry'),
++      'type' => 'feedback',
++      'configurable' => FALSE,
++      'triggers' => array('feedback_insert', 'feedback_update'),
++    ),
++    'feedback_send_email_action' => array(
++      'label' => t('Send e-mail of feedback'),
++      'type' => 'feedback',
++      'configurable' => TRUE,
++      'triggers' => array('feedback_insert', 'feedback_update'),
++    ),
++  );
++}
++
++/**
++* Implements hook_trigger_info().
++*/
++function feedback_trigger_info() {
++  return array(
++    'feedback' => array(
++      'feedback_insert' => array(
++        'label' => t('New feedback is added.'),
++      ),
++      'feedback_update' => array(
++        'label' => t('Feedback is marked processed or open.'),
++      ),
++    ),
++  );
++}
++
++/**
++ * Implements hook_feedback_insert().
++ */
++function feedback_feedback_insert($entry) {
++  $aids = trigger_get_assigned_actions('feedback_insert');
++  if (!$aids) {
++    return;
++  }
++
++  $context = array(
++    'group' => 'feedback',
++    'hook' => 'feedback_insert',
++  );
++
++  foreach ($aids as $aid => $info) {
++    actions_do($aid, $entry, $context);
++  }
++}
++
++/**
++ * Implements hook_feedback_update().
++ */
++function feedback_feedback_update($entry) {
++  $aids = trigger_get_assigned_actions('feedback_update');
++  if (!$aids) {
++    return;
++  }
++
++  $context = array(
++    'group' => 'feedback',
++    'hook' => 'feedback_update',
++  );
++
++  foreach ($aids as $aid => $info) {
++    actions_do($aid, $entry, $context);
++  }
++}
++
++/**
++ * Sets the status of an entry to processed.
++ *
++ * @ingroup actions
++ */
++function feedback_process_action($entry, $context) {
++  $entry->status = FEEDBACK_PROCESSED;
++  drupal_write_record('feedback', $entry, 'fid');
++}
++
++/**
++ * Sets the status of an entry to open.
++ *
++ * @ingroup actions
++ */
++function feedback_open_action($entry, $context) {
++  $entry->status = FEEDBACK_OPEN;
++  drupal_write_record('feedback', $entry, 'fid');
++}
++
++/**
++ * Deletes a feedback entry.
++ *
++ * @ingroup actions
++ */
++function feedback_delete_action($entry, $context) {
++  feedback_delete($entry->fid);
++}
++
++/**
++ * Return a form definition so the Feedback send email action can be configured.
++ *
++ * @param $context
++ *   Default values (if we are editing an existing action instance).
++ * @return
++ *   Form definition.
++ */
++function feedback_send_email_action_form($context = array()) {
++  // Set default values for form.
++  $context += array(
++   'recipients' => '',
++   'subject' => '',
++   'message' => '',
++  );
++
++  $form['recipients'] = array(
++    '#type' => 'textarea',
++    '#title' => t('Recipients'),
++    '#default_value' => $context['recipients'],
++    '#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."),
++    '#required' => TRUE,
++  );
++  $form['subject'] = array(
++    '#type' => 'textfield',
++    '#title' => t('Subject'),
++    '#default_value' => $context['subject'],
++    '#maxlength' => '254',
++    '#description' => t('The subject of the message.'),
++    '#required' => TRUE,
++  );
++  $form['message'] = array(
++    '#type' => 'textarea',
++    '#title' => t('Message'),
++    '#default_value' => $context['message'],
++    '#cols' => '80',
++    '#rows' => '20',
++    '#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.'),
++    '#required' => TRUE,
++  );
++  return $form;
++}
++
++/**
++ * Validate the send e-mail action form submission.
++ */
++function feedback_send_email_action_validate($form, &$form_state) {
++  if (empty($form_state['values']['recipients'])) {
++    form_set_error('recipients', t('You must enter one or more recipients.'));
++  }
++  else {
++    $recipients = explode(',', $form_state['values']['recipients']);
++    foreach ($recipients as $recipient) {
++      if (!valid_email_address(trim($recipient))) {
++        form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
++      }
++    }
++  }
++}
++
++/**
++ * Process the send e-mail action form submission.
++ */
++function feedback_send_email_action_submit($form, $form_state) {
++  // Process the HTML form to store configuration. The keyed array that
++  // we return will be serialized to the database.
++  $params = array(
++    'recipients' => $form_state['values']['recipients'],
++    'subject'    => $form_state['values']['subject'],
++    'message'    => $form_state['values']['message'],
++  );
++  return $params;
++}
++
++/**
++ * Implements the feedback send e-mail action.
++ */
++function feedback_send_email_action($entry, $context) {
++  $account = user_load($entry->uid);
++  $from = variable_get('site_name', 'Drupal') . ' <' . variable_get('site_mail', '') . '>';
++  $params = array('entry' => $entry, 'account' => $account, 'context' => $context);
++  // Send the e-mail to the recipients using the site default language.
++  drupal_mail('feedback', 'send_email_action', $context['recipients'], language_default(), $params, $from);
++  watchdog('feedback', 'Feedback information sent to %recipients', array('%recipients' => $context['recipients']));
++}
++
++/**
++ * Implements hook_mail().
++ */
++function feedback_mail($key, &$message, $params) {
++  $language = $message['language'];
++  $entry = $params['entry'];
++  $account = $params['account'];
++  $context = $params['context'];
++  $variables = array(
++    '!site_name' => variable_get('site_name', 'Drupal'),
++    '!uid' => $account->uid,
++    '!username' => $account->name ? $account->name : t('Anonymous'),
++    '!usermail' => $account->mail ? $account->mail : t('unknown'),
++    '!status' => $entry->status ? t('Processed') : t('Open'),
++    '!message' => $entry->message,
++    '!url' => url($entry->location, array('absolute' => TRUE, 'language' => $language)),
++    '!useragent' => $entry->useragent,
++    '!date' => format_date($entry->timestamp, 'small', '', NULL, $language->language),
++  );
++  $subject = strtr($context['subject'], $variables);
++  $body = strtr($context['message'], $variables);
++  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
++  $message['body'][] = drupal_html_to_text($body);
++}
++
++
++/**
+  * Implements hook_mollom_form_list().
+  */
+ function feedback_mollom_form_list() {
+diff --git a/feedback.module.orig b/feedback.module.orig
+new file mode 100755
+index 0000000..a4acfc0
+--- /dev/null
++++ b/feedback.module.orig
+@@ -0,0 +1,593 @@
++<?php
++
++/**
++ * @file
++ * Allows site visitors and users to report issues about this site.
++ */
++
++/**
++ * Open state (unprocessed) for feedback entries.
++ */
++define('FEEDBACK_OPEN', 0);
++
++/**
++ * Processed state for feedback entries.
++ */
++define('FEEDBACK_PROCESSED', 1);
++
++/**
++ * Implements hook_theme().
++ */
++function feedback_theme() {
++  return array(
++    'feedback_admin_view_form' => array(
++      'render element' => 'form',
++    ),
++    'feedback_entry' => array(
++      'render element' => 'elements',
++      'template' => 'feedback-entry',
++      'file' => 'feedback.admin.inc',
++    ),
++    'feedback_form_display' => array(
++      'template' => 'feedback-form-display',
++      'variables' => array('title' => NULL, 'content' => NULL),
++    ),
++  );
++}
++
++/**
++ * Implements hook_entity_info().
++ */
++function feedback_entity_info() {
++  $return = array(
++    'feedback' => array(
++      'label' => t('Feedback'),
++      'controller class' => 'FeedbackController',
++      'base table' => 'feedback',
++      'uri callback' => 'feedback_uri',
++      'fieldable' => TRUE,
++      'entity keys' => array(
++        'id' => 'fid',
++      ),
++      'bundles' => array(
++        'feedback' => array(
++          'label' => t('Feedback'),
++          'admin' => array(
++            'path' => 'admin/config/user-interface/feedback',
++            'access arguments' => array('administer feedback'),
++          ),
++        ),
++      ),
++      'view modes' => array(
++        'full' => array(
++          'label' => t('Full feedback entry'),
++          'custom settings' => FALSE,
++        ),
++        'teaser' => array(
++          'label' => t('Teaser'),
++          'custom settings' => FALSE,
++        ),
++        'widget' => array(
++          'label' => t('Widget'),
++          'custom settings' => FALSE,
++        ),
++      ),
++      // Disable Metatags (metatag) module's entity form additions.
++      'metatags' => FALSE,
++    ),
++  );
++
++  return $return;
++}
++
++/**
++ * Implements hook_field_extra_fields().
++ */
++function feedback_field_extra_fields() {
++  $extras['feedback']['feedback']['form']['help'] = array(
++    'label' => t('Help'),
++    'description' => t('Feedback submission guidelines'),
++    'weight' => -10,
++  );
++  $extras['feedback']['feedback']['form']['messages'] = array(
++    'label' => t('Entries'),
++    'description' => t('Existing feedback entries for the current page'),
++    'weight' => -5,
++  );
++  $extras['feedback']['feedback']['form']['message'] = array(
++    'label' => t('Message'),
++    'description' => t('Feedback message form text field'),
++    'weight' => 0,
++  );
++
++  $extras['feedback']['feedback']['display']['location'] = array(
++    'label' => t('Location'),
++    'description' => t('The URL of the page the message was submitted on'),
++    'weight' => -15,
++  );
++  $extras['feedback']['feedback']['display']['date'] = array(
++    'label' => t('Date'),
++    'description' => t('The submission date of the message'),
++    'weight' => -10,
++  );
++  $extras['feedback']['feedback']['display']['user'] = array(
++    'label' => t('User'),
++    'description' => t('The name of the user who submitted the message'),
++    'weight' => -5,
++  );
++  $extras['feedback']['feedback']['display']['message'] = array(
++    'label' => t('Message'),
++    'description' => t('The main feedback message'),
++    'weight' => 0,
++  );
++  return $extras;
++}
++
++/**
++ * Entity uri callback.
++ */
++function feedback_uri($entry) {
++  return array(
++    'path' => 'admin/reports/feedback/' . $entry->fid,
++  );
++}
++
++/**
++ * Implements hook_permission().
++ */
++function feedback_permission() {
++  return array(
++    'access feedback form' => array(
++      'title' => t('Access feedback form'),
++      'description' => t('Submit feedback messages.'),
++    ),
++    'view feedback messages' => array(
++      'title' => t('View feedback messages'),
++      'description' => t('View, process, and delete submitted feedback messages.'),
++    ),
++    'administer feedback' => array(
++      'title' => t('Administer feedback settings'),
++    ),
++  );
++}
++
++/**
++ * Implements hook_menu().
++ */
++function feedback_menu() {
++  $items['admin/reports/feedback'] = array(
++    'title' => 'Feedback messages',
++    'description' => 'View feedback messages.',
++    'page callback' => 'drupal_get_form',
++    'page arguments' => array('feedback_admin_view_form'),
++    'access arguments' => array('view feedback messages'),
++    'file' => 'feedback.admin.inc',
++  );
++  $items['admin/reports/feedback/%feedback'] = array(
++    'title' => 'Feedback entry',
++    'page callback' => 'feedback_view',
++    'page arguments' => array(3),
++    'access arguments' => array('view feedback messages'),
++    'file' => 'feedback.admin.inc',
++  );
++  $items['admin/reports/feedback/%feedback/view'] = array(
++    'title' => 'View',
++    'type' => MENU_DEFAULT_LOCAL_TASK,
++    'weight' => -10,
++  );
++  $items['admin/reports/feedback/%feedback/edit'] = array(
++    'title' => 'Edit',
++    'page callback' => 'drupal_get_form',
++    'page arguments' => array('feedback_entry_form', 3),
++    'access arguments' => array('view feedback messages'),
++    'type' => MENU_LOCAL_TASK,
++    'file' => 'feedback.admin.inc',
++  );
++  $items['admin/reports/feedback/%feedback/delete'] = array(
++    'title' => 'Delete feedback entry',
++    'page callback' => 'drupal_get_form',
++    'page arguments' => array('feedback_delete_confirm', 3),
++    'access arguments' => array('view feedback messages'),
++    'type' => MENU_CALLBACK,
++    'file' => 'feedback.admin.inc',
++  );
++  $items['admin/config/user-interface/feedback'] = array(
++    'title' => 'Feedback',
++    'description' => 'Administer feedback settings.',
++    'page callback' => 'drupal_get_form',
++    'page arguments' => array('feedback_admin_settings_form'),
++    'access arguments' => array('administer feedback'),
++    'file' => 'feedback.admin.inc',
++  );
++  $items['admin/config/user-interface/feedback/settings'] = array(
++    'title' => 'Settings',
++    'type' => MENU_DEFAULT_LOCAL_TASK,
++    'weight' => -10,
++  );
++
++  return $items;
++}
++
++/**
++ * Implements hook_page_build().
++ */
++function feedback_page_build(&$page) {
++  if (user_access('access feedback form') && !feedback_match_path(variable_get('feedback_excluded_paths', 'admin/reports/feedback'))) {
++    $page['page_bottom']['feedback'] = array(
++      '#theme' => 'feedback_form_display',
++      '#title' => t('Feedback'),
++      '#content' => drupal_get_form('feedback_form'),
++    );
++    $path = drupal_get_path('module', 'feedback');
++    $page['page_bottom']['feedback']['#attached']['css'][] = $path . '/feedback.css';
++    $page['page_bottom']['feedback']['#attached']['js'][] = $path . '/feedback.js';
++  }
++}
++
++/**
++ * Check if the current path matches any pattern in a set of patterns.
++ *
++ * @param $patterns
++ *   String containing a set of patterns separated by \n, \r or \r\n.
++ *
++ * @return
++ *   Boolean value: TRUE if the current path or alias matches a pattern.
++ */
++function feedback_match_path($patterns) {
++  // Convert path to lowercase. This allows comparison of the same path
++  // with different case. Ex: /Page, /page, /PAGE.
++  $patterns = drupal_strtolower($patterns);
++
++  // Convert the current path to lowercase.
++  $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
++
++  // Compare the lowercase internal and lowercase path alias (if any).
++  $page_match = drupal_match_path($path, $patterns);
++  if ($path != $_GET['q']) {
++    $page_match = $page_match || drupal_match_path($_GET['q'], $patterns);
++  }
++
++  return $page_match;
++}
++
++/**
++ * Form constructor for the feedback form.
++ *
++ * @see feedback_form_submit()
++ * @ingroup forms
++ */
++function feedback_form($form, &$form_state) {
++  $form['#attributes']['class'] = array('feedback-form');
++
++  // Store the path on which this form is displayed.
++  if (!isset($form_state['inline']['location'])) {
++    $form_state['inline']['location'] = $_GET['q'];
++  }
++  $form['location'] = array(
++    '#type' => 'value',
++    '#value' => $form_state['inline']['location'],
++  );
++
++  $form['help'] = array(
++    '#prefix' => '<div class="feedback-help">',
++    '#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.'),
++    '#suffix' => '</div>',
++  );
++  if (user_access('view feedback messages')) {
++    if (arg(0) != 'node') {
++      $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location_masked' => feedback_mask_path($_GET['q'])));
++    }
++    else {
++      $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location' => $_GET['q']));
++    }
++    if ($feedbacks) {
++      form_load_include($form_state, 'inc', 'feedback', 'feedback.admin');
++      $form['messages'] = array(
++        '#prefix' => '<div class="feedback-messages">',
++        '#suffix' => '</div>',
++      );
++      foreach ($feedbacks as $fid => $feedback) {
++        $form['messages'][$fid]['#feedback'] = $feedback;
++        $form['messages'][$fid]['submitted'] = array('#markup' => t('@feedback-author !feedback-date:', array('@feedback-author' => format_username($feedback), '!feedback-date' => format_date($feedback->timestamp, 'small'))));
++        $form['messages'][$fid]['submitted']['#prefix'] = '<div class="feedback-submitted">';
++        $form['messages'][$fid]['submitted']['#suffix'] = '</div>';
++        $form['messages'][$fid]['body'] = feedback_build_content($feedback, 'widget');
++        $form['messages'][$fid]['body']['#prefix'] = '<div class="feedback-body">';
++        $form['messages'][$fid]['body']['#suffix'] = '</div>';
++      }
++    }
++  }
++  $form['message'] = array(
++    '#type' => 'textarea',
++    '#attributes' => array('class' => array('feedback-message')),
++    '#cols' => 20,
++    '#title' => t('Message'),
++    '#required' => TRUE,
++    '#wysiwyg' => FALSE,
++  );
++
++  $entry = new stdClass();
++  field_attach_form('feedback', $entry, $form, $form_state);
++
++  $form['actions'] = array(
++    '#type' => 'actions',
++    // Without clearfix, the AJAX throbber wraps in an ugly way.
++    // @todo Patch #type actions in core?
++    '#attributes' => array('class' => array('clearfix')),
++  );
++  $form['actions']['submit'] = array(
++    '#type' => 'submit',
++    '#value' => t('Send feedback'),
++    '#id' => 'feedback-submit',
++    '#ajax' => array(
++      'wrapper' => 'feedback-form',
++      'callback' => 'feedback_form_ajax_callback',
++      'progress' => array(
++        'type' => 'throbber',
++        'message' => '',
++      ),
++    ),
++  );
++
++  return $form;
++}
++
++/**
++ * Form submission handler for feedback_form().
++ */
++function feedback_form_submit($form, &$form_state) {
++  $entry = new stdClass();
++  entity_form_submit_build_entity('feedback', $entry, $form, $form_state);
++  $entry->message = $form_state['values']['message'];
++  $entry->location = $form_state['values']['location'];
++  feedback_save($entry);
++
++  drupal_set_message(t('Thanks for your feedback!'));
++}
++
++/**
++ * AJAX callback for feedback_form() submissions.
++ */
++function feedback_form_ajax_callback($form, &$form_state) {
++  // If there was a form validation error, re-render the entire form.
++  if (!$form_state['executed']) {
++    return $form;
++  }
++
++  // Otherwise, return a fresh copy of the form, so the user may post additional
++  // feedback.
++  // Reset the static cache of drupal_html_id().
++  // @see drupal_process_form()
++  // @see drupal_html_id()
++  $seen_ids = &drupal_static('drupal_html_id');
++  $seen_ids = array();
++
++  // Prevent the form from being processed again.
++  // @see drupal_build_form()
++  list($form, $new_form_state) = ajax_get_form();
++  $new_form_state['input'] = array();
++  drupal_process_form($form['#form_id'], $form, $new_form_state);
++
++  // Return AJAX commands in order to output the special success message.
++  // @see ajax_deliver()
++  $build = array('#type' => 'ajax');
++  $html = drupal_render($form);
++  $build['#commands'][] = ajax_command_insert(NULL, $html);
++
++  // A successful form submission normally means that there were no errors, so
++  // we only render status messages.
++  $messages = drupal_get_messages();
++  $messages += array('status' => array());
++  $messages = implode('<br />', $messages['status']);
++  $html = '<div id="feedback-status-message">' . $messages . '</div>';
++  $build['#commands'][] = ajax_command_append('#block-feedback-form', $html);
++  return $build;
++}
++
++/**
++ * Loads a feedback entry from the database.
++ *
++ * @param $fid
++ *   Integer specifying the feedback ID to load.
++ *
++ * @return
++ *   A loaded feedback entry object upon successful load, or FALSE if the entry
++ *   cannot be loaded.
++ *
++ * @see feedback_load_multiple()
++ */
++function feedback_load($fid) {
++  $entries = feedback_load_multiple(array($fid));
++  return (isset($entries[$fid]) ? $entries[$fid] : FALSE);
++}
++
++/**
++ * Loads feedback entries from the database.
++ *
++ * @param $fids
++ *   An array of feedback entry IDs.
++ * @param $conditions
++ *   An associative array of conditions on the {feedback} table, where the keys
++ *   are the database fields and the values are the values those fields
++ *   must have.
++ *
++ * @return
++ *   An array of feedback entry objects indexed by fid.
++ *
++ * @see hook_feedback_load()
++ * @see feedback_load()
++ * @see entity_load()
++ * @see EntityFieldQuery
++ */
++function feedback_load_multiple($fids = array(), $conditions = array()) {
++  return entity_load('feedback', $fids, $conditions);
++}
++
++/**
++ * Saves changes to a feedback entry or adds a new feedback entry.
++ *
++ * @param $entry
++ *   The feedback entry object to modify or add. If $entry->fid is omitted, a
++ *   new entry will be added.
++ *
++ * @see hook_feedback_insert()
++ * @see hook_feedback_update()
++ */
++function feedback_save($entry) {
++  global $user;
++
++  // Load the stored entity, if any.
++  if (!empty($entry->fid) && !isset($entry->original)) {
++    $entry->original = entity_load_unchanged('feedback', $entry->fid);
++  }
++
++  field_attach_presave('feedback', $entry);
++
++  // Allow modules to alter the feedback entry before saving.
++  module_invoke_all('feedback_presave', $entry);
++  module_invoke_all('entity_presave', $entry, 'feedback');
++
++  if (empty($entry->fid)) {
++    $entry->message = trim($entry->message);
++
++    $defaults = array(
++      'uid' => $user->uid,
++      'location_masked' => feedback_mask_path($entry->location),
++      'url' => url($entry->location, array('absolute' => TRUE)),
++      'timestamp' => REQUEST_TIME,
++      'useragent' => $_SERVER['HTTP_USER_AGENT'],
++    );
++    foreach ($defaults as $key => $default) {
++      if (!isset($entry->$key)) {
++        $entry->$key = $default;
++      }
++    }
++
++    $status = drupal_write_record('feedback', $entry);
++    field_attach_insert('feedback', $entry);
++    module_invoke_all('feedback_insert', $entry);
++    module_invoke_all('entity_insert', $entry, 'feedback');
++  }
++  else {
++    $status = drupal_write_record('feedback', $entry, 'fid');
++
++    field_attach_update('feedback', $entry);
++    module_invoke_all('feedback_update', $entry);
++    module_invoke_all('entity_update', $entry, 'feedback');
++  }
++  unset($entry->original);
++
++  return $status;
++}
++
++/**
++ * Deletes a feedback entry.
++ *
++ * @param $fid
++ *   A feedback entry ID.
++ */
++function feedback_delete($fid) {
++  feedback_delete_multiple(array($fid));
++}
++
++/**
++ * Deletes multiple feedback entries.
++ *
++ * @param $fids
++ *   An array of feedback entry IDs.
++ */
++function feedback_delete_multiple($fids) {
++  if (!empty($fids)) {
++    $entries = feedback_load_multiple($fids);
++    foreach ($entries as $fid => $entry) {
++      field_attach_delete('feedback', $entry);
++      module_invoke_all('feedback_delete', $entry);
++      module_invoke_all('entity_delete', $entry, 'feedback');
++    }
++    db_delete('feedback')
++      ->condition('fid', $fids, 'IN')
++      ->execute();
++  }
++}
++
++/**
++ * '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'.
++ *
++ * @todo Use the untranslated patch of menu_get_item() instead.
++ */
++function feedback_mask_path($path) {
++  return preg_replace('@/\d+@', '/%', $path);
++}
++
++/**
++ * Implements hook_user_cancel().
++ */
++function feedback_user_cancel($edit, $account, $method) {
++  switch ($method) {
++    case 'user_cancel_reassign':
++      db_update('feedback')
++        ->fields(array('uid' => 0))
++        ->condition('uid', $account->uid)
++        ->execute();
++      break;
++  }
++}
++
++/**
++ * Implements hook_user_delete().
++ */
++function feedback_user_delete($account) {
++  $fids = db_query('SELECT fid FROM {feedback} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
++  feedback_delete_multiple($fids);
++}
++
++/**
++ * Implements hook_mollom_form_list().
++ */
++function feedback_mollom_form_list() {
++  $forms['feedback_form'] = array(
++    'title' => t('Feedback form'),
++    'entity' => 'feedback',
++    'bundle' => 'feedback',
++    'entity delete multiple callback' => 'feedback_delete_multiple',
++    'delete form' => 'feedback_delete_confirm',
++    'delete form file' => array(
++      'name' => 'feedback.admin',
++    ),
++    'report access' => array('view feedback messages'),
++  );
++  return $forms;
++}
++
++/**
++ * Implements hook_mollom_form_info().
++ */
++function feedback_mollom_form_info($form_id) {
++  $form_info = array(
++    'mode' => MOLLOM_MODE_ANALYSIS,
++    'bypass access' => array('administer feedback'),
++    'elements' => array(
++      'message' => t('Message'),
++    ),
++  );
++  mollom_form_info_add_fields($form_info, 'feedback', 'feedback');
++  return $form_info;
++}
++
++/**
++ * Implements hook_views_api();
++ */
++function feedback_views_api() {
++  return array(
++    'api' => 3.0,
++    'path' => drupal_get_path('module', 'feedback') . '/views',
++  );
++}
+diff --git a/tests/feedback.test b/tests/feedback.test
+old mode 100755
+new mode 100644
+index 4d4244c..09ce922
+--- a/tests/feedback.test
++++ b/tests/feedback.test
+@@ -20,8 +20,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
+   }
+ 
+   function setUp() {
+-    // @todo Remove soft-dependency on Block.
+-    parent::setUp(array('block', 'feedback'));
++    parent::setUp(array('feedback', 'trigger'));
+ 
+     $this->admin_user = $this->drupalCreateUser(array('access feedback form', 'view feedback messages', 'administer feedback'));
+     $this->web_user = $this->drupalCreateUser(array('access feedback form'));
+@@ -49,7 +48,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
+     $edit = array(
+       'feedback-messages[0][1]' => TRUE,
+     );
+-    $this->drupalPost(NULL, $edit, t('Submit'));
++    $this->drupalPost(NULL, $edit, t('Update'));
+     $this->assertFieldByName('feedback-messages[1][1]', 1, t('Processed message found.'));
+   }
+ 
+@@ -89,4 +88,72 @@ class FeedbackTestCase extends DrupalWebTestCase {
+     $this->assertNoLinkByHref('admin/reports/feedback/1/delete');
+     $this->assertNoRaw(check_plain($message), t('Message not found.'));
+   }
+-}
++
++  /**
++   * Test the feedback triggers and actions.
++   */
++  function testFeedbackEmailAction() {
++    $test_user = $this->drupalCreateUser(array('administer actions', 'administer feedback', 'access feedback form'));
++    $this->drupalLogin($test_user);
++    $this->assignFeedbackEmailAction('feedback_insert', $test_user->mail);
++
++    // Insert a feedback entry.
++    $message = $this->randomString();
++    $edit = array(
++      'message' => $message,
++    );
++    $this->drupalPost('node', $edit, t('Send feedback'));
++    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $message);
++
++    $this->assignFeedbackEmailAction('feedback_update', $test_user->mail);
++
++    // Update a feedback entry.
++    $fid = db_query("SELECT fid FROM {feedback} LIMIT 0,1")->fetchField();
++    $entry = feedback_load($fid);
++    feedback_save($entry);
++    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $entry->message);
++  }
++
++  /**
++   * Assigns a system_send_email_action to the passed-in trigger.
++   *
++   * @param $trigger
++   *   For example, 'user_login'
++   */
++  function assignFeedbackEmailAction($trigger, $mail) {
++    $form_name = "trigger_{$trigger}_assign_form";
++    $form_html_id = strtr($form_name, '_', '-');
++
++    $edit = array(
++      'actions_label' => $trigger . "_feedback_send_email_action",
++      'recipients' => $mail,
++      'subject' => $this->randomName(),
++      'message' => '!message',
++    );
++
++    $hash = drupal_hash_base64('feedback_send_email_action');
++    $this->drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
++    $this->assertText(t('The action has been successfully saved.'));
++
++    // Now we have to find out the action ID of what we created.
++    $aid = db_query('SELECT aid FROM {actions} WHERE callback = :callback AND label = :label', array(':callback' => 'feedback_send_email_action', ':label' => $edit['actions_label']))->fetchField();
++
++    $edit = array('aid' => drupal_hash_base64($aid));
++    $this->drupalPost('admin/structure/trigger/feedback', $edit, t('Assign'), array(), array(), $form_html_id);
++  }
++
++
++  /**
++   * Asserts correct token replacement for the given trigger and account.
++   *
++   * @param $account
++   *   The user account which triggered the action.
++   * @param $email_depth
++   *   Number of emails to scan, starting with most recent.
++   */
++  function assertFeedbackEmailTokenReplacement($mail, $message, $email_depth = 1) {
++    $this->verboseEmail($email_depth);
++    $this->assertMailString('body', $message, $email_depth);
++    $this->assertMail('to', $mail, t('Mail sent to correct destination'));
++  }
++}
+\ No newline at end of file
+-- 
+2.3.5
+

+ 0 - 338
sites/all/modules/contrib/users/feedback/feedback-353548-45.patch

@@ -1,338 +0,0 @@
-diff --git a/feedback.module b/feedback.module
-index 9763575..ef5b24a 100644
---- a/feedback.module
-+++ b/feedback.module
-@@ -534,6 +534,235 @@ function feedback_user_delete($account) {
- }
- 
- /**
-+ * Implements hook_action_info().
-+ */
-+function feedback_action_info() {
-+  return array(
-+    'feedback_process_action' => array(
-+      'label' => t('Process entry'),
-+      'type' => 'feedback',
-+      'configurable' => FALSE,
-+      'behavior' => array('changes_property'),
-+      'triggers' => array('feedback_insert', 'feedback_update'),
-+    ),
-+    'feedback_open_action' => array(
-+      'label' => t('Open entry'),
-+      'type' => 'feedback',
-+      'configurable' => FALSE,
-+      'behavior' => array('changes_property'),
-+      'triggers' => array('feedback_insert', 'feedback_update'),
-+    ),
-+    'feedback_delete_action' => array(
-+      'label' => t('Delete entry'),
-+      'type' => 'feedback',
-+      'configurable' => FALSE,
-+      'triggers' => array('feedback_insert', 'feedback_update'),
-+    ),
-+    'feedback_send_email_action' => array(
-+      'label' => t('Send e-mail of feedback'),
-+      'type' => 'feedback',
-+      'configurable' => TRUE,
-+      'triggers' => array('feedback_insert', 'feedback_update'),
-+    ),
-+  );
-+}
-+
-+/**
-+* Implements hook_trigger_info().
-+*/
-+function feedback_trigger_info() {
-+  return array(
-+    'feedback' => array(
-+      'feedback_insert' => array(
-+        'label' => t('New feedback is added.'),
-+      ),
-+      'feedback_update' => array(
-+        'label' => t('Feedback is marked processed or open.'),
-+      ),
-+    ),
-+  );
-+}
-+
-+/**
-+ * Implements hook_feedback_insert().
-+ */
-+function feedback_feedback_insert($entry) {
-+  $aids = trigger_get_assigned_actions('feedback_insert');
-+  if (!$aids) {
-+    return;
-+  }
-+
-+  $context = array(
-+    'group' => 'feedback',
-+    'hook' => 'feedback_insert',
-+  );
-+
-+  foreach ($aids as $aid => $info) {
-+    actions_do($aid, $entry, $context);
-+  }
-+}
-+
-+/**
-+ * Implements hook_feedback_update().
-+ */
-+function feedback_feedback_update($entry) {
-+  $aids = trigger_get_assigned_actions('feedback_update');
-+  if (!$aids) {
-+    return;
-+  }
-+
-+  $context = array(
-+    'group' => 'feedback',
-+    'hook' => 'feedback_update',
-+  );
-+
-+  foreach ($aids as $aid => $info) {
-+    actions_do($aid, $entry, $context);
-+  }
-+}
-+
-+/**
-+ * Sets the status of an entry to processed.
-+ *
-+ * @ingroup actions
-+ */
-+function feedback_process_action($entry, $context) {
-+  $entry->status = FEEDBACK_PROCESSED;
-+  drupal_write_record('feedback', $entry, 'fid');
-+}
-+
-+/**
-+ * Sets the status of an entry to open.
-+ *
-+ * @ingroup actions
-+ */
-+function feedback_open_action($entry, $context) {
-+  $entry->status = FEEDBACK_OPEN;
-+  drupal_write_record('feedback', $entry, 'fid');
-+}
-+
-+/**
-+ * Deletes a feedback entry.
-+ *
-+ * @ingroup actions
-+ */
-+function feedback_delete_action($entry, $context) {
-+  feedback_delete($entry->fid);
-+}
-+
-+/**
-+ * Return a form definition so the Feedback send email action can be configured.
-+ *
-+ * @param $context
-+ *   Default values (if we are editing an existing action instance).
-+ * @return
-+ *   Form definition.
-+ */
-+function feedback_send_email_action_form($context = array()) {
-+  // Set default values for form.
-+  $context += array(
-+   'recipients' => '',
-+   'subject' => '',
-+   'message' => '',
-+  );
-+
-+  $form['recipients'] = array(
-+    '#type' => 'textarea',
-+    '#title' => t('Recipients'),
-+    '#default_value' => $context['recipients'],
-+    '#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."),
-+    '#required' => TRUE,
-+  );
-+  $form['subject'] = array(
-+    '#type' => 'textfield',
-+    '#title' => t('Subject'),
-+    '#default_value' => $context['subject'],
-+    '#maxlength' => '254',
-+    '#description' => t('The subject of the message.'),
-+    '#required' => TRUE,
-+  );
-+  $form['message'] = array(
-+    '#type' => 'textarea',
-+    '#title' => t('Message'),
-+    '#default_value' => $context['message'],
-+    '#cols' => '80',
-+    '#rows' => '20',
-+    '#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.'),
-+    '#required' => TRUE,
-+  );
-+  return $form;
-+}
-+
-+/**
-+ * Validate the send e-mail action form submission.
-+ */
-+function feedback_send_email_action_validate($form, &$form_state) {
-+  if (empty($form_state['values']['recipients'])) {
-+    form_set_error('recipients', t('You must enter one or more recipients.'));
-+  }
-+  else {
-+    $recipients = explode(',', $form_state['values']['recipients']);
-+    foreach ($recipients as $recipient) {
-+      if (!valid_email_address(trim($recipient))) {
-+        form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
-+      }
-+    }
-+  }
-+}
-+
-+/**
-+ * Process the send e-mail action form submission.
-+ */
-+function feedback_send_email_action_submit($form, $form_state) {
-+  // Process the HTML form to store configuration. The keyed array that
-+  // we return will be serialized to the database.
-+  $params = array(
-+    'recipients' => $form_state['values']['recipients'],
-+    'subject'    => $form_state['values']['subject'],
-+    'message'    => $form_state['values']['message'],
-+  );
-+  return $params;
-+}
-+
-+/**
-+ * Implements the feedback send e-mail action.
-+ */
-+function feedback_send_email_action($entry, $context) {
-+  $account = user_load($entry->uid);
-+  $from = variable_get('site_name', 'Drupal') . ' <' . variable_get('site_mail', '') . '>';
-+  $params = array('entry' => $entry, 'account' => $account, 'context' => $context);
-+  // Send the e-mail to the recipients using the site default language.
-+  drupal_mail('feedback', 'send_email_action', $context['recipients'], language_default(), $params, $from);
-+  watchdog('feedback', 'Feedback information sent to %recipients', array('%recipients' => $context['recipients']));
-+}
-+
-+/**
-+ * Implements hook_mail().
-+ */
-+function feedback_mail($key, &$message, $params) {
-+  $language = $message['language'];
-+  $entry = $params['entry'];
-+  $account = $params['account'];
-+  $context = $params['context'];
-+  $variables = array(
-+    '!site_name' => variable_get('site_name', 'Drupal'),
-+    '!uid' => $account->uid,
-+    '!username' => $account->name ? $account->name : t('Anonymous'),
-+    '!usermail' => $account->mail ? $account->mail : t('unknown'),
-+    '!status' => $entry->status ? t('Processed') : t('Open'),
-+    '!message' => $entry->message,
-+    '!url' => url($entry->location, array('absolute' => TRUE, 'language' => $language)),
-+    '!useragent' => $entry->useragent,
-+    '!date' => format_date($entry->timestamp, 'small', '', NULL, $language->language),
-+  );
-+  $subject = strtr($context['subject'], $variables);
-+  $body = strtr($context['message'], $variables);
-+  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
-+  $message['body'][] = drupal_html_to_text($body);
-+}
-+
-+
-+/**
-  * Implements hook_mollom_form_list().
-  */
- function feedback_mollom_form_list() {
-diff --git a/tests/feedback.test b/tests/feedback.test
-index 4d4244c..09ce922 100644
---- a/tests/feedback.test
-+++ b/tests/feedback.test
-@@ -20,8 +20,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
-   }
- 
-   function setUp() {
--    // @todo Remove soft-dependency on Block.
--    parent::setUp(array('block', 'feedback'));
-+    parent::setUp(array('feedback', 'trigger'));
- 
-     $this->admin_user = $this->drupalCreateUser(array('access feedback form', 'view feedback messages', 'administer feedback'));
-     $this->web_user = $this->drupalCreateUser(array('access feedback form'));
-@@ -49,7 +48,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
-     $edit = array(
-       'feedback-messages[0][1]' => TRUE,
-     );
--    $this->drupalPost(NULL, $edit, t('Submit'));
-+    $this->drupalPost(NULL, $edit, t('Update'));
-     $this->assertFieldByName('feedback-messages[1][1]', 1, t('Processed message found.'));
-   }
- 
-@@ -89,4 +88,72 @@ class FeedbackTestCase extends DrupalWebTestCase {
-     $this->assertNoLinkByHref('admin/reports/feedback/1/delete');
-     $this->assertNoRaw(check_plain($message), t('Message not found.'));
-   }
--}
-+
-+  /**
-+   * Test the feedback triggers and actions.
-+   */
-+  function testFeedbackEmailAction() {
-+    $test_user = $this->drupalCreateUser(array('administer actions', 'administer feedback', 'access feedback form'));
-+    $this->drupalLogin($test_user);
-+    $this->assignFeedbackEmailAction('feedback_insert', $test_user->mail);
-+
-+    // Insert a feedback entry.
-+    $message = $this->randomString();
-+    $edit = array(
-+      'message' => $message,
-+    );
-+    $this->drupalPost('node', $edit, t('Send feedback'));
-+    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $message);
-+
-+    $this->assignFeedbackEmailAction('feedback_update', $test_user->mail);
-+
-+    // Update a feedback entry.
-+    $fid = db_query("SELECT fid FROM {feedback} LIMIT 0,1")->fetchField();
-+    $entry = feedback_load($fid);
-+    feedback_save($entry);
-+    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $entry->message);
-+  }
-+
-+  /**
-+   * Assigns a system_send_email_action to the passed-in trigger.
-+   *
-+   * @param $trigger
-+   *   For example, 'user_login'
-+   */
-+  function assignFeedbackEmailAction($trigger, $mail) {
-+    $form_name = "trigger_{$trigger}_assign_form";
-+    $form_html_id = strtr($form_name, '_', '-');
-+
-+    $edit = array(
-+      'actions_label' => $trigger . "_feedback_send_email_action",
-+      'recipients' => $mail,
-+      'subject' => $this->randomName(),
-+      'message' => '!message',
-+    );
-+
-+    $hash = drupal_hash_base64('feedback_send_email_action');
-+    $this->drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
-+    $this->assertText(t('The action has been successfully saved.'));
-+
-+    // Now we have to find out the action ID of what we created.
-+    $aid = db_query('SELECT aid FROM {actions} WHERE callback = :callback AND label = :label', array(':callback' => 'feedback_send_email_action', ':label' => $edit['actions_label']))->fetchField();
-+
-+    $edit = array('aid' => drupal_hash_base64($aid));
-+    $this->drupalPost('admin/structure/trigger/feedback', $edit, t('Assign'), array(), array(), $form_html_id);
-+  }
-+
-+
-+  /**
-+   * Asserts correct token replacement for the given trigger and account.
-+   *
-+   * @param $account
-+   *   The user account which triggered the action.
-+   * @param $email_depth
-+   *   Number of emails to scan, starting with most recent.
-+   */
-+  function assertFeedbackEmailTokenReplacement($mail, $message, $email_depth = 1) {
-+    $this->verboseEmail($email_depth);
-+    $this->assertMailString('body', $message, $email_depth);
-+    $this->assertMail('to', $mail, t('Mail sent to correct destination'));
-+  }
-+}
-\ No newline at end of file

+ 14 - 4
sites/all/modules/contrib/users/feedback/feedback.admin.inc

@@ -56,10 +56,20 @@ function feedback_admin_view_form($form, &$form_state) {
           '#return_value' => FEEDBACK_PROCESSED,
           '#default_value' => FALSE,
         );
-        $form['feedback-messages'][$status][$fid]['location'] = array('#markup' => l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->url));
-        $form['feedback-messages'][$status][$fid]['date'] = array('#markup' => format_date($entry->timestamp, 'small'));
-        $form['feedback-messages'][$status][$fid]['user'] = array('#markup' => check_plain(format_username($entry)));
-        $form['feedback-messages'][$status][$fid]['message'] = feedback_build_content($entry, 'teaser');
+        $form['feedback-messages'][$status][$fid]['location'] = array(
+          '#markup' => l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->url),
+        );
+        $form['feedback-messages'][$status][$fid]['date'] = array(
+          '#markup' => format_date($entry->timestamp, 'small'),
+        );
+        $form['feedback-messages'][$status][$fid]['user'] = array(
+          '#markup' => check_plain(format_username($entry)),
+        );
+
+        feedback_build_content($entry, 'teaser');
+        $form['feedback-messages'][$status][$fid]['message'] = $entry->content;
+        unset($entry->content);
+
         $form['feedback-messages'][$status][$fid]['operations'] = array(
           '#theme' => 'links',
           '#links' => array(

+ 21 - 2
sites/all/modules/contrib/users/feedback/feedback.css

@@ -54,6 +54,18 @@
   font-size: 10px;
   line-height: normal;
 }
+#block-feedback-form input[type="text"] {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  max-width: 100%;
+}
+#block-feedback-form .form-actions {
+  margin: 1em 0 0;
+  padding: 0;
+}
+
+/* Ajax interaction styles */
 #block-feedback-form .feedback-message {
   height: 10ex;
 }
@@ -66,7 +78,14 @@
 /**
  * Styles for existing feedback messages.
  */
-#block-feedback-form .feedback-submitted {
+#block-feedback-form .feedback-entry {
+  font-size: 80%;
+}
+.feedback-entry .feedback-submitted {
   margin-top: 0.2em;
-  font-size: 10px;
+  font-size: 90%;
+}
+.feedback-entry .browserinfo {
+  color: #666;
+  font-size: 80%;
 }

+ 2 - 2
sites/all/modules/contrib/users/feedback/feedback.info

@@ -9,9 +9,9 @@ files[] = views/feedback_handler_field_feedback_link_delete.inc
 files[] = views/feedback_handler_field_feedback_link_edit.inc
 files[] = tests/feedback.test
 
-; Information added by drupal.org packaging script on 2013-03-04
+; Information added by Drupal.org packaging script on 2015-02-11
 version = "7.x-2.x-dev"
 core = "7.x"
 project = "feedback"
-datestamp = "1362358407"
+datestamp = "1423690684"
 

+ 79 - 232
sites/all/modules/contrib/users/feedback/feedback.module

@@ -80,6 +80,51 @@ function feedback_entity_info() {
   return $return;
 }
 
+/**
+ * Implements hook_entity_property_info().
+ */
+function feedback_entity_property_info() {
+  $info = array();
+  $properties = &$info['feedback']['properties'];
+
+  $properties['fid'] = array(
+    'label' => t('Feedback ID'),
+    'type' => 'integer',
+    'description' => t('The Feedback ID'),
+    'schema field' => 'fid',
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'type' => 'integer',
+    'description' => t("0 for new, 1 for processed"),
+    'schema field' => 'status',
+  );
+  $properties['author'] = array(
+    'label' => t("Author"),
+    'type' => 'user',
+    'description' => t("The author of the feedback."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'uid',
+  );
+  $properties['message'] = array(
+    'label' => t("Title"),
+    'description' => t("The feedback message."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'message',
+    'required' => TRUE,
+  );
+  $properties['timestamp'] = array(
+    'label' => t("Date created"),
+    'type' => 'date',
+    'schema field' => 'timestamp',
+    'description' => t("The date the feedback was created."),
+  );
+
+  return $info;
+}
+
+
 /**
  * Implements hook_field_extra_fields().
  */
@@ -287,11 +332,22 @@ function feedback_form($form, &$form_state) {
         '#suffix' => '</div>',
       );
       foreach ($feedbacks as $fid => $feedback) {
-        $form['messages'][$fid]['#feedback'] = $feedback;
-        $form['messages'][$fid]['submitted'] = array('#markup' => t('@feedback-author !feedback-date:', array('@feedback-author' => format_username($feedback), '!feedback-date' => format_date($feedback->timestamp, 'small'))));
+        $form['messages'][$fid] = array(
+          '#type' => 'container',
+          '#attributes' => array('class' => array('feedback-entry')),
+          '#feedback' => $feedback,
+        );
+        $form['messages'][$fid]['submitted'] = array(
+          '#markup' => t('@feedback-author !feedback-date:', array(
+            '@feedback-author' => format_username($feedback),
+            '!feedback-date' => format_date($feedback->timestamp, 'small'),
+          )),
+        );
         $form['messages'][$fid]['submitted']['#prefix'] = '<div class="feedback-submitted">';
         $form['messages'][$fid]['submitted']['#suffix'] = '</div>';
-        $form['messages'][$fid]['body'] = feedback_build_content($feedback, 'widget');
+        feedback_build_content($feedback, 'widget');
+        $form['messages'][$fid]['body'] = $feedback->content;
+        unset($feedback->content);
         $form['messages'][$fid]['body']['#prefix'] = '<div class="feedback-body">';
         $form['messages'][$fid]['body']['#suffix'] = '</div>';
       }
@@ -549,235 +605,6 @@ function feedback_user_delete($account) {
   feedback_delete_multiple($fids);
 }
 
-/**
- * Implements hook_action_info().
- */
-function feedback_action_info() {
-  return array(
-    'feedback_process_action' => array(
-      'label' => t('Process entry'),
-      'type' => 'feedback',
-      'configurable' => FALSE,
-      'behavior' => array('changes_property'),
-      'triggers' => array('feedback_insert', 'feedback_update'),
-    ),
-    'feedback_open_action' => array(
-      'label' => t('Open entry'),
-      'type' => 'feedback',
-      'configurable' => FALSE,
-      'behavior' => array('changes_property'),
-      'triggers' => array('feedback_insert', 'feedback_update'),
-    ),
-    'feedback_delete_action' => array(
-      'label' => t('Delete entry'),
-      'type' => 'feedback',
-      'configurable' => FALSE,
-      'triggers' => array('feedback_insert', 'feedback_update'),
-    ),
-    'feedback_send_email_action' => array(
-      'label' => t('Send e-mail of feedback'),
-      'type' => 'feedback',
-      'configurable' => TRUE,
-      'triggers' => array('feedback_insert', 'feedback_update'),
-    ),
-  );
-}
-
-/**
-* Implements hook_trigger_info().
-*/
-function feedback_trigger_info() {
-  return array(
-    'feedback' => array(
-      'feedback_insert' => array(
-        'label' => t('New feedback is added.'),
-      ),
-      'feedback_update' => array(
-        'label' => t('Feedback is marked processed or open.'),
-      ),
-    ),
-  );
-}
-
-/**
- * Implements hook_feedback_insert().
- */
-function feedback_feedback_insert($entry) {
-  $aids = trigger_get_assigned_actions('feedback_insert');
-  if (!$aids) {
-    return;
-  }
-
-  $context = array(
-    'group' => 'feedback',
-    'hook' => 'feedback_insert',
-  );
-
-  foreach ($aids as $aid => $info) {
-    actions_do($aid, $entry, $context);
-  }
-}
-
-/**
- * Implements hook_feedback_update().
- */
-function feedback_feedback_update($entry) {
-  $aids = trigger_get_assigned_actions('feedback_update');
-  if (!$aids) {
-    return;
-  }
-
-  $context = array(
-    'group' => 'feedback',
-    'hook' => 'feedback_update',
-  );
-
-  foreach ($aids as $aid => $info) {
-    actions_do($aid, $entry, $context);
-  }
-}
-
-/**
- * Sets the status of an entry to processed.
- *
- * @ingroup actions
- */
-function feedback_process_action($entry, $context) {
-  $entry->status = FEEDBACK_PROCESSED;
-  drupal_write_record('feedback', $entry, 'fid');
-}
-
-/**
- * Sets the status of an entry to open.
- *
- * @ingroup actions
- */
-function feedback_open_action($entry, $context) {
-  $entry->status = FEEDBACK_OPEN;
-  drupal_write_record('feedback', $entry, 'fid');
-}
-
-/**
- * Deletes a feedback entry.
- *
- * @ingroup actions
- */
-function feedback_delete_action($entry, $context) {
-  feedback_delete($entry->fid);
-}
-
-/**
- * Return a form definition so the Feedback send email action can be configured.
- *
- * @param $context
- *   Default values (if we are editing an existing action instance).
- * @return
- *   Form definition.
- */
-function feedback_send_email_action_form($context = array()) {
-  // Set default values for form.
-  $context += array(
-   'recipients' => '',
-   'subject' => '',
-   'message' => '',
-  );
-
-  $form['recipients'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Recipients'),
-    '#default_value' => $context['recipients'],
-    '#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."),
-    '#required' => TRUE,
-  );
-  $form['subject'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Subject'),
-    '#default_value' => $context['subject'],
-    '#maxlength' => '254',
-    '#description' => t('The subject of the message.'),
-    '#required' => TRUE,
-  );
-  $form['message'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Message'),
-    '#default_value' => $context['message'],
-    '#cols' => '80',
-    '#rows' => '20',
-    '#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.'),
-    '#required' => TRUE,
-  );
-  return $form;
-}
-
-/**
- * Validate the send e-mail action form submission.
- */
-function feedback_send_email_action_validate($form, &$form_state) {
-  if (empty($form_state['values']['recipients'])) {
-    form_set_error('recipients', t('You must enter one or more recipients.'));
-  }
-  else {
-    $recipients = explode(',', $form_state['values']['recipients']);
-    foreach ($recipients as $recipient) {
-      if (!valid_email_address(trim($recipient))) {
-        form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
-      }
-    }
-  }
-}
-
-/**
- * Process the send e-mail action form submission.
- */
-function feedback_send_email_action_submit($form, $form_state) {
-  // Process the HTML form to store configuration. The keyed array that
-  // we return will be serialized to the database.
-  $params = array(
-    'recipients' => $form_state['values']['recipients'],
-    'subject'    => $form_state['values']['subject'],
-    'message'    => $form_state['values']['message'],
-  );
-  return $params;
-}
-
-/**
- * Implements the feedback send e-mail action.
- */
-function feedback_send_email_action($entry, $context) {
-  $account = user_load($entry->uid);
-  $from = variable_get('site_name', 'Drupal') . ' <' . variable_get('site_mail', '') . '>';
-  $params = array('entry' => $entry, 'account' => $account, 'context' => $context);
-  // Send the e-mail to the recipients using the site default language.
-  drupal_mail('feedback', 'send_email_action', $context['recipients'], language_default(), $params, $from);
-  watchdog('feedback', 'Feedback information sent to %recipients', array('%recipients' => $context['recipients']));
-}
-
-/**
- * Implements hook_mail().
- */
-function feedback_mail($key, &$message, $params) {
-  $language = $message['language'];
-  $entry = $params['entry'];
-  $account = $params['account'];
-  $context = $params['context'];
-  $variables = array(
-    '!site_name' => variable_get('site_name', 'Drupal'),
-    '!uid' => $account->uid,
-    '!username' => $account->name ? $account->name : t('Anonymous'),
-    '!usermail' => $account->mail ? $account->mail : t('unknown'),
-    '!status' => $entry->status ? t('Processed') : t('Open'),
-    '!message' => $entry->message,
-    '!url' => url($entry->location, array('absolute' => TRUE, 'language' => $language)),
-    '!useragent' => $entry->useragent,
-    '!date' => format_date($entry->timestamp, 'small', '', NULL, $language->language),
-  );
-  $subject = strtr($context['subject'], $variables);
-  $body = strtr($context['message'], $variables);
-  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
-  $message['body'][] = drupal_html_to_text($body);
-}
-
-
 /**
  * Implements hook_mollom_form_list().
  */
@@ -820,3 +647,23 @@ function feedback_views_api() {
     'path' => drupal_get_path('module', 'feedback') . '/views',
   );
 }
+
+/**
+ * Implements hook_feedback_insert().
+ */
+function feedback_feedback_insert($entry) {
+  // Trigger rule if Rules is enabled
+  if (module_exists('rules')) {
+    rules_invoke_event('feedback_insert', $entry);
+  }
+}
+
+/**
+ * Implements hook_feedback_update().
+ */
+function feedback_feedback_update($entry) {
+  // Trigger rule if Rules is enabled
+  if (module_exists('rules')) {
+    rules_invoke_event('feedback_update', $entry);
+  }
+}

+ 0 - 593
sites/all/modules/contrib/users/feedback/feedback.module.orig

@@ -1,593 +0,0 @@
-<?php
-
-/**
- * @file
- * Allows site visitors and users to report issues about this site.
- */
-
-/**
- * Open state (unprocessed) for feedback entries.
- */
-define('FEEDBACK_OPEN', 0);
-
-/**
- * Processed state for feedback entries.
- */
-define('FEEDBACK_PROCESSED', 1);
-
-/**
- * Implements hook_theme().
- */
-function feedback_theme() {
-  return array(
-    'feedback_admin_view_form' => array(
-      'render element' => 'form',
-    ),
-    'feedback_entry' => array(
-      'render element' => 'elements',
-      'template' => 'feedback-entry',
-      'file' => 'feedback.admin.inc',
-    ),
-    'feedback_form_display' => array(
-      'template' => 'feedback-form-display',
-      'variables' => array('title' => NULL, 'content' => NULL),
-    ),
-  );
-}
-
-/**
- * Implements hook_entity_info().
- */
-function feedback_entity_info() {
-  $return = array(
-    'feedback' => array(
-      'label' => t('Feedback'),
-      'controller class' => 'FeedbackController',
-      'base table' => 'feedback',
-      'uri callback' => 'feedback_uri',
-      'fieldable' => TRUE,
-      'entity keys' => array(
-        'id' => 'fid',
-      ),
-      'bundles' => array(
-        'feedback' => array(
-          'label' => t('Feedback'),
-          'admin' => array(
-            'path' => 'admin/config/user-interface/feedback',
-            'access arguments' => array('administer feedback'),
-          ),
-        ),
-      ),
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full feedback entry'),
-          'custom settings' => FALSE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom settings' => FALSE,
-        ),
-        'widget' => array(
-          'label' => t('Widget'),
-          'custom settings' => FALSE,
-        ),
-      ),
-      // Disable Metatags (metatag) module's entity form additions.
-      'metatags' => FALSE,
-    ),
-  );
-
-  return $return;
-}
-
-/**
- * Implements hook_field_extra_fields().
- */
-function feedback_field_extra_fields() {
-  $extras['feedback']['feedback']['form']['help'] = array(
-    'label' => t('Help'),
-    'description' => t('Feedback submission guidelines'),
-    'weight' => -10,
-  );
-  $extras['feedback']['feedback']['form']['messages'] = array(
-    'label' => t('Entries'),
-    'description' => t('Existing feedback entries for the current page'),
-    'weight' => -5,
-  );
-  $extras['feedback']['feedback']['form']['message'] = array(
-    'label' => t('Message'),
-    'description' => t('Feedback message form text field'),
-    'weight' => 0,
-  );
-
-  $extras['feedback']['feedback']['display']['location'] = array(
-    'label' => t('Location'),
-    'description' => t('The URL of the page the message was submitted on'),
-    'weight' => -15,
-  );
-  $extras['feedback']['feedback']['display']['date'] = array(
-    'label' => t('Date'),
-    'description' => t('The submission date of the message'),
-    'weight' => -10,
-  );
-  $extras['feedback']['feedback']['display']['user'] = array(
-    'label' => t('User'),
-    'description' => t('The name of the user who submitted the message'),
-    'weight' => -5,
-  );
-  $extras['feedback']['feedback']['display']['message'] = array(
-    'label' => t('Message'),
-    'description' => t('The main feedback message'),
-    'weight' => 0,
-  );
-  return $extras;
-}
-
-/**
- * Entity uri callback.
- */
-function feedback_uri($entry) {
-  return array(
-    'path' => 'admin/reports/feedback/' . $entry->fid,
-  );
-}
-
-/**
- * Implements hook_permission().
- */
-function feedback_permission() {
-  return array(
-    'access feedback form' => array(
-      'title' => t('Access feedback form'),
-      'description' => t('Submit feedback messages.'),
-    ),
-    'view feedback messages' => array(
-      'title' => t('View feedback messages'),
-      'description' => t('View, process, and delete submitted feedback messages.'),
-    ),
-    'administer feedback' => array(
-      'title' => t('Administer feedback settings'),
-    ),
-  );
-}
-
-/**
- * Implements hook_menu().
- */
-function feedback_menu() {
-  $items['admin/reports/feedback'] = array(
-    'title' => 'Feedback messages',
-    'description' => 'View feedback messages.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('feedback_admin_view_form'),
-    'access arguments' => array('view feedback messages'),
-    'file' => 'feedback.admin.inc',
-  );
-  $items['admin/reports/feedback/%feedback'] = array(
-    'title' => 'Feedback entry',
-    'page callback' => 'feedback_view',
-    'page arguments' => array(3),
-    'access arguments' => array('view feedback messages'),
-    'file' => 'feedback.admin.inc',
-  );
-  $items['admin/reports/feedback/%feedback/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-  $items['admin/reports/feedback/%feedback/edit'] = array(
-    'title' => 'Edit',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('feedback_entry_form', 3),
-    'access arguments' => array('view feedback messages'),
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'feedback.admin.inc',
-  );
-  $items['admin/reports/feedback/%feedback/delete'] = array(
-    'title' => 'Delete feedback entry',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('feedback_delete_confirm', 3),
-    'access arguments' => array('view feedback messages'),
-    'type' => MENU_CALLBACK,
-    'file' => 'feedback.admin.inc',
-  );
-  $items['admin/config/user-interface/feedback'] = array(
-    'title' => 'Feedback',
-    'description' => 'Administer feedback settings.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('feedback_admin_settings_form'),
-    'access arguments' => array('administer feedback'),
-    'file' => 'feedback.admin.inc',
-  );
-  $items['admin/config/user-interface/feedback/settings'] = array(
-    'title' => 'Settings',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-
-  return $items;
-}
-
-/**
- * Implements hook_page_build().
- */
-function feedback_page_build(&$page) {
-  if (user_access('access feedback form') && !feedback_match_path(variable_get('feedback_excluded_paths', 'admin/reports/feedback'))) {
-    $page['page_bottom']['feedback'] = array(
-      '#theme' => 'feedback_form_display',
-      '#title' => t('Feedback'),
-      '#content' => drupal_get_form('feedback_form'),
-    );
-    $path = drupal_get_path('module', 'feedback');
-    $page['page_bottom']['feedback']['#attached']['css'][] = $path . '/feedback.css';
-    $page['page_bottom']['feedback']['#attached']['js'][] = $path . '/feedback.js';
-  }
-}
-
-/**
- * Check if the current path matches any pattern in a set of patterns.
- *
- * @param $patterns
- *   String containing a set of patterns separated by \n, \r or \r\n.
- *
- * @return
- *   Boolean value: TRUE if the current path or alias matches a pattern.
- */
-function feedback_match_path($patterns) {
-  // Convert path to lowercase. This allows comparison of the same path
-  // with different case. Ex: /Page, /page, /PAGE.
-  $patterns = drupal_strtolower($patterns);
-
-  // Convert the current path to lowercase.
-  $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
-
-  // Compare the lowercase internal and lowercase path alias (if any).
-  $page_match = drupal_match_path($path, $patterns);
-  if ($path != $_GET['q']) {
-    $page_match = $page_match || drupal_match_path($_GET['q'], $patterns);
-  }
-
-  return $page_match;
-}
-
-/**
- * Form constructor for the feedback form.
- *
- * @see feedback_form_submit()
- * @ingroup forms
- */
-function feedback_form($form, &$form_state) {
-  $form['#attributes']['class'] = array('feedback-form');
-
-  // Store the path on which this form is displayed.
-  if (!isset($form_state['inline']['location'])) {
-    $form_state['inline']['location'] = $_GET['q'];
-  }
-  $form['location'] = array(
-    '#type' => 'value',
-    '#value' => $form_state['inline']['location'],
-  );
-
-  $form['help'] = array(
-    '#prefix' => '<div class="feedback-help">',
-    '#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.'),
-    '#suffix' => '</div>',
-  );
-  if (user_access('view feedback messages')) {
-    if (arg(0) != 'node') {
-      $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location_masked' => feedback_mask_path($_GET['q'])));
-    }
-    else {
-      $feedbacks = feedback_load_multiple(array(), array('status' => FEEDBACK_OPEN, 'location' => $_GET['q']));
-    }
-    if ($feedbacks) {
-      form_load_include($form_state, 'inc', 'feedback', 'feedback.admin');
-      $form['messages'] = array(
-        '#prefix' => '<div class="feedback-messages">',
-        '#suffix' => '</div>',
-      );
-      foreach ($feedbacks as $fid => $feedback) {
-        $form['messages'][$fid]['#feedback'] = $feedback;
-        $form['messages'][$fid]['submitted'] = array('#markup' => t('@feedback-author !feedback-date:', array('@feedback-author' => format_username($feedback), '!feedback-date' => format_date($feedback->timestamp, 'small'))));
-        $form['messages'][$fid]['submitted']['#prefix'] = '<div class="feedback-submitted">';
-        $form['messages'][$fid]['submitted']['#suffix'] = '</div>';
-        $form['messages'][$fid]['body'] = feedback_build_content($feedback, 'widget');
-        $form['messages'][$fid]['body']['#prefix'] = '<div class="feedback-body">';
-        $form['messages'][$fid]['body']['#suffix'] = '</div>';
-      }
-    }
-  }
-  $form['message'] = array(
-    '#type' => 'textarea',
-    '#attributes' => array('class' => array('feedback-message')),
-    '#cols' => 20,
-    '#title' => t('Message'),
-    '#required' => TRUE,
-    '#wysiwyg' => FALSE,
-  );
-
-  $entry = new stdClass();
-  field_attach_form('feedback', $entry, $form, $form_state);
-
-  $form['actions'] = array(
-    '#type' => 'actions',
-    // Without clearfix, the AJAX throbber wraps in an ugly way.
-    // @todo Patch #type actions in core?
-    '#attributes' => array('class' => array('clearfix')),
-  );
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Send feedback'),
-    '#id' => 'feedback-submit',
-    '#ajax' => array(
-      'wrapper' => 'feedback-form',
-      'callback' => 'feedback_form_ajax_callback',
-      'progress' => array(
-        'type' => 'throbber',
-        'message' => '',
-      ),
-    ),
-  );
-
-  return $form;
-}
-
-/**
- * Form submission handler for feedback_form().
- */
-function feedback_form_submit($form, &$form_state) {
-  $entry = new stdClass();
-  entity_form_submit_build_entity('feedback', $entry, $form, $form_state);
-  $entry->message = $form_state['values']['message'];
-  $entry->location = $form_state['values']['location'];
-  feedback_save($entry);
-
-  drupal_set_message(t('Thanks for your feedback!'));
-}
-
-/**
- * AJAX callback for feedback_form() submissions.
- */
-function feedback_form_ajax_callback($form, &$form_state) {
-  // If there was a form validation error, re-render the entire form.
-  if (!$form_state['executed']) {
-    return $form;
-  }
-
-  // Otherwise, return a fresh copy of the form, so the user may post additional
-  // feedback.
-  // Reset the static cache of drupal_html_id().
-  // @see drupal_process_form()
-  // @see drupal_html_id()
-  $seen_ids = &drupal_static('drupal_html_id');
-  $seen_ids = array();
-
-  // Prevent the form from being processed again.
-  // @see drupal_build_form()
-  list($form, $new_form_state) = ajax_get_form();
-  $new_form_state['input'] = array();
-  drupal_process_form($form['#form_id'], $form, $new_form_state);
-
-  // Return AJAX commands in order to output the special success message.
-  // @see ajax_deliver()
-  $build = array('#type' => 'ajax');
-  $html = drupal_render($form);
-  $build['#commands'][] = ajax_command_insert(NULL, $html);
-
-  // A successful form submission normally means that there were no errors, so
-  // we only render status messages.
-  $messages = drupal_get_messages();
-  $messages += array('status' => array());
-  $messages = implode('<br />', $messages['status']);
-  $html = '<div id="feedback-status-message">' . $messages . '</div>';
-  $build['#commands'][] = ajax_command_append('#block-feedback-form', $html);
-  return $build;
-}
-
-/**
- * Loads a feedback entry from the database.
- *
- * @param $fid
- *   Integer specifying the feedback ID to load.
- *
- * @return
- *   A loaded feedback entry object upon successful load, or FALSE if the entry
- *   cannot be loaded.
- *
- * @see feedback_load_multiple()
- */
-function feedback_load($fid) {
-  $entries = feedback_load_multiple(array($fid));
-  return (isset($entries[$fid]) ? $entries[$fid] : FALSE);
-}
-
-/**
- * Loads feedback entries from the database.
- *
- * @param $fids
- *   An array of feedback entry IDs.
- * @param $conditions
- *   An associative array of conditions on the {feedback} table, where the keys
- *   are the database fields and the values are the values those fields
- *   must have.
- *
- * @return
- *   An array of feedback entry objects indexed by fid.
- *
- * @see hook_feedback_load()
- * @see feedback_load()
- * @see entity_load()
- * @see EntityFieldQuery
- */
-function feedback_load_multiple($fids = array(), $conditions = array()) {
-  return entity_load('feedback', $fids, $conditions);
-}
-
-/**
- * Saves changes to a feedback entry or adds a new feedback entry.
- *
- * @param $entry
- *   The feedback entry object to modify or add. If $entry->fid is omitted, a
- *   new entry will be added.
- *
- * @see hook_feedback_insert()
- * @see hook_feedback_update()
- */
-function feedback_save($entry) {
-  global $user;
-
-  // Load the stored entity, if any.
-  if (!empty($entry->fid) && !isset($entry->original)) {
-    $entry->original = entity_load_unchanged('feedback', $entry->fid);
-  }
-
-  field_attach_presave('feedback', $entry);
-
-  // Allow modules to alter the feedback entry before saving.
-  module_invoke_all('feedback_presave', $entry);
-  module_invoke_all('entity_presave', $entry, 'feedback');
-
-  if (empty($entry->fid)) {
-    $entry->message = trim($entry->message);
-
-    $defaults = array(
-      'uid' => $user->uid,
-      'location_masked' => feedback_mask_path($entry->location),
-      'url' => url($entry->location, array('absolute' => TRUE)),
-      'timestamp' => REQUEST_TIME,
-      'useragent' => $_SERVER['HTTP_USER_AGENT'],
-    );
-    foreach ($defaults as $key => $default) {
-      if (!isset($entry->$key)) {
-        $entry->$key = $default;
-      }
-    }
-
-    $status = drupal_write_record('feedback', $entry);
-    field_attach_insert('feedback', $entry);
-    module_invoke_all('feedback_insert', $entry);
-    module_invoke_all('entity_insert', $entry, 'feedback');
-  }
-  else {
-    $status = drupal_write_record('feedback', $entry, 'fid');
-
-    field_attach_update('feedback', $entry);
-    module_invoke_all('feedback_update', $entry);
-    module_invoke_all('entity_update', $entry, 'feedback');
-  }
-  unset($entry->original);
-
-  return $status;
-}
-
-/**
- * Deletes a feedback entry.
- *
- * @param $fid
- *   A feedback entry ID.
- */
-function feedback_delete($fid) {
-  feedback_delete_multiple(array($fid));
-}
-
-/**
- * Deletes multiple feedback entries.
- *
- * @param $fids
- *   An array of feedback entry IDs.
- */
-function feedback_delete_multiple($fids) {
-  if (!empty($fids)) {
-    $entries = feedback_load_multiple($fids);
-    foreach ($entries as $fid => $entry) {
-      field_attach_delete('feedback', $entry);
-      module_invoke_all('feedback_delete', $entry);
-      module_invoke_all('entity_delete', $entry, 'feedback');
-    }
-    db_delete('feedback')
-      ->condition('fid', $fids, 'IN')
-      ->execute();
-  }
-}
-
-/**
- * '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'.
- *
- * @todo Use the untranslated patch of menu_get_item() instead.
- */
-function feedback_mask_path($path) {
-  return preg_replace('@/\d+@', '/%', $path);
-}
-
-/**
- * Implements hook_user_cancel().
- */
-function feedback_user_cancel($edit, $account, $method) {
-  switch ($method) {
-    case 'user_cancel_reassign':
-      db_update('feedback')
-        ->fields(array('uid' => 0))
-        ->condition('uid', $account->uid)
-        ->execute();
-      break;
-  }
-}
-
-/**
- * Implements hook_user_delete().
- */
-function feedback_user_delete($account) {
-  $fids = db_query('SELECT fid FROM {feedback} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
-  feedback_delete_multiple($fids);
-}
-
-/**
- * Implements hook_mollom_form_list().
- */
-function feedback_mollom_form_list() {
-  $forms['feedback_form'] = array(
-    'title' => t('Feedback form'),
-    'entity' => 'feedback',
-    'bundle' => 'feedback',
-    'entity delete multiple callback' => 'feedback_delete_multiple',
-    'delete form' => 'feedback_delete_confirm',
-    'delete form file' => array(
-      'name' => 'feedback.admin',
-    ),
-    'report access' => array('view feedback messages'),
-  );
-  return $forms;
-}
-
-/**
- * Implements hook_mollom_form_info().
- */
-function feedback_mollom_form_info($form_id) {
-  $form_info = array(
-    'mode' => MOLLOM_MODE_ANALYSIS,
-    'bypass access' => array('administer feedback'),
-    'elements' => array(
-      'message' => t('Message'),
-    ),
-  );
-  mollom_form_info_add_fields($form_info, 'feedback', 'feedback');
-  return $form_info;
-}
-
-/**
- * Implements hook_views_api();
- */
-function feedback_views_api() {
-  return array(
-    'api' => 3.0,
-    'path' => drupal_get_path('module', 'feedback') . '/views',
-  );
-}

+ 55 - 0
sites/all/modules/contrib/users/feedback/feedback.rules.inc

@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Rules integration for feedback.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function feedback_rules_event_info() {
+  $defaults = array(
+    'group' => t('Feedback'),
+    'module' => 'feedback',
+    'access callback' => 'feedback_rules_integration_access',
+  );
+  return array(
+    'feedback_insert' => $defaults + array(
+      'label' => t('After saving new feedback'),
+      'variables' => array(
+        'feedback' => array('type' => 'feedback', 'label' => t('Feedback message')),
+      ),
+    ),
+    'feedback_update' => $defaults + array(
+      'label' => t('After saving existing feedback'),
+      'variables' => array(
+        'feedback' => array(
+          'type' => 'feedback',
+          'label' => t('Feedback message'),
+        ),
+        'feedback_unchanged' => array(
+          'type' => 'feedback',
+          'label' => t('unchanged feedback entity'),
+          'handler' => 'rules_events_entity_unchanged',
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * Rules integration access callback.
+ */
+function feedback_rules_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'feedback');
+  }
+}
+
+/**
+ * @}
+ */

+ 4 - 71
sites/all/modules/contrib/users/feedback/tests/feedback.test

@@ -20,7 +20,8 @@ class FeedbackTestCase extends DrupalWebTestCase {
   }
 
   function setUp() {
-    parent::setUp(array('feedback', 'trigger'));
+    // @todo Remove soft-dependency on Block.
+    parent::setUp(array('block', 'feedback'));
 
     $this->admin_user = $this->drupalCreateUser(array('access feedback form', 'view feedback messages', 'administer feedback'));
     $this->web_user = $this->drupalCreateUser(array('access feedback form'));
@@ -48,7 +49,7 @@ class FeedbackTestCase extends DrupalWebTestCase {
     $edit = array(
       'feedback-messages[0][1]' => TRUE,
     );
-    $this->drupalPost(NULL, $edit, t('Update'));
+    $this->drupalPost(NULL, $edit, t('Submit'));
     $this->assertFieldByName('feedback-messages[1][1]', 1, t('Processed message found.'));
   }
 
@@ -88,72 +89,4 @@ class FeedbackTestCase extends DrupalWebTestCase {
     $this->assertNoLinkByHref('admin/reports/feedback/1/delete');
     $this->assertNoRaw(check_plain($message), t('Message not found.'));
   }
-
-  /**
-   * Test the feedback triggers and actions.
-   */
-  function testFeedbackEmailAction() {
-    $test_user = $this->drupalCreateUser(array('administer actions', 'administer feedback', 'access feedback form'));
-    $this->drupalLogin($test_user);
-    $this->assignFeedbackEmailAction('feedback_insert', $test_user->mail);
-
-    // Insert a feedback entry.
-    $message = $this->randomString();
-    $edit = array(
-      'message' => $message,
-    );
-    $this->drupalPost('node', $edit, t('Send feedback'));
-    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $message);
-
-    $this->assignFeedbackEmailAction('feedback_update', $test_user->mail);
-
-    // Update a feedback entry.
-    $fid = db_query("SELECT fid FROM {feedback} LIMIT 0,1")->fetchField();
-    $entry = feedback_load($fid);
-    feedback_save($entry);
-    $this->assertFeedbackEmailTokenReplacement($test_user->mail, $entry->message);
-  }
-
-  /**
-   * Assigns a system_send_email_action to the passed-in trigger.
-   *
-   * @param $trigger
-   *   For example, 'user_login'
-   */
-  function assignFeedbackEmailAction($trigger, $mail) {
-    $form_name = "trigger_{$trigger}_assign_form";
-    $form_html_id = strtr($form_name, '_', '-');
-
-    $edit = array(
-      'actions_label' => $trigger . "_feedback_send_email_action",
-      'recipients' => $mail,
-      'subject' => $this->randomName(),
-      'message' => '!message',
-    );
-
-    $hash = drupal_hash_base64('feedback_send_email_action');
-    $this->drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
-    $this->assertText(t('The action has been successfully saved.'));
-
-    // Now we have to find out the action ID of what we created.
-    $aid = db_query('SELECT aid FROM {actions} WHERE callback = :callback AND label = :label', array(':callback' => 'feedback_send_email_action', ':label' => $edit['actions_label']))->fetchField();
-
-    $edit = array('aid' => drupal_hash_base64($aid));
-    $this->drupalPost('admin/structure/trigger/feedback', $edit, t('Assign'), array(), array(), $form_html_id);
-  }
-
-
-  /**
-   * Asserts correct token replacement for the given trigger and account.
-   *
-   * @param $account
-   *   The user account which triggered the action.
-   * @param $email_depth
-   *   Number of emails to scan, starting with most recent.
-   */
-  function assertFeedbackEmailTokenReplacement($mail, $message, $email_depth = 1) {
-    $this->verboseEmail($email_depth);
-    $this->assertMailString('body', $message, $email_depth);
-    $this->assertMail('to', $mail, t('Mail sent to correct destination'));
-  }
-}
+}