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