diff --git a/core/modules/contact/contact.routing.yml b/core/modules/contact/contact.routing.yml index 7932479..e237b9e 100644 --- a/core/modules/contact/contact.routing.yml +++ b/core/modules/contact/contact.routing.yml @@ -1,9 +1,9 @@ contact_category_delete: pattern: 'admin/structure/contact/manage/{contact_category}/delete' defaults: - _entity_form: contact_category.delete + _entity_form: 'contact_category.delete' requirements: - _entity_access: contact_category.delete + _entity_access: 'contact_category.delete' contact_category_list: pattern: '/admin/structure/contact' @@ -15,16 +15,16 @@ contact_category_list: contact_category_add: pattern: '/admin/structure/contact/add' defaults: - _entity_form: contact_category.add + _entity_form: 'contact_category.add' requirements: _permission: 'administer contact forms' contact_category_edit: pattern: '/admin/structure/contact/manage/{contact_category}' defaults: - _entity_form: contact_category.edit + _entity_form: 'contact_category.edit' requirements: - _entity_access: contact_category.update + _entity_access: 'contact_category.update' contact_site_page: pattern: 'contact' @@ -36,9 +36,9 @@ contact_site_page: contact_site_page_category: pattern: 'contact/{contact_category}' defaults: - _content: '\Drupal\contact\Controller\ContactPageController::contactSitePage' + _content: '\Drupal\contact\Controller\ContactPageController::contactSitePageCategory' requirements: - _permission: 'access site-wide contact form' + _entity_access: 'contact_category.page' contact_personal_page: pattern: 'user/{user}/contact' diff --git a/core/modules/contact/contact.services.yml b/core/modules/contact/contact.services.yml index fb1142e..cccd1fd 100644 --- a/core/modules/contact/contact.services.yml +++ b/core/modules/contact/contact.services.yml @@ -1,5 +1,5 @@ services: - access_check.contact: + access_check.contact_personal: class: Drupal\contact\Access\ContactPageAccess tags: - { name: access_check } diff --git a/core/modules/contact/lib/Drupal/contact/Access/ContactPageAccess.php b/core/modules/contact/lib/Drupal/contact/Access/ContactPageAccess.php index 96af0fb..e698bf4 100644 --- a/core/modules/contact/lib/Drupal/contact/Access/ContactPageAccess.php +++ b/core/modules/contact/lib/Drupal/contact/Access/ContactPageAccess.php @@ -58,13 +58,14 @@ public function appliesTo() { */ public function access(Route $route, Request $request) { $contact_account = $request->attributes->get('user'); - $current_account = $request->attributes->get('_account') ?: $GLOBALS['user']; // Anonymous users cannot have contact forms. if ($contact_account->isAnonymous()) { return static::DENY; } + $current_account = $request->attributes->get('_account');; + // Users may not contact themselves. if ($current_account->id() == $contact_account->id()) { return static::DENY; diff --git a/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php b/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php index ca6ca90..af7ae55 100644 --- a/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php +++ b/core/modules/contact/lib/Drupal/contact/CategoryAccessController.php @@ -23,10 +23,14 @@ class CategoryAccessController extends EntityAccessController { public function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) { if ($operation == 'delete' || $operation == 'update') { // Do not allow delete 'personal' category used for personal contact form. - return user_access('administer contact forms', $account) && $entity->id() !== 'personal'; + return $account->hasPermission('administer contact forms') && $entity->id() !== 'personal'; + } + elseif ($operation == 'page') { + // Do not allow access personal category via site-wide route. + return $account->hasPermission('access site-wide contact form') && $entity->id() !== 'personal'; } else { - return user_access('administer contact forms', $account); + return $account->hasPermission('administer contact forms'); } } diff --git a/core/modules/contact/lib/Drupal/contact/Controller/ContactPageController.php b/core/modules/contact/lib/Drupal/contact/Controller/ContactPageController.php index 8c8bc03..fed3d5b 100644 --- a/core/modules/contact/lib/Drupal/contact/Controller/ContactPageController.php +++ b/core/modules/contact/lib/Drupal/contact/Controller/ContactPageController.php @@ -13,6 +13,7 @@ use Drupal\Core\Flood\FloodInterface; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityManager; +use Drupal\Core\StringTranslation\Translator\TranslatorInterface; use Drupal\contact\Plugin\Core\Entity\Category; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -54,11 +55,14 @@ class ContactPageController implements ControllerInterface { * Configuration Factory. * @param \Drupal\Core\Entity\EntityManager $entity_manager * Entity Manager. + * @param \Drupal\Core\StringTranslation\Translator\TranslatorInterface $translator + * The translator service. */ - public function __construct(FloodInterface $flood, ConfigFactory $config_factory, EntityManager $entity_manager) { + public function __construct(FloodInterface $flood, ConfigFactory $config_factory, EntityManager $entity_manager, TranslatorInterface $translator) { $this->flood = $flood; $this->configFactory = $config_factory; $this->entityManager = $entity_manager; + $this->translator = $translator; } /** @@ -74,10 +78,10 @@ public static function create(ContainerInterface $container) { } /** - * Presents the site-wide contact form. + * Builds the contact category form. * - * @param \Drupal\contact\Plugin\Core\Entity\Category $contact_category - * (optional) The contact category to use. + * @param string $contact_category_id + * The contact category to use for form building. * @param \Drupal\Core\Session\AccountInterface $_account * The current account. * @@ -86,44 +90,84 @@ public static function create(ContainerInterface $container) { * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * Exception is thrown when user tries to access non existing contact - * category form and does not have permissions to set it up. + * category form. */ - public function contactSitePage(Category $contact_category = NULL, AccountInterface $_account) { - // Check if flood control has been activated for sending e-mails. - if (!$_account->hasPermission('administer contact forms')) { - $this->contactFloodControl(); - } - // Use the default category if no category has been passed. + public function contactCategoryForm($contact_category_id, AccountInterface $_account) { + $contact_category = $this + ->entityManager + ->getStorageController('contact_category') + ->load($contact_category_id); + // If there are no categories, do not display the form. if (empty($contact_category)) { - $controller = $this->entityManager->getStorageController('contact_category'); - $default_category = $this->configFactory->get('contact.settings')->get('default_category'); - $contact_category = $controller->load($default_category); - - // If there are no categories, do not display the form. - if (empty($contact_category)) { - if ($_account->hasPermission('administer contact forms')) { - drupal_set_message(t('The contact form has not been configured. Add one or more categories to the form.', array('@add' => url('admin/structure/contact/add'))), 'error'); - return array(); - } - else { - throw new NotFoundHttpException(); - } + if ($_account->hasPermission('administer contact forms')) { + drupal_set_message(t('The contact form has not been configured. Add one or more categories to the form.', array('@add' => url('admin/structure/contact/add'))), 'error'); + debug("$contact_category_id"); + debug($contact_category, $contact_category_id); + return array('#markup' => 'errrrr'); + } + else { + throw new NotFoundHttpException(); } - } - elseif ($contact_category->id() == 'personal') { - throw new NotFoundHttpException(); } $message = $this->entityManager ->getStorageController('contact_message') ->create(array( - 'category' => $contact_category->id(), + 'category' => $contact_category_id, )); return $this->entityManager->getForm($message); } /** + * Presents the site-wide default contact form. + * + * @param \Drupal\Core\Session\AccountInterface $_account + * The current account. + * + * @return array + * The form as render array as expected by drupal_render(). + * + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * Exception is thrown when user tries to access non existing contact + * category form and does not have permissions to set it up. + */ + public function contactSitePage(AccountInterface $_account) { + // Check if flood control has been activated for sending e-mails. + if (!$_account->hasPermission('administer contact forms')) { + $this->contactFloodControl(); + } + // Use the default category if andy. + $default_category = $this->configFactory->get('contact.settings')->get('default_category'); + + return $this->contactCategoryForm($default_category, $_account); + } + + /** + * Presents the site-wide default contact form. + * + * @param \Drupal\contact\Plugin\Core\Entity\Category $contact_category + * The contact category to use. + * @param \Drupal\Core\Session\AccountInterface $_account + * The current account. + * + * @return array + * The form as render array as expected by drupal_render(). + * + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * Exception is thrown when user tries to access non existing contact + * category form and does not have permissions to set it up. + */ + public function contactSitePageCategory(Category $contact_category, AccountInterface $_account) { + // Check if flood control has been activated for sending e-mails. + if (!$_account->hasPermission('administer contact forms')) { + $this->contactFloodControl(); + } + + return $this->contactCategoryForm($contact_category->id(), $_account); + } + + /** * Form constructor for the personal contact form. * * @param \Drupal\user\UserInterface $user @@ -140,16 +184,9 @@ public function contactPersonalPage(UserInterface $user, AccountInterface $_acco $this->contactFloodControl(); } - drupal_set_title(t('Contact @username', array('@username' => $user->getUsername())), PASS_THROUGH); + drupal_set_title($this->translator->translate('Contact @username', array('@username' => $user->getUsername())), PASS_THROUGH); - $message = $this->entityManager - ->getStorageController('contact_message') - ->create(array( - 'category' => 'personal', - 'recipient' => $user->id(), - )); - - return $this->entityManager->getForm($message); + return $this->contactCategoryForm('personal', $_account); } /** @@ -162,7 +199,7 @@ protected function contactFloodControl() { $limit = $contact_settings->get('flood.limit'); $interval = $contact_settings->get('flood.interval'); if (!$this->flood->isAllowed('contact', $limit, $interval)) { - drupal_set_message(t('You cannot send more than %limit messages in @interval. Try again later.', array( + drupal_set_message($this->translator->translate('You cannot send more than %limit messages in @interval. Try again later.', array( '%limit' => $limit, '@interval' => format_interval($interval), )), 'error'); diff --git a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php index 42f4423..924dbb2 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php @@ -44,7 +44,8 @@ function testSiteWideContact() { $this->drupalLogin($admin_user); $flood_limit = 3; - config('contact.settings') + $this->container->get('config.factory') + ->get('contact.settings') ->set('flood.limit', $flood_limit) ->set('flood.interval', 600) ->save(); @@ -110,7 +111,8 @@ function testSiteWideContact() { $this->assertRaw(t('Category %label has been added.', array('%label' => $label))); // Check that the category was created in site default language. - $langcode = config('contact.category.' . $id)->get('langcode'); + $langcode = $this->container->get('config.factory') + ->get('contact.category.' . $id)->get('langcode'); $default_langcode = language_default()->id; $this->assertEqual($langcode, $default_langcode); @@ -119,7 +121,8 @@ function testSiteWideContact() { // Test update contact form category. $this->updateCategory($id, $label = $this->randomName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomName(30), FALSE); - $config = config('contact.category.' . $id)->get(); + $config = $this->container->get('config.factory') + ->get('contact.category.' . $id)->get(); $this->assertEqual($config['label'], $label); $this->assertEqual($config['recipients'], array($recipients[0], $recipients[1])); $this->assertEqual($config['reply'], $reply); @@ -127,7 +130,10 @@ function testSiteWideContact() { $this->assertRaw(t('Category %label has been updated.', array('%label' => $label))); // Reset the category back to be the default category. - config('contact.settings')->set('default_category', $id)->save(); + $this->container->get('config.factory') + ->get('contact.settings') + ->set('default_category', $id) + ->save(); // Ensure that the contact form is shown without a category selection input. user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form')); @@ -181,8 +187,23 @@ function testSiteWideContact() { $this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $id, ''); $this->assertText(t('Message field is required.')); + // Submit contact form with correct values and check flood interval. + for ($i = 0; $i < $flood_limit; $i++) { + $this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $id, $this->randomName(64)); + $this->assertText(t('Your message has been sent.')); + } + // Submit contact form one over limit. + $this->drupalGet('contact'); + $this->assertResponse(403); + $this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array( + '%number' => $this->container->get('config.factory')->get('contact.settings')->get('flood.limit'), + '@interval' => format_interval(600)) + )); + + $this->container->get('flood')->clear('contact'); // Test contact form with no default category selected. - config('contact.settings') + $this->container->get('config.factory') + ->get('contact.settings') ->set('default_category', '') ->save(); $this->drupalGet('contact'); @@ -194,20 +215,21 @@ function testSiteWideContact() { $this->drupalGet('contact/' . $this->randomName()); $this->assertResponse(404); - // Submit contact form with correct values and check flood interval. - for ($i = 0; $i < $flood_limit; $i++) { - $this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $id, $this->randomName(64)); - $this->assertText(t('Your message has been sent.')); - } - // Submit contact form one over limit. - $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)))); - // Test listing controller. $this->drupalLogin($admin_user); $this->deleteCategories(); + // Test contact form with unknown category selected for admin. + $this->container->get('config.factory') + ->get('contact.settings') + ->set('default_category', drupal_strtolower($this->randomName(16))) + ->save(); + $this->drupalGet('contact'); + $this->assertResponse(200); + $this->assertRaw( + t('The contact form has not been configured. Add one or more categories to the form.', array('@add' => url('admin/structure/contact/add'))), + 'Admin error found' + ); $label = $this->randomName(16); $recipients = implode(',', array($recipients[0], $recipients[1], $recipients[2])); @@ -376,7 +398,7 @@ function submitContact($name, $mail, $subject, $id, $message) { $edit['mail'] = $mail; $edit['subject'] = $subject; $edit['message'] = $message; - if ($id == config('contact.settings')->get('default_category')) { + if ($id == $this->container->get('config.factory')->get('contact.settings')->get('default_category')) { $this->drupalPost('contact', $edit, t('Send message')); } else {