From 06caf9c7c50b9c162af1a4831e16c94358b60faa Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 1 Aug 2016 11:58:51 +0100
Subject: [PATCH] Issue #306662 by naveenvalecha, andypost, larowlan, tim-e,
 mr.baileys, pguillard, alexpott, hussainweb, frankcarey, Tor Arne Thune,
 deepakaryan1988, jibran, tstoeckler: Add redirect option to site-wide contact
 forms

---
 .../config/install/contact.form.personal.yml  |  2 +
 .../contact/config/schema/contact.schema.yml  |  6 ++
 core/modules/contact/contact.post_update.php  | 30 ++++++++++
 .../contact/src/ContactFormEditForm.php       | 35 ++++++++++-
 .../contact/src/ContactFormInterface.php      | 46 ++++++++++++++
 .../contact/src/Entity/ContactForm.php        | 60 +++++++++++++++++++
 core/modules/contact/src/MessageForm.php      |  7 ++-
 .../contact/src/Tests/ContactSitewideTest.php | 58 +++++++++++++++++-
 .../contact/src/Tests/ContactStorageTest.php  |  2 +-
 .../src/Tests/Update/ContactUpdateTest.php    | 53 ++++++++++++++++
 .../config/install/contact.form.feedback.yml  |  2 +
 .../config/install/contact.form.feedback.yml  |  2 +
 12 files changed, 295 insertions(+), 8 deletions(-)
 create mode 100644 core/modules/contact/contact.post_update.php
 create mode 100644 core/modules/contact/src/Tests/Update/ContactUpdateTest.php

diff --git a/core/modules/contact/config/install/contact.form.personal.yml b/core/modules/contact/config/install/contact.form.personal.yml
index c766fddb3dd6..f08682a513e2 100644
--- a/core/modules/contact/config/install/contact.form.personal.yml
+++ b/core/modules/contact/config/install/contact.form.personal.yml
@@ -6,3 +6,5 @@ label: 'Personal contact form'
 recipients: {  }
 reply: ''
 weight: 0
+message: 'Your message has been sent.'
+redirect: ''
diff --git a/core/modules/contact/config/schema/contact.schema.yml b/core/modules/contact/config/schema/contact.schema.yml
index 5a62e9da32e4..1f0585db856b 100644
--- a/core/modules/contact/config/schema/contact.schema.yml
+++ b/core/modules/contact/config/schema/contact.schema.yml
@@ -22,6 +22,12 @@ contact.form.*:
     weight:
       type: integer
       label: 'Weight'
+    message:
+      type: label
+      label: 'Message displayed to user on submission'
+    redirect:
+      type: path
+      label: 'Redirect path on submission'
 
 contact.settings:
   type: config_object
diff --git a/core/modules/contact/contact.post_update.php b/core/modules/contact/contact.post_update.php
new file mode 100644
index 000000000000..32469a5a5145
--- /dev/null
+++ b/core/modules/contact/contact.post_update.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Post update functions for Contact.
+ */
+
+use Drupal\contact\Entity\ContactForm;
+
+/**
+ * @addtogroup updates-8.1.x-to-8.2.x
+ * @{
+ */
+
+/**
+ * Initialize 'message' and 'redirect' field values to 'contact_form' entities.
+ */
+function contact_post_update_add_message_redirect_field_to_contact_form() {
+  /** @var \Drupal\contact\ContactFormInterface $contact */
+  foreach (ContactForm::loadMultiple() as $contact) {
+    $contact
+      ->setMessage('Your message has been sent.')
+      ->setRedirectPath('')
+      ->save();
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.1.x-to-8.2.x".
+ */
diff --git a/core/modules/contact/src/ContactFormEditForm.php b/core/modules/contact/src/ContactFormEditForm.php
index 4eacea2ea2c0..473d31775900 100644
--- a/core/modules/contact/src/ContactFormEditForm.php
+++ b/core/modules/contact/src/ContactFormEditForm.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\contact;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityForm;
@@ -9,6 +10,8 @@
 use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
 use Egulias\EmailValidator\EmailValidator;
+use Drupal\Core\Path\PathValidatorInterface;
+use Drupal\Core\Render\Element\PathElement;
 
 /**
  * Base form for contact form edit forms.
@@ -23,14 +26,22 @@ class ContactFormEditForm extends EntityForm implements ContainerInjectionInterf
    */
   protected $emailValidator;
 
+  /**
+   * The path validator.
+   *
+   * @var \Drupal\Core\Path\PathValidatorInterface
+   */
+  protected $pathValidator;
+
   /**
    * Constructs a new ContactFormEditForm.
    *
    * @param \Egulias\EmailValidator\EmailValidator $email_validator
    *   The email validator.
    */
-  public function __construct(EmailValidator $email_validator) {
+  public function __construct(EmailValidator $email_validator, PathValidatorInterface $path_validator) {
    $this->emailValidator = $email_validator;
+   $this->pathValidator = $path_validator;
   }
 
   /**
@@ -38,7 +49,8 @@ public function __construct(EmailValidator $email_validator) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('email.validator')
+      $container->get('email.validator'),
+      $container->get('path.validator')
     );
   }
 
@@ -82,6 +94,19 @@ public function form(array $form, FormStateInterface $form_state) {
       '#description' => $this->t("Example: 'webmaster@example.com' or 'sales@example.com,support@example.com' . To specify multiple recipients, separate each email address with a comma."),
       '#required' => TRUE,
     );
+    $form['message'] = array(
+      '#type' => 'textarea',
+      '#title' => $this->t('Message'),
+      '#default_value' => $contact_form->getMessage(),
+      '#description' => $this->t('The message to display to the user after submission of this form. Leave blank for no message.'),
+    );
+    $form['redirect'] = array(
+      '#type' => 'path',
+      '#title' => $this->t('Redirect path'),
+      '#convert_path' => PathElement::CONVERT_NONE,
+      '#default_value' => $contact_form->getRedirectPath(),
+      '#description' => $this->t('Path to redirect the user to after submission of this form. For example, type "/about" to redirect to that page. Use a relative path with a slash in front.'),
+    );
     $form['reply'] = array(
       '#type' => 'textarea',
       '#title' => $this->t('Auto-reply'),
@@ -119,6 +144,12 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
       }
     }
     $form_state->setValue('recipients', $recipients);
+    $redirect_url = $form_state->getValue('redirect');
+    if ($redirect_url && $this->pathValidator->isValid($redirect_url)) {
+      if (Unicode::substr($redirect_url, 0, 1) !== '/') {
+        $form_state->setErrorByName('redirect', $this->t('The path should start with /.'));
+      }
+    }
   }
 
   /**
diff --git a/core/modules/contact/src/ContactFormInterface.php b/core/modules/contact/src/ContactFormInterface.php
index eb24fcf2c20a..d179c1563d56 100644
--- a/core/modules/contact/src/ContactFormInterface.php
+++ b/core/modules/contact/src/ContactFormInterface.php
@@ -9,6 +9,14 @@
  */
 interface ContactFormInterface extends ConfigEntityInterface {
 
+  /**
+   * Returns the message to be displayed to user.
+   *
+   * @return string
+   *   A user message.
+   */
+  public function getMessage();
+
   /**
    * Returns list of recipient email addresses.
    *
@@ -17,6 +25,24 @@ interface ContactFormInterface extends ConfigEntityInterface {
    */
   public function getRecipients();
 
+  /**
+   * Returns the path for redirect.
+   *
+   * @return string
+   *   The redirect path.
+   */
+  public function getRedirectPath();
+
+  /**
+   * Returns the url object for redirect path.
+   *
+   * Empty redirect property results a url object of front page.
+   *
+   * @return \Drupal\core\Url
+   *   The redirect url object.
+   */
+  public function getRedirectUrl();
+
   /**
    * Returns an auto-reply message to send to the message author.
    *
@@ -33,6 +59,16 @@ public function getReply();
    */
   public function getWeight();
 
+  /**
+   * Sets the message to be displayed to the user.
+   *
+   * @param string $message
+   *   The message to display after form is submitted.
+   *
+   * @return $this
+   */
+  public function setMessage($message);
+
   /**
    * Sets list of recipient email addresses.
    *
@@ -43,6 +79,16 @@ public function getWeight();
    */
   public function setRecipients($recipients);
 
+  /**
+   * Sets the redirect path.
+   *
+   * @param string $redirect
+   *   The desired path.
+   *
+   * @return $this
+   */
+  public function setRedirectPath($redirect);
+
   /**
    * Sets an auto-reply message to send to the message author.
    *
diff --git a/core/modules/contact/src/Entity/ContactForm.php b/core/modules/contact/src/Entity/ContactForm.php
index 255d51455eb9..9c6374706559 100644
--- a/core/modules/contact/src/Entity/ContactForm.php
+++ b/core/modules/contact/src/Entity/ContactForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\contact\ContactFormInterface;
+use Drupal\Core\Url;
 
 /**
  * Defines the contact form entity.
@@ -39,6 +40,8 @@
  *     "recipients",
  *     "reply",
  *     "weight",
+ *     "message",
+ *     "redirect",
  *   }
  * )
  */
@@ -58,6 +61,13 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
    */
   protected $label;
 
+  /**
+   * The message displayed to user on form submission.
+   *
+   * @var string
+   */
+  protected $message;
+
   /**
    * List of recipient email addresses.
    *
@@ -65,6 +75,13 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
    */
   protected $recipients = array();
 
+  /**
+   * The path to redirect to on form submission.
+   *
+   * @var string
+   */
+  protected $redirect;
+
   /**
    * An auto-reply message.
    *
@@ -79,6 +96,21 @@ class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface
    */
   protected $weight = 0;
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getMessage() {
+    return $this->message;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMessage($message) {
+    $this->message = $message;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -94,6 +126,34 @@ public function setRecipients($recipients) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectPath() {
+    return $this->redirect;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectUrl() {
+    if ($this->redirect) {
+      $url = Url::fromUserInput($this->redirect);
+    }
+    else {
+      $url = Url::fromRoute('<front>');
+    }
+    return $url;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRedirectPath($redirect) {
+    $this->redirect = $redirect;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php
index 15ddd72b533f..668dd0638fa5 100644
--- a/core/modules/contact/src/MessageForm.php
+++ b/core/modules/contact/src/MessageForm.php
@@ -206,9 +206,12 @@ public function save(array $form, FormStateInterface $form_state) {
     $message = $this->entity;
     $user = $this->currentUser();
     $this->mailHandler->sendMailMessages($message, $user);
+    $contact_form = $message->getContactForm();
 
     $this->flood->register('contact', $this->config('contact.settings')->get('flood.interval'));
-    drupal_set_message($this->t('Your message has been sent.'));
+    if ($submission_message = $contact_form->getMessage()) {
+      drupal_set_message($submission_message);
+    }
 
     // To avoid false error messages caused by flood control, redirect away from
     // the contact form; either to the contacted user account or the front page.
@@ -216,7 +219,7 @@ public function save(array $form, FormStateInterface $form_state) {
       $form_state->setRedirectUrl($message->getPersonalRecipient()->urlInfo());
     }
     else {
-      $form_state->setRedirect('<front>');
+      $form_state->setRedirectUrl($contact_form->getRedirectUrl());
     }
     // Save the message. In core this is a no-op but should contrib wish to
     // implement message storage, this will make the task of swapping in a real
diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php
index b049f2517f53..c148715039eb 100644
--- a/core/modules/contact/src/Tests/ContactSitewideTest.php
+++ b/core/modules/contact/src/Tests/ContactSitewideTest.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\contact\Entity\ContactForm;
 use Drupal\Core\Mail\MailFormatHelper;
+use Drupal\Core\Url;
 use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\simpletest\WebTestBase;
 use Drupal\Core\Entity\EntityTypeInterface;
@@ -154,7 +155,7 @@ function testSiteWideContact() {
     $this->assertEscaped($recipients[0]);
 
     // Test update contact form.
-    $this->updateContactForm($id, $label = $this->randomMachineName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomMachineName(30), FALSE);
+    $this->updateContactForm($id, $label = $this->randomMachineName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomMachineName(30), FALSE, 'Your message has been sent.', '/user');
     $config = $this->config('contact.form.' . $id)->get();
     $this->assertEqual($config['label'], $label);
     $this->assertEqual($config['recipients'], array($recipients[0], $recipients[1]));
@@ -298,6 +299,46 @@ function testSiteWideContact() {
     $this->assertEqual($mail['subject'], t('[@label] @subject', array('@label' => $label, '@subject' => $edit['subject[0][value]'])));
     $this->assertTrue(strpos($mail['body'], $field_label));
     $this->assertTrue(strpos($mail['body'], $edit[$field_name . '[0][value]']));
+
+    // Test messages and redirect.
+    /** @var \Drupal\contact\ContactFormInterface $form */
+    $form = ContactForm::load($contact_form);
+    $form->setMessage('Thanks for your submission.');
+    $form->setRedirectPath('/user/' . $admin_user->id());
+    $form->save();
+    // Check that the field is displayed.
+    $this->drupalGet('contact/' . $contact_form);
+
+    // Submit the contact form and verify the content.
+    $edit = array(
+      'subject[0][value]' => $this->randomMachineName(),
+      'message[0][value]' => $this->randomMachineName(),
+      $field_name . '[0][value]' => $this->randomMachineName(),
+    );
+    $this->drupalPostForm(NULL, $edit, t('Send message'));
+    $this->assertText('Thanks for your submission.');
+    $this->assertUrl('user/' . $admin_user->id());
+
+    // Test Empty message.
+    /** @var \Drupal\contact\ContactFormInterface $form */
+    $form = ContactForm::load($contact_form);
+    $form->setMessage('');
+    $form->setRedirectPath('/user/' . $admin_user->id());
+    $form->save();
+    $this->drupalGet('admin/structure/contact/manage/' . $contact_form);
+    // Check that the field is displayed.
+    $this->drupalGet('contact/' . $contact_form);
+
+    // Submit the contact form and verify the content.
+    $edit = array(
+      'subject[0][value]' => $this->randomMachineName(),
+      'message[0][value]' => $this->randomMachineName(),
+      $field_name . '[0][value]' => $this->randomMachineName(),
+    );
+    $this->drupalPostForm(NULL, $edit, t('Send message'));
+    $result = $this->xpath('//div[@role=:role]', array(':role' => 'contentinfo'));
+    $this->assertEqual(count($result), 0, 'Messages not found.');
+    $this->assertUrl('user/' . $admin_user->id());
   }
 
   /**
@@ -359,13 +400,17 @@ function testAutoReply() {
    *   form.
    * @param bool $selected
    *   A Boolean indicating whether the form should be selected by default.
+   * @param string $message
+   *   The message that will be displayed to a user upon completing the contact
+   *   form.
    * @param array $third_party_settings
    *   Array of third party settings to be added to the posted form data.
    */
-  function addContactForm($id, $label, $recipients, $reply, $selected, $third_party_settings = []) {
+  function addContactForm($id, $label, $recipients, $reply, $selected, $message = 'Your message has been sent.', $third_party_settings = []) {
     $edit = array();
     $edit['label'] = $label;
     $edit['id'] = $id;
+    $edit['message'] = $message;
     $edit['recipients'] = $recipients;
     $edit['reply'] = $reply;
     $edit['selected'] = ($selected ? TRUE : FALSE);
@@ -387,13 +432,20 @@ function addContactForm($id, $label, $recipients, $reply, $selected, $third_part
    *   form.
    * @param bool $selected
    *   A Boolean indicating whether the form should be selected by default.
+   * @param string $message
+   *   The message that will be displayed to a user upon completing the contact
+   *   form.
+   * @param string $redirect
+   *   The path where user will be redirect after this form has been submitted..
    */
-  function updateContactForm($id, $label, $recipients, $reply, $selected) {
+  function updateContactForm($id, $label, $recipients, $reply, $selected, $message = 'Your message has been sent.', $redirect = '/') {
     $edit = array();
     $edit['label'] = $label;
     $edit['recipients'] = $recipients;
     $edit['reply'] = $reply;
     $edit['selected'] = ($selected ? TRUE : FALSE);
+    $edit['message'] = $message;
+    $edit['redirect'] = $redirect;
     $this->drupalPostForm("admin/structure/contact/manage/$id", $edit, t('Save'));
   }
 
diff --git a/core/modules/contact/src/Tests/ContactStorageTest.php b/core/modules/contact/src/Tests/ContactStorageTest.php
index 6fd3edd2df1b..ad0e8d46c534 100644
--- a/core/modules/contact/src/Tests/ContactStorageTest.php
+++ b/core/modules/contact/src/Tests/ContactStorageTest.php
@@ -47,7 +47,7 @@ public function testContactStorage() {
     $this->drupalLogin($admin_user);
     // Create first valid contact form.
     $mail = 'simpletest@example.com';
-    $this->addContactForm($id = Unicode::strtolower($this->randomMachineName(16)), $label = $this->randomMachineName(16), implode(',', array($mail)), '', TRUE, [
+    $this->addContactForm($id = Unicode::strtolower($this->randomMachineName(16)), $label = $this->randomMachineName(16), implode(',', array($mail)), '', TRUE, 'Your message has been sent.', [
       'send_a_pony' => 1,
     ]);
     $this->assertText(t('Contact form @label has been added.', array('@label' => $label)));
diff --git a/core/modules/contact/src/Tests/Update/ContactUpdateTest.php b/core/modules/contact/src/Tests/Update/ContactUpdateTest.php
new file mode 100644
index 000000000000..4cbfd64aaa64
--- /dev/null
+++ b/core/modules/contact/src/Tests/Update/ContactUpdateTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\contact\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests contact update path.
+ *
+ * @group contact
+ */
+class ContactUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests contact_form updates.
+   *
+   * @see contact_post_update_add_message_redirect_field_to_contact_form()
+   */
+  public function testPostUpdateContactFormFields() {
+    // Check that contact_form does not have fields redirect and message.
+    $config_factory = \Drupal::configFactory();
+    // Check that contact_form entities are more than zero.
+    $contact_forms = $config_factory->listAll('contact.form.');
+    $this->assertTrue(count($contact_forms), 'There are contact forms to update.');
+    foreach ($contact_forms as $contact_config_name) {
+      $contact_form_data = $config_factory->get($contact_config_name)->get();
+      $this->assertFalse(isset($contact_form_data['message']), 'Prior to running the update the "message" key does not exist.');
+      $this->assertFalse(isset($contact_form_data['redirect']), 'Prior to running the update the "redirect" key does not exist.');
+    }
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that the contact_form entities have been updated.
+    foreach ($contact_forms as $contact_config_name) {
+      $contact_form_data = $config_factory->get($contact_config_name)->get();
+      $this->assertTrue(isset($contact_form_data['message']), 'After running the update the "message" key exists.');
+      $this->assertEqual('Your message has been sent.', $contact_form_data['message']);
+      $this->assertTrue(isset($contact_form_data['redirect']), 'After running the update the "redirect" key exists.');
+      $this->assertEqual('', $contact_form_data['redirect']);
+    }
+  }
+
+}
diff --git a/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml b/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
index 8fb776506cb2..d6e048f779b4 100644
--- a/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
+++ b/core/modules/contact/tests/modules/contact_test/config/install/contact.form.feedback.yml
@@ -5,3 +5,5 @@ reply: ''
 weight: 0
 status: true
 langcode: en
+message: 'Your message has been sent.'
+redirect: ''
diff --git a/core/profiles/standard/config/install/contact.form.feedback.yml b/core/profiles/standard/config/install/contact.form.feedback.yml
index 47f0e908d473..e222ecd4bffa 100644
--- a/core/profiles/standard/config/install/contact.form.feedback.yml
+++ b/core/profiles/standard/config/install/contact.form.feedback.yml
@@ -7,3 +7,5 @@ recipients:
   - admin@example.com
 reply: ''
 weight: 0
+message: 'Your message has been sent.'
+redirect: ''
-- 
GitLab