diff --git a/core/modules/contact/config/contact.category.personal.yml b/core/modules/contact/config/contact.category.personal.yml new file mode 100644 index 0000000..6b40a8d --- /dev/null +++ b/core/modules/contact/config/contact.category.personal.yml @@ -0,0 +1,5 @@ +id: personal +label: 'Personal contact form' +recipients: [] +reply: '' +weight: '0' diff --git a/core/modules/contact/contact.pages.inc b/core/modules/contact/contact.pages.inc index 5ee9fb7..423cd72 100644 --- a/core/modules/contact/contact.pages.inc +++ b/core/modules/contact/contact.pages.inc @@ -76,6 +76,7 @@ function contact_personal_page($recipient) { $message = entity_create('contact_message', array( 'recipient' => $recipient, + 'category' => 'personal', )); return entity_get_form($message); } diff --git a/core/modules/contact/contact.routing.yml b/core/modules/contact/contact.routing.yml index 4cbfff2..01ec7a0 100644 --- a/core/modules/contact/contact.routing.yml +++ b/core/modules/contact/contact.routing.yml @@ -3,7 +3,7 @@ contact_category_delete: defaults: _form: '\Drupal\contact\Form\DeleteForm' requirements: - _permission: 'administer contact forms' + _entity_access: 'contact_category.delete' contact_category_list: pattern: '/admin/structure/contact' @@ -25,4 +25,4 @@ contact_category_edit: defaults: _entity_form: contact_category.edit requirements: - _permission: 'administer contact forms' + _entity_access: 'contact_category.update' diff --git a/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php b/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php new file mode 100644 index 0000000..91114a7 --- /dev/null +++ b/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php @@ -0,0 +1,34 @@ +id() !== 'personal'; + } + else { + return user_access('administer contact forms', $account); + } + } + +} diff --git a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php index 8febed8..5f2e78c 100644 --- a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php +++ b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php @@ -128,8 +128,7 @@ public function save(array $form, array &$form_state) { * Overrides Drupal\Core\Entity\EntityFormController::delete(). */ public function delete(array $form, array &$form_state) { - $category = $this->entity; - $form_state['redirect'] = 'admin/structure/contact/manage/' . $category->id() . '/delete'; + $form_state['redirect'] = 'admin/structure/contact/manage/' . $this->entity->id() . '/delete'; } } diff --git a/core/modules/contact/lib/Drupal/contact/CategoryListController.php b/core/modules/contact/lib/Drupal/contact/CategoryListController.php index a3ec886..8a0bb02 100644 --- a/core/modules/contact/lib/Drupal/contact/CategoryListController.php +++ b/core/modules/contact/lib/Drupal/contact/CategoryListController.php @@ -34,6 +34,13 @@ public function getOperations(EntityInterface $entity) { 'weight' => 12, ); } + + if (!$entity->access('delete')) { + unset($operations['delete']); + } + if (!$entity->access('update')) { + unset($operations['edit']); + } return $operations; } @@ -53,9 +60,16 @@ public function buildHeader() { */ public function buildRow(EntityInterface $entity) { $row['category'] = check_plain($entity->label()); - $row['recipients'] = check_plain(implode(', ', $entity->recipients)); - $default_category = config('contact.settings')->get('default_category'); - $row['selected'] = ($default_category == $entity->id() ? t('Yes') : t('No')); + // Special case the personal category. + if ($entity->id() == 'personal') { + $row['recipients'] = t('Selected user'); + $row['selected'] = t('No'); + } + else { + $row['recipients'] = check_plain(implode(', ', $entity->recipients)); + $default_category = config('contact.settings')->get('default_category'); + $row['selected'] = ($default_category == $entity->id() ? t('Yes') : t('No')); + } $row['operations']['data'] = $this->buildOperations($entity); return $row; } diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php index 1f56dd1..c8bc85b 100644 --- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php +++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php @@ -62,9 +62,8 @@ public function form(array $form, array &$form_state) { $form['mail']['#markup'] = check_plain($user->mail); } - // The user contact form only has a recipient, not a category. - // @todo Convert user contact form into a locked contact category. - if ($message->recipient instanceof User) { + // The user contact form has a preset recipient. + if ($message->isPersonal()) { $form['recipient'] = array( '#type' => 'item', '#title' => t('To'), @@ -160,7 +159,7 @@ public function save(array $form, array &$form_state) { $params['contact_message'] = $message; $params['sender'] = $sender; - if ($message->category) { + if (!$message->isPersonal()) { // Send to the category recipient(s), using the site's default language. $category = entity_load('contact_category', $message->category); $params['contact_category'] = $category; @@ -186,14 +185,14 @@ public function save(array $form, array &$form_state) { } // If configured, send an auto-reply, using the current language. - if ($message->category && $category->reply) { + if (!$message->isPersonal() && $category->reply) { // User contact forms do not support an auto-reply message, so this // message always originates from the site. drupal_mail('contact', 'page_autoreply', $sender->mail, $language_interface->langcode, $params); } \Drupal::service('flood')->register('contact', config('contact.settings')->get('flood.interval')); - if ($message->category) { + if (!$message->isPersonal()) { watchdog('contact', '%sender-name (@sender-from) sent an e-mail regarding %category.', array( '%sender-name' => $sender->name, '@sender-from' => $sender->mail, diff --git a/core/modules/contact/lib/Drupal/contact/MessageInterface.php b/core/modules/contact/lib/Drupal/contact/MessageInterface.php index 9e8879b..f01ad9f 100644 --- a/core/modules/contact/lib/Drupal/contact/MessageInterface.php +++ b/core/modules/contact/lib/Drupal/contact/MessageInterface.php @@ -14,4 +14,12 @@ */ interface MessageInterface extends EntityInterface { + /** + * Return TRUE if this is the personal contact form. + * + * @return bool + * TRUE if the message bundle is personal. + */ + public function isPersonal(); + } diff --git a/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php index a224d1a..12a9fc0 100644 --- a/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php +++ b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php @@ -21,6 +21,7 @@ * module = "contact", * controllers = { * "storage" = "Drupal\contact\CategoryStorageController", + * "access" = "Drupal\contact\CategoryAccessController", * "list" = "Drupal\contact\CategoryListController", * "form" = { * "add" = "Drupal\contact\CategoryFormController", diff --git a/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php index 667c06a..3bec9e9 100644 --- a/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php +++ b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php @@ -69,9 +69,8 @@ class Message extends Entity implements MessageInterface { * @see Drupal\contact\MessageFormController::form() * @see Drupal\contact\MessageFormController::save() * - * @todo Convert user contact form into a locked contact category, and replace - * Category::$recipients with the user account's e-mail address upon - * Entity::create(). + * @todo Replace Category::$recipients with the user account's e-mail address + * upon Entity::create(). * * @var Drupal\user\Plugin\Core\Entity\User */ @@ -113,17 +112,10 @@ public function bundle() { } /** - * Overrides Drupal\Core\Entity\Entity::entityInfo(). + * {@inheritdoc} */ - public function entityInfo() { - // The user contact form is not a category/bundle currently, so it is not - // fieldable. Prevent EntityFormController from calling into Field Attach - // functions, since those will throw errors without a bundle name. - $info = entity_get_info($this->entityType); - if (isset($this->recipient)) { - $info['fieldable'] = FALSE; - } - return $info; + public function isPersonal() { + return $this->bundle() == 'personal'; } } diff --git a/core/modules/contact/lib/Drupal/contact/Tests/ContactPersonalTest.php b/core/modules/contact/lib/Drupal/contact/Tests/ContactPersonalTest.php index bb7d7d4..026b169 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/ContactPersonalTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/ContactPersonalTest.php @@ -63,6 +63,22 @@ function setUp() { } /** + * Tests that mails for contact messages are correctly sent. + */ + function testSendPersonalContactMessage() { + $this->drupalLogin($this->web_user); + + $message = $this->submitPersonalContact($this->contact_user); + $mails = $this->drupalGetMails(); + $this->assertEqual(1, count($mails)); + $mail = $mails[0]; + $this->assertEqual($mail['to'], $this->contact_user->mail); + $this->assertEqual($mail['from'], $this->web_user->mail); + $this->assertTrue(strpos($mail['subject'], $message['subject']) !== FALSE, 'Subject is in sent message.'); + $this->assertTrue(strpos($mail['body'], $message['message']) !== FALSE, 'Subject is in sent message.'); + } + + /** * Tests access to the personal contact form. */ function testPersonalContactAccess() { @@ -188,5 +204,6 @@ protected function submitPersonalContact($account, array $message = array()) { 'message' => $this->randomName(64), ); $this->drupalPost('user/' . $account->uid . '/contact', $message, t('Send message')); + return $message; } } diff --git a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php index 9ae74b9..64586ae 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php @@ -49,8 +49,21 @@ function testSiteWideContact() { $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration')); $this->assertText(t('The configuration options have been saved.')); + $this->drupalGet('admin/structure/contact'); + // Default category exists. + $this->assertLinkByHref('admin/structure/contact/manage/feedback/delete'); + // User category could not be changed or deleted. + $this->assertNoLinkByHref('admin/structure/contact/manage/personal'); + $this->assertNoLinkByHref('admin/structure/contact/manage/personal/delete'); + + $this->drupalGet('admin/structure/contact/manage/personal'); + $this->assertResponse(403); + // Delete old categories to ensure that new categories are used. $this->deleteCategories(); + $this->drupalGet('admin/structure/contact'); + $this->assertText('Personal', 'Personal category was not deleted'); + $this->assertNoLinkByHref('admin/structure/contact/manage/feedback'); // Ensure that the contact form won't be shown without categories. user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form')); @@ -139,9 +152,6 @@ function testSiteWideContact() { $this->assertResponse(200); // Submit contact form with invalid values. - $categories = entity_load_multiple('contact_category'); - $id = key($categories); - $this->submitContact('', $recipients[0], $this->randomName(16), $id, $this->randomName(64)); $this->assertText(t('Your name field is required.')); @@ -179,10 +189,6 @@ function testSiteWideContact() { $this->drupalGet('contact'); $this->assertResponse(403); $this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array('%number' => config('contact.settings')->get('flood.limit'), '@interval' => format_interval(600)))); - - // Delete created categories. - $this->drupalLogin($admin_user); - $this->deleteCategories(); } /** @@ -313,9 +319,16 @@ function submitContact($name, $mail, $subject, $id, $message) { function deleteCategories() { $categories = entity_load_multiple('contact_category'); foreach ($categories as $id => $category) { - $this->drupalPost("admin/structure/contact/manage/$id/delete", array(), t('Delete')); - $this->assertRaw(t('Category %label has been deleted.', array('%label' => $category->label()))); - $this->assertFalse(entity_load('contact_category', $id), format_string('Category %category not found', array('%category' => $category->label()))); + if ($id == 'personal') { + // Personal category could not be deleted. + $this->drupalGet("admin/structure/contact/manage/$id/delete"); + $this->assertResponse(403); + } + else { + $this->drupalPost("admin/structure/contact/manage/$id/delete", array(), t('Delete')); + $this->assertRaw(t('Category %label has been deleted.', array('%label' => $category->label()))); + $this->assertFalse(entity_load('contact_category', $id), format_string('Category %category not found', array('%category' => $category->label()))); + } } }