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
* Contains Drupal\Core\Access\AccessManager.
* Contains \Drupal\Core\Access\AccessManager.
*/
namespace Drupal\Core\Access;

View File

@ -5,9 +5,6 @@
* Enables the use of personal and site-wide contact forms.
*/
use Drupal\contact\Entity\Category;
use Drupal\user\UserInterface;
/**
* Implements hook_help().
*/
@ -76,26 +73,12 @@ function contact_menu() {
);
$items['contact/%contact_category'] = array(
'title' => 'Contact category form',
'title callback' => 'entity_page_label',
'title arguments' => array(1),
'route_name' => 'contact.site_page_category',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
);
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().
*/

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

View File

@ -10,6 +10,7 @@ namespace Drupal\contact;
use Drupal\Core\Entity\EntityAccessController;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Defines an access controller for the contact category entity.
*
@ -21,12 +22,17 @@ class CategoryAccessController extends EntityAccessController {
* {@inheritdoc}
*/
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';
if ($operation == 'view') {
// Do not allow access personal category via site-wide route.
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 {
return user_access('administer contact forms', $account);
return $account->hasPermission('administer contact forms');
}
}

View File

@ -7,28 +7,135 @@
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\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.
*/
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) {
module_load_include('pages.inc', 'contact');
return contact_site_page($contact_category);
protected $flood;
/**
* 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) {
module_load_include('pages.inc', 'contact');
return contact_personal_page($user);
// Check if flood control has been activated for sending e-mails.
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;
use Drupal\Core\Access\AccessManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\user\Plugin\views\field\Link;
use Drupal\views\ResultRow;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* 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 {
/**
* 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}
*/
@ -50,15 +110,12 @@ class ContactLink extends Link {
// Check access when we pull up the user account so we know
// if the user has made the contact page available.
$uid = $entity->id();
$path = "user/$uid/contact";
if (!_contact_personal_tab_access($entity)) {
if (!$this->accessManager->checkNamedRoute('contact.personal_page', array('user' => $entity->id()), $this->currentUser())) {
return;
}
$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));
$this->options['alter']['attributes'] = array('title' => $title);

View File

@ -90,6 +90,9 @@ class ContactSitewideTest extends WebTestBase {
$this->drupalGet('contact');
$this->assertResponse(200);
$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.
// Test invalid recipients.