Initial Drupal 11 with DDEV setup
This commit is contained in:
99
web/core/modules/contact/src/Access/ContactPageAccess.php
Normal file
99
web/core/modules/contact/src/Access/ContactPageAccess.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\UserDataInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Access check for contact_personal_page route.
|
||||
*/
|
||||
class ContactPageAccess implements AccessInterface {
|
||||
|
||||
/**
|
||||
* The contact settings config object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The user data service.
|
||||
*
|
||||
* @var \Drupal\user\UserDataInterface
|
||||
*/
|
||||
protected $userData;
|
||||
|
||||
/**
|
||||
* Constructs a ContactPageAccess instance.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\user\UserDataInterface $user_data
|
||||
* The user data service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, UserDataInterface $user_data) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->userData = $user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks access to the given user's contact page.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user being contacted.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(UserInterface $user, AccountInterface $account) {
|
||||
$contact_account = $user;
|
||||
|
||||
// Anonymous users cannot have contact forms.
|
||||
if ($contact_account->isAnonymous()) {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
// Users may not contact themselves by default, hence this requires user
|
||||
// granularity for caching.
|
||||
$access = AccessResult::neutral()->cachePerUser();
|
||||
if ($account->id() == $contact_account->id()) {
|
||||
return $access;
|
||||
}
|
||||
|
||||
// User administrators should always have access to personal contact forms.
|
||||
$permission_access = AccessResult::allowedIfHasPermission($account, 'administer users');
|
||||
if ($permission_access->isAllowed()) {
|
||||
return $access->orIf($permission_access);
|
||||
}
|
||||
|
||||
// If requested user has been blocked, do not allow users to contact them.
|
||||
$access->addCacheableDependency($contact_account);
|
||||
if ($contact_account->isBlocked()) {
|
||||
return $access;
|
||||
}
|
||||
|
||||
// Forbid access if the requested user has disabled their contact form.
|
||||
$account_data = $this->userData->get('contact', $contact_account->id(), 'enabled');
|
||||
if (isset($account_data) && !$account_data) {
|
||||
return $access;
|
||||
}
|
||||
|
||||
// If the requested user did not save a preference yet, deny access if the
|
||||
// configured default is disabled.
|
||||
$contact_settings = $this->configFactory->get('contact.settings');
|
||||
$access->addCacheableDependency($contact_settings);
|
||||
if (!isset($account_data) && !$contact_settings->get('user_default_enabled')) {
|
||||
return $access;
|
||||
}
|
||||
|
||||
return $access->orIf(AccessResult::allowedIfHasPermission($account, 'access user contact forms'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the contact form entity type.
|
||||
*
|
||||
* @see \Drupal\contact\Entity\ContactForm.
|
||||
*/
|
||||
class ContactFormAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($operation == 'view') {
|
||||
// Do not allow access personal form via site-wide route.
|
||||
return AccessResult::allowedIfHasPermission($account, 'access site-wide contact form')->andIf(AccessResult::allowedIf($entity->id() !== 'personal'));
|
||||
}
|
||||
elseif ($operation == 'delete' || $operation == 'update') {
|
||||
// Do not allow the 'personal' form to be deleted, as it's used for
|
||||
// the personal contact form.
|
||||
return AccessResult::allowedIfHasPermission($account, 'administer contact forms')->andIf(AccessResult::allowedIf($entity->id() !== 'personal'));
|
||||
}
|
||||
|
||||
return parent::checkAccess($entity, $operation, $account);
|
||||
}
|
||||
|
||||
}
|
||||
193
web/core/modules/contact/src/ContactFormEditForm.php
Normal file
193
web/core/modules/contact/src/ContactFormEditForm.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Component\Utility\EmailValidatorInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Form\ConfigFormBaseTrait;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\Core\Render\Element\PathElement;
|
||||
|
||||
/**
|
||||
* Base form for contact form edit forms.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ContactFormEditForm extends EntityForm implements ContainerInjectionInterface {
|
||||
use ConfigFormBaseTrait;
|
||||
|
||||
/**
|
||||
* The email validator.
|
||||
*
|
||||
* @var \Drupal\Component\Utility\EmailValidatorInterface
|
||||
*/
|
||||
protected $emailValidator;
|
||||
|
||||
/**
|
||||
* The path validator.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathValidatorInterface
|
||||
*/
|
||||
protected $pathValidator;
|
||||
|
||||
/**
|
||||
* Constructs a new ContactFormEditForm.
|
||||
*
|
||||
* @param \Drupal\Component\Utility\EmailValidatorInterface $email_validator
|
||||
* The email validator.
|
||||
* @param \Drupal\Core\Path\PathValidatorInterface $path_validator
|
||||
* The path validator service.
|
||||
*/
|
||||
public function __construct(EmailValidatorInterface $email_validator, PathValidatorInterface $path_validator) {
|
||||
$this->emailValidator = $email_validator;
|
||||
$this->pathValidator = $path_validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('email.validator'),
|
||||
$container->get('path.validator')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['contact.settings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
$contact_form = $this->entity;
|
||||
$default_form = $this->config('contact.settings')->get('default_form');
|
||||
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $contact_form->label(),
|
||||
'#description' => $this->t("Example: 'website feedback' or 'product information'."),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['id'] = [
|
||||
'#type' => 'machine_name',
|
||||
'#default_value' => $contact_form->id(),
|
||||
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
|
||||
'#machine_name' => [
|
||||
'exists' => '\Drupal\contact\Entity\ContactForm::load',
|
||||
],
|
||||
'#disabled' => !$contact_form->isNew(),
|
||||
];
|
||||
$form['recipients'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Recipients'),
|
||||
'#default_value' => implode(', ', $contact_form->getRecipients()),
|
||||
'#description' => $this->t("Example: 'webmaster@example.com' or 'sales@example.com,support@example.com' . To specify multiple recipients, separate each email address with a comma."),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['message'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Message'),
|
||||
'#default_value' => $contact_form->getMessage(),
|
||||
'#description' => $this->t('The message to display to the user after submission of this form. Leave blank for no message.'),
|
||||
];
|
||||
$form['redirect'] = [
|
||||
'#type' => 'path',
|
||||
'#title' => $this->t('Redirect path'),
|
||||
'#convert_path' => PathElement::CONVERT_NONE,
|
||||
'#default_value' => $contact_form->getRedirectPath(),
|
||||
'#description' => $this->t('Path to redirect the user to after submission of this form. For example, type "/about" to redirect to that page. Use a relative path with a slash in front.'),
|
||||
];
|
||||
$form['reply'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Auto-reply'),
|
||||
'#default_value' => $contact_form->getReply(),
|
||||
'#description' => $this->t('Optional auto-reply. Leave empty if you do not want to send the user an auto-reply message.'),
|
||||
];
|
||||
$form['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#title' => $this->t('Weight'),
|
||||
'#default_value' => $contact_form->getWeight(),
|
||||
'#description' => $this->t('When listing forms, those with lighter (smaller) weights get listed before forms with heavier (larger) weights. Forms with equal weights are sorted alphabetically.'),
|
||||
];
|
||||
$form['selected'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Make this the default form'),
|
||||
'#default_value' => $default_form === $contact_form->id(),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
// Validate and each email recipient.
|
||||
$recipients = explode(',', $form_state->getValue('recipients'));
|
||||
|
||||
foreach ($recipients as &$recipient) {
|
||||
$recipient = trim($recipient);
|
||||
if (!$this->emailValidator->isValid($recipient)) {
|
||||
$form_state->setErrorByName('recipients', $this->t('%recipient is an invalid email address.', ['%recipient' => $recipient]));
|
||||
}
|
||||
}
|
||||
$form_state->setValue('recipients', $recipients);
|
||||
$redirect_url = $form_state->getValue('redirect');
|
||||
if ($redirect_url && $this->pathValidator->isValid($redirect_url)) {
|
||||
if (mb_substr($redirect_url, 0, 1) !== '/') {
|
||||
$form_state->setErrorByName('redirect', $this->t('The path should start with /.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$contact_form = $this->entity;
|
||||
$status = $contact_form->save();
|
||||
$contact_settings = $this->config('contact.settings');
|
||||
|
||||
$edit_link = $this->entity->toLink($this->t('Edit'))->toString();
|
||||
$view_link = $contact_form->toLink($contact_form->label(), 'canonical')->toString();
|
||||
if ($status == SAVED_UPDATED) {
|
||||
$this->messenger()->addStatus($this->t('Contact form %label has been updated.', ['%label' => $view_link]));
|
||||
$this->logger('contact')->notice('Contact form %label has been updated.', ['%label' => $contact_form->label(), 'link' => $edit_link]);
|
||||
}
|
||||
else {
|
||||
$this->messenger()->addStatus($this->t('Contact form %label has been added.', ['%label' => $view_link]));
|
||||
$this->logger('contact')->notice('Contact form %label has been added.', ['%label' => $contact_form->label(), 'link' => $edit_link]);
|
||||
}
|
||||
|
||||
// Update the default form.
|
||||
if ($form_state->getValue('selected')) {
|
||||
$contact_settings
|
||||
->set('default_form', $contact_form->id())
|
||||
->save();
|
||||
}
|
||||
// If it was the default form, empty out the setting.
|
||||
elseif ($contact_settings->get('default_form') == $contact_form->id()) {
|
||||
$contact_settings
|
||||
->set('default_form', NULL)
|
||||
->save();
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($contact_form->toUrl('collection'));
|
||||
}
|
||||
|
||||
}
|
||||
112
web/core/modules/contact/src/ContactFormInterface.php
Normal file
112
web/core/modules/contact/src/ContactFormInterface.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a contact form entity.
|
||||
*/
|
||||
interface ContactFormInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Returns the message to be displayed to user.
|
||||
*
|
||||
* @return string
|
||||
* A user message.
|
||||
*/
|
||||
public function getMessage();
|
||||
|
||||
/**
|
||||
* Returns list of recipient email addresses.
|
||||
*
|
||||
* @return array
|
||||
* List of recipient email addresses.
|
||||
*/
|
||||
public function getRecipients();
|
||||
|
||||
/**
|
||||
* Returns the path for redirect.
|
||||
*
|
||||
* @return string
|
||||
* The redirect path.
|
||||
*/
|
||||
public function getRedirectPath();
|
||||
|
||||
/**
|
||||
* Returns the \Drupal\Core\Url object for redirect path.
|
||||
*
|
||||
* Empty redirect property results a \Drupal\Core\Url object of front page.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The redirect \Drupal\Core\Url object.
|
||||
*/
|
||||
public function getRedirectUrl();
|
||||
|
||||
/**
|
||||
* Returns an auto-reply message to send to the message author.
|
||||
*
|
||||
* @return string
|
||||
* An auto-reply message
|
||||
*/
|
||||
public function getReply();
|
||||
|
||||
/**
|
||||
* Returns the weight of this category (used for sorting).
|
||||
*
|
||||
* @return int
|
||||
* The weight of this category.
|
||||
*/
|
||||
public function getWeight();
|
||||
|
||||
/**
|
||||
* Sets the message to be displayed to the user.
|
||||
*
|
||||
* @param string $message
|
||||
* The message to display after form is submitted.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMessage($message);
|
||||
|
||||
/**
|
||||
* Sets list of recipient email addresses.
|
||||
*
|
||||
* @param array $recipients
|
||||
* The desired list of email addresses of this category.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRecipients($recipients);
|
||||
|
||||
/**
|
||||
* Sets the redirect path.
|
||||
*
|
||||
* @param string $redirect
|
||||
* The desired path.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRedirectPath($redirect);
|
||||
|
||||
/**
|
||||
* Sets an auto-reply message to send to the message author.
|
||||
*
|
||||
* @param string $reply
|
||||
* The desired reply.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setReply($reply);
|
||||
|
||||
/**
|
||||
* Sets the weight.
|
||||
*
|
||||
* @param int $weight
|
||||
* The desired weight.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setWeight($weight);
|
||||
|
||||
}
|
||||
48
web/core/modules/contact/src/ContactFormListBuilder.php
Normal file
48
web/core/modules/contact/src/ContactFormListBuilder.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of contact form entities.
|
||||
*
|
||||
* @see \Drupal\contact\Entity\ContactForm
|
||||
*/
|
||||
class ContactFormListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['form'] = $this->t('Form');
|
||||
$header['recipients'] = $this->t('Recipients');
|
||||
$header['selected'] = $this->t('Selected');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
// Special case the personal form.
|
||||
if ($entity->id() == 'personal') {
|
||||
$row['form'] = $entity->label();
|
||||
$row['recipients'] = $this->t('Selected user');
|
||||
$row['selected'] = $this->t('No');
|
||||
}
|
||||
else {
|
||||
$row['form'] = $entity->toLink(NULL, 'canonical')->toString();
|
||||
$row['recipients']['data'] = [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $entity->getRecipients(),
|
||||
'#context' => ['list_style' => 'comma-list'],
|
||||
];
|
||||
$default_form = \Drupal::config('contact.settings')->get('default_form');
|
||||
$row['selected'] = ($default_form == $entity->id() ? $this->t('Yes') : $this->t('No'));
|
||||
}
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the message form entity type.
|
||||
*
|
||||
* @see \Drupal\contact\Entity\Message.
|
||||
*/
|
||||
class ContactMessageAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
|
||||
return AccessResult::allowedIfHasPermission($account, 'access site-wide contact form');
|
||||
}
|
||||
|
||||
}
|
||||
124
web/core/modules/contact/src/Controller/ContactController.php
Normal file
124
web/core/modules/contact/src/Controller/ContactController.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\contact\ContactFormInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\UserInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Controller routines for contact routes.
|
||||
*/
|
||||
class ContactController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs a ContactController object.
|
||||
*
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
*/
|
||||
public function __construct(RendererInterface $renderer) {
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents the site-wide contact form.
|
||||
*
|
||||
* @param \Drupal\contact\ContactFormInterface $contact_form
|
||||
* The contact form to use.
|
||||
*
|
||||
* @return array
|
||||
* The form as render array as expected by
|
||||
* \Drupal\Core\Render\RendererInterface::render().
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Exception is thrown when user tries to access non existing default
|
||||
* contact form.
|
||||
*/
|
||||
public function contactSitePage(?ContactFormInterface $contact_form = NULL) {
|
||||
$config = $this->config('contact.settings');
|
||||
|
||||
// Use the default form if no form has been passed.
|
||||
if (empty($contact_form)) {
|
||||
$default_form = $config->get('default_form');
|
||||
// Load the default form, if configured.
|
||||
if (!is_null($default_form)) {
|
||||
$contact_form = $this->entityTypeManager()
|
||||
->getStorage('contact_form')
|
||||
->load($default_form);
|
||||
}
|
||||
// If there are no forms, do not display the form.
|
||||
if (empty($contact_form)) {
|
||||
if ($this->currentUser()->hasPermission('administer contact forms')) {
|
||||
$this->messenger()->addError($this->t('The contact form has not been configured. <a href=":add">Add one or more forms</a> .', [
|
||||
':add' => Url::fromRoute('contact.form_add')->toString(),
|
||||
]));
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$message = $this->entityTypeManager()
|
||||
->getStorage('contact_message')
|
||||
->create([
|
||||
'contact_form' => $contact_form->id(),
|
||||
]);
|
||||
|
||||
$form = $this->entityFormBuilder()->getForm($message);
|
||||
$form['#title'] = $contact_form->label();
|
||||
$form['#cache']['contexts'][] = 'user.permissions';
|
||||
$this->renderer->addCacheableDependency($form, $config);
|
||||
|
||||
// The form might not have the correct cacheability metadata, so make it
|
||||
// uncacheable by default.
|
||||
// @todo Remove this in https://www.drupal.org/node/3395506.
|
||||
$form['#cache']['max-age'] = 0;
|
||||
|
||||
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\Core\Render\RendererInterface::render().
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Exception is thrown when user tries to access a contact form for a
|
||||
* user who does not have an email address configured.
|
||||
*/
|
||||
public function contactPersonalPage(UserInterface $user) {
|
||||
// Do not continue if the user does not have an email address configured.
|
||||
if (!$user->getEmail()) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$message = $this->entityTypeManager()->getStorage('contact_message')->create([
|
||||
'contact_form' => 'personal',
|
||||
'recipient' => $user->id(),
|
||||
]);
|
||||
|
||||
$form = $this->entityFormBuilder()->getForm($message);
|
||||
$form['#title'] = $this->t('Contact @username', ['@username' => $user->getDisplayName()]);
|
||||
$form['#cache']['contexts'][] = 'user.permissions';
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
208
web/core/modules/contact/src/Entity/ContactForm.php
Normal file
208
web/core/modules/contact/src/Entity/ContactForm.php
Normal file
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Entity;
|
||||
|
||||
use Drupal\contact\ContactFormAccessControlHandler;
|
||||
use Drupal\contact\ContactFormEditForm;
|
||||
use Drupal\contact\ContactFormInterface;
|
||||
use Drupal\contact\ContactFormListBuilder;
|
||||
use Drupal\Core\Config\Action\Attribute\ActionMethod;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
|
||||
use Drupal\Core\Entity\Attribute\ConfigEntityType;
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\Entity\EntityPermissionsRouteProvider;
|
||||
|
||||
/**
|
||||
* Defines the contact form entity.
|
||||
*/
|
||||
#[ConfigEntityType(
|
||||
id: 'contact_form',
|
||||
label: new TranslatableMarkup('Contact form'),
|
||||
label_collection: new TranslatableMarkup('Contact forms'),
|
||||
label_singular: new TranslatableMarkup('contact form'),
|
||||
label_plural: new TranslatableMarkup('contact forms'),
|
||||
config_prefix: 'form',
|
||||
entity_keys: [
|
||||
'id' => 'id',
|
||||
'label' => 'label',
|
||||
],
|
||||
handlers: [
|
||||
'access' => ContactFormAccessControlHandler::class,
|
||||
'list_builder' => ContactFormListBuilder::class,
|
||||
'form' => [
|
||||
'add' => ContactFormEditForm::class,
|
||||
'edit' => ContactFormEditForm::class,
|
||||
'delete' => EntityDeleteForm::class,
|
||||
],
|
||||
'route_provider' => ['permissions' => EntityPermissionsRouteProvider::class],
|
||||
],
|
||||
links: [
|
||||
'delete-form' => '/admin/structure/contact/manage/{contact_form}/delete',
|
||||
'edit-form' => '/admin/structure/contact/manage/{contact_form}',
|
||||
'entity-permissions-form' => '/admin/structure/contact/manage/{contact_form}/permissions',
|
||||
'collection' => '/admin/structure/contact',
|
||||
'canonical' => '/contact/{contact_form}',
|
||||
],
|
||||
admin_permission: 'administer contact forms',
|
||||
bundle_of: 'contact_message',
|
||||
label_count: [
|
||||
'singular' => '@count contact form',
|
||||
'plural' => '@count contact forms',
|
||||
],
|
||||
config_export: [
|
||||
'id',
|
||||
'label',
|
||||
'recipients',
|
||||
'reply',
|
||||
'weight',
|
||||
'message',
|
||||
'redirect',
|
||||
],
|
||||
)]
|
||||
class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface {
|
||||
|
||||
/**
|
||||
* The form ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The human-readable label of the category.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The message displayed to user on form submission.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* List of recipient email addresses.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $recipients = [];
|
||||
|
||||
/**
|
||||
* The path to redirect to on form submission.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirect;
|
||||
|
||||
/**
|
||||
* An auto-reply message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $reply = '';
|
||||
|
||||
/**
|
||||
* The weight of the category.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $weight = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessage() {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Set contact form message'), pluralize: FALSE)]
|
||||
public function setMessage($message) {
|
||||
$this->message = $message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRecipients() {
|
||||
return $this->recipients;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Set recipients'), pluralize: FALSE)]
|
||||
public function setRecipients($recipients) {
|
||||
$this->recipients = $recipients;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRedirectPath() {
|
||||
return $this->redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRedirectUrl() {
|
||||
if ($this->redirect) {
|
||||
$url = Url::fromUserInput($this->redirect);
|
||||
}
|
||||
else {
|
||||
$url = Url::fromRoute('<front>');
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Set redirect path'), pluralize: FALSE)]
|
||||
public function setRedirectPath($redirect) {
|
||||
$this->redirect = $redirect;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReply() {
|
||||
return $this->reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Set auto-reply message'), pluralize: FALSE)]
|
||||
public function setReply($reply) {
|
||||
$this->reply = $reply;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWeight() {
|
||||
return $this->weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Set weight'), pluralize: FALSE)]
|
||||
public function setWeight($weight) {
|
||||
$this->weight = $weight;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
204
web/core/modules/contact/src/Entity/Message.php
Normal file
204
web/core/modules/contact/src/Entity/Message.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Entity;
|
||||
|
||||
use Drupal\contact\ContactMessageAccessControlHandler;
|
||||
use Drupal\contact\MessageForm;
|
||||
use Drupal\contact\MessageViewBuilder;
|
||||
use Drupal\Core\Entity\Attribute\ContentEntityType;
|
||||
use Drupal\Core\Entity\ContentEntityNullStorage;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\contact\MessageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
|
||||
/**
|
||||
* Defines the contact message entity.
|
||||
*/
|
||||
#[ContentEntityType(
|
||||
id: 'contact_message',
|
||||
label: new TranslatableMarkup('Contact message'),
|
||||
label_collection: new TranslatableMarkup('Contact messages'),
|
||||
label_singular: new TranslatableMarkup('contact message'),
|
||||
label_plural: new TranslatableMarkup('contact messages'),
|
||||
entity_keys: [
|
||||
'bundle' => 'contact_form',
|
||||
'uuid' => 'uuid',
|
||||
'langcode' => 'langcode',
|
||||
],
|
||||
handlers: [
|
||||
'access' => ContactMessageAccessControlHandler::class,
|
||||
'storage' => ContentEntityNullStorage::class,
|
||||
'view_builder' => MessageViewBuilder::class,
|
||||
'form' => ['default' => MessageForm::class],
|
||||
],
|
||||
admin_permission: 'administer contact forms',
|
||||
bundle_entity_type: 'contact_form',
|
||||
bundle_label: new TranslatableMarkup('Contact form'),
|
||||
label_count: [
|
||||
'singular' => '@count contact message',
|
||||
'plural' => '@count contact messages',
|
||||
],
|
||||
field_ui_base_route: 'entity.contact_form.edit_form'
|
||||
)]
|
||||
class Message extends ContentEntityBase implements MessageInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isPersonal() {
|
||||
return $this->bundle() == 'personal';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContactForm() {
|
||||
return $this->get('contact_form')->entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSenderName() {
|
||||
return $this->get('name')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSenderName($sender_name) {
|
||||
$this->set('name', $sender_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSenderMail() {
|
||||
return $this->get('mail')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSenderMail($sender_mail) {
|
||||
$this->set('mail', $sender_mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSubject() {
|
||||
return $this->get('subject')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSubject($subject) {
|
||||
$this->set('subject', $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessage() {
|
||||
return $this->get('message')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMessage($message) {
|
||||
$this->set('message', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function copySender() {
|
||||
return (bool) $this->get('copy')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCopySender($inform) {
|
||||
$this->set('copy', (bool) $inform);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPersonalRecipient() {
|
||||
if ($this->isPersonal()) {
|
||||
return $this->get('recipient')->entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
$fields['contact_form']->setLabel(t('Form ID'))
|
||||
->setDescription(t('The ID of the associated form.'));
|
||||
|
||||
$fields['uuid']->setDescription(t('The message UUID.'));
|
||||
|
||||
$fields['langcode']->setDescription(t('The message language code.'));
|
||||
|
||||
$fields['name'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t("The sender's name"))
|
||||
->setDescription(t('The name of the person that is sending the contact message.'));
|
||||
|
||||
$fields['mail'] = BaseFieldDefinition::create('email')
|
||||
->setLabel(t("The sender's email"))
|
||||
->setDescription(t('The email of the person that is sending the contact message.'));
|
||||
|
||||
// The subject of the contact message.
|
||||
$fields['subject'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Subject'))
|
||||
->setRequired(TRUE)
|
||||
->setSetting('max_length', 100)
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'string_textfield',
|
||||
'weight' => -10,
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE);
|
||||
|
||||
// The text of the contact message.
|
||||
$fields['message'] = BaseFieldDefinition::create('string_long')
|
||||
->setLabel(t('Message'))
|
||||
->setRequired(TRUE)
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'string_textarea',
|
||||
'weight' => 0,
|
||||
'settings' => [
|
||||
'rows' => 12,
|
||||
],
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setDisplayOptions('view', [
|
||||
'type' => 'string',
|
||||
'weight' => 0,
|
||||
'label' => 'above',
|
||||
])
|
||||
->setDisplayConfigurable('view', TRUE);
|
||||
|
||||
$fields['copy'] = BaseFieldDefinition::create('boolean')
|
||||
->setLabel(t('Copy'))
|
||||
->setDescription(t('Whether to send a copy of the message to the sender.'));
|
||||
|
||||
$fields['recipient'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Recipient ID'))
|
||||
->setDescription(t('The ID of the recipient user for personal contact messages.'))
|
||||
->setSetting('target_type', 'user');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
76
web/core/modules/contact/src/Hook/ContactFormHooks.php
Normal file
76
web/core/modules/contact/src/Hook/ContactFormHooks.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Hook;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Hook\Attribute\Hook;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\UserDataInterface;
|
||||
|
||||
/**
|
||||
* Form hook implementations for Contact module.
|
||||
*/
|
||||
class ContactFormHooks {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
public function __construct(
|
||||
protected readonly AccountInterface $currentUser,
|
||||
protected readonly UserDataInterface $userData,
|
||||
protected readonly configFactoryInterface $configFactory,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for \Drupal\user\ProfileForm.
|
||||
*
|
||||
* Add the enable personal contact form to an individual user's account page.
|
||||
*
|
||||
* @see \Drupal\user\ProfileForm::form()
|
||||
*/
|
||||
#[Hook('form_user_form_alter')]
|
||||
public function formUserFormAlter(&$form, FormStateInterface $form_state) : void {
|
||||
$form['contact'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Contact settings'),
|
||||
'#open' => TRUE,
|
||||
'#weight' => 5,
|
||||
];
|
||||
$account = $form_state->getFormObject()->getEntity();
|
||||
if (!$this->currentUser->isAnonymous() && $account->id()) {
|
||||
$account_data = $this->userData->get('contact', $account->id(), 'enabled');
|
||||
}
|
||||
$form['contact']['contact'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Personal contact form'),
|
||||
'#default_value' => $account_data ?? $this->configFactory->getEditable('contact.settings')->get('user_default_enabled'),
|
||||
'#description' => $this->t('Allow other users to contact you via a personal contact form which keeps your email address hidden. Note that some privileged users such as site administrators are still able to contact you even if you choose to disable this feature.'),
|
||||
];
|
||||
$form['actions']['submit']['#submit'][] = 'contact_user_profile_form_submit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for \Drupal\user\AccountSettingsForm.
|
||||
*
|
||||
* Adds the default personal contact setting on the user settings page.
|
||||
*/
|
||||
#[Hook('form_user_admin_settings_alter')]
|
||||
public function formUserAdminSettingsAlter(&$form, FormStateInterface $form_state) : void {
|
||||
$form['contact'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Contact settings'),
|
||||
'#open' => TRUE,
|
||||
'#weight' => 0,
|
||||
];
|
||||
$form['contact']['contact_default_status'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Enable the personal contact form by default for new users'),
|
||||
'#description' => $this->t('Changing this setting will not affect existing users.'),
|
||||
'#default_value' => $this->configFactory->getEditable('contact.settings')->get('user_default_enabled'),
|
||||
];
|
||||
// Add submit handler to save contact configuration.
|
||||
$form['#submit'][] = 'contact_form_user_admin_settings_submit';
|
||||
}
|
||||
|
||||
}
|
||||
182
web/core/modules/contact/src/Hook/ContactHooks.php
Normal file
182
web/core/modules/contact/src/Hook/ContactHooks.php
Normal file
@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Hook;
|
||||
|
||||
use Drupal\contact\Plugin\rest\resource\ContactMessageResource;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Hook\Attribute\Hook;
|
||||
|
||||
/**
|
||||
* Hook implementations for contact.
|
||||
*/
|
||||
class ContactHooks {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
#[Hook('help')]
|
||||
public function help($route_name, RouteMatchInterface $route_match): ?string {
|
||||
switch ($route_name) {
|
||||
case 'help.page.contact':
|
||||
$menu_page = \Drupal::moduleHandler()->moduleExists('menu_ui') ? Url::fromRoute('entity.menu.collection')->toString() : '#';
|
||||
$block_page = \Drupal::moduleHandler()->moduleExists('block') ? Url::fromRoute('block.admin_display')->toString() : '#';
|
||||
$contact_page = Url::fromRoute('entity.contact_form.collection')->toString();
|
||||
$output = '';
|
||||
$output .= '<h2>' . $this->t('About') . '</h2>';
|
||||
$output .= '<p>' . $this->t('The Contact module allows visitors to contact registered users on your site, using the personal contact form, and also allows you to set up site-wide contact forms. For more information, see the <a href=":contact">online documentation for the Contact module</a>.', [':contact' => 'https://www.drupal.org/documentation/modules/contact']) . '</p>';
|
||||
$output .= '<h2>' . $this->t('Uses') . '</h2>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . $this->t('Using the personal contact form') . '</dt>';
|
||||
$output .= '<dd>' . $this->t("Site visitors can email registered users on your site by using the personal contact form, without knowing or learning the email address of the recipient. When a site visitor is viewing a user profile, the viewer will see a <em>Contact</em> tab or link, which leads to the personal contact form. The personal contact link is not shown when you are viewing your own profile, and users must have both <em>View user information</em> (to see user profiles) and <em>Use users' personal contact forms</em> permission to see the link. The user whose profile is being viewed must also have their personal contact form enabled (this is a user account setting); viewers with <em>Administer users</em> permission can bypass this setting.") . '</dd>';
|
||||
$output .= '<dt>' . $this->t('Configuring contact forms') . '</dt>';
|
||||
$output .= '<dd>' . $this->t('On the <a href=":contact_admin">Contact forms page</a>, you can configure the fields and display of the personal contact form, and you can set up one or more site-wide contact forms. Each site-wide contact form has a machine name, a label, and one or more defined recipients; when a site visitor submits the form, the field values are sent to those recipients.', [':contact_admin' => $contact_page]) . '</dd>';
|
||||
$output .= '<dt>' . $this->t('Linking to contact forms') . '</dt>';
|
||||
$output .= '<dd>' . $this->t('One site-wide contact form can be designated as the default contact form. If you choose to designate a default form, the <em>Contact</em> menu link in the <em>Footer</em> menu will link to it. You can modify this link from the <a href=":menu-settings">Menus page</a> if you have the Menu UI module installed. You can also create links to other contact forms; the URL for each form you have set up has format <em>contact/machine_name_of_form</em>.', [':menu-settings' => $menu_page]) . '</p>';
|
||||
$output .= '<dt>' . $this->t('Adding content to contact forms') . '</dt>';
|
||||
$output .= '<dd>' . $this->t('From the <a href=":contact_admin">Contact forms page</a>, you can configure the fields to be shown on contact forms, including their labels and help text. If you would like other content (such as text or images) to appear on a contact form, use a block. You can create and edit blocks on the <a href=":blocks">Block layout page</a>, if the Block module is installed.', [':blocks' => $block_page, ':contact_admin' => $contact_page]) . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_type_alter().
|
||||
*/
|
||||
#[Hook('entity_type_alter')]
|
||||
public function entityTypeAlter(array &$entity_types) : void {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
|
||||
$entity_types['user']->setLinkTemplate('contact-form', '/user/{user}/contact');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_extra_field_info().
|
||||
*/
|
||||
#[Hook('entity_extra_field_info')]
|
||||
public function entityExtraFieldInfo(): array {
|
||||
$fields = [];
|
||||
foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('contact_message')) as $bundle) {
|
||||
$fields['contact_message'][$bundle]['form']['name'] = ['label' => $this->t('Sender name'), 'description' => $this->t('Text'), 'weight' => -50];
|
||||
$fields['contact_message'][$bundle]['form']['mail'] = ['label' => $this->t('Sender email'), 'description' => $this->t('Email'), 'weight' => -40];
|
||||
if ($bundle == 'personal') {
|
||||
$fields['contact_message'][$bundle]['form']['recipient'] = ['label' => $this->t('Recipient username'), 'description' => $this->t('User'), 'weight' => -30];
|
||||
}
|
||||
$fields['contact_message'][$bundle]['form']['preview'] = [
|
||||
'label' => $this->t('Preview sender message'),
|
||||
'description' => $this->t('Preview'),
|
||||
'weight' => 40,
|
||||
];
|
||||
$fields['contact_message'][$bundle]['form']['copy'] = [
|
||||
'label' => $this->t('Send copy to sender'),
|
||||
'description' => $this->t('Option'),
|
||||
'weight' => 50,
|
||||
];
|
||||
}
|
||||
$fields['user']['user']['form']['contact'] = [
|
||||
'label' => $this->t('Contact settings'),
|
||||
'description' => $this->t('Contact module form element.'),
|
||||
'weight' => 5,
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_local_tasks_alter().
|
||||
*
|
||||
* Hides the 'Contact' tab on the user profile if the user does not have an
|
||||
* email address configured.
|
||||
*/
|
||||
#[Hook('menu_local_tasks_alter')]
|
||||
public function menuLocalTasksAlter(&$data, $route_name): void {
|
||||
if ($route_name == 'entity.user.canonical' && isset($data['tabs'][0])) {
|
||||
foreach ($data['tabs'][0] as $href => $tab_data) {
|
||||
if ($href == 'entity.user.contact_form') {
|
||||
$link_params = $tab_data['#link']['url']->getRouteParameters();
|
||||
$account = User::load($link_params['user']);
|
||||
if (!$account->getEmail()) {
|
||||
unset($data['tabs'][0]['entity.user.contact_form']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_mail().
|
||||
*/
|
||||
#[Hook('mail')]
|
||||
public function mail($key, &$message, $params): void {
|
||||
$contact_message = $params['contact_message'];
|
||||
/** @var \Drupal\user\UserInterface $sender */
|
||||
$sender = $params['sender'];
|
||||
$language = \Drupal::languageManager()->getLanguage($message['langcode']);
|
||||
$variables = [
|
||||
'@site-name' => \Drupal::config('system.site')->get('name'),
|
||||
'@subject' => $contact_message->getSubject(),
|
||||
'@form' => !empty($params['contact_form']) ? $params['contact_form']->label() : '',
|
||||
'@form-url' => Url::fromRoute('<current>', [], [
|
||||
'absolute' => TRUE,
|
||||
'language' => $language,
|
||||
])->toString(),
|
||||
'@sender-name' => $sender->getDisplayName(),
|
||||
];
|
||||
if ($sender->isAuthenticated()) {
|
||||
$variables['@sender-url'] = $sender->toUrl('canonical', ['absolute' => TRUE, 'language' => $language])->toString();
|
||||
}
|
||||
else {
|
||||
$variables['@sender-url'] = $params['sender']->getEmail() ?? '';
|
||||
}
|
||||
$options = ['langcode' => $language->getId()];
|
||||
switch ($key) {
|
||||
case 'page_mail':
|
||||
case 'page_copy':
|
||||
$message['subject'] .= $this->t('[@form] @subject', $variables, $options);
|
||||
$message['body'][] = $this->t("@sender-name (@sender-url) sent a message using the contact form at @form-url.", $variables, $options);
|
||||
$build = \Drupal::entityTypeManager()->getViewBuilder('contact_message')->view($contact_message, 'mail');
|
||||
$message['body'][] = \Drupal::service('renderer')->renderInIsolation($build);
|
||||
break;
|
||||
|
||||
case 'page_autoreply':
|
||||
$message['subject'] .= $this->t('[@form] @subject', $variables, $options);
|
||||
$message['body'][] = $params['contact_form']->getReply();
|
||||
break;
|
||||
|
||||
case 'user_mail':
|
||||
case 'user_copy':
|
||||
$variables += [
|
||||
'@recipient-name' => $params['recipient']->getDisplayName(),
|
||||
'@recipient-edit-url' => $params['recipient']->toUrl('edit-form', [
|
||||
'absolute' => TRUE,
|
||||
'language' => $language,
|
||||
])->toString(),
|
||||
];
|
||||
$message['subject'] .= $this->t('[@site-name] @subject', $variables, $options);
|
||||
$message['body'][] = $this->t('Hello @recipient-name,', $variables, $options);
|
||||
$message['body'][] = $this->t("@sender-name (@sender-url) has sent you a message via your contact form at @site-name.", $variables, $options);
|
||||
// Only include the opt-out line in the original email and not in the
|
||||
// copy to the sender. Also exclude this if the email was sent from a
|
||||
// user administrator because they can always send emails even if the
|
||||
// contacted user has disabled their contact form.
|
||||
if ($key === 'user_mail' && !$params['sender']->hasPermission('administer users')) {
|
||||
$message['body'][] = $this->t("If you don't want to receive such messages, you can change your settings at @recipient-edit-url.", $variables, $options);
|
||||
}
|
||||
$build = \Drupal::entityTypeManager()->getViewBuilder('contact_message')->view($contact_message, 'mail');
|
||||
$message['body'][] = \Drupal::service('renderer')->renderInIsolation($build);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_rest_resource_alter().
|
||||
*/
|
||||
#[Hook('rest_resource_alter')]
|
||||
public function restResourceAlter(&$definitions): void {
|
||||
$definitions['entity:contact_message']['class'] = ContactMessageResource::class;
|
||||
}
|
||||
|
||||
}
|
||||
29
web/core/modules/contact/src/Hook/ContactViewsHooks.php
Normal file
29
web/core/modules/contact/src/Hook/ContactViewsHooks.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Hook;
|
||||
|
||||
use Drupal\Core\Hook\Attribute\Hook;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Hook implementations for contact.
|
||||
*/
|
||||
class ContactViewsHooks {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Implements hook_views_data_alter().
|
||||
*/
|
||||
#[Hook('views_data_alter')]
|
||||
public function viewsDataAlter(&$data): void {
|
||||
$data['users']['contact'] = [
|
||||
'field' => [
|
||||
'title' => $this->t('Contact link'),
|
||||
'help' => $this->t('Provide a simple link to the user contact page.'),
|
||||
'id' => 'contact_link',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
151
web/core/modules/contact/src/MailHandler.php
Normal file
151
web/core/modules/contact/src/MailHandler.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Mail\MailManagerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Provides a class for handling assembly and dispatch of contact mail messages.
|
||||
*/
|
||||
class MailHandler implements MailHandlerInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Language manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Logger service.
|
||||
*
|
||||
* @var \Drupal\Core\Logger\LoggerChannelInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* Mail manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Mail\MailManagerInterface
|
||||
*/
|
||||
protected $mailManager;
|
||||
|
||||
/**
|
||||
* The user entity storage handler.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new \Drupal\contact\MailHandler object.
|
||||
*
|
||||
* @param \Drupal\Core\Mail\MailManagerInterface $mail_manager
|
||||
* Mail manager service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* Language manager service.
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* A logger instance.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* String translation service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(MailManagerInterface $mail_manager, LanguageManagerInterface $language_manager, LoggerInterface $logger, TranslationInterface $string_translation, EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->languageManager = $language_manager;
|
||||
$this->mailManager = $mail_manager;
|
||||
$this->logger = $logger;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->userStorage = $entity_type_manager->getStorage('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sendMailMessages(MessageInterface $message, AccountInterface $sender) {
|
||||
// Clone the sender, as we make changes to mail and name properties.
|
||||
$sender_cloned = clone $this->userStorage->load($sender->id());
|
||||
$params = [];
|
||||
$current_langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
$recipient_langcode = $this->languageManager->getDefaultLanguage()->getId();
|
||||
$contact_form = $message->getContactForm();
|
||||
|
||||
if ($sender_cloned->isAnonymous()) {
|
||||
// At this point, $sender contains an anonymous user, so we need to take
|
||||
// over the submitted form values.
|
||||
$sender_cloned->name = $message->getSenderName();
|
||||
$sender_cloned->mail = $message->getSenderMail();
|
||||
|
||||
// For the email message, clarify that the sender name is not verified; it
|
||||
// could potentially clash with a username on this site.
|
||||
$sender_cloned->name = $this->t('@name (not verified)', ['@name' => $message->getSenderName()]);
|
||||
}
|
||||
|
||||
// Build email parameters.
|
||||
$params['contact_message'] = $message;
|
||||
$params['sender'] = $sender_cloned;
|
||||
|
||||
if (!$message->isPersonal()) {
|
||||
// Send to the form recipient(s), using the site's default language.
|
||||
$params['contact_form'] = $contact_form;
|
||||
|
||||
$to = implode(', ', $contact_form->getRecipients());
|
||||
}
|
||||
elseif ($recipient = $message->getPersonalRecipient()) {
|
||||
// Send to the user in the user's preferred language.
|
||||
$to = $recipient->getEmail();
|
||||
$recipient_langcode = $recipient->getPreferredLangcode();
|
||||
$params['recipient'] = $recipient;
|
||||
}
|
||||
else {
|
||||
throw new MailHandlerException('Unable to determine message recipient');
|
||||
}
|
||||
|
||||
// Send email to the recipient(s).
|
||||
$key_prefix = $message->isPersonal() ? 'user' : 'page';
|
||||
$this->mailManager->mail('contact', $key_prefix . '_mail', $to, $recipient_langcode, $params, $sender_cloned->getEmail());
|
||||
|
||||
// If requested, send a copy to the user, using the current language.
|
||||
if ($message->copySender()) {
|
||||
$this->mailManager->mail('contact', $key_prefix . '_copy', $sender_cloned->getEmail(), $current_langcode, $params, $sender_cloned->getEmail());
|
||||
}
|
||||
|
||||
// If configured, send an auto-reply, using the current language.
|
||||
if (!$message->isPersonal() && $contact_form->getReply()) {
|
||||
// User contact forms do not support an auto-reply message, so this
|
||||
// message always originates from the site.
|
||||
if (!$sender_cloned->getEmail()) {
|
||||
$this->logger->error('Error sending auto-reply, missing sender email address in %contact_form', [
|
||||
'%contact_form' => $contact_form->label(),
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$this->mailManager->mail('contact', 'page_autoreply', $sender_cloned->getEmail(), $current_langcode, $params);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$message->isPersonal()) {
|
||||
$this->logger->info('%sender-name (@sender-from) sent an email regarding %contact_form.', [
|
||||
'%sender-name' => $sender_cloned->getAccountName(),
|
||||
'@sender-from' => $sender_cloned->getEmail() ?? '',
|
||||
'%contact_form' => $contact_form->label(),
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$this->logger->info('%sender-name (@sender-from) sent %recipient-name an email.', [
|
||||
'%sender-name' => $sender_cloned->getAccountName(),
|
||||
'@sender-from' => $sender_cloned->getEmail(),
|
||||
'%recipient-name' => $message->getPersonalRecipient()->getAccountName(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
8
web/core/modules/contact/src/MailHandlerException.php
Normal file
8
web/core/modules/contact/src/MailHandlerException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
/**
|
||||
* Exception thrown by MailHandler when unable to determine message recipient.
|
||||
*/
|
||||
class MailHandlerException extends \RuntimeException {}
|
||||
30
web/core/modules/contact/src/MailHandlerInterface.php
Normal file
30
web/core/modules/contact/src/MailHandlerInterface.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for assembly and dispatch of contact mail messages.
|
||||
*/
|
||||
interface MailHandlerInterface {
|
||||
|
||||
/**
|
||||
* Sends mail messages as appropriate for a given Message form submission.
|
||||
*
|
||||
* Can potentially send up to three messages as follows:
|
||||
* - To the configured recipient;
|
||||
* - Auto-reply to the sender; and
|
||||
* - Carbon copy to the sender.
|
||||
*
|
||||
* @param \Drupal\contact\MessageInterface $message
|
||||
* Submitted message entity.
|
||||
* @param \Drupal\Core\Session\AccountInterface $sender
|
||||
* User that submitted the message entity form.
|
||||
*
|
||||
* @throws \Drupal\contact\MailHandlerException
|
||||
* When unable to determine message recipient.
|
||||
*/
|
||||
public function sendMailMessages(MessageInterface $message, AccountInterface $sender);
|
||||
|
||||
}
|
||||
237
web/core/modules/contact/src/MessageForm.php
Normal file
237
web/core/modules/contact/src/MessageForm.php
Normal file
@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Component\Datetime\TimeInterface;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Entity\ContentEntityForm;
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Flood\FloodInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for contact message forms.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MessageForm extends ContentEntityForm {
|
||||
|
||||
/**
|
||||
* The message being used by this form.
|
||||
*
|
||||
* @var \Drupal\contact\MessageInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The flood control mechanism.
|
||||
*
|
||||
* @var \Drupal\Core\Flood\FloodInterface
|
||||
*/
|
||||
protected $flood;
|
||||
|
||||
/**
|
||||
* The language manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The contact mail handler service.
|
||||
*
|
||||
* @var \Drupal\contact\MailHandlerInterface
|
||||
*/
|
||||
protected $mailHandler;
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs a MessageForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
* @param \Drupal\Core\Flood\FloodInterface $flood
|
||||
* The flood control mechanism.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager service.
|
||||
* @param \Drupal\contact\MailHandlerInterface $mail_handler
|
||||
* The contact mail handler service.
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
|
||||
* The entity type bundle service.
|
||||
* @param \Drupal\Component\Datetime\TimeInterface $time
|
||||
* The time service.
|
||||
*/
|
||||
public function __construct(EntityRepositoryInterface $entity_repository, FloodInterface $flood, LanguageManagerInterface $language_manager, MailHandlerInterface $mail_handler, DateFormatterInterface $date_formatter, ?EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, ?TimeInterface $time = NULL) {
|
||||
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
|
||||
$this->flood = $flood;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->mailHandler = $mail_handler;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.repository'),
|
||||
$container->get('flood'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('contact.mail_handler'),
|
||||
$container->get('date.formatter'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$container->get('datetime.time')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$user = $this->currentUser();
|
||||
$message = $this->entity;
|
||||
$form = parent::form($form, $form_state);
|
||||
$form['#attributes']['class'][] = 'contact-form';
|
||||
|
||||
if (!empty($message->preview)) {
|
||||
$form['preview'] = [
|
||||
'#theme_wrappers' => ['container__preview'],
|
||||
'#attributes' => ['class' => ['preview']],
|
||||
];
|
||||
$form['preview']['message'] = $this->entityTypeManager->getViewBuilder('contact_message')->view($message, 'full');
|
||||
}
|
||||
|
||||
$form['name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Your name'),
|
||||
'#maxlength' => 255,
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['mail'] = [
|
||||
'#type' => 'email',
|
||||
'#title' => $this->t('Your email address'),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
// Do not allow authenticated users to alter the name or email values to
|
||||
// prevent the impersonation of other users.
|
||||
if ($user->isAuthenticated()) {
|
||||
$form['name']['#type'] = 'item';
|
||||
$form['name']['#value'] = $user->getDisplayName();
|
||||
$form['name']['#required'] = FALSE;
|
||||
$form['name']['#plain_text'] = $user->getDisplayName();
|
||||
|
||||
$form['mail']['#type'] = 'item';
|
||||
$form['mail']['#value'] = $user->getEmail();
|
||||
$form['mail']['#required'] = FALSE;
|
||||
$form['mail']['#plain_text'] = $user->getEmail();
|
||||
}
|
||||
|
||||
// The user contact form has a preset recipient.
|
||||
if ($message->isPersonal()) {
|
||||
$form['recipient'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->t('To'),
|
||||
'#value' => $message->getPersonalRecipient()->id(),
|
||||
'name' => [
|
||||
'#theme' => 'username',
|
||||
'#account' => $message->getPersonalRecipient(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$form['copy'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Send yourself a copy'),
|
||||
// Do not allow anonymous users to send themselves a copy, because it can
|
||||
// be abused to spam people.
|
||||
'#access' => $user->isAuthenticated(),
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function actions(array $form, FormStateInterface $form_state) {
|
||||
$elements = parent::actions($form, $form_state);
|
||||
$elements['submit']['#value'] = $this->t('Send message');
|
||||
$elements['preview'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Preview'),
|
||||
'#submit' => ['::submitForm', '::preview'],
|
||||
'#access' => !empty($form_state->getStorage()['form_display']->getComponent('preview')),
|
||||
];
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for the 'preview' action.
|
||||
*/
|
||||
public function preview(array $form, FormStateInterface $form_state) {
|
||||
$message = $this->entity;
|
||||
$message->preview = TRUE;
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$message = parent::validateForm($form, $form_state);
|
||||
|
||||
// Check if flood control has been activated for sending emails.
|
||||
if (!$this->currentUser()->hasPermission('administer contact forms') && (!$message->isPersonal() || !$this->currentUser()->hasPermission('administer users'))) {
|
||||
$limit = $this->config('contact.settings')->get('flood.limit');
|
||||
$interval = $this->config('contact.settings')->get('flood.interval');
|
||||
|
||||
if (!$this->flood->isAllowed('contact', $limit, $interval)) {
|
||||
$form_state->setErrorByName('', $this->t('You cannot send more than %limit messages in @interval. Try again later.', [
|
||||
'%limit' => $limit,
|
||||
'@interval' => $this->dateFormatter->formatInterval($interval),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$message = $this->entity;
|
||||
$user = $this->currentUser();
|
||||
// Save the message. In core this is a no-op but should contrib wish to
|
||||
// implement message storage, this will make the task of swapping in a real
|
||||
// storage controller straight-forward.
|
||||
$message->save();
|
||||
$this->mailHandler->sendMailMessages($message, $user);
|
||||
$contact_form = $message->getContactForm();
|
||||
|
||||
$this->flood->register('contact', $this->config('contact.settings')->get('flood.interval'));
|
||||
if ($submission_message = $contact_form->getMessage()) {
|
||||
$this->messenger()->addStatus($submission_message);
|
||||
}
|
||||
|
||||
// To avoid false error messages caused by flood control, redirect away from
|
||||
// the contact form; either to the contacted user account or the front page.
|
||||
if ($message->isPersonal() && $user->hasPermission('access user profiles')) {
|
||||
$form_state->setRedirectUrl($message->getPersonalRecipient()->toUrl());
|
||||
}
|
||||
else {
|
||||
$form_state->setRedirectUrl($contact_form->getRedirectUrl());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
116
web/core/modules/contact/src/MessageInterface.php
Normal file
116
web/core/modules/contact/src/MessageInterface.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a contact message entity.
|
||||
*/
|
||||
interface MessageInterface extends ContentEntityInterface {
|
||||
|
||||
/**
|
||||
* Returns the form this contact message belongs to.
|
||||
*
|
||||
* @return \Drupal\contact\ContactFormInterface
|
||||
* The contact form entity.
|
||||
*/
|
||||
public function getContactForm();
|
||||
|
||||
/**
|
||||
* Returns the name of the sender.
|
||||
*
|
||||
* @return string
|
||||
* The name of the message sender.
|
||||
*/
|
||||
public function getSenderName();
|
||||
|
||||
/**
|
||||
* Sets the name of the message sender.
|
||||
*
|
||||
* @param string $sender_name
|
||||
* The name of the message sender.
|
||||
*/
|
||||
public function setSenderName($sender_name);
|
||||
|
||||
/**
|
||||
* Returns the email address of the sender.
|
||||
*
|
||||
* @return string
|
||||
* The email address of the message sender.
|
||||
*/
|
||||
public function getSenderMail();
|
||||
|
||||
/**
|
||||
* Sets the email address of the sender.
|
||||
*
|
||||
* @param string $sender_mail
|
||||
* The email address of the message sender.
|
||||
*/
|
||||
public function setSenderMail($sender_mail);
|
||||
|
||||
/**
|
||||
* Returns the message subject.
|
||||
*
|
||||
* @return string
|
||||
* The message subject.
|
||||
*/
|
||||
public function getSubject();
|
||||
|
||||
/**
|
||||
* Sets the subject for the email.
|
||||
*
|
||||
* @param string $subject
|
||||
* The message subject.
|
||||
*/
|
||||
public function setSubject($subject);
|
||||
|
||||
/**
|
||||
* Returns the message body.
|
||||
*
|
||||
* @return string
|
||||
* The message body.
|
||||
*/
|
||||
public function getMessage();
|
||||
|
||||
/**
|
||||
* Sets the email message to send.
|
||||
*
|
||||
* @param string $message
|
||||
* The message body.
|
||||
*/
|
||||
public function setMessage($message);
|
||||
|
||||
/**
|
||||
* Returns TRUE if a copy should be sent to the sender.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if a copy should be sent, FALSE if not.
|
||||
*/
|
||||
public function copySender();
|
||||
|
||||
/**
|
||||
* Sets if the sender should receive a copy of this email or not.
|
||||
*
|
||||
* @param bool $inform
|
||||
* TRUE if a copy should be sent, FALSE if not.
|
||||
*/
|
||||
public function setCopySender($inform);
|
||||
|
||||
/**
|
||||
* Returns TRUE if this is the personal contact form.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the message bundle is personal.
|
||||
*/
|
||||
public function isPersonal();
|
||||
|
||||
/**
|
||||
* Returns the user this message is being sent to.
|
||||
*
|
||||
* @return \Drupal\user\UserInterface
|
||||
* The user entity of the recipient, NULL if this is not a personal message.
|
||||
*/
|
||||
public function getPersonalRecipient();
|
||||
|
||||
}
|
||||
46
web/core/modules/contact/src/MessageViewBuilder.php
Normal file
46
web/core/modules/contact/src/MessageViewBuilder.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityViewBuilder;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
||||
/**
|
||||
* Render controller for contact messages.
|
||||
*/
|
||||
class MessageViewBuilder extends EntityViewBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
|
||||
$build = parent::getBuildDefaults($entity, $view_mode);
|
||||
// The message fields are individually rendered into email templates, so
|
||||
// the entity has no template itself.
|
||||
unset($build['#theme']);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
|
||||
$build = parent::view($entity, $view_mode, $langcode);
|
||||
|
||||
if ($view_mode == 'mail') {
|
||||
// Convert field labels into headings.
|
||||
// @todo Improve \Drupal\Core\Mail\MailFormatHelper::htmlToText() to
|
||||
// convert DIVs correctly.
|
||||
foreach (Element::children($build) as $key) {
|
||||
if (isset($build[$key]['#label_display']) && $build[$key]['#label_display'] == 'above') {
|
||||
$build[$key] += ['#prefix' => ''];
|
||||
$build[$key]['#prefix'] = $build[$key]['#title'] . ":\n";
|
||||
$build[$key]['#label_display'] = 'hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 6/7 contact category source from database.
|
||||
*
|
||||
* For available configuration keys, refer to the parent classes.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "contact_category",
|
||||
* source_module = "contact"
|
||||
* )
|
||||
*/
|
||||
class ContactCategory extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('contact', 'c')
|
||||
->fields('c', [
|
||||
'cid',
|
||||
'category',
|
||||
'recipients',
|
||||
'reply',
|
||||
'weight',
|
||||
'selected',
|
||||
]
|
||||
);
|
||||
$query->orderBy('c.cid');
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
$row->setSourceProperty('recipients', explode(',', $row->getSourceProperty('recipients')));
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'cid' => $this->t('Primary Key: Unique category ID.'),
|
||||
'category' => $this->t('Category name.'),
|
||||
'recipients' => $this->t('Comma-separated list of recipient email addresses.'),
|
||||
'reply' => $this->t('Text of the auto-reply message.'),
|
||||
'weight' => $this->t("The category's weight."),
|
||||
'selected' => $this->t('Flag to indicate whether or not category is selected by default. (1 = Yes, 0 = No)'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['cid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\Variable;
|
||||
|
||||
/**
|
||||
* Drupal 6/7 contact settings source from database.
|
||||
*
|
||||
* For available configuration keys, refer to the parent classes.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "contact_settings",
|
||||
* source_module = "contact"
|
||||
* )
|
||||
*/
|
||||
class ContactSettings extends Variable {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$default_category = $this->select('contact', 'c')
|
||||
->fields('c', ['cid'])
|
||||
->condition('c.selected', 1)
|
||||
->execute()
|
||||
->fetchField();
|
||||
return new \ArrayIterator([$this->values() + ['default_category' => $default_category]]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Plugin\rest\resource;
|
||||
|
||||
use Drupal\rest\Plugin\rest\resource\EntityResource;
|
||||
|
||||
/**
|
||||
* Customizes the entity REST Resource plugin for Contact's Message entities.
|
||||
*
|
||||
* Message entities are not stored, so they cannot be:
|
||||
* - retrieved (GET)
|
||||
* - modified (PATCH)
|
||||
* - deleted (DELETE)
|
||||
* Messages can only be sent/created (POST).
|
||||
*/
|
||||
class ContactMessageResource extends EntityResource {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function availableMethods() {
|
||||
return ['POST'];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\contact\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\views\Attribute\ViewsField;
|
||||
use Drupal\views\Plugin\views\field\LinkBase;
|
||||
use Drupal\views\ResultRow;
|
||||
|
||||
/**
|
||||
* Defines a field that links to the user contact page, if access is permitted.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*/
|
||||
#[ViewsField("contact_link")]
|
||||
class ContactLink extends LinkBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
$form['text']['#title'] = $this->t('Link label');
|
||||
$form['text']['#required'] = TRUE;
|
||||
$form['text']['#default_value'] = empty($this->options['text']) ? $this->getDefaultLabel() : $this->options['text'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUrlInfo(ResultRow $row) {
|
||||
$entity = $this->getEntity($row);
|
||||
if (!$entity) {
|
||||
return NULL;
|
||||
}
|
||||
return Url::fromRoute('entity.user.contact_form', ['user' => $entity->id()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function renderLink(ResultRow $row) {
|
||||
$entity = $this->getEntity($row);
|
||||
if (!$entity) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
$this->options['alter']['url'] = $this->getUrlInfo($row);
|
||||
|
||||
$title = $this->t('Contact %user', ['%user' => $entity->label()]);
|
||||
$this->options['alter']['attributes'] = ['title' => $title];
|
||||
|
||||
if (!empty($this->options['text'])) {
|
||||
return $this->options['text'];
|
||||
}
|
||||
else {
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultLabel() {
|
||||
return $this->t('contact');
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user