Commit f03337ad authored by Dries's avatar Dries
Browse files

Issue #1825044 by sun: turn contact form submissions into full-blown Contact...

Issue #1825044 by sun: turn contact form submissions into full-blown Contact Message entities, without storage.
parent 3250f84a
......@@ -117,7 +117,14 @@ public function __construct($entityType) {
$this->entityInfo = entity_get_info($entityType);
$this->entityCache = array();
$this->hookLoadArguments = array();
$this->idKey = $this->entityInfo['entity_keys']['id'];
// Check if the entity type supports IDs.
if (isset($this->entityInfo['entity_keys']['id'])) {
$this->idKey = $this->entityInfo['entity_keys']['id'];
}
else {
$this->idKey = FALSE;
}
// Check if the entity type supports UUIDs.
if (!empty($this->entityInfo['entity_keys']['uuid'])) {
......
......@@ -184,6 +184,9 @@ public function validate(array $form, array &$form_state) {
* A reference to a keyed array containing the current state of the form.
*/
public function submit(array $form, array &$form_state) {
// Remove button and internal Form API values from submitted values.
form_state_values_clean($form_state);
$this->submitEntityLanguage($form, $form_state);
$entity = $this->buildEntity($form, $form_state);
$this->setEntity($entity, $form_state);
......
......@@ -74,6 +74,8 @@ function contact_menu() {
);
$items['admin/structure/contact/manage/%contact_category'] = array(
'title' => 'Edit contact category',
'title callback' => 'entity_page_label',
'title arguments' => array(4),
'page callback' => 'contact_category_edit',
'page arguments' => array(4),
'access arguments' => array('administer contact forms'),
......@@ -90,21 +92,32 @@ function contact_menu() {
'page arguments' => array('contact_category_delete_form', 4),
'access arguments' => array('administer contact forms'),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'file' => 'contact.admin.inc',
);
$items['contact'] = array(
'title' => 'Contact',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_site_form'),
'page callback' => 'contact_site_page',
'access arguments' => array('access site-wide contact form'),
'menu_name' => 'footer',
'type' => MENU_SUGGESTED_ITEM,
'file' => 'contact.pages.inc',
);
$items['contact/%contact_category'] = array(
'title' => 'Contact category form',
'title callback' => 'entity_page_label',
'title arguments' => array(1),
'page callback' => 'contact_site_page',
'page arguments' => array(1),
'access arguments' => array('access site-wide contact form'),
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'file' => 'contact.pages.inc',
);
$items['user/%user/contact'] = array(
'title' => 'Contact',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_personal_form', 1),
'page callback' => 'contact_personal_page',
'page arguments' => array(1),
'type' => MENU_LOCAL_TASK,
'access callback' => '_contact_personal_tab_access',
'access arguments' => array(1),
......@@ -210,6 +223,72 @@ function contact_config_import_delete($name, $new_config, $old_config) {
return TRUE;
}
/**
* Implements hook_entity_info().
*/
function contact_entity_info(&$types) {
foreach (config_get_storage_names_with_prefix('contact.category.') as $config_name) {
$config = config($config_name);
$types['contact_message']['bundles'][$config->get('id')] = array(
'label' => $config->get('label'),
'admin' => array(
'path' => 'admin/structure/contact/manage/%contact_category',
'real path' => 'admin/structure/contact/manage/' . $config->get('id'),
'bundle argument' => 4,
'access arguments' => array('administer contact forms'),
),
);
}
}
/**
* Implements hook_field_extra_fields().
*/
function contact_field_extra_fields() {
$fields = array();
$entity_info = entity_get_info('contact_message');
foreach (array_keys($entity_info['bundles']) as $bundle) {
$fields['contact_message'][$bundle]['form']['name'] = array(
'label' => t('Sender name'),
'description' => t('Text'),
'weight' => -50,
);
$fields['contact_message'][$bundle]['form']['mail'] = array(
'label' => t('Sender e-mail'),
'description' => t('E-mail'),
'weight' => -40,
);
// @todo Recipient only makes sense if user contact form is a bundle/category.
$fields['contact_message'][$bundle]['form']['recipient'] = array(
'label' => t('Recipient user name'),
'description' => t('User'),
'weight' => -30,
);
$fields['contact_message'][$bundle]['form']['subject'] = array(
'label' => t('Subject'),
'description' => t('Text'),
'weight' => -10,
);
$fields['contact_message'][$bundle]['form']['message'] = array(
'label' => t('Message'),
'description' => t('Long text'),
'weight' => 0,
);
$fields['contact_message'][$bundle]['form']['copy'] = array(
'label' => t('Send copy to sender'),
'description' => t('Option'),
'weight' => 50,
);
$fields['contact_message'][$bundle]['display']['message'] = array(
'label' => t('Message'),
'description' => t('The main contact message'),
'weight' => 0,
);
}
return $fields;
}
/**
* Loads a contact category.
*
......@@ -242,27 +321,39 @@ function contact_category_uri(Category $category) {
* Implements hook_mail().
*/
function contact_mail($key, &$message, $params) {
$contact_message = $params['contact_message'];
$sender = $params['sender'];
$language = language_load($message['langcode']);
$variables = array(
'!site-name' => config('system.site')->get('name'),
'!subject' => $params['subject'],
'!category' => isset($params['category']) ? $params['category']->label() : '',
'!subject' => $contact_message->subject,
'!category' => isset($params['contact_category']) ? $params['contact_category']->label() : NULL,
'!form-url' => url(current_path(), array('absolute' => TRUE, 'language' => $language)),
'!sender-name' => user_format_name($params['sender']),
'!sender-url' => $params['sender']->uid ? url('user/' . $params['sender']->uid, array('absolute' => TRUE, 'language' => $language)) : $params['sender']->mail,
'!sender-name' => user_format_name($sender),
);
if (!empty($sender->uid)) {
$sender_uri = $sender->uri();
$variables['!sender-url'] = url($sender_uri['path'], array('absolute' => TRUE, 'language' => $language) + $sender_uri['options']);
}
else {
$variables['!sender-url'] = $params['sender']->mail;
}
$options = array('langcode' => $language->langcode);
switch ($key) {
case 'page_mail':
case 'page_copy':
$message['subject'] .= t('[!category] !subject', $variables, array('langcode' => $language->langcode));
$message['body'][] = t("!sender-name (!sender-url) sent a message using the contact form at !form-url.", $variables, array('langcode' => $language->langcode));
$message['body'][] = $params['message'];
$message['subject'] .= t('[!category] !subject', $variables, $options);
$message['body'][] = t("!sender-name (!sender-url) sent a message using the contact form at !form-url.", $variables, $options);
$build = entity_view($contact_message, 'mail', $language->langcode);
$message['body'][] = drupal_render($build);
break;
case 'page_autoreply':
$message['subject'] .= t('[!category] !subject', $variables, array('langcode' => $language->langcode));
$message['body'][] = $params['category']->reply;
$message['subject'] .= t('[!category] !subject', $variables, $options);
$message['body'][] = $params['contact_category']->reply;
break;
case 'user_mail':
......@@ -271,12 +362,12 @@ function contact_mail($key, &$message, $params) {
'!recipient-name' => user_format_name($params['recipient']),
'!recipient-edit-url' => url('user/' . $params['recipient']->uid . '/edit', array('absolute' => TRUE, 'language' => $language)),
);
$message['subject'] .= t('[!site-name] !subject', $variables, array('langcode' => $language->langcode));
$message['body'][] = t('Hello !recipient-name,', $variables, array('langcode' => $language->langcode));
$message['body'][] = t("!sender-name (!sender-url) has sent you a message via your contact form at !site-name.", $variables, array('langcode' => $language->langcode));
$message['body'][] = t("If you don't want to receive such e-mails, you can change your settings at !recipient-edit-url.", $variables, array('langcode' => $language->langcode));
$message['body'][] = t('Message:', array(), array('langcode' => $language->langcode));
$message['body'][] = $params['message'];
$message['subject'] .= t('[!site-name] !subject', $variables, $options);
$message['body'][] = t('Hello !recipient-name,', $variables, $options);
$message['body'][] = t("!sender-name (!sender-url) has sent you a message via your contact form at !site-name.", $variables, $options);
$message['body'][] = t("If you don't want to receive such e-mails, you can change your settings at !recipient-edit-url.", $variables, $options);
$message['body'][] = t('Message:', array(), $options);
$message['body'][] = $contact_message->message;
break;
}
}
......
......@@ -5,11 +5,15 @@
* Page callbacks for the Contact module.
*/
use Drupal\contact\Plugin\Core\Entity\Category;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Page callback: Form constructor for the site-wide contact form.
* Page callback: Presents the site-wide contact form.
*
* @param Drupal\contact\Plugin\Core\Entity\Category $category
* (optional) The contact category to use.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
......@@ -18,161 +22,33 @@
* @see contact_site_form_submit()
* @ingroup forms
*/
function contact_site_form($form, &$form_state) {
global $user;
function contact_site_page(Category $category = NULL) {
// Check if flood control has been activated for sending e-mails.
$config = config('contact.settings');
$limit = $config->get('flood.limit');
$interval = $config->get('flood.interval');
if (!drupal_container()->get('flood')->isAllowed('contact', $limit, $interval) && !user_access('administer contact forms')) {
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();
if (!user_access('administer contact forms')) {
contact_flood_control();
}
// Get an array of the categories and the current default category.
$categories = entity_load_multiple('contact_category');
// If there are no categories, do not display the form.
if (!$categories) {
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');
if (!isset($category)) {
$categories = entity_load_multiple('contact_category');
$default_category = 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 {
throw new NotFoundHttpException();
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();
}
}
}
// Prepare array for select options.
uasort($categories, 'Drupal\Core\Config\Entity\ConfigEntityBase::sort');
$options = array();
foreach ($categories as $category) {
$options[$category->id()] = $category->label();
}
// If there is more than one category available and no default category has
// been selected, prepend a default placeholder value.
$default_category = $config->get('default_category');
if (!$default_category) {
$default_category = !empty($categories) ? key($categories) : NULL;
}
if (!$user->uid) {
$form['#attached']['library'][] = array('system', 'jquery.cookie');
$form['#attributes']['class'][] = 'user-info-from-cookie';
}
$form['#attributes']['class'][] = 'contact-form';
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Your name'),
'#maxlength' => 255,
'#default_value' => $user->uid ? user_format_name($user) : '',
'#required' => TRUE,
);
$form['mail'] = array(
'#type' => 'email',
'#title' => t('Your e-mail address'),
'#default_value' => $user->uid ? $user->mail : '',
'#required' => TRUE,
);
// Do not allow authenticated users to alter the name or e-mail values to
// prevent the impersonation of other users.
if ($user->uid) {
// Hide the original name and e-mail address fields and display read-only
// versions in their place.
$form['name']['#access'] = $form['mail']['#access'] = FALSE;
$form['name_display'] = array(
'#type' => 'item',
'#title' => t('Your name'),
'#markup' => check_plain($form['name']['#default_value']),
);
$form['mail_display'] = array(
'#type' => 'item',
'#title' => t('Your e-mail address'),
'#markup' => check_plain($form['mail']['#default_value']),
);
}
$form['subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#maxlength' => 255,
'#required' => TRUE,
);
$form['category'] = array(
'#type' => 'select',
'#title' => t('Category'),
'#default_value' => $default_category,
'#options' => $options,
'#empty_value' => 0,
'#required' => TRUE,
'#access' => count($categories) > 1,
);
$form['message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#required' => TRUE,
);
// Do not allow anonymous users to send themselves a copy because it can be
// abused to spam people.
$form['copy'] = array(
'#type' => 'checkbox',
'#title' => t('Send yourself a copy.'),
'#access' => $user->uid,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Send message'),
);
return $form;
}
/**
* Form submission handler for contact_site_form().
*/
function contact_site_form_submit($form, &$form_state) {
global $user;
$language_interface = language(LANGUAGE_TYPE_INTERFACE);
$values = $form_state['values'];
$values['sender'] = $user;
$values['sender']->name = $values['name'];
$values['sender']->mail = $values['mail'];
$values['category'] = entity_load('contact_category', $values['category']);
if (!$user->uid) {
$values['sender']->name .= ' (' . t('not verified') . ')';
// Save the anonymous user information to a cookie for reuse.
user_cookie_save(array_intersect_key($values, array_flip(array('name', 'mail'))));
}
// Get the to and from e-mail addresses.
$to = implode(', ', $values['category']->recipients);
$from = $values['sender']->mail;
// Send the e-mail to the recipients using the site default language.
drupal_mail('contact', 'page_mail', $to, language_default()->langcode, $values, $from);
// If the user requests it, send a copy using the current language.
if ($values['copy']) {
drupal_mail('contact', 'page_copy', $from, $language_interface->langcode, $values, $from);
}
// Send an auto-reply if necessary using the current language.
if ($values['category']->reply) {
drupal_mail('contact', 'page_autoreply', $from, $language_interface->langcode, $values, $to);
}
drupal_container()->get('flood')->register('contact', config('contact.settings')->get('flood.interval'));
watchdog('mail', '%sender-name (@sender-from) sent an e-mail regarding %category.', array('%sender-name' => $values['name'], '@sender-from' => $from, '%category' => $values['category']->label()));
// Jump to home page rather than back to contact page to avoid
// contradictory messages if flood control has been activated.
drupal_set_message(t('Your message has been sent.'));
$form_state['redirect'] = '';
$message = entity_create('contact_message', array(
'category' => $category->id(),
));
return entity_get_form($message);
}
/**
......@@ -188,126 +64,39 @@ function contact_site_form_submit($form, &$form_state) {
*
* @ingroup forms
*/
function contact_personal_form($form, &$form_state, $recipient) {
function contact_personal_page($recipient) {
global $user;
// Check if flood control has been activated for sending e-mails.
$config = config('contact.settings');
$limit = $config->get('flood.limit');
$interval = $config->get('flood.interval');
if (!drupal_container()->get('flood')->isAllowed('contact', $limit, $interval) && !user_access('administer contact forms') && !user_access('administer users')) {
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();
if (!user_access('administer contact forms') && !user_access('administer users')) {
contact_flood_control();
}
drupal_set_title(t('Contact @username', array('@username' => user_format_name($recipient))), PASS_THROUGH);
if (!$user->uid) {
$form['#attached']['library'][] = array('system', 'jquery.cookie');
$form['#attributes']['class'][] = 'user-info-from-cookie';
}
$form['#attributes']['class'][] = 'contact-form';
$form['recipient'] = array(
'#type' => 'value',
'#value' => $recipient,
);
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Your name'),
'#maxlength' => 255,
'#default_value' => $user->uid ? user_format_name($user) : '',
'#required' => TRUE,
);
$form['mail'] = array(
'#type' => 'email',
'#title' => t('Your e-mail address'),
'#default_value' => $user->uid ? $user->mail : '',
'#required' => TRUE,
);
// Do not allow authenticated users to alter the name or e-mail values to
// prevent the impersonation of other users.
if ($user->uid) {
// Hide the original name and e-mail address fields and display read-only
// versions in their place.
$form['name']['#access'] = $form['mail']['#access'] = FALSE;
$form['name_display'] = array(
'#type' => 'item',
'#title' => t('Your name'),
'#markup' => check_plain($form['name']['#default_value']),
);
$form['mail_display'] = array(
'#type' => 'item',
'#title' => t('Your e-mail address'),
'#markup' => check_plain($form['mail']['#default_value']),
);
}
$form['to'] = array(
'#type' => 'item',
'#title' => t('To'),
'#markup' => theme('username', array('account' => $recipient)),
);
$form['subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#maxlength' => 50,
'#required' => TRUE,
);
$form['message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#rows' => 15,
'#required' => TRUE,
);
// Do not allow anonymous users to send themselves a copy
// because it can be abused to spam people.
$form['copy'] = array(
'#type' => 'checkbox',
'#title' => t('Send yourself a copy.'),
'#access' => $user->uid,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Send message'),
);
return $form;
$message = entity_create('contact_message', array(
'recipient' => $recipient,
));
return entity_get_form($message);
}
/**
* Form submission handler for contact_personal_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_personal_form_submit($form, &$form_state) {
global $user;
$language_interface = language(LANGUAGE_TYPE_INTERFACE);
$values = $form_state['values'];
$values['sender'] = $user;
$values['sender']->name = $values['name'];
$values['sender']->mail = $values['mail'];
if (!$user->uid) {
$values['sender']->name .= ' (' . t('not verified') . ')';
// Save the anonymous user information to a cookie for reuse.
user_cookie_save(array_intersect_key($values, array_flip(array('name', 'mail'))));
}
// Get the to and from e-mail addresses.
$to = $values['recipient']->mail;
$from = $values['sender']->mail;
// Send the e-mail in the requested user language.
drupal_mail('contact', 'user_mail', $to, user_preferred_langcode($values['recipient']), $values, $from);
// Send a copy if requested, using current page language.
if ($values['copy']) {
drupal_mail('contact', 'user_copy', $from, $language_interface->langcode, $values, $from);
function contact_flood_control() {
$config = config('contact.settings');
$limit = $config->get('flood.limit');
$interval = $config->get('flood.interval');
if (!drupal_container()->get('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();
}
drupal_container()->get('flood')->register('contact', config('contact.settings')->get('flood.interval'));
watchdog('mail', '%sender-name (@sender-from) sent %recipient-name an e-mail.', array('%sender-name' => $values['name'], '@sender-from' => $from, '%recipient-name' => $values['recipient']->name));
// Jump to the contacted user's profile page.
drupal_set_message(t('Your message has been sent.'));
$form_state['redirect'] = user_access('access user profiles') ? 'user/' . $values['recipient']->uid : '';
}
......@@ -14,6 +14,29 @@
*/
class CategoryListController extends ConfigEntityListController {
/**
* Overrides Drupal\Core\Entity\EntityListController::getOperations().
*/
public function getOperations(EntityInterface $entity) {
$operations = parent::getOperations($entity);
if (module_exists('field_ui')) {
$uri = $entity->uri();
$operations['manage-fields'] = array(
'title' => t('Manage fields'),
'href' => $uri['path'] . '/fields',
'options' => $uri['options'],
'weight' => 11,
);
$operations['manage-display'] = array(
'title' => t('Manage display'),
'href' => $uri['path'] . '/display',
'options' => $uri['options'],
'weight' => 12,
);
}
return $operations;
}