소스 검색

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 9 년 전
부모
커밋
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'));
-  }
-}
+}