Issue #1938390 by andypost, disasm, jibran, dawehner, ygerasimov, pfrenssen: Convert contact_site_page and contact_person_page to a new-style Controller.

8.0.x
Alex Pott 2013-12-12 16:14:47 +00:00
parent c120a661e4
commit 94cba6d2d4
8 changed files with 197 additions and 154 deletions

View File

@ -2,7 +2,7 @@
/** /**
* @file * @file
* Contains Drupal\Core\Access\AccessManager. * Contains \Drupal\Core\Access\AccessManager.
*/ */
namespace Drupal\Core\Access; namespace Drupal\Core\Access;

View File

@ -5,9 +5,6 @@
* Enables the use of personal and site-wide contact forms. * Enables the use of personal and site-wide contact forms.
*/ */
use Drupal\contact\Entity\Category;
use Drupal\user\UserInterface;
/** /**
* Implements hook_help(). * Implements hook_help().
*/ */
@ -76,26 +73,12 @@ function contact_menu() {
); );
$items['contact/%contact_category'] = array( $items['contact/%contact_category'] = array(
'title' => 'Contact category form', 'title' => 'Contact category form',
'title callback' => 'entity_page_label',
'title arguments' => array(1),
'route_name' => 'contact.site_page_category', 'route_name' => 'contact.site_page_category',
'type' => MENU_VISIBLE_IN_BREADCRUMB, 'type' => MENU_VISIBLE_IN_BREADCRUMB,
); );
return $items; return $items;
} }
/**
* Access callback: Checks access for a user's personal contact form.
*
* @param $account
* The user object of the user whose contact form is being requested.
*
* @see contact_menu()
*/
function _contact_personal_tab_access(UserInterface $account) {
return \Drupal::service('access_manager')->checkNamedRoute('contact.personal_page', array('user' => $account->id()), \Drupal::currentUser());
}
/** /**
* Implements hook_entity_bundle_info(). * Implements hook_entity_bundle_info().
*/ */

View File

@ -1,113 +0,0 @@
<?php
/**
* @file
* Page callbacks for the Contact module.
*/
use Drupal\contact\Entity\Category;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\Component\Utility\String;
/**
* Page callback: Presents the site-wide contact form.
*
* @param \Drupal\contact\Entity\Category $category
* (optional) The contact category to use.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*
* @see contact_menu()
* @see contact_site_form_submit()
* @ingroup forms
*
* @deprecated Use \Drupal\contact\Controller\ContactController::contactSitePage()
*/
function contact_site_page(Category $category = NULL) {
// Check if flood control has been activated for sending e-mails.
if (!user_access('administer contact forms')) {
contact_flood_control();
}
if (!isset($category)) {
$categories = entity_load_multiple('contact_category');
$default_category = \Drupal::config('contact.settings')->get('default_category');
if (isset($categories[$default_category])) {
$category = $categories[$default_category];
}
// If there are no categories, do not display the form.
else {
if (user_access('administer contact forms')) {
drupal_set_message(t('The contact form has not been configured. <a href="@add">Add one or more categories</a> to the form.', array('@add' => url('admin/structure/contact/add'))), 'error');
return array();
}
else {
throw new NotFoundHttpException();
}
}
}
else if ($category->id() == 'personal') {
throw new NotFoundHttpException();
}
$message = entity_create('contact_message', array(
'category' => $category->id(),
));
$form = \Drupal::entityManager()->getForm($message);
$form['#title'] = String::checkPlain($category->label());
return $form;
}
/**
* Page callback: Form constructor for the personal contact form.
*
* @param $recipient
* The account for which a personal contact form should be generated.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*
* @see contact_menu()
* @see contact_personal_form_submit()
*
* @ingroup forms
*
* @deprecated Use \Drupal\contact\Controller\ContactController::contactPersonalPage()
*/
function contact_personal_page($recipient) {
global $user;
// Check if flood control has been activated for sending e-mails.
if (!user_access('administer contact forms') && !user_access('administer users')) {
contact_flood_control();
}
$message = entity_create('contact_message', array(
'recipient' => $recipient,
'category' => 'personal',
));
$form = \Drupal::entityManager()->getForm($message);
$form['#title'] = t('Contact @username', array('@username' => $recipient->getUsername()));
return $form;
}
/**
* Throws an exception if the current user is not allowed to submit a contact form.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*
* @see contact_site_page()
* @see contact_personal_page()
*/
function contact_flood_control() {
$config = \Drupal::config('contact.settings');
$limit = $config->get('flood.limit');
$interval = $config->get('flood.interval');
if (!\Drupal::service('flood')->isAllowed('contact', $limit, $interval)) {
drupal_set_message(t("You cannot send more than %limit messages in @interval. Try again later.", array(
'%limit' => $limit,
'@interval' => format_interval($interval),
)), 'error');
throw new AccessDeniedHttpException();
}
}

View File

@ -1,10 +1,10 @@
contact.category_delete: contact.category_delete:
path: '/admin/structure/contact/manage/{contact_category}/delete' path: '/admin/structure/contact/manage/{contact_category}/delete'
defaults: defaults:
_entity_form: contact_category.delete _entity_form: 'contact_category.delete'
_title: 'Delete' _title: 'Delete'
requirements: requirements:
_entity_access: contact_category.delete _entity_access: 'contact_category.delete'
contact.category_list: contact.category_list:
path: '/admin/structure/contact' path: '/admin/structure/contact'
@ -17,7 +17,7 @@ contact.category_list:
contact.category_add: contact.category_add:
path: '/admin/structure/contact/add' path: '/admin/structure/contact/add'
defaults: defaults:
_entity_form: contact_category.add _entity_form: 'contact_category.add'
_title: 'Add category' _title: 'Add category'
requirements: requirements:
_permission: 'administer contact forms' _permission: 'administer contact forms'
@ -25,10 +25,10 @@ contact.category_add:
contact.category_edit: contact.category_edit:
path: '/admin/structure/contact/manage/{contact_category}' path: '/admin/structure/contact/manage/{contact_category}'
defaults: defaults:
_entity_form: contact_category.edit _entity_form: 'contact_category.edit'
_title: 'Edit contact category' _title: 'Edit contact category'
requirements: requirements:
_entity_access: contact_category.update _entity_access: 'contact_category.update'
contact.site_page: contact.site_page:
path: '/contact' path: '/contact'
@ -45,7 +45,7 @@ contact.site_page_category:
_title: 'Contact category form' _title: 'Contact category form'
_content: '\Drupal\contact\Controller\ContactController::contactSitePage' _content: '\Drupal\contact\Controller\ContactController::contactSitePage'
requirements: requirements:
_permission: 'access site-wide contact form' _entity_access: 'contact_category.view'
contact.personal_page: contact.personal_page:
path: '/user/{user}/contact' path: '/user/{user}/contact'

View File

@ -10,6 +10,7 @@ namespace Drupal\contact;
use Drupal\Core\Entity\EntityAccessController; use Drupal\Core\Entity\EntityAccessController;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
/** /**
* Defines an access controller for the contact category entity. * Defines an access controller for the contact category entity.
* *
@ -21,12 +22,17 @@ class CategoryAccessController extends EntityAccessController {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) { public function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
if ($operation == 'delete' || $operation == 'update') { if ($operation == 'view') {
// Do not allow delete 'personal' category used for personal contact form. // Do not allow access personal category via site-wide route.
return user_access('administer contact forms', $account) && $entity->id() !== 'personal'; return $account->hasPermission('access site-wide contact form') && $entity->id() !== 'personal';
}
elseif ($operation == 'delete' || $operation == 'update') {
// Do not allow the 'personal' category to be deleted, as it's used for
// the personal contact form.
return $account->hasPermission('administer contact forms') && $entity->id() !== 'personal';
} }
else { else {
return user_access('administer contact forms', $account); return $account->hasPermission('administer contact forms');
} }
} }

View File

@ -7,28 +7,135 @@
namespace Drupal\contact\Controller; namespace Drupal\contact\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Flood\FloodInterface;
use Drupal\contact\CategoryInterface; use Drupal\contact\CategoryInterface;
use Drupal\user\UserInterface; use Drupal\user\UserInterface;
use Drupal\Component\Utility\String;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* Controller routines for contact routes. * Controller routines for contact routes.
*/ */
class ContactController { class ContactController extends ControllerBase implements ContainerInjectionInterface {
/** /**
* @todo Remove contact_site_page(). * The flood service.
*
* @var \Drupal\Core\Flood\FloodInterface
*/ */
public function contactSitePage(CategoryInterface $contact_category = NULL) { protected $flood;
module_load_include('pages.inc', 'contact');
return contact_site_page($contact_category); /**
* Constructs a ContactController object.
*
* @param \Drupal\Core\Flood\FloodInterface $flood
* The flood service.
*/
public function __construct(FloodInterface $flood) {
$this->flood = $flood;
} }
/** /**
* @todo Remove contact_personal_page(). * {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('flood')
);
}
/**
* Presents the site-wide contact form.
*
* @param \Drupal\contact\CategoryInterface $contact_category
* The contact category to use.
*
* @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 default
* contact category form.
*/
public function contactSitePage(CategoryInterface $contact_category = NULL) {
// Check if flood control has been activated for sending e-mails.
if (!$this->currentUser()->hasPermission('administer contact forms')) {
$this->contactFloodControl();
}
// Use the default category if no category has been passed.
if (empty($contact_category)) {
$contact_category = $this->entityManager()
->getStorageController('contact_category')
->load($this->config('contact.settings')->get('default_category'));
// If there are no categories, do not display the form.
if (empty($contact_category)) {
if ($this->currentUser()->hasPermission('administer contact forms')) {
drupal_set_message($this->t('The contact form has not been configured. <a href="@add">Add one or more categories</a> to the form.', array(
'@add' => $this->urlGenerator()->generateFromRoute('contact.category_add'))), 'error');
return array();
}
else {
throw new NotFoundHttpException();
}
}
}
$message = $this->entityManager()
->getStorageController('contact_message')
->create(array(
'category' => $contact_category->id(),
));
$form = $this->entityManager()->getForm($message);
$form['#title'] = String::checkPlain($contact_category->label());
return $form;
}
/**
* Form constructor for the personal contact form.
*
* @param \Drupal\user\UserInterface $user
* The account for which a personal contact form should be generated.
*
* @return array
* The personal contact form as render array as expected by drupal_render().
*/ */
public function contactPersonalPage(UserInterface $user) { public function contactPersonalPage(UserInterface $user) {
module_load_include('pages.inc', 'contact'); // Check if flood control has been activated for sending e-mails.
return contact_personal_page($user); if (!$this->currentUser()->hasPermission('administer contact forms') && !$this->currentUser()->hasPermission('administer users')) {
$this->contactFloodControl();
}
$message = $this->entityManager()->getStorageController('contact_message')->create(array(
'category' => 'personal',
'recipient' => $user->id(),
));
$form = $this->entityManager()->getForm($message);
$form['#title'] = $this->t('Contact @username', array('@username' => $user->getUsername()));
return $form;
}
/**
* Throws an exception if the current user triggers flood control.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*/
protected function contactFloodControl() {
$limit = $this->config('contact.settings')->get('flood.limit');
$interval = $this->config('contact.settings')->get('flood.interval');
if (!$this->flood->isAllowed('contact', $limit, $interval)) {
drupal_set_message($this->t('You cannot send more than %limit messages in @interval. Try again later.', array(
'%limit' => $limit,
'@interval' => format_interval($interval),
)), 'error');
throw new AccessDeniedHttpException();
}
} }
} }

View File

@ -7,9 +7,11 @@
namespace Drupal\contact\Plugin\views\field; namespace Drupal\contact\Plugin\views\field;
use Drupal\Core\Access\AccessManager;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\user\Plugin\views\field\Link; use Drupal\user\Plugin\views\field\Link;
use Drupal\views\ResultRow; use Drupal\views\ResultRow;
use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Defines a field that links to the user contact page, if access is permitted. * Defines a field that links to the user contact page, if access is permitted.
@ -20,6 +22,64 @@ use Drupal\views\ResultRow;
*/ */
class ContactLink extends Link { class ContactLink extends Link {
/**
* The access manager.
*
* @var \Drupal\Core\Access\AccessManager
*/
protected $accessManager;
/**
* Current user object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Gets the current active user.
*
* @todo: https://drupal.org/node/2105123 put this method in
* \Drupal\Core\Plugin\PluginBase instead.
*
* @return \Drupal\Core\Session\AccountInterface
*/
protected function currentUser() {
if (!$this->currentUser) {
$this->currentUser = \Drupal::currentUser();
}
return $this->currentUser;
}
/**
* Constructs a ContactLink object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Access\AccessManager $access_manager
* The access manager.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, AccessManager $access_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->accessManager = $access_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('access_manager')
);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -50,15 +110,12 @@ class ContactLink extends Link {
// Check access when we pull up the user account so we know // Check access when we pull up the user account so we know
// if the user has made the contact page available. // if the user has made the contact page available.
$uid = $entity->id(); if (!$this->accessManager->checkNamedRoute('contact.personal_page', array('user' => $entity->id()), $this->currentUser())) {
$path = "user/$uid/contact";
if (!_contact_personal_tab_access($entity)) {
return; return;
} }
$this->options['alter']['make_link'] = TRUE; $this->options['alter']['make_link'] = TRUE;
$this->options['alter']['path'] = $path; $this->options['alter']['path'] = "user/{$entity->id()}/contact";
$title = t('Contact %user', array('%user' => $entity->name->value)); $title = t('Contact %user', array('%user' => $entity->name->value));
$this->options['alter']['attributes'] = array('title' => $title); $this->options['alter']['attributes'] = array('title' => $title);

View File

@ -90,6 +90,9 @@ class ContactSitewideTest extends WebTestBase {
$this->drupalGet('contact'); $this->drupalGet('contact');
$this->assertResponse(200); $this->assertResponse(200);
$this->assertText(t('The contact form has not been configured.')); $this->assertText(t('The contact form has not been configured.'));
// Test access personal category via site-wide contact page.
$this->drupalGet('contact/personal');
$this->assertResponse(403);
// Add categories. // Add categories.
// Test invalid recipients. // Test invalid recipients.