First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,228 @@
<?php
/**
* @file
* Admin page callbacks for the Contact module.
*/
/**
* Categories/list tab.
*/
function contact_category_list() {
$header = array(
t('Category'),
t('Recipients'),
t('Selected'),
array('data' => t('Operations'), 'colspan' => 2),
);
$rows = array();
// Get all the contact categories from the database.
$categories = db_select('contact', 'c')
->addTag('translatable')
->fields('c', array('cid', 'category', 'recipients', 'selected'))
->orderBy('weight')
->orderBy('category')
->execute()
->fetchAll();
// Loop through the categories and add them to the table.
foreach ($categories as $category) {
$rows[] = array(
check_plain($category->category),
check_plain($category->recipients),
($category->selected ? t('Yes') : t('No')),
l(t('Edit'), 'admin/structure/contact/edit/' . $category->cid),
l(t('Delete'), 'admin/structure/contact/delete/' . $category->cid),
);
}
if (!$rows) {
$rows[] = array(array(
'data' => t('No categories available.'),
'colspan' => 5,
));
}
$build['category_table'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
);
return $build;
}
/**
* Form constructor for the category edit form.
*
* @param $category
* An array describing the category to be edited. May be empty for new
* categories. Recognized array keys are:
* - category: The name of the category.
* - recipients: A comma-separated list of recipients.
* - reply: (optional) The body of the auto-reply message.
* - weight: The weight of the category.
* - selected: Boolean indicating whether the category should be selected by
* default.
* - cid: The category ID for which the form is to be displayed.
*
* @see contact_category_edit_form_validate()
* @see contact_category_edit_form_submit()
* @ingroup forms
*/
function contact_category_edit_form($form, &$form_state, array $category = array()) {
// If this is a new category, add the default values.
$category += array(
'category' => '',
'recipients' => '',
'reply' => '',
'weight' => 0,
'selected' => 0,
'cid' => NULL,
);
$form['category'] = array(
'#type' => 'textfield',
'#title' => t('Category'),
'#maxlength' => 255,
'#default_value' => $category['category'],
'#description' => t("Example: 'website feedback' or 'product information'."),
'#required' => TRUE,
);
$form['recipients'] = array(
'#type' => 'textarea',
'#title' => t('Recipients'),
'#default_value' => $category['recipients'],
'#description' => t("Example: 'webmaster@example.com' or 'sales@example.com,support@example.com' . To specify multiple recipients, separate each e-mail address with a comma."),
'#required' => TRUE,
);
$form['reply'] = array(
'#type' => 'textarea',
'#title' => t('Auto-reply'),
'#default_value' => $category['reply'],
'#description' => t('Optional auto-reply. Leave empty if you do not want to send the user an auto-reply message.'),
);
$form['weight'] = array(
'#type' => 'weight',
'#title' => t('Weight'),
'#default_value' => $category['weight'],
'#description' => t('When listing categories, those with lighter (smaller) weights get listed before categories with heavier (larger) weights. Categories with equal weights are sorted alphabetically.'),
);
$form['selected'] = array(
'#type' => 'select',
'#title' => t('Selected'),
'#options' => array(
0 => t('No'),
1 => t('Yes'),
),
'#default_value' => $category['selected'],
'#description' => t('Set this to <em>Yes</em> if you would like this category to be selected by default.'),
);
$form['cid'] = array(
'#type' => 'value',
'#value' => $category['cid'],
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
* Form validation handler for contact_category_edit_form().
*
* @see contact_category_edit_form_submit()
*/
function contact_category_edit_form_validate($form, &$form_state) {
// Validate and each e-mail recipient.
$recipients = explode(',', $form_state['values']['recipients']);
// When creating a new contact form, or renaming the category on an existing
// contact form, make sure that the given category is unique.
$category = $form_state['values']['category'];
$query = db_select('contact', 'c')->condition('c.category', $category, '=');
if (!empty($form_state['values']['cid'])) {
$query->condition('c.cid', $form_state['values']['cid'], '<>');
}
if ($query->countQuery()->execute()->fetchField()) {
form_set_error('category', t('A contact form with category %category already exists.', array('%category' => $category)));
}
foreach ($recipients as &$recipient) {
$recipient = trim($recipient);
if (!valid_email_address($recipient)) {
form_set_error('recipients', t('%recipient is an invalid e-mail address.', array('%recipient' => $recipient)));
}
}
$form_state['values']['recipients'] = implode(',', $recipients);
}
/**
* Form submission handler for contact_category_edit_form().
*
* @see contact_category_edit_form_validate()
*/
function contact_category_edit_form_submit($form, &$form_state) {
if ($form_state['values']['selected']) {
// Unselect all other contact categories.
db_update('contact')
->fields(array('selected' => '0'))
->execute();
}
if (empty($form_state['values']['cid'])) {
drupal_write_record('contact', $form_state['values']);
}
else {
drupal_write_record('contact', $form_state['values'], array('cid'));
}
drupal_set_message(t('Category %category has been saved.', array('%category' => $form_state['values']['category'])));
watchdog('contact', 'Category %category has been saved.', array('%category' => $form_state['values']['category']), WATCHDOG_NOTICE, l(t('Edit'), 'admin/structure/contact/edit/' . $form_state['values']['cid']));
$form_state['redirect'] = 'admin/structure/contact';
}
/**
* Form constructor for the contact category deletion form.
*
* @param $contact
* Array describing the contact category to be deleted. See the documentation
* of contact_category_edit_form() for the recognized keys.
*
* @see contact_menu()
* @see contact_category_delete_form_submit()
*/
function contact_category_delete_form($form, &$form_state, array $contact) {
$form['contact'] = array(
'#type' => 'value',
'#value' => $contact,
);
return confirm_form(
$form,
t('Are you sure you want to delete %category?', array('%category' => $contact['category'])),
'admin/structure/contact',
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
/**
* Form submission handler for contact_category_delete_form().
*/
function contact_category_delete_form_submit($form, &$form_state) {
$contact = $form['contact']['#value'];
db_delete('contact')
->condition('cid', $contact['cid'])
->execute();
drupal_set_message(t('Category %category has been deleted.', array('%category' => $contact['category'])));
watchdog('contact', 'Category %category has been deleted.', array('%category' => $contact['category']), WATCHDOG_NOTICE);
$form_state['redirect'] = 'admin/structure/contact';
}

View file

@ -0,0 +1,13 @@
name = Contact
description = Enables the use of both personal and site-wide contact forms.
package = Core
version = VERSION
core = 7.x
files[] = contact.test
configure = admin/structure/contact
; Information added by Drupal.org packaging script on 2017-06-21
version = "7.56"
project = "drupal"
datestamp = "1498069849"

View file

@ -0,0 +1,168 @@
<?php
/**
* @file
* Install, update and uninstall functions for the contact module.
*/
/**
* Implements hook_schema().
*/
function contact_schema() {
$schema['contact'] = array(
'description' => 'Contact form category settings.',
'fields' => array(
'cid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Primary Key: Unique category ID.',
),
'category' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Category name.',
'translatable' => TRUE,
),
'recipients' => array(
'type' => 'text',
'not null' => TRUE,
'size' => 'big',
'description' => 'Comma-separated list of recipient e-mail addresses.',
),
'reply' => array(
'type' => 'text',
'not null' => TRUE,
'size' => 'big',
'description' => 'Text of the auto-reply message.',
),
'weight' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "The category's weight.",
),
'selected' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'Flag to indicate whether or not category is selected by default. (1 = Yes, 0 = No)',
),
),
'primary key' => array('cid'),
'unique keys' => array(
'category' => array('category'),
),
'indexes' => array(
'list' => array('weight', 'category'),
),
);
return $schema;
}
/**
* Implements hook_install().
*/
function contact_install() {
// Insert a default contact category.
db_insert('contact')
->fields(array(
'category' => 'Website feedback',
'recipients' => variable_get('site_mail', ini_get('sendmail_from')),
'selected' => 1,
'reply' => '',
))
->execute();
}
/**
* Implements hook_uninstall().
*/
function contact_uninstall() {
variable_del('contact_default_status');
variable_del('contact_threshold_limit');
variable_del('contact_threshold_window');
}
/**
* Implements hook_update_dependencies().
*/
function contact_update_dependencies() {
// contact_update_7001() relies on the {role_permission} table being updated
// to the new format and filled with data.
$dependencies['contact'][7001] = array(
'system' => 7007,
);
// contact_update_7002() relies on the {role_permission} table having the
// module field, which is created in user_update_7006().
$dependencies['contact'][7002] = array(
'user' => 7006,
);
return $dependencies;
}
/**
* @addtogroup updates-6.x-to-7.x
* @{
*/
/**
* Rename the threshold limit variable.
*/
function contact_update_7000() {
variable_set('contact_threshold_limit', variable_get('contact_hourly_threshold', 5));
variable_del('contact_hourly_threshold');
}
/**
* Rename the administer contact forms permission.
*/
function contact_update_7001() {
db_update('role_permission')
->fields(array('permission' => 'administer contact forms'))
->condition('permission', 'administer site-wide contact form')
->execute();
}
/**
* Enable the 'access user contact forms' for registered users by default.
*/
function contact_update_7002() {
// Do not use user_role_grant_permission() since it relies on
// hook_permission(), which will not run for contact module if it is
// disabled.
db_merge('role_permission')
->key(array(
'rid' => DRUPAL_AUTHENTICATED_RID,
'permission' => 'access user contact forms',
'module' => 'contact',
))
->execute();
}
/**
* Change the weight column to normal int.
*/
function contact_update_7003() {
db_drop_index('contact', 'list');
db_change_field('contact', 'weight', 'weight', array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "The category's weight.",
), array(
'indexes' => array(
'list' => array('weight', 'category'),
),
));
}
/**
* @} End of "addtogroup updates-6.x-to-7.x".
*/

View file

@ -0,0 +1,266 @@
<?php
/**
* @file
* Enables the use of personal and site-wide contact forms.
*/
/**
* Implements hook_help().
*/
function contact_help($path, $arg) {
switch ($path) {
case 'admin/help#contact':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Contact module allows visitors to contact site administrators and other users. Users specify a subject, write their message, and can have a copy of their message sent to their own e-mail address. For more information, see the online handbook entry for <a href="@contact">Contact module</a>.', array('@contact' => 'http://drupal.org/documentation/modules/contact/')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('User contact forms') . '</dt>';
$output .= '<dd>' . t('Site users can be contacted with a user contact form that keeps their e-mail address private. Users may enable or disable their personal contact forms by editing their <em>My account</em> page. If enabled, a <em>Contact</em> tab leads to a personal contact form displayed on their user profile. Site administrators are still able to use the contact form, even if has been disabled. The <em>Contact</em> tab is not shown when you view your own profile.') . '</dd>';
$output .= '<dt>' . t('Site-wide contact forms') . '</dt>';
$output .= '<dd>' . t('The <a href="@contact">Contact page</a> provides a simple form for users with the <em>Use the site-wide contact form</em> permission to send comments, feedback, or other requests. You can create categories for directing the contact form messages to a set of defined recipients. Common categories for a business site, for example, might include "Website feedback" (messages are forwarded to website administrators) and "Product information" (messages are forwarded to members of the sales department). E-mail addresses defined within a category are not displayed publicly.', array('@contact' => url('contact'))) . '</p>';
$output .= '<dt>' . t('Navigation') . '</dt>';
$output .= '<dd>' . t("When the site-wide contact form is enabled, a link in the main <em>Navigation</em> menu is created, but the link is disabled by default. This menu link can be enabled on the <a href='@menu'>Menus administration page</a>.", array('@contact' => url('contact'), '@menu' => url('admin/structure/menu'))) . '</dd>';
$output .= '<dt>' . t('Customization') . '</dt>';
$output .= '<dd>' . t('If you would like additional text to appear on the site-wide or personal contact page, use a block. You can create and edit blocks on the <a href="@blocks">Blocks administration page</a>.', array('@blocks' => url('admin/structure/block'))) . '</dd>';
$output .= '</dl>';
return $output;
case 'admin/structure/contact':
$output = '<p>' . t('Add one or more categories on this page to set up your site-wide <a href="@form">contact form</a>.', array('@form' => url('contact'))) . '</p>';
$output .= '<p>' . t('A <em>Contact</em> menu item (disabled by default) is added to the Navigation menu, which you can modify on the <a href="@menu-settings">Menus administration page</a>.', array('@menu-settings' => url('admin/structure/menu'))) . '</p>';
$output .= '<p>' . t('If you would like additional text to appear on the site-wide contact page, use a block. You can create and edit blocks on the <a href="@blocks">Blocks administration page</a>.', array('@blocks' => url('admin/structure/block'))) . '</p>';
return $output;
}
}
/**
* Implements hook_permission().
*/
function contact_permission() {
return array(
'administer contact forms' => array(
'title' => t('Administer contact forms and contact form settings'),
),
'access site-wide contact form' => array(
'title' => t('Use the site-wide contact form'),
),
'access user contact forms' => array(
'title' => t("Use users' personal contact forms"),
),
);
}
/**
* Implements hook_menu().
*/
function contact_menu() {
$items['admin/structure/contact'] = array(
'title' => 'Contact form',
'description' => 'Create a system contact form and set up categories for the form to use.',
'page callback' => 'contact_category_list',
'access arguments' => array('administer contact forms'),
'file' => 'contact.admin.inc',
);
$items['admin/structure/contact/add'] = array(
'title' => 'Add category',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_category_edit_form'),
'access arguments' => array('administer contact forms'),
'type' => MENU_LOCAL_ACTION,
'weight' => 1,
'file' => 'contact.admin.inc',
);
$items['admin/structure/contact/edit/%contact'] = array(
'title' => 'Edit contact category',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_category_edit_form', 4),
'access arguments' => array('administer contact forms'),
'file' => 'contact.admin.inc',
);
$items['admin/structure/contact/delete/%contact'] = array(
'title' => 'Delete contact',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_category_delete_form', 4),
'access arguments' => array('administer contact forms'),
'file' => 'contact.admin.inc',
);
$items['contact'] = array(
'title' => 'Contact',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_site_form'),
'access arguments' => array('access site-wide contact form'),
'type' => MENU_SUGGESTED_ITEM,
'file' => 'contact.pages.inc',
);
$items['user/%user/contact'] = array(
'title' => 'Contact',
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_personal_form', 1),
'type' => MENU_LOCAL_TASK,
'access callback' => '_contact_personal_tab_access',
'access arguments' => array(1),
'weight' => 2,
'file' => 'contact.pages.inc',
);
return $items;
}
/**
* Menu access callback for a user's personal contact form.
*
* @param $account
* The user object of the user whose contact form is being requested.
*/
function _contact_personal_tab_access($account) {
global $user;
// Anonymous users cannot have contact forms.
if (!$account->uid) {
return FALSE;
}
// User administrators should always have access to personal contact forms.
if (user_access('administer users')) {
return TRUE;
}
// Users may not contact themselves.
if ($user->uid == $account->uid) {
return FALSE;
}
// If the requested user has disabled their contact form, or this preference
// has not yet been saved, do not allow users to contact them.
if (empty($account->data['contact'])) {
return FALSE;
}
// If requested user has been blocked, do not allow users to contact them.
if (empty($account->status)) {
return FALSE;
}
return user_access('access user contact forms');
}
/**
* Loads a contact category.
*
* @param $cid
* The contact category ID.
*
* @return
* An array with the contact category's data.
*/
function contact_load($cid) {
return db_select('contact', 'c')
->addTag('translatable')
->fields('c')
->condition('cid', $cid)
->execute()
->fetchAssoc();
}
/**
* Implements hook_mail().
*/
function contact_mail($key, &$message, $params) {
$language = $message['language'];
$variables = array(
'!site-name' => variable_get('site_name', 'Drupal'),
'!subject' => $params['subject'],
'!category' => isset($params['category']['category']) ? $params['category']['category'] : '',
'!form-url' => url($_GET['q'], array('absolute' => TRUE, 'language' => $language)),
'!sender-name' => format_username($params['sender']),
'!sender-url' => $params['sender']->uid ? url('user/' . $params['sender']->uid, array('absolute' => TRUE, 'language' => $language)) : $params['sender']->mail,
);
switch ($key) {
case 'page_mail':
case 'page_copy':
$message['subject'] .= t('[!category] !subject', $variables, array('langcode' => $language->language));
$message['body'][] = t("!sender-name (!sender-url) sent a message using the contact form at !form-url.", $variables, array('langcode' => $language->language));
$message['body'][] = $params['message'];
break;
case 'page_autoreply':
$message['subject'] .= t('[!category] !subject', $variables, array('langcode' => $language->language));
$message['body'][] = $params['category']['reply'];
break;
case 'user_mail':
case 'user_copy':
$variables += array(
'!recipient-name' => format_username($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->language));
$message['body'][] = t('Hello !recipient-name,', $variables, array('langcode' => $language->language));
$message['body'][] = t("!sender-name (!sender-url) has sent you a message via your contact form (!form-url) at !site-name.", $variables, array('langcode' => $language->language));
$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->language));
$message['body'][] = t('Message:', array(), array('langcode' => $language->language));
$message['body'][] = $params['message'];
break;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add the enable personal contact form to an individual user's account page.
*
* @see user_profile_form()
*/
function contact_form_user_profile_form_alter(&$form, &$form_state) {
if ($form['#user_category'] == 'account') {
$account = $form['#user'];
$form['contact'] = array(
'#type' => 'fieldset',
'#title' => t('Contact settings'),
'#weight' => 5,
'#collapsible' => TRUE,
);
$form['contact']['contact'] = array(
'#type' => 'checkbox',
'#title' => t('Personal contact form'),
'#default_value' => !empty($account->data['contact']) ? $account->data['contact'] : FALSE,
'#description' => t('Allow other users to contact you via a <a href="@url">personal contact form</a> which keeps your e-mail 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.', array('@url' => url("user/$account->uid/contact"))),
);
}
}
/**
* Implements hook_user_presave().
*/
function contact_user_presave(&$edit, $account, $category) {
if (isset($edit['contact'])) {
// Set new value.
$edit['data']['contact'] = $edit['contact'];
}
elseif (!isset($account->data['contact'])) {
// Use default if none has been set.
$edit['data']['contact'] = variable_get('contact_default_status', 1);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add the default personal contact setting on the user settings page.
*
* @see user_admin_settings()
*/
function contact_form_user_admin_settings_alter(&$form, &$form_state) {
$form['contact'] = array(
'#type' => 'fieldset',
'#title' => t('Contact settings'),
'#weight' => 0,
);
$form['contact']['contact_default_status'] = array(
'#type' => 'checkbox',
'#title' => t('Enable the personal contact form by default for new users.'),
'#description' => t('Changing this setting will not affect existing users.'),
'#default_value' => variable_get('contact_default_status', 1),
);
}

View file

@ -0,0 +1,300 @@
<?php
/**
* @file
* Page callbacks for the Contact module.
*/
/**
* Form constructor for the site-wide contact form.
*
* @see contact_site_form_validate()
* @see contact_site_form_submit()
* @ingroup forms
*/
function contact_site_form($form, &$form_state) {
global $user;
// Check if flood control has been activated for sending e-mails.
$limit = variable_get('contact_threshold_limit', 5);
$window = variable_get('contact_threshold_window', 3600);
if (!flood_is_allowed('contact', $limit, $window) && !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($window))), 'error');
drupal_access_denied();
drupal_exit();
}
// Get an array of the categories and the current default category.
$categories = db_select('contact', 'c')
->addTag('translatable')
->fields('c', array('cid', 'category'))
->orderBy('weight')
->orderBy('category')
->execute()
->fetchAllKeyed();
$default_category = db_query("SELECT cid FROM {contact} WHERE selected = 1")->fetchField();
// 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');
}
else {
drupal_not_found();
drupal_exit();
}
}
// If there is more than one category available and no default category has
// been selected, prepend a default placeholder value.
if (!$default_category) {
if (count($categories) > 1) {
$categories = array(0 => t('- Please choose -')) + $categories;
}
else {
$default_category = key($categories);
}
}
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 ? format_username($user) : '',
'#required' => TRUE,
);
$form['mail'] = array(
'#type' => 'textfield',
'#title' => t('Your e-mail address'),
'#maxlength' => 255,
'#default_value' => $user->uid ? $user->mail : '',
'#required' => TRUE,
);
$form['subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#maxlength' => 255,
'#required' => TRUE,
);
$form['cid'] = array(
'#type' => 'select',
'#title' => t('Category'),
'#default_value' => $default_category,
'#options' => $categories,
'#required' => TRUE,
'#access' => count($categories) > 1,
);
$form['message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#required' => TRUE,
);
// We 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 validation handler for contact_site_form().
*
* @see contact_site_form_submit()
*/
function contact_site_form_validate($form, &$form_state) {
if (!$form_state['values']['cid']) {
form_set_error('cid', t('You must select a valid category.'));
}
if (!valid_email_address($form_state['values']['mail'])) {
form_set_error('mail', t('You must enter a valid e-mail address.'));
}
}
/**
* Form submission handler for contact_site_form().
*
* @see contact_site_form_validate()
*/
function contact_site_form_submit($form, &$form_state) {
global $user, $language;
$values = $form_state['values'];
$values['sender'] = clone $user;
$values['sender']->name = $values['name'];
$values['sender']->mail = $values['mail'];
$values['category'] = contact_load($values['cid']);
// Save the anonymous user information to a cookie for reuse.
if (!$user->uid) {
user_cookie_save(array_intersect_key($values, array_flip(array('name', 'mail'))));
}
// Get the to and from e-mail addresses.
$to = $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(), $values, $from);
// If the user requests it, send a copy using the current language.
if ($values['copy']) {
drupal_mail('contact', 'page_copy', $from, $language, $values, $from);
}
// Send an auto-reply if necessary using the current language.
if ($values['category']['reply']) {
drupal_mail('contact', 'page_autoreply', $from, $language, $values, $to);
}
flood_register_event('contact', variable_get('contact_threshold_window', 3600));
watchdog('mail', '%sender-name (@sender-from) sent an e-mail regarding %category.', array('%sender-name' => $values['name'], '@sender-from' => $from, '%category' => $values['category']['category']));
// 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'] = '';
}
/**
* Form constructor for the personal contact form.
*
* Path: user/%user/contact
*
* @see contact_menu()
* @see contact_personal_form_validate()
* @see contact_personal_form_submit()
* @ingroup forms
*/
function contact_personal_form($form, &$form_state, $recipient) {
global $user;
// Check if flood control has been activated for sending e-mails.
$limit = variable_get('contact_threshold_limit', 5);
$window = variable_get('contact_threshold_window', 3600);
if (!flood_is_allowed('contact', $limit, $window) && !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($window))), 'error');
drupal_access_denied();
drupal_exit();
}
drupal_set_title(t('Contact @username', array('@username' => format_username($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 ? format_username($user) : '',
'#required' => TRUE,
);
$form['mail'] = array(
'#type' => 'textfield',
'#title' => t('Your e-mail address'),
'#maxlength' => 255,
'#default_value' => $user->uid ? $user->mail : '',
'#required' => TRUE,
);
$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,
);
// We 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 validation handler for contact_personal_form().
*
* @see contact_personal_form_submit()
*/
function contact_personal_form_validate($form, &$form_state) {
if (!valid_email_address($form_state['values']['mail'])) {
form_set_error('mail', t('You must enter a valid e-mail address.'));
}
}
/**
* Form submission handler for contact_personal_form().
*
* @see contact_personal_form_validate()
*/
function contact_personal_form_submit($form, &$form_state) {
global $user, $language;
$values = $form_state['values'];
$values['sender'] = clone $user;
$values['sender']->name = $values['name'];
$values['sender']->mail = $values['mail'];
// Save the anonymous user information to a cookie for reuse.
if (!$user->uid) {
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_language($values['recipient']), $values, $from);
// Send a copy if requested, using current page language.
if ($values['copy']) {
drupal_mail('contact', 'user_copy', $from, $language, $values, $from);
}
flood_register_event('contact', variable_get('contact_threshold_window', 3600));
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 : '';
}

View file

@ -0,0 +1,456 @@
<?php
/**
* @file
* Tests for the Contact module.
*/
/**
* Tests the site-wide contact form.
*/
class ContactSitewideTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Site-wide contact form',
'description' => 'Tests site-wide contact form functionality.',
'group' => 'Contact',
);
}
function setUp() {
parent::setUp('contact');
}
/**
* Tests configuration options and the site-wide contact form.
*/
function testSiteWideContact() {
// Create and login administrative user.
$admin_user = $this->drupalCreateUser(array('access site-wide contact form', 'administer contact forms', 'administer users'));
$this->drupalLogin($admin_user);
$flood_limit = 3;
variable_set('contact_threshold_limit', $flood_limit);
variable_set('contact_threshold_window', 600);
// Set settings.
$edit = array();
$edit['contact_default_status'] = TRUE;
$this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Setting successfully saved.');
// Delete old categories to ensure that new categories are used.
$this->deleteCategories();
// Ensure that the contact form won't be shown without categories.
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
$this->drupalLogout();
$this->drupalGet('contact');
$this->assertResponse(404);
$this->drupalLogin($admin_user);
$this->drupalGet('contact');
$this->assertResponse(200);
$this->assertText(t('The contact form has not been configured.'));
// Add categories.
// Test invalid recipients.
$invalid_recipients = array('invalid', 'invalid@', 'invalid@site.', '@site.', '@site.com');
foreach ($invalid_recipients as $invalid_recipient) {
$this->addCategory($this->randomName(16), $invalid_recipient, '', FALSE);
$this->assertRaw(t('%recipient is an invalid e-mail address.', array('%recipient' => $invalid_recipient)), format_string('Caught invalid recipient (@invalid_recipient).', array('@invalid_recipient' => $invalid_recipient)));
}
// Test validation of empty category and recipients fields.
$this->addCategory($category = '', '', '', TRUE);
$this->assertText(t('Category field is required.'), 'Caught empty category field');
$this->assertText(t('Recipients field is required.'), 'Caught empty recipients field.');
// Create first valid category.
$recipients = array('simpletest@example.com', 'simpletest2@example.com', 'simpletest3@example.com');
$this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0])), '', TRUE);
$this->assertRaw(t('Category %category has been saved.', array('%category' => $category)), 'Category successfully saved.');
// Make sure the newly created category is included in the list of categories.
$this->assertNoUniqueText($category, 'New category included in categories list.');
// Test update contact form category.
$categories = $this->getCategories();
$category_id = $this->updateCategory($categories, $category = $this->randomName(16), $recipients_str = implode(',', array($recipients[0], $recipients[1])), $reply = $this->randomName(30), FALSE);
$category_array = db_query("SELECT category, recipients, reply, selected FROM {contact} WHERE cid = :cid", array(':cid' => $category_id))->fetchAssoc();
$this->assertEqual($category_array['category'], $category);
$this->assertEqual($category_array['recipients'], $recipients_str);
$this->assertEqual($category_array['reply'], $reply);
$this->assertFalse($category_array['selected']);
$this->assertRaw(t('Category %category has been saved.', array('%category' => $category)), 'Category successfully saved.');
// Ensure that the contact form is shown without a category selection input.
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
$this->drupalLogout();
$this->drupalGet('contact');
$this->assertText(t('Your e-mail address'), 'Contact form is shown when there is one category.');
$this->assertNoText(t('Category'), 'When there is only one category, the category selection element is hidden.');
$this->drupalLogin($admin_user);
// Add more categories.
$this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0], $recipients[1])), '', FALSE);
$this->assertRaw(t('Category %category has been saved.', array('%category' => $category)), 'Category successfully saved.');
$this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0], $recipients[1], $recipients[2])), '', FALSE);
$this->assertRaw(t('Category %category has been saved.', array('%category' => $category)), 'Category successfully saved.');
// Try adding a category that already exists.
$this->addCategory($category, '', '', FALSE);
$this->assertNoRaw(t('Category %category has been saved.', array('%category' => $category)), 'Category not saved.');
$this->assertRaw(t('A contact form with category %category already exists.', array('%category' => $category)), 'Duplicate category error found.');
// Clear flood table in preparation for flood test and allow other checks to complete.
db_delete('flood')->execute();
$num_records_after = db_query("SELECT COUNT(*) FROM {flood}")->fetchField();
$this->assertIdentical($num_records_after, '0', 'Flood table emptied.');
$this->drupalLogout();
// Check to see that anonymous user cannot see contact page without permission.
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
$this->drupalGet('contact');
$this->assertResponse(403, 'Access denied to anonymous user without permission.');
// Give anonymous user permission and see that page is viewable.
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
$this->drupalGet('contact');
$this->assertResponse(200, 'Access granted to anonymous user with permission.');
// Submit contact form with invalid values.
$this->submitContact('', $recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
$this->assertText(t('Your name field is required.'), 'Name required.');
$this->submitContact($this->randomName(16), '', $this->randomName(16), $categories[0], $this->randomName(64));
$this->assertText(t('Your e-mail address field is required.'), 'E-mail required.');
$this->submitContact($this->randomName(16), $invalid_recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
$this->assertText(t('You must enter a valid e-mail address.'), 'Valid e-mail required.');
$this->submitContact($this->randomName(16), $recipients[0], '', $categories[0], $this->randomName(64));
$this->assertText(t('Subject field is required.'), 'Subject required.');
$this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $categories[0], '');
$this->assertText(t('Message field is required.'), 'Message required.');
// Test contact form with no default category selected.
db_update('contact')
->fields(array('selected' => 0))
->execute();
$this->drupalGet('contact');
$this->assertRaw(t('- Please choose -'), 'Without selected categories the visitor is asked to chose a category.');
// Submit contact form with invalid category id (cid 0).
$this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), 0, '');
$this->assertText(t('You must select a valid category.'), 'Valid category required.');
// Submit contact form with correct values and check flood interval.
for ($i = 0; $i < $flood_limit; $i++) {
$this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
$this->assertText(t('Your message has been sent.'), 'Message sent.');
}
// Submit contact form one over limit.
$this->drupalGet('contact');
$this->assertResponse(403, 'Access denied to anonymous user after reaching message treshold.');
$this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array('%number' => variable_get('contact_threshold_limit', 3), '@interval' => format_interval(600))), 'Message threshold reached.');
// Delete created categories.
$this->drupalLogin($admin_user);
$this->deleteCategories();
}
/**
* Tests auto-reply on the site-wide contact form.
*/
function testAutoReply() {
// Create and login administrative user.
$admin_user = $this->drupalCreateUser(array('access site-wide contact form', 'administer contact forms', 'administer permissions', 'administer users'));
$this->drupalLogin($admin_user);
// Set up three categories, 2 with an auto-reply and one without.
$foo_autoreply = $this->randomName(40);
$bar_autoreply = $this->randomName(40);
$this->addCategory('foo', 'foo@example.com', $foo_autoreply, FALSE);
$this->addCategory('bar', 'bar@example.com', $bar_autoreply, FALSE);
$this->addCategory('no_autoreply', 'bar@example.com', '', FALSE);
// Test the auto-reply for category 'foo'.
$email = $this->randomName(32) . '@example.com';
$subject = $this->randomName(64);
$this->submitContact($this->randomName(16), $email, $subject, 2, $this->randomString(128));
// We are testing the auto-reply, so there should be one e-mail going to the sender.
$captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email, 'from' => 'foo@example.com'));
$this->assertEqual(count($captured_emails), 1, 'Auto-reply e-mail was sent to the sender for category "foo".', 'Contact');
$this->assertEqual($captured_emails[0]['body'], drupal_html_to_text($foo_autoreply), 'Auto-reply e-mail body is correct for category "foo".', 'Contact');
// Test the auto-reply for category 'bar'.
$email = $this->randomName(32) . '@example.com';
$this->submitContact($this->randomName(16), $email, $this->randomString(64), 3, $this->randomString(128));
// Auto-reply for category 'bar' should result in one auto-reply e-mail to the sender.
$captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email, 'from' => 'bar@example.com'));
$this->assertEqual(count($captured_emails), 1, 'Auto-reply e-mail was sent to the sender for category "bar".', 'Contact');
$this->assertEqual($captured_emails[0]['body'], drupal_html_to_text($bar_autoreply), 'Auto-reply e-mail body is correct for category "bar".', 'Contact');
// Verify that no auto-reply is sent when the auto-reply field is left blank.
$email = $this->randomName(32) . '@example.com';
$this->submitContact($this->randomName(16), $email, $this->randomString(64), 4, $this->randomString(128));
$captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email, 'from' => 'no_autoreply@example.com'));
$this->assertEqual(count($captured_emails), 0, 'No auto-reply e-mail was sent to the sender for category "no-autoreply".', 'Contact');
}
/**
* Adds a category.
*
* @param string $category
* The category name.
* @param string $recipients
* The list of recipient e-mail addresses.
* @param string $reply
* The auto-reply text that is sent to a user upon completing the contact
* form.
* @param boolean $selected
* Boolean indicating whether the category should be selected by default.
*/
function addCategory($category, $recipients, $reply, $selected) {
$edit = array();
$edit['category'] = $category;
$edit['recipients'] = $recipients;
$edit['reply'] = $reply;
$edit['selected'] = ($selected ? '1' : '0');
$this->drupalPost('admin/structure/contact/add', $edit, t('Save'));
}
/**
* Updates a category.
*
* @param string $category
* The category name.
* @param string $recipients
* The list of recipient e-mail addresses.
* @param string $reply
* The auto-reply text that is sent to a user upon completing the contact
* form.
* @param boolean $selected
* Boolean indicating whether the category should be selected by default.
*/
function updateCategory($categories, $category, $recipients, $reply, $selected) {
$category_id = $categories[array_rand($categories)];
$edit = array();
$edit['category'] = $category;
$edit['recipients'] = $recipients;
$edit['reply'] = $reply;
$edit['selected'] = ($selected ? '1' : '0');
$this->drupalPost('admin/structure/contact/edit/' . $category_id, $edit, t('Save'));
return ($category_id);
}
/**
* Submits the contact form.
*
* @param string $name
* The name of the sender.
* @param string $mail
* The e-mail address of the sender.
* @param string $subject
* The subject of the message.
* @param integer $cid
* The category ID of the message.
* @param string $message
* The message body.
*/
function submitContact($name, $mail, $subject, $cid, $message) {
$edit = array();
$edit['name'] = $name;
$edit['mail'] = $mail;
$edit['subject'] = $subject;
$edit['cid'] = $cid;
$edit['message'] = $message;
$this->drupalPost('contact', $edit, t('Send message'));
}
/**
* Deletes all categories.
*/
function deleteCategories() {
$categories = $this->getCategories();
foreach ($categories as $category) {
$category_name = db_query("SELECT category FROM {contact} WHERE cid = :cid", array(':cid' => $category))->fetchField();
$this->drupalPost('admin/structure/contact/delete/' . $category, array(), t('Delete'));
$this->assertRaw(t('Category %category has been deleted.', array('%category' => $category_name)), 'Category deleted successfully.');
}
}
/**
* Gets a list of all category IDs.
*
* @return array
* A list of the category IDs.
*/
function getCategories() {
$categories = db_query('SELECT cid FROM {contact}')->fetchCol();
return $categories;
}
}
/**
* Tests the personal contact form.
*/
class ContactPersonalTestCase extends DrupalWebTestCase {
private $admin_user;
private $web_user;
private $contact_user;
public static function getInfo() {
return array(
'name' => 'Personal contact form',
'description' => 'Tests personal contact form functionality.',
'group' => 'Contact',
);
}
function setUp() {
parent::setUp('contact');
// Create an admin user.
$this->admin_user = $this->drupalCreateUser(array('administer contact forms', 'administer users'));
// Create some normal users with their contact forms enabled by default.
variable_set('contact_default_status', TRUE);
$this->web_user = $this->drupalCreateUser(array('access user contact forms'));
$this->contact_user = $this->drupalCreateUser();
}
/**
* Tests access to the personal contact form.
*/
function testPersonalContactAccess() {
// Test allowed access to user with contact form enabled.
$this->drupalLogin($this->web_user);
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
// Test denied access to the user's own contact form.
$this->drupalGet('user/' . $this->web_user->uid . '/contact');
$this->assertResponse(403);
// Test always denied access to the anonymous user contact form.
$this->drupalGet('user/0/contact');
$this->assertResponse(403);
// Test that anonymous users can access the contact form.
$this->drupalLogout();
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access user contact forms'));
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
// Test that users can disable their contact form.
$this->drupalLogin($this->contact_user);
$edit = array('contact' => FALSE);
$this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save');
$this->drupalLogout();
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(403);
// Test that user's contact status stays disabled when saving.
$contact_user_temp = user_load($this->contact_user->uid, TRUE);
user_save($contact_user_temp);
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(403);
// Test that users can enable their contact form.
$this->drupalLogin($this->contact_user);
$edit = array('contact' => TRUE);
$this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save');
$this->drupalLogout();
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
// Revoke the personal contact permission for the anonymous user.
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access user contact forms'));
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(403);
// Disable the personal contact form.
$this->drupalLogin($this->admin_user);
$edit = array('contact_default_status' => FALSE);
$this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), 'Setting successfully saved.');
$this->drupalLogout();
// Re-create our contacted user with personal contact forms disabled by
// default.
$this->contact_user = $this->drupalCreateUser();
// Test denied access to a user with contact form disabled.
$this->drupalLogin($this->web_user);
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(403);
// Test allowed access for admin user to a user with contact form disabled.
$this->drupalLogin($this->admin_user);
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
// Re-create our contacted user as a blocked user.
$this->contact_user = $this->drupalCreateUser();
user_save($this->contact_user, array('status' => 0));
// Test that blocked users can still be contacted by admin.
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
// Test that blocked users cannot be contacted by non-admins.
$this->drupalLogin($this->web_user);
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(403);
}
/**
* Tests the personal contact form flood protection.
*/
function testPersonalContactFlood() {
$flood_limit = 3;
variable_set('contact_threshold_limit', $flood_limit);
// Clear flood table in preparation for flood test and allow other checks to complete.
db_delete('flood')->execute();
$num_records_flood = db_query("SELECT COUNT(*) FROM {flood}")->fetchField();
$this->assertIdentical($num_records_flood, '0', 'Flood table emptied.');
$this->drupalLogin($this->web_user);
// Submit contact form with correct values and check flood interval.
for ($i = 0; $i < $flood_limit; $i++) {
$this->submitPersonalContact($this->contact_user);
$this->assertText(t('Your message has been sent.'), 'Message sent.');
}
// Submit contact form one over limit.
$this->drupalGet('user/' . $this->contact_user->uid. '/contact');
$this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array('%number' => $flood_limit, '@interval' => format_interval(variable_get('contact_threshold_window', 3600)))), 'Normal user denied access to flooded contact form.');
// Test that the admin user can still access the contact form even though
// the flood limit was reached.
$this->drupalLogin($this->admin_user);
$this->assertNoText('Try again later.', 'Admin user not denied access to flooded contact form.');
}
/**
* Fills out a user's personal contact form and submits it.
*
* @param $account
* A user object of the user being contacted.
* @param $message
* An optional array with the form fields being used.
*/
protected function submitPersonalContact($account, array $message = array()) {
$message += array(
'subject' => $this->randomName(16),
'message' => $this->randomName(64),
);
$this->drupalPost('user/' . $account->uid . '/contact', $message, t('Send message'));
}
}