security upadtes
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
|
||||
This directory should be used to place downloaded and custom modules
|
||||
which are common to all sites. This will allow you to more easily
|
||||
update Drupal core files.
|
@@ -1,3 +1,20 @@
|
||||
References 7.x-2.x
|
||||
==================
|
||||
|
||||
#1391814 by yched: Fixed encoded HTML entities in select widget (regression
|
||||
introduced in 2.0)
|
||||
#1354580 by bforchhammer, yched: Fixed unpublished referenced nodes not
|
||||
displayed to users that are allowed to see them (regression introduced in 2.0)
|
||||
#1345816 by bforchhammer: Added support for the 'view_unpublished' module.
|
||||
#1256280 by girishmuraly: Added query alterability in hook_field_prepare_view().
|
||||
#1183300 by scor: Fixed extraneaous #maxlength in node_reference_autocomplete
|
||||
widget.
|
||||
#1410300 by yched: Fixed hook_field_install() should live in .install files.
|
||||
#1409022 by yched: Fixed missing view name notification message in D6 migration.
|
||||
#1391814 followup by yched: Fixed raw HTML in Views exposed filters.
|
||||
#998848 followup by larowlan, stevector, yched: template suggestions for
|
||||
referenced node in a specific view mode are wrong.
|
||||
|
||||
References 7.x-2.0
|
||||
==================
|
||||
|
||||
@@ -72,7 +89,7 @@ settings" will lose the currently selected view if it doesn't have a
|
||||
References 7.x-2.0-beta3
|
||||
========================
|
||||
|
||||
This release primarily aims at facilitating synchronized releases of 3rd party
|
||||
This release primarily aims at facilitating synchronized releases of 3rd party
|
||||
modules making use of the node_reference_potential_references() function.
|
||||
|
||||
#1154998 by yched: Rename _node_reference_potential_references() to
|
||||
|
@@ -7,9 +7,9 @@ dependencies[] = references
|
||||
dependencies[] = options
|
||||
files[] = node_reference.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2011-12-22
|
||||
version = "7.x-2.0"
|
||||
; Information added by Drupal.org packaging script on 2017-04-18
|
||||
version = "7.x-2.2"
|
||||
core = "7.x"
|
||||
project = "references"
|
||||
datestamp = "1324596643"
|
||||
datestamp = "1492534745"
|
||||
|
||||
|
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the node_reference module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema().
|
||||
*/
|
||||
function node_reference_field_schema($field) {
|
||||
$columns = array(
|
||||
'nid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
);
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
'indexes' => array('nid' => array('nid')),
|
||||
'foreign keys' => array(
|
||||
'nid' => array(
|
||||
'table' => 'node',
|
||||
'columns' => array('nid' => 'nid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild views data cache (a callabck was renamed).
|
||||
*/
|
||||
function node_reference_update_7000() {
|
||||
if (function_exists('views_invalidate_cache')) {
|
||||
views_invalidate_cache();
|
||||
}
|
||||
}
|
@@ -47,29 +47,6 @@ function node_reference_field_info() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema().
|
||||
*/
|
||||
function node_reference_field_schema($field) {
|
||||
$columns = array(
|
||||
'nid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
);
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
'indexes' => array('nid' => array('nid')),
|
||||
'foreign keys' => array(
|
||||
'nid' => array(
|
||||
'table' => 'node',
|
||||
'columns' => array('nid' => 'nid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_settings_form().
|
||||
*/
|
||||
@@ -220,8 +197,8 @@ function node_reference_field_validate($entity_type, $entity, $field, $instance,
|
||||
function node_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
|
||||
$checked_ids = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
// Set an 'access' property on each item (TRUE if the node exists and is
|
||||
// accessible by the current user.
|
||||
// Set an 'access' property on each item (TRUE if the node exists and is
|
||||
// accessible by the current user).
|
||||
|
||||
// Extract ids to check.
|
||||
$ids = array();
|
||||
@@ -243,22 +220,35 @@ function node_reference_field_prepare_view($entity_type, $entities, $field, $ins
|
||||
$ids_to_check = array_diff($ids, array_keys($checked_ids));
|
||||
if (!empty($ids_to_check)) {
|
||||
$query = db_select('node', 'n')
|
||||
->addTag('node_access')
|
||||
->addMetaData('id', 'node_reference_field_prepare_view')
|
||||
->addMetaData('field', $field)
|
||||
->fields('n', array('nid'))
|
||||
->addTag('node_access');
|
||||
$condition = db_and()
|
||||
->condition('n.nid', $ids_to_check, 'IN')
|
||||
->condition('n.status', NODE_PUBLISHED);
|
||||
// Take the 'view own unpublished content' permission into account to
|
||||
// decide whether unpublished nodes should be hidden.
|
||||
if (!user_access('administer nodes') && !user_access('bypass node access')) {
|
||||
if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
|
||||
// (n.nid IN (nodes) AND n.status = 1) OR n.nid = (unpublished)
|
||||
$condition = db_or()
|
||||
->condition($condition)
|
||||
// WHERE n.nid IN (nids to check) AND ...
|
||||
->condition('n.nid', $ids_to_check, 'IN');
|
||||
|
||||
// Unless the user has the right permissions, restrict on the node status.
|
||||
// (note: the 'view any unpublished content' permission is provided by the
|
||||
// 'view_unpublished' contrib module.)
|
||||
if (!user_access('bypass node access') && !user_access('view any unpublished content')) {
|
||||
// ... AND n.status = 1
|
||||
$status_condition = db_or()
|
||||
->condition('n.status', NODE_PUBLISHED);
|
||||
|
||||
// Take the 'view own unpublished content' permission into account to
|
||||
// decide whether some unpublished nodes should still be visible. We
|
||||
// only need the items in $ids_to_check because those are the only
|
||||
// entries that we are interested in. Any other nodes created by the
|
||||
// user are simply ignored so lets only retrieve that subset.
|
||||
if (user_access('view own unpublished content') && ($own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status AND nid IN (:nodes)', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED, ':nodes' => $ids_to_check))->fetchCol())) {
|
||||
// ... AND (n.status = 1 OR n.nid IN (own unpublished))
|
||||
$status_condition
|
||||
->condition('n.nid', $own_unpublished, 'IN');
|
||||
}
|
||||
|
||||
$query->condition($status_condition);
|
||||
}
|
||||
$query->condition($condition);
|
||||
|
||||
$accessible_ids = $query->execute()->fetchAllAssoc('nid');
|
||||
|
||||
// Populate our static list so that we do not query on those ids again.
|
||||
@@ -599,6 +589,7 @@ function node_reference_field_widget_settings_form($field, $instance) {
|
||||
'#options' => array(
|
||||
'starts_with' => t('Starts with'),
|
||||
'contains' => t('Contains'),
|
||||
'fuzzy' => t('Fuzzy search'),
|
||||
),
|
||||
'#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
|
||||
);
|
||||
@@ -624,6 +615,7 @@ function node_reference_field_widget_form(&$form, &$form_state, $field, $instanc
|
||||
'#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
|
||||
'#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
|
||||
'#size' => $instance['widget']['settings']['size'],
|
||||
'#maxlength' => NULL,
|
||||
'#element_validate' => array('node_reference_autocomplete_validate'),
|
||||
'#value_callback' => 'node_reference_autocomplete_value',
|
||||
);
|
||||
@@ -675,14 +667,14 @@ function node_reference_autocomplete_validate($element, &$form_state, $form) {
|
||||
// Explicit nid. Check that the 'title' part matches the actual title for
|
||||
// the nid.
|
||||
list(, $title, $nid) = $matches;
|
||||
if (!empty($title)) {
|
||||
if (!empty($nid)) {
|
||||
$real_title = db_select('node', 'n')
|
||||
->fields('n', array('title'))
|
||||
->condition('n.nid', $nid)
|
||||
->execute()
|
||||
->fetchField();
|
||||
if (trim($title) != trim($real_title)) {
|
||||
form_error($element, t('%name: title mismatch. Please check your selection.', array('%name' => $instance['label'])));
|
||||
if (empty($real_title)) {
|
||||
form_error($element, t('%name: No node found. Please check your selection.', array('%name' => $instance['label'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -741,14 +733,18 @@ function _node_reference_options($field, $flat = TRUE) {
|
||||
|
||||
$options = array();
|
||||
foreach ($references as $key => $value) {
|
||||
// The label, displayed in selects and checkboxes/radios, should have HTML
|
||||
// entities unencoded. The widgets (core's options.module) take care of
|
||||
// applying the relevant filters (strip_tags() or filter_xss()).
|
||||
$label = html_entity_decode($value['rendered'], ENT_QUOTES);
|
||||
if (empty($value['group']) || $flat) {
|
||||
$options[$key] = $value['rendered'];
|
||||
$options[$key] = $label;
|
||||
}
|
||||
else {
|
||||
// The group name, displayed in selects, cannot contain tags, and should
|
||||
// have HTML entities unencoded.
|
||||
$group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
|
||||
$options[$group][$key] = $value['rendered'];
|
||||
$options[$group][$key] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,11 +838,29 @@ function _node_reference_potential_references_standard($field, $options) {
|
||||
}
|
||||
|
||||
$query = db_select('node', 'n');
|
||||
|
||||
if (!user_access('bypass node access')) {
|
||||
// If the user is able to view their own unpublished nodes, allow them to
|
||||
// see these in addition to published nodes. Check that they actually have
|
||||
// some unpublished nodes to view before adding the condition.
|
||||
if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
|
||||
$query->condition(db_or()
|
||||
->condition('n.status', NODE_PUBLISHED)
|
||||
->condition('n.nid', $own_unpublished, 'IN')
|
||||
);
|
||||
}
|
||||
else {
|
||||
// If not, restrict the query to published nodes.
|
||||
$query->condition('n.status', NODE_PUBLISHED);
|
||||
}
|
||||
|
||||
$query->addTag('node_access');
|
||||
}
|
||||
|
||||
$node_nid_alias = $query->addField('n', 'nid');
|
||||
$node_title_alias = $query->addField('n', 'title', 'node_title');
|
||||
$node_type_alias = $query->addField('n', 'type', 'node_type');
|
||||
$query->addTag('node_access')
|
||||
->addMetaData('id', ' _node_reference_potential_references_standard')
|
||||
$query->addMetaData('id', ' _node_reference_potential_references_standard')
|
||||
->addMetaData('field', $field)
|
||||
->addMetaData('options', $options);
|
||||
|
||||
@@ -864,6 +878,13 @@ function _node_reference_potential_references_standard($field, $options) {
|
||||
$query->condition('n.title', $options['string'] . '%', 'LIKE');
|
||||
break;
|
||||
|
||||
case 'fuzzy':
|
||||
$words = explode(' ', $options['string']);
|
||||
foreach ($words as $word) {
|
||||
$query->condition('n.title', '%' . $word . '%', 'LIKE');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'equals':
|
||||
default: // no match type or incorrect match type: use "="
|
||||
$query->condition('n.title', $options['string']);
|
||||
@@ -898,8 +919,8 @@ function _node_reference_potential_references_standard($field, $options) {
|
||||
* Menu callback for the autocomplete results.
|
||||
*/
|
||||
function node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
|
||||
$field = field_info_field($field_name);
|
||||
$instance = field_info_instance($entity_type, $field_name, $bundle);
|
||||
$field = field_info_field($field_name);
|
||||
|
||||
$options = array(
|
||||
'string' => $string,
|
||||
@@ -953,11 +974,11 @@ function node_reference_preprocess_node(&$vars) {
|
||||
// in a specific view mode).
|
||||
if (!empty($vars['node']->referencing_field)) {
|
||||
$node = $vars['node'];
|
||||
$field = $node->referencing_field;
|
||||
$vars['theme_hook_suggestions'][] = 'node_reference';
|
||||
$vars['theme_hook_suggestions'][] = 'node_reference__' . $field['field_name'];
|
||||
$vars['theme_hook_suggestions'][] = 'node_reference__' . $node->type;
|
||||
$vars['theme_hook_suggestions'][] = 'node_reference__' . $field['field_name'] . '__' . $node->type;
|
||||
$field_name = $node->referencing_field;
|
||||
$vars['theme_hook_suggestions'][] = 'node__node_reference';
|
||||
$vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name;
|
||||
$vars['theme_hook_suggestions'][] = 'node__node_reference__' . $node->type;
|
||||
$vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name . '__' . $node->type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,33 +987,42 @@ function node_reference_preprocess_node(&$vars) {
|
||||
*
|
||||
* When preparing a translation, load any translations of existing
|
||||
* references.
|
||||
* @todo Correctly implement after http://drupal.org/node/362021 is fixed.
|
||||
*/
|
||||
function node_reference_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
$addition = array();
|
||||
$addition[$field['field_name']] = array();
|
||||
if (isset($entity->translation_source->$field['field_name'])
|
||||
&& is_array($entity->translation_source->$field['field_name'])) {
|
||||
foreach ($entity->translation_source->$field['field_name'] as $key => $reference) {
|
||||
$reference_node = node_load($reference['nid']);
|
||||
// Test if the referenced node type is translatable and, if so,
|
||||
// load translations if the reference is not for the current language.
|
||||
// We can assume the translation module is present because it invokes 'prepare translation'.
|
||||
if (translation_supported_type($reference_node->type)
|
||||
&& !empty($reference_node->language)
|
||||
&& $reference_node->language != $node->language
|
||||
&& $translations = translation_node_get_translations($reference_node->tnid)) {
|
||||
// If there is a translation for the current language, use it.
|
||||
$addition[$field['field_name']][] = array(
|
||||
'nid' => isset($translations[$node->language])
|
||||
? $translations[$node->language]->nid
|
||||
: $reference['nid'],
|
||||
);
|
||||
function node_reference_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
|
||||
if (isset($items) && is_array($items)) {
|
||||
// Match each reference with its matching translation, if it exists.
|
||||
foreach ($items as $key => $item) {
|
||||
$reference_node = node_load($item['nid']);
|
||||
$items[$key]['nid'] = node_reference_find_translation($reference_node, $entity->language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a translation for a specific node reference, if it exists.
|
||||
*
|
||||
* @param $reference_node
|
||||
* The untranslated node reference.
|
||||
* @param $langcode
|
||||
*
|
||||
* @return
|
||||
* A nid for the translation of the node reference,
|
||||
* otherwise the original untranslated nid if no translation exists.
|
||||
*/
|
||||
function node_reference_find_translation($reference_node, $langcode) {
|
||||
// Check if the source node translation is set and if translations are supported.
|
||||
if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
|
||||
// Determine whether an alternative language is being used.
|
||||
if (!empty($reference_node->language) && $reference_node->language != $langcode) {
|
||||
// Return a corresponding translation nid for the reference (if it exists).
|
||||
$translations = translation_node_get_translations($reference_node->tnid);
|
||||
if (isset($translations[$langcode])) {
|
||||
return $translations[$langcode]->nid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $addition;
|
||||
// Return the untranslated reference nid, no matching translations found.
|
||||
return $reference_node->nid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1028,7 +1058,7 @@ function node_reference_content_migrate_field_alter(&$field_value, $instance_val
|
||||
'args' => $view_args,
|
||||
);
|
||||
if ($view_name) {
|
||||
$field_value['messages'][] = t("The field uses the view @view_name to determine referenceable nodes. You will need to manually edit the view and add a display of type 'References'.");
|
||||
$field_value['messages'][] = t("The field uses the view @view_name to determine referenceable nodes. You will need to manually edit the view and add a display of type 'References'.", array('@view_name' => $view_name));
|
||||
}
|
||||
unset($field_value['settings']['advanced_view']);
|
||||
unset($field_value['settings']['advanced_view_args']);
|
||||
@@ -1105,7 +1135,7 @@ function node_reference_field_views_data($field) {
|
||||
// the field name instead of the whole $field structure to keep views
|
||||
// data to a reasonable size.
|
||||
$data[$table][$id_column]['filter']['handler'] = 'views_handler_filter_in_operator';
|
||||
$data[$table][$id_column]['filter']['options callback'] = 'node_reference_views_options';
|
||||
$data[$table][$id_column]['filter']['options callback'] = 'node_reference_views_filter_options';
|
||||
$data[$table][$id_column]['filter']['options arguments'] = array($field['field_name']);
|
||||
|
||||
// Argument: display node.title in argument titles (handled in our custom
|
||||
@@ -1174,20 +1204,24 @@ function node_reference_field_views_data_views_data_alter(&$data, $field) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper callback for the views_handler_filter_in_operator filter.
|
||||
* 'options callback' for the views_handler_filter_in_operator filter.
|
||||
*
|
||||
* @param $field_name
|
||||
* The field name.
|
||||
*/
|
||||
function node_reference_views_options($field_name) {
|
||||
function node_reference_views_filter_options($field_name) {
|
||||
$options = array();
|
||||
|
||||
if ($field = field_info_field($field_name)) {
|
||||
$options = _node_reference_options($field, TRUE);
|
||||
// The options will be used as is in checkboxes, and thus need to be
|
||||
// sanitized first.
|
||||
|
||||
// The options are displayed in checkboxes within the filter admin form, and
|
||||
// in a select within an exposed filter. Checkboxes accept HTML, other
|
||||
// entities should be encoded; selects require the exact opposite: no HTML,
|
||||
// no encoding. We go for a middle ground: strip tags, leave entities
|
||||
// unencoded.
|
||||
foreach ($options as $key => $value) {
|
||||
$options[$key] = field_filter_xss($value);
|
||||
$options[$key] = strip_tags($value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -97,4 +97,59 @@ class NodeReferenceFormTest extends FieldTestCase {
|
||||
$allowed = array_slice(node_type_get_names(), 0, 1, TRUE);
|
||||
$this->runReferenceableNodeTest($allowed, t('Limited referencing'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test autocomplete widget.
|
||||
*/
|
||||
function testLongNodeReferenceWidget() {
|
||||
// Create regular test user.
|
||||
$web_user = $this->drupalCreateUser(array('create article content', 'access content'));
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Create test field instance on article node type.
|
||||
$instance = array(
|
||||
'field_name' => $this->field_name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'article',
|
||||
'widget' => array(
|
||||
'type' => 'node_reference_autocomplete',
|
||||
),
|
||||
);
|
||||
$instance = field_create_instance($instance);
|
||||
|
||||
// Create a node with a short title and a node with a title longer than
|
||||
// 128 characters.
|
||||
$node_short_title = $this->drupalCreateNode(array(
|
||||
'type' => 'page',
|
||||
'title' => $this->randomName(8),
|
||||
));
|
||||
$node_long_title = $this->drupalCreateNode(array(
|
||||
'type' => 'page',
|
||||
'title' => $this->randomName(200),
|
||||
));
|
||||
|
||||
// Display node creation form.
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertFieldByName("{$this->field_name}[$langcode][0][nid]", '', t('Widget is displayed'));
|
||||
|
||||
// Submit node form with autocomplete value for short title.
|
||||
$edit = array(
|
||||
'title' => $this->randomName(8),
|
||||
"{$this->field_name}[$langcode][0][nid]" => $node_short_title->title . ' [nid:' . $node_short_title->nid . ']',
|
||||
);
|
||||
$this->drupalPost('node/add/article', $edit, t('Save'));
|
||||
$this->assertRaw(t('!post %title has been created.', array('!post' => 'Article', '%title' => $edit["title"])), t('Article created.'));
|
||||
$this->assertText($node_short_title->title, t('Referenced node title is displayed.'));
|
||||
|
||||
// Submit node form with autocomplete value for long title.
|
||||
$edit = array(
|
||||
'title' => $this->randomName(8),
|
||||
"{$this->field_name}[$langcode][0][nid]" => $node_long_title->title . ' [nid:' . $node_long_title->nid . ']',
|
||||
);
|
||||
$this->drupalPost('node/add/article', $edit, t('Save'));
|
||||
$this->assertRaw(t('!post %title has been created.', array('!post' => 'Article', '%title' => $edit["title"])), t('Article created.'));
|
||||
$this->assertText($node_long_title->title, t('Referenced node title is displayed.'));
|
||||
}
|
||||
}
|
||||
|
@@ -189,7 +189,7 @@ function user_reference_feeds_processor_targets_alter(&$targets, $entity_type, $
|
||||
* The value to map. Can be an array or a string.
|
||||
*/
|
||||
function references_feeds_set_target($source, $entity, $target, $value) {
|
||||
if (empty($value)) {
|
||||
if (empty($value) || empty($value[key($value)])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -10,9 +10,9 @@ files[] = views/references_plugin_display.inc
|
||||
files[] = views/references_plugin_style.inc
|
||||
files[] = views/references_plugin_row_fields.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2011-12-22
|
||||
version = "7.x-2.0"
|
||||
; Information added by Drupal.org packaging script on 2017-04-18
|
||||
version = "7.x-2.2"
|
||||
core = "7.x"
|
||||
project = "references"
|
||||
datestamp = "1324596643"
|
||||
datestamp = "1492534745"
|
||||
|
||||
|
@@ -13,8 +13,8 @@
|
||||
*/
|
||||
function reference_autocomplete_access($entity_type, $bundle, $field_name, $entity = NULL, $account = NULL) {
|
||||
return user_access('access content', $account)
|
||||
&& ($field = field_info_field($field_name))
|
||||
&& field_info_instance($entity_type, $field_name, $bundle)
|
||||
&& ($field = field_info_field($field_name))
|
||||
&& field_access('view', $field, $entity_type, $entity, $account)
|
||||
&& field_access('edit', $field, $entity_type, $entity, $account);
|
||||
}
|
||||
|
@@ -0,0 +1,12 @@
|
||||
name = References UUID
|
||||
core = 7.x
|
||||
package = Fields
|
||||
dependencies[] = references
|
||||
dependencies[] = uuid
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-04-18
|
||||
version = "7.x-2.2"
|
||||
core = "7.x"
|
||||
project = "references"
|
||||
datestamp = "1492534745"
|
||||
|
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* This provides UUID support for node and user references
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_uuid_load().
|
||||
*/
|
||||
function node_reference_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
entity_property_id_to_uuid($items, 'node', 'nid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_uuid_presave().
|
||||
*/
|
||||
function node_reference_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
entity_property_uuid_to_id($items, 'node', 'nid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_uuid_load().
|
||||
*/
|
||||
function user_reference_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
entity_property_id_to_uuid($items, 'user', 'uid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_uuid_presave().
|
||||
*/
|
||||
function user_reference_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
entity_property_uuid_to_id($items, 'user', 'uid');
|
||||
}
|
@@ -6,9 +6,9 @@ dependencies[] = field
|
||||
dependencies[] = references
|
||||
dependencies[] = options
|
||||
|
||||
; Information added by drupal.org packaging script on 2011-12-22
|
||||
version = "7.x-2.0"
|
||||
; Information added by Drupal.org packaging script on 2017-04-18
|
||||
version = "7.x-2.2"
|
||||
core = "7.x"
|
||||
project = "references"
|
||||
datestamp = "1324596643"
|
||||
datestamp = "1492534745"
|
||||
|
||||
|
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the user_reference module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema();
|
||||
*/
|
||||
function user_reference_field_schema($field) {
|
||||
$columns = array(
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
);
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
'indexes' => array('uid' => array('uid')),
|
||||
'foreign keys' => array(
|
||||
'uid' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@@ -46,29 +46,6 @@ function user_reference_field_info() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema();
|
||||
*/
|
||||
function user_reference_field_schema($field) {
|
||||
$columns = array(
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
);
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
'indexes' => array('uid' => array('uid')),
|
||||
'foreign keys' => array(
|
||||
'uid' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_settings_form().
|
||||
*/
|
||||
@@ -250,6 +227,8 @@ function user_reference_field_prepare_view($entity_type, $entities, $field, $ins
|
||||
$ids_to_check = array_diff($ids, array_keys($checked_ids));
|
||||
if (!empty($ids_to_check)) {
|
||||
$query = db_select('users', 'u')
|
||||
->addMetaData('id', 'user_reference_field_prepare_view')
|
||||
->addMetaData('field', $field)
|
||||
->fields('u', array('uid'))
|
||||
->condition('u.uid', $ids_to_check, 'IN');
|
||||
$accessible_ids = $query->execute()->fetchAllAssoc('uid');
|
||||
@@ -415,7 +394,7 @@ function user_reference_field_formatter_prepare_view($entity_type, $entities, $f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -766,14 +745,18 @@ function _user_reference_options($field, $flat = TRUE) {
|
||||
|
||||
$options = array();
|
||||
foreach ($references as $key => $value) {
|
||||
// The label, displayed in selects and checkboxes/radios, should have HTML
|
||||
// entities unencoded. The widgets (core's options.module) take care of
|
||||
// applying the relevant filters (strip_tags() or filter_xss()).
|
||||
$label = html_entity_decode($value['rendered'], ENT_QUOTES);
|
||||
if (empty($value['group']) || $flat) {
|
||||
$options[$key] = $value['rendered'];
|
||||
$options[$key] = $label;
|
||||
}
|
||||
else {
|
||||
// The group name, displayed in selects, cannot contain tags, and should
|
||||
// have HTML entities unencoded.
|
||||
$group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
|
||||
$options[$group][$key] = $value['rendered'];
|
||||
$options[$group][$key] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,8 +912,8 @@ function _user_reference_potential_references_standard($field, $options) {
|
||||
* Menu callback; Retrieve a pipe delimited string of autocomplete suggestions for existing users
|
||||
*/
|
||||
function user_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
|
||||
$field = field_info_field($field_name);
|
||||
$instance = field_info_instance($entity_type, $field_name, $bundle);
|
||||
$field = field_info_field($field_name);
|
||||
|
||||
$options = array(
|
||||
'string' => $string,
|
||||
@@ -1062,7 +1045,7 @@ function user_reference_content_migrate_field_alter(&$field_value, $instance_val
|
||||
'args' => $view_args,
|
||||
);
|
||||
if ($view_name) {
|
||||
$field_value['messages'][] = t("The field uses the view @view_name to determine referenceable users. You will need to manually edit the view and add a display of type 'References'.");
|
||||
$field_value['messages'][] = t("The field uses the view @view_name to determine referenceable users. You will need to manually edit the view and add a display of type 'References'.", array('@view_name' => $view_name));
|
||||
}
|
||||
unset($field_value['settings']['advanced_view']);
|
||||
unset($field_value['settings']['advanced_view_args']);
|
||||
@@ -1197,7 +1180,7 @@ function user_reference_field_views_data_views_data_alter(&$data, $field) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper callback for the views_handler_filter_in_operator filter.
|
||||
* 'options callback' for the views_handler_filter_in_operator filter.
|
||||
*
|
||||
* @param $field_name
|
||||
* The field name.
|
||||
@@ -1210,10 +1193,14 @@ function user_reference_views_filter_options($field_name) {
|
||||
|
||||
if ($field = field_info_field($field_name)) {
|
||||
$options = _user_reference_options($field, TRUE);
|
||||
// The options will be used as is in checkboxes, and thus need to be
|
||||
// sanitized first.
|
||||
|
||||
// The options are displayed in checkboxes within the filter admin form, and
|
||||
// in a select within an exposed filter. Checkboxes accept HTML, other
|
||||
// entities should be encoded; selects require the exact opposite: no HTML,
|
||||
// no encoding. We go for a middle ground: strip tags, leave entities
|
||||
// unencoded.
|
||||
foreach ($options as $key => $value) {
|
||||
$options[$key] = field_filter_xss($value);
|
||||
$options[$key] = strip_tags($value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,60 +0,0 @@
|
||||
|
||||
|
||||
2009-11-12 Franz G Vanderlinde franz@chuva-inc.com
|
||||
* bug report #132903 by johngriffin: definitive integration between Mimemail and SMTP
|
||||
* feature request #132903 by mishhh,franz: Mimemail integration
|
||||
* bug report #465750 from bbirtle,franz: Better parsing and handling of charsets
|
||||
* bug report #207925 by Wim Leers,franz: Adds reply-to in case there are none.
|
||||
* file sv.po was initially added on branch DRUPAL-6--1.
|
||||
* file fr.po was initially added on branch DRUPAL-6--1.
|
||||
|
||||
2008-09-23 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Added the final touch: a workaround for a multipart/mixed
|
||||
logic error in PHPMailer.
|
||||
* po/smtp.pot: Moved to translations/.
|
||||
* class.phpmailer.php.2.0.2.patch, class.phpmailer.php.2.2.1.patch: Added
|
||||
to apply a work around to a logic error in PHPMailer, which is reported
|
||||
here:
|
||||
http://sourceforge.net/tracker/index.php?func=detail&aid=2125119&group_id=26031&atid=385707
|
||||
|
||||
2008-09-18 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: After many hours of research, code refactoring and testing,
|
||||
this module is hopefully MIME 1.0 compliant.
|
||||
|
||||
2008-08-26 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Changed admin/reports/watchdog to admin/reports/dblog, per
|
||||
greggles in IRC.
|
||||
|
||||
2008-07-17 Jason Flatt drupal@oadaeh.net
|
||||
* po: Changed to translations (http://drupal.org/node/262455).
|
||||
translations/de.po: Added (http://drupal.org/node/262455).
|
||||
Added e-mail address validation check for the settings page.
|
||||
Added additional from e-mail address validation checking during the
|
||||
processing of the e-mail message (http://drupal.org/node/281599).
|
||||
|
||||
2008-07-12 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Uncommented two functions that set the from name and e-mail
|
||||
address, per jcwatson11 in http://drupal.org/node/281599.
|
||||
Changed the way two wathcdog message were formatted.
|
||||
po/smtp.pot: Added.
|
||||
|
||||
2008-07-11 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Changed the encryption protocol variable name from
|
||||
$mail->Protocol to $mail->SMTPSecure, per root_of_roots in
|
||||
http://drupal.org/node/280081.
|
||||
Added an administrative option for enabling debugging, per dennys in
|
||||
http://drupal.org/node/199843.
|
||||
Made the "On" and "Off" radio options translatable, per
|
||||
rastatt@drupal.org in http://drupal.org/node/262455#comment-917055.
|
||||
|
||||
2008-07-06 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Continued upgrade process to Drupal 6.x compatibility.
|
||||
Tweaked the inline comments and documentation.
|
||||
Removed _smtp_initialize_language().
|
||||
|
||||
2008-07-04 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Continued upgrade process to Drupal 6.x compatibility.
|
||||
Added $mail->ContentType = 'multipart/mixed';
|
||||
|
||||
2008-07-03 Jason Flatt drupal@oadaeh.net
|
||||
* smtp.module: Began the upgrade process to Drupal 6.x compatibility.
|
@@ -1,4 +1,3 @@
|
||||
|
||||
SMTP Authentication Support module for Drupal 7.x.
|
||||
This module adds SMTP functionality to Drupal.
|
||||
|
||||
@@ -16,10 +15,10 @@ INSTALLATION INSTRUCTIONS
|
||||
1. Copy the files included in the tarball into a directory named "smtp" in
|
||||
your Drupal sites/all/modules/ directory.
|
||||
2. Login as site administrator.
|
||||
3. Enable the SMTP Authentication Support module on the Administer -> Site
|
||||
building -> Modules page.
|
||||
4. Fill in required settings on the Administer -> Site configuration -> SMTP
|
||||
Authentication Support page.
|
||||
3. Enable the SMTP Authentication Support module on the Administer -> Modules
|
||||
page.
|
||||
4. Fill in required settings on the Administer -> Configuration -> System ->
|
||||
SMTP Authentication Support page.
|
||||
5. Enjoy.
|
||||
|
||||
NOTES
|
||||
@@ -27,10 +26,10 @@ NOTES
|
||||
This module sends email by connecting to an SMTP server. Therefore, you need
|
||||
to have access to an SMTP server for this module to work.
|
||||
|
||||
Drupal will often use the email address entered into Administrator -> Site
|
||||
configuration -> E-mail address as the from address. It is important for
|
||||
this to be the correct address and some ISPs will block email that comes from
|
||||
an invalid address.
|
||||
Drupal will often use the email address entered into Administrator ->
|
||||
Configuration -> Site information -> E-mail address as the from address. It is
|
||||
important for this to be the correct address and some ISPs will block email that
|
||||
comes from an invalid address.
|
||||
|
||||
This module no longer uses the PHPMailer package as an external library, instead
|
||||
a slimmed down version of the library have been relicensed and integrated with the
|
||||
@@ -41,3 +40,6 @@ extension is working. If the SMTP module detects openssl is available it
|
||||
will display the options in the modules settings page.
|
||||
|
||||
Sending mail to Gmail requires SSL or TLS.
|
||||
|
||||
If the Maillog module (https://www.drupal.org/project/maillog) is installed, it
|
||||
can be used to keep copies of all messages sent through the site.
|
||||
|
@@ -1,40 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Administrative page code for the smtp module.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Administrative settings.
|
||||
*
|
||||
* @return
|
||||
* An array containing form items to place on the module settings page.
|
||||
*/
|
||||
function smtp_admin_settings() {
|
||||
// Override the smtp_library variable.
|
||||
if (module_exists('mimemail') &&
|
||||
strpos(variable_get('smtp_library', ''), 'mimemail')) {
|
||||
// don't touch smtp_library
|
||||
if (variable_get('smtp_on', 0)) {
|
||||
drupal_set_message(t('SMTP.module is active.'));
|
||||
}
|
||||
else {
|
||||
if (variable_get('smtp_on', 0)) {
|
||||
$smtp_path = drupal_get_filename('module', 'smtp');
|
||||
if ($smtp_path) {
|
||||
variable_set('smtp_library', $smtp_path);
|
||||
drupal_set_message(t('SMTP.module is active.'));
|
||||
}
|
||||
// If drupal can't find the path to the module, display an error.
|
||||
else {
|
||||
drupal_set_message(t("SMTP.module error: Can't find file."), 'error');
|
||||
}
|
||||
}
|
||||
// If this module is turned off, delete the variable.
|
||||
else {
|
||||
variable_del('smtp_library');
|
||||
drupal_set_message(t('SMTP.module is INACTIVE.'));
|
||||
}
|
||||
drupal_set_message(t('SMTP.module is INACTIVE.'));
|
||||
}
|
||||
|
||||
$logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
|
||||
|
||||
$form['onoff'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Install options'),
|
||||
@@ -42,10 +25,29 @@ function smtp_admin_settings() {
|
||||
$form['onoff']['smtp_on'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Turn this module on or off'),
|
||||
'#default_value' => variable_get('smtp_on', 0),
|
||||
'#default_value' => variable_get('smtp_on', FALSE),
|
||||
'#options' => array(1 => t('On'), 0 => t('Off')),
|
||||
'#description' => t('To uninstall this module you must turn it off here first.'),
|
||||
);
|
||||
$form['onoff']['smtp_deliver'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Turn on delivery of emails'),
|
||||
'#default_value' => variable_get('smtp_deliver', TRUE),
|
||||
'#options' => array(1 => t('On'), 0 => t('Off')),
|
||||
'#description' => t('With this option turned off, email messages will be queued up and processed as normal, but not actually delivered. This option should only be used for testing purposes.'),
|
||||
);
|
||||
$form['onoff']['smtp_queue'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Send mail by queue'),
|
||||
'#default_value' => variable_get('smtp_queue', FALSE),
|
||||
'#description' => t('Mails will be sent by drupal queue api.'),
|
||||
);
|
||||
$form['onoff']['smtp_queue_fail'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Retry sending mail on error.'),
|
||||
'#default_value' => variable_get('smtp_queue_fail', FALSE),
|
||||
'#description' => t('Mails will be added to the queue and sent by drupal queue api.'),
|
||||
);
|
||||
|
||||
$form['server'] = array(
|
||||
'#type' => 'fieldset',
|
||||
@@ -71,6 +73,7 @@ function smtp_admin_settings() {
|
||||
'#default_value' => variable_get('smtp_port', '25'),
|
||||
'#description' => t('The default SMTP port is 25, if that is being blocked try 80. Gmail uses 465. See !url for more information on configuring for use with Gmail.', array('!url' => l(t('this page'), 'http://gmail.google.com/support/bin/answer.py?answer=13287'))),
|
||||
);
|
||||
|
||||
// Only display the option if openssl is installed.
|
||||
if (function_exists('openssl_open')) {
|
||||
$encryption_options = array(
|
||||
@@ -78,7 +81,7 @@ function smtp_admin_settings() {
|
||||
'ssl' => t('Use SSL'),
|
||||
'tls' => t('Use TLS'),
|
||||
);
|
||||
$encryption_description = t('This allows connection to an SMTP server that requires SSL encryption such as Gmail.');
|
||||
$encryption_description = t('This allows connection to a SMTP server that requires SSL encryption such as Gmail.');
|
||||
}
|
||||
// If openssl is not installed, use normal protocol.
|
||||
else {
|
||||
@@ -109,7 +112,10 @@ function smtp_admin_settings() {
|
||||
'#type' => 'password',
|
||||
'#title' => t('Password'),
|
||||
'#default_value' => variable_get('smtp_password', ''),
|
||||
'#description' => t('SMTP password. Leave blank if you don\'t wish to change it.'),
|
||||
'#description' => t('SMTP password. If you have already entered your password before, you should leave this field blank, unless you want to change the stored password.'),
|
||||
'#attributes' => array(
|
||||
'autocomplete' => 'off',
|
||||
),
|
||||
);
|
||||
|
||||
$form['email_options'] = array(
|
||||
@@ -130,22 +136,28 @@ function smtp_admin_settings() {
|
||||
);
|
||||
$form['email_options']['smtp_allowhtml'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow to send e-mails formated as Html'),
|
||||
'#title' => t('Allow to send e-mails formatted as Html'),
|
||||
'#default_value' => variable_get('smtp_allowhtml', 0),
|
||||
'#description' => t('Cheking this box will allow Html formated e-mails to be sent with the SMTP protocol.'),
|
||||
'#description' => t('Checking this box will allow Html formatted e-mails to be sent with the SMTP protocol.'),
|
||||
);
|
||||
|
||||
$form['client'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('SMTP client settings'),
|
||||
);
|
||||
$form['client']['smtp_client_hostname'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Hostname'),
|
||||
'#default_value' => variable_get('smtp_client_hostname', ''),
|
||||
'#description' => t('The hostname to use in the Message-Id and Received headers, and as the default HELO string. Leave blank for using %server_name.', array('%server_name' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain')),
|
||||
);
|
||||
$form['client']['smtp_client_helo'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('HELO'),
|
||||
'#default_value' => variable_get('smtp_client_helo', ''),
|
||||
'#description' => t('The SMTP HELO/EHLO of the message. Defaults to hostname (see above).'),
|
||||
);
|
||||
|
||||
// If an address was given, send a test e-mail message.
|
||||
$test_address = variable_get('smtp_test_address', '');
|
||||
if ($test_address != '') {
|
||||
// Clear the variable so only one message is sent.
|
||||
variable_del('smtp_test_address');
|
||||
global $language;
|
||||
$params['subject'] = t('Drupal SMTP test e-mail');
|
||||
$params['body'] = array(t('If you receive this message it means your site is capable of using SMTP to send e-mail.'));
|
||||
drupal_mail('smtp', 'smtp-test', $test_address, $language, $params);
|
||||
drupal_set_message(t('A test e-mail has been sent to @email. You may want to !check for any error messages.', array('@email' => $test_address, '!check' => l(t('check the logs'), 'admin/reports/dblog'))));
|
||||
}
|
||||
$form['email_test'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Send test e-mail'),
|
||||
@@ -157,47 +169,132 @@ function smtp_admin_settings() {
|
||||
'#description' => t('Type in an address to have a test e-mail sent there.'),
|
||||
);
|
||||
|
||||
$form['smtp_debugging'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable debugging'),
|
||||
'#default_value' => variable_get('smtp_debugging', 0),
|
||||
'#description' => t('Checking this box will print SMTP messages from the server for every e-mail that is sent.'),
|
||||
$form['debugging'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Debugging and logging'),
|
||||
);
|
||||
|
||||
return system_settings_form($form);
|
||||
} // End of smtp_admin_settings().
|
||||
$logging_options = array(
|
||||
SMTP_LOGGING_ALL => t('Log everything'),
|
||||
SMTP_LOGGING_ERRORS => t('Errors only'),
|
||||
SMTP_LOGGING_NONE => t('No logging'),
|
||||
);
|
||||
$form['debugging']['smtp_debugging'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Logging'),
|
||||
'#options' => $logging_options,
|
||||
'#default_value' => $logging,
|
||||
'#description' => t('Choose the appropriate log level. "Log everything" will log errors and informational messages when an email is sent. "Errors only" will only create a log entry when sending failed. "No logging" will disable all logging for this module.'),
|
||||
);
|
||||
$form['email_test']['smtp_reroute_address'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('E-mail address to reroute all emails to'),
|
||||
'#default_value' => variable_get('smtp_reroute_address', ''),
|
||||
'#description' => t('All emails sent by the site will be rerouted to this email address; use with caution.'),
|
||||
);
|
||||
|
||||
$form['debugging']['maillog'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Maillog integration'),
|
||||
);
|
||||
|
||||
if (!module_exists('maillog')) {
|
||||
$form['debugging']['maillog']['#description'] = t('Installing the <a href="@url">Maillog module</a> also allows keeping copies of all emails sent through the site.', array('@url' => 'https://www.drupal.org/project/maillog'));
|
||||
}
|
||||
else {
|
||||
$form['debugging']['maillog']['#description'] = t('The <a href="@url">Maillog module</a> is installed, it can also be used to keep copies of all emails sent through the site.', array('@url' => url('admin/config/development/maillog')));
|
||||
|
||||
$form['debugging']['maillog']['maillog_log'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t("Create table entries in maillog table for each e-mail."),
|
||||
'#default_value' => variable_get('maillog_log', TRUE),
|
||||
);
|
||||
|
||||
$form['debugging']['maillog']['maillog_devel'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t("Display the e-mails on page using devel module (if enabled)."),
|
||||
'#default_value' => variable_get('maillog_devel', TRUE),
|
||||
'#disabled' => !module_exists('devel'),
|
||||
);
|
||||
}
|
||||
|
||||
$form['#submit'][] = 'smtp_admin_settings_form_submit';
|
||||
$form = system_settings_form($form);
|
||||
$form['#submit'][] = 'smtp_admin_settings_submit_post_system_settings';
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for the administrative settings form.
|
||||
*
|
||||
* @param form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
*/
|
||||
function smtp_admin_settings_validate($form, &$form_state) {
|
||||
if ($form_state['values']['smtp_on'] == 1 && $form_state['values']['smtp_host'] == '') {
|
||||
form_set_error('smtp_host', t('You must enter an SMTP server address.'));
|
||||
form_set_error('smtp_host', t('You must enter a SMTP server address.'));
|
||||
}
|
||||
|
||||
if ($form_state['values']['smtp_on'] == 1 && $form_state['values']['smtp_port'] == '') {
|
||||
form_set_error('smtp_port', t('You must enter an SMTP port number.'));
|
||||
form_set_error('smtp_port', t('You must enter a SMTP port number.'));
|
||||
}
|
||||
|
||||
if ($form_state['values']['smtp_from'] && !valid_email_address($form_state['values']['smtp_from'])) {
|
||||
form_set_error('smtp_from', t('The provided from e-mail address is not valid.'));
|
||||
}
|
||||
// If username is set empty, we must set both username/password empty as
|
||||
// as well.
|
||||
} // End of smtp_admin_settings_validate().
|
||||
|
||||
/**
|
||||
* Submit handler().
|
||||
*/
|
||||
function smtp_admin_settings_form_submit($form, &$form_state) {
|
||||
// Check if SMTP status has been changed.
|
||||
if (
|
||||
(!variable_get('smtp_on', FALSE) && $form_state['values']['smtp_on']) ||
|
||||
(variable_get('smtp_on', FALSE) && !$form_state['values']['smtp_on'])
|
||||
) {
|
||||
$mail_modes = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
|
||||
|
||||
// Turning on.
|
||||
if ($form_state['values']['smtp_on']) {
|
||||
variable_set('smtp_previous_mail_system', $mail_modes['default-system']);
|
||||
$mail_modes['default-system'] = 'SmtpMailSystem';
|
||||
}
|
||||
// Turning off.
|
||||
else {
|
||||
$mail_modes['default-system'] = variable_get('smtp_previous_mail_system', 'DefaultMailSystem');
|
||||
}
|
||||
|
||||
variable_set('mail_system', $mail_modes);
|
||||
}
|
||||
|
||||
// If username is set empty, we must set both username/password empty as well.
|
||||
if (empty($form_state['values']['smtp_username'])) {
|
||||
$form_state['values']['smtp_password'] = '';
|
||||
}
|
||||
// A little hack. When form is presentend, the password is not shown (Drupal way of doing).
|
||||
// So, if user submits the form without changing the password, we must prevent it from being reset.
|
||||
|
||||
// A little hack. When form is presentend, the password is not shown (Drupal
|
||||
// way of doing). So, if user submits the form without changing the password,
|
||||
// we must prevent it from being reset.
|
||||
elseif (empty($form_state['values']['smtp_password'])) {
|
||||
unset($form_state['values']['smtp_password']);
|
||||
}
|
||||
} // End of smtp_admin_settings_validate().
|
||||
|
||||
// Save the test address to send an email after all the settings have been
|
||||
// updated.
|
||||
$form_state['storage']['smtp']['smtp_test_address'] = $form_state['values']['smtp_test_address'];
|
||||
unset($form_state['values']['smtp_test_address']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the administrative settings form containing all
|
||||
* functionality to be run after system_settings_form_submit.
|
||||
*/
|
||||
function smtp_admin_settings_submit_post_system_settings($form, &$form_state) {
|
||||
// If an address was given, send a test e-mail message.
|
||||
$test_address = $form_state['storage']['smtp']['smtp_test_address'];
|
||||
if ($test_address != '') {
|
||||
$language = language_default();
|
||||
$params['subject'] = t('Drupal SMTP test e-mail');
|
||||
$params['body'] = array(t('If you receive this message it means your site is capable of using SMTP to send e-mail.'));
|
||||
drupal_mail('smtp', 'smtp-test', $test_address, $language, $params);
|
||||
drupal_set_message(t('A test e-mail has been sent to @email. You may want to !check for any error messages.', array('@email' => $test_address, '!check' => l(t('check the logs'), 'admin/reports/dblog'))));
|
||||
}
|
||||
}
|
||||
|
@@ -3,15 +3,19 @@ description = "Allow for site emails to be sent through an SMTP server of your c
|
||||
core = 7.x
|
||||
package = Mail
|
||||
configure = admin/config/system/smtp
|
||||
files[] = smtp.module
|
||||
files[] = smtp.admin.inc
|
||||
files[] = smtp.mail.inc
|
||||
files[] = smtp.phpmailer.inc
|
||||
files[] = smtp.transport.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-09-21
|
||||
version = "7.x-1.0-beta2"
|
||||
; Test suite.
|
||||
files[] = tests/smtp.unit.test
|
||||
|
||||
; For the tests the Maillog module is also required.
|
||||
test_dependencies[] = maillog
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-27
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "smtp"
|
||||
datestamp = "1348254500"
|
||||
datestamp = "1498593247"
|
||||
|
||||
|
@@ -6,20 +6,45 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_install().
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function smtp_requirements($phase) {
|
||||
$requirements = array();
|
||||
|
||||
if ($phase == 'runtime') {
|
||||
if (variable_get('smtp_queue', FALSE) || variable_get('smtp_queue_fail', FALSE)) {
|
||||
$count = db_query("SELECT count('name') FROM {queue} WHERE name='smtp_send_queue'")->fetchField();
|
||||
$requirements['smtp_queue'] = array(
|
||||
'title' => t('SMTP Queue'),
|
||||
'value' => '',
|
||||
'severity' => REQUIREMENT_INFO,
|
||||
);
|
||||
if ($count > 0) {
|
||||
$requirements['smtp_queue']['value'] = format_plural($count, 'There is 1 message queued for delivery.', 'There are @count messages queued for delivery.', array('@count' => $count))
|
||||
. ' '
|
||||
. t('Delivery of the message(s) will be attempted the next time cron runs.');
|
||||
}
|
||||
else {
|
||||
$requirements['smtp_queue']['value'] = t('There are no messages queued for delivery.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function smtp_install() {
|
||||
variable_set('smtp_on', 0);
|
||||
}
|
||||
/**
|
||||
* @file
|
||||
* The uninstallation instructions for the SMTP Authentication Support.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_uninstall().
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function smtp_uninstall() {
|
||||
variable_del('smtp_allowhtml');
|
||||
variable_del('smtp_from');
|
||||
variable_del('smtp_fromname');
|
||||
variable_del('smtp_host');
|
||||
@@ -28,24 +53,79 @@ function smtp_uninstall() {
|
||||
variable_del('smtp_password');
|
||||
variable_del('smtp_port');
|
||||
variable_del('smtp_protocol');
|
||||
variable_del('smtp_test_address');
|
||||
variable_del('smtp_queue');
|
||||
variable_del('smtp_queue_fail');
|
||||
variable_del('smtp_username');
|
||||
|
||||
if (variable_get('smtp_library', '') == drupal_get_path('module', 'smtp') . '/smtp.module') {
|
||||
variable_del('smtp_library');
|
||||
}
|
||||
} // End of contact_attach_uninstall().
|
||||
|
||||
function smtp_enable() {
|
||||
variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
|
||||
variable_del('smtp_debugging');
|
||||
variable_del('smtp_client_hostname');
|
||||
variable_del('smtp_client_helo');
|
||||
variable_del('smtp_deliver');
|
||||
variable_del('smtp_reroute_address');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_disable().
|
||||
*/
|
||||
function smtp_disable() {
|
||||
variable_set('mail_system', array('default-system' => 'DefaultMailSystem'));
|
||||
$mail_modes = variable_get('mail_system');
|
||||
$mail_modes['default-system'] = 'DefaultMailSystem';
|
||||
variable_set('mail_system', $mail_modes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementations of hook_update_N().
|
||||
*/
|
||||
|
||||
/**
|
||||
* Upgrade to Drupal 7.x
|
||||
*/
|
||||
function smtp_update_7000() {
|
||||
if (variable_get('smtp_on', 0) != 0) {
|
||||
variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
|
||||
}
|
||||
// Not used any more in D7.
|
||||
variable_del('smtp_library');
|
||||
}
|
||||
|
||||
/**
|
||||
* Back to default mail system if the status flag is off.
|
||||
*/
|
||||
function smtp_update_7100() {
|
||||
$mail_modes = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
|
||||
if ($mail_modes['default-system'] == 'SmtpMailSystem' && !variable_get('smtp_on', FALSE)) {
|
||||
$mail_modes['default-system'] = 'DefaultMailSystem';
|
||||
variable_set('mail_system', $mail_modes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updating variable value now that new SMTP logging behavior has been
|
||||
* implemented.
|
||||
*/
|
||||
function smtp_update_7101() {
|
||||
$old_debugging_value = variable_get('smtp_debugging', 0);
|
||||
|
||||
$logging = SMTP_LOGGING_NONE;
|
||||
|
||||
if ($old_debugging_value == 1) {
|
||||
$logging = SMTP_LOGGING_ERRORS;
|
||||
}
|
||||
|
||||
variable_set('smtp_debugging', $logging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the unused 'smtp_library' variable.
|
||||
*/
|
||||
function smtp_update_7102() {
|
||||
variable_del('smtp_library');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the variable "smtp_test_address". It is unlikely that this would
|
||||
* actually be set in the normal course of events, and it's no longer needed as
|
||||
* it was replaced with a form submit handler.
|
||||
*/
|
||||
function smtp_update_7103() {
|
||||
variable_del('smtp_test_address');
|
||||
}
|
||||
|
@@ -46,35 +46,84 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
* TRUE if the mail was successfully accepted, otherwise FALSE.
|
||||
*/
|
||||
public function mail(array $message) {
|
||||
$id = $message['id'];
|
||||
$to = $message['to'];
|
||||
$from = $message['from'];
|
||||
$subject = $message['subject'];
|
||||
$body = $message['body'];
|
||||
$headers = $message['headers'];
|
||||
if (variable_get('smtp_queue', FALSE)
|
||||
&& (!isset($message['params']['skip_queue']) || !$message['params']['skip_queue'])) {
|
||||
smtp_send_queue($message);
|
||||
if (variable_get('smtp_debugging', SMTP_LOGGING_ERRORS) == SMTP_LOGGING_ALL) {
|
||||
watchdog('smtp', 'Queue sending mail to: @to', array('@to' => $message['to']));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return $this->mailWithoutQueue($message);
|
||||
}
|
||||
}
|
||||
|
||||
public function mailWithoutQueue(array $message) {
|
||||
$to = $message['to'];
|
||||
$from = $message['from'];
|
||||
$body = $message['body'];
|
||||
$headers = $message['headers'];
|
||||
$subject = $message['subject'];
|
||||
|
||||
// Optionally reroute all emails to a single address.
|
||||
$reroute_address = variable_get('smtp_reroute_address', '');
|
||||
if (!empty($reroute_address)) {
|
||||
$to = $reroute_address;
|
||||
// Remove any CC and BCC headers that might have been set.
|
||||
unset($headers['cc']);
|
||||
unset($headers['bcc']);
|
||||
}
|
||||
|
||||
// Create a new PHPMailer object - autoloaded from registry.
|
||||
$mailer = new PHPMailer();
|
||||
|
||||
$logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
|
||||
|
||||
// Turn on debugging, if requested.
|
||||
if (variable_get('smtp_debugging', 0) == 1) {
|
||||
if ($logging == SMTP_LOGGING_ALL && user_access('administer smtp module')) {
|
||||
$mailer->SMTPDebug = TRUE;
|
||||
}
|
||||
|
||||
// Set the from name and e-mail address.
|
||||
if (variable_get('smtp_fromname', '') != '') {
|
||||
$from_name = variable_get('smtp_fromname', '');
|
||||
// Set the from name. First we try to get the name from i18n, in the case
|
||||
// that it has been translated. The name is set according to the language
|
||||
// of the email being sent.
|
||||
$from_name = FALSE;
|
||||
if (function_exists('i18n_variable_get')) {
|
||||
// The 'language' value may be stored as an object.
|
||||
$langcode = $message['language'];
|
||||
if (is_object($langcode)) {
|
||||
$langcode = $langcode->language;
|
||||
}
|
||||
if (i18n_variable_get('smtp_fromname', $langcode, '') != '') {
|
||||
$from_name = i18n_variable_get('smtp_fromname', $langcode, '');
|
||||
}
|
||||
else {
|
||||
// If value is not defined in settings, use site_name.
|
||||
$from_name = i18n_variable_get('site_name', $langcode, '');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If value is not defined in settings, use site_name.
|
||||
$from_name = variable_get('site_name', '');
|
||||
|
||||
if (variable_get('smtp_client_hostname', '') != '') {
|
||||
$mailer->Hostname = variable_get('smtp_client_hostname', '');
|
||||
}
|
||||
|
||||
if (variable_get('smtp_client_helo', '') != '') {
|
||||
$mailer->Helo = variable_get('smtp_client_helo', '');
|
||||
}
|
||||
|
||||
// If i18n is not enabled, we get the From Name through normal variables
|
||||
if (!$from_name) {
|
||||
if (variable_get('smtp_fromname', '') != '') {
|
||||
$from_name = variable_get('smtp_fromname', '');
|
||||
}
|
||||
else {
|
||||
// If value is not defined in settings, use site_name.
|
||||
$from_name = variable_get('site_name', '');
|
||||
}
|
||||
}
|
||||
|
||||
//Hack to fix reply-to issue.
|
||||
$properfrom = variable_get('site_mail', '');
|
||||
if (!empty($properfrom)) {
|
||||
$headers['From'] = $properfrom;
|
||||
}
|
||||
if (!isset($headers['Reply-To']) || empty($headers['Reply-To'])) {
|
||||
if (strpos($from, '<')) {
|
||||
$reply = preg_replace('/>.*/', '', preg_replace('/.*</', '', $from));
|
||||
@@ -84,6 +133,11 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
}
|
||||
$headers['Reply-To'] = $reply;
|
||||
}
|
||||
$properfrom = variable_get('smtp_from', '');
|
||||
if (!empty($properfrom)) {
|
||||
$headers['From'] = $properfrom;
|
||||
$from = $properfrom;
|
||||
}
|
||||
|
||||
// Blank value will let the e-mail address appear.
|
||||
|
||||
@@ -93,42 +147,34 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
// If smtp_from config option is blank, use site_email.
|
||||
if (($from = variable_get('site_mail', '')) == '') {
|
||||
drupal_set_message(t('There is no submitted from address.'), 'error');
|
||||
watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
|
||||
if ($logging) {
|
||||
watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (preg_match('/^"?.*"?\s*<.*>$/', $from)) {
|
||||
// . == Matches any single character except line break characters \r and \n.
|
||||
// * == Repeats the previous item zero or more times.
|
||||
$from_name = preg_replace('/"?([^("\t\n)]*)"?.*$/', '$1', $from); // It gives: Name
|
||||
$from = preg_replace("/(.*)\<(.*)\>/i", '$2', $from); // It gives: name@domain.tld
|
||||
}
|
||||
elseif (!valid_email_address($from)) {
|
||||
drupal_set_message(t('The submitted from address (@from) is not valid.', array('@from' => $from)), 'error');
|
||||
watchdog('smtp', 'The submitted from address (@from) is not valid.', array('@from' => $from), WATCHDOG_ERROR);
|
||||
$from_comp = $this->_get_components($from);
|
||||
|
||||
if (!valid_email_address($from_comp['email'])) {
|
||||
drupal_set_message(t('The submitted from address (@from) is not valid.', array('@from' => $from_comp['email'])), 'error');
|
||||
if ($logging) {
|
||||
watchdog('smtp', 'The submitted from address (@from) is not valid.', array('@from' => $from_comp['email']), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Defines the From value to what we expect.
|
||||
$mailer->From = $from;
|
||||
$mailer->FromName = $from_name;
|
||||
$mailer->Sender = $from;
|
||||
$mailer->From = $from_comp['email'];
|
||||
$mailer->FromName = empty($from_comp['name']) ? $from_name : $from_comp['name'];
|
||||
$mailer->Sender = $from_comp['email'];
|
||||
|
||||
|
||||
// Create the list of 'To:' recipients.
|
||||
$torecipients = explode(',', $to);
|
||||
foreach ($torecipients as $torecipient) {
|
||||
if (strpos($torecipient, '<') !== FALSE) {
|
||||
$toparts = explode(' <', $torecipient);
|
||||
$toname = $toparts[0];
|
||||
$toaddr = rtrim($toparts[1], '>');
|
||||
}
|
||||
else {
|
||||
$toname = '';
|
||||
$toaddr = $torecipient;
|
||||
}
|
||||
$mailer->AddAddress($toaddr, $toname);
|
||||
$to_comp = $this->_get_components($torecipient);
|
||||
$mailer->AddAddress($to_comp['email'], $to_comp['name']);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +209,8 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
}
|
||||
// Set the charset based on the provided value, otherwise set it to UTF-8 (which is Drupals internal default).
|
||||
$mailer->CharSet = isset($vars['charset']) ? $vars['charset'] : 'UTF-8';
|
||||
// If $vars is empty then set an empty value at index 0 to avoid a PHP warning in the next statement
|
||||
$vars[0] = isset($vars[0])?$vars[0]:'';
|
||||
|
||||
switch ($vars[0]) {
|
||||
case 'text/plain':
|
||||
@@ -199,8 +247,9 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
default:
|
||||
// Everything else is unsuppored by PHPMailer.
|
||||
drupal_set_message(t('The %header of your message is not supported by PHPMailer and will be sent as text/plain instead.', array('%header' => "Content-Type: $value")), 'error');
|
||||
watchdog('smtp', 'The %header of your message is not supported by PHPMailer and will be sent as text/plain instead.', array('%header' => "Content-Type: $value"), WATCHDOG_ERROR);
|
||||
|
||||
if ($logging) {
|
||||
watchdog('smtp', 'The %header of your message is not supported by PHPMailer and will be sent as text/plain instead.', array('%header' => "Content-Type: $value"), WATCHDOG_ERROR);
|
||||
}
|
||||
// Force the Content-Type to be text/plain.
|
||||
$mailer->IsHTML(FALSE);
|
||||
$content_type = 'text/plain';
|
||||
@@ -210,16 +259,8 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
case 'reply-to':
|
||||
// Only add a "reply-to" if it's not the same as "return-path".
|
||||
if ($value != $headers['Return-Path']) {
|
||||
if (strpos($value, '<') !== FALSE) {
|
||||
$replyToParts = explode('<', $value);
|
||||
$replyToName = trim($replyToParts[0]);
|
||||
$replyToName = trim($replyToName, '"');
|
||||
$replyToAddr = rtrim($replyToParts[1], '>');
|
||||
$mailer->AddReplyTo($replyToAddr, $replyToName);
|
||||
}
|
||||
else {
|
||||
$mailer->AddReplyTo($value);
|
||||
}
|
||||
$replyto_comp = $this->_get_components($value);
|
||||
$mailer->AddReplyTo($replyto_comp['email'], $replyto_comp['name']);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -228,6 +269,10 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
break;
|
||||
|
||||
case 'return-path':
|
||||
$returnpath_comp = $this->_get_components($value);
|
||||
$mailer->Sender = $returnpath_comp['email'];
|
||||
break;
|
||||
|
||||
case 'mime-version':
|
||||
case 'x-mailer':
|
||||
// Let PHPMailer specify these.
|
||||
@@ -240,73 +285,52 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
case 'cc':
|
||||
$ccrecipients = explode(',', $value);
|
||||
foreach ($ccrecipients as $ccrecipient) {
|
||||
if (strpos($ccrecipient, '<') !== FALSE) {
|
||||
$ccparts = explode(' <', $ccrecipient);
|
||||
$ccname = $ccparts[0];
|
||||
$ccaddr = rtrim($ccparts[1], '>');
|
||||
}
|
||||
else {
|
||||
$ccname = '';
|
||||
$ccaddr = $ccrecipient;
|
||||
}
|
||||
$mailer->AddBCC($ccaddr, $ccname);
|
||||
$cc_comp = $this->_get_components($ccrecipient);
|
||||
$mailer->AddCC($cc_comp['email'], $cc_comp['name']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bcc':
|
||||
$bccrecipients = explode(',', $value);
|
||||
foreach ($bccrecipients as $bccrecipient) {
|
||||
if (strpos($bccrecipient, '<') !== FALSE) {
|
||||
$bccparts = explode(' <', $bccrecipient);
|
||||
$bccname = $bccparts[0];
|
||||
$bccaddr = rtrim($bccparts[1], '>');
|
||||
}
|
||||
else {
|
||||
$bccname = '';
|
||||
$bccaddr = $bccrecipient;
|
||||
}
|
||||
$mailer->AddBCC($bccaddr, $bccname);
|
||||
$bcc_comp = $this->_get_components($bccrecipient);
|
||||
$mailer->AddBCC($bcc_comp['email'], $bcc_comp['name']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'message-id':
|
||||
$mailer->MessageID = $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
// The header key is not special - add it as is.
|
||||
$mailer->AddCustomHeader($key . ': ' . $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Need to figure out the following.
|
||||
|
||||
// Add one last header item, but not if it has already been added.
|
||||
$errors_to = FALSE;
|
||||
foreach ($mailer->CustomHeader as $custom_header) {
|
||||
if ($custom_header[0] = '') {
|
||||
$errors_to = TRUE;
|
||||
}
|
||||
}
|
||||
if ($errors_to) {
|
||||
$mailer->AddCustomHeader('Errors-To: '. $from);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Need to figure out the following.
|
||||
*
|
||||
* Add one last header item, but not if it has already been added.
|
||||
* $errors_to = FALSE;
|
||||
* foreach ($mailer->CustomHeader as $custom_header) {
|
||||
* if ($custom_header[0] = '') {
|
||||
* $errors_to = TRUE;
|
||||
* }
|
||||
* }
|
||||
* if ($errors_to) {
|
||||
* $mailer->AddCustomHeader('Errors-To: '. $from);
|
||||
* }
|
||||
*/
|
||||
// Add the message's subject.
|
||||
$mailer->Subject = $subject;
|
||||
|
||||
|
||||
// Processes the message's body.
|
||||
switch ($content_type) {
|
||||
case 'multipart/related':
|
||||
$mailer->Body = $body;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Firgure out if there is anything more to handling this type.
|
||||
*/
|
||||
|
||||
// TODO: Figure out if there is anything more to handling this type.
|
||||
break;
|
||||
|
||||
case 'multipart/alternative':
|
||||
@@ -351,10 +375,10 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
// $mailer->AltBody or $mailer->Body, depending on whether there is
|
||||
// also a text/html part ot not.
|
||||
if (strpos($body_part, 'multipart/alternative')) {
|
||||
// Clean up the text.
|
||||
$body_part = trim($this->_remove_headers(trim($body_part)));
|
||||
// Get boundary ID from the Content-Type header.
|
||||
$boundary2 = $this->_get_substring($body_part, 'boundary', '"', '"');
|
||||
// Clean up the text.
|
||||
$body_part = trim($this->_remove_headers(trim($body_part)));
|
||||
// Split the body based on the boundary ID.
|
||||
$body_parts2 = $this->_boundary_split($body_part, $boundary2);
|
||||
|
||||
@@ -369,10 +393,21 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
}
|
||||
// If plain/html within the body part, add it to $mailer->Body.
|
||||
elseif (strpos($body_part2, 'text/html')) {
|
||||
// Get the encoding.
|
||||
$body_part2_encoding = trim($this->_get_substring($body_part2, 'Content-Transfer-Encoding', ':', "\n"));
|
||||
// Clean up the text.
|
||||
$body_part2 = trim($this->_remove_headers(trim($body_part2)));
|
||||
// Include it as part of the mail object.
|
||||
$mailer->Body = $body_part2;
|
||||
// Check whether the encoding is base64, and if so, decode it.
|
||||
if (drupal_strtolower($body_part2_encoding) == 'base64') {
|
||||
// Include it as part of the mail object.
|
||||
$mailer->Body = base64_decode($body_part2);
|
||||
// Ensure the whole message is recoded in the base64 format.
|
||||
$mailer->Encoding = 'base64';
|
||||
}
|
||||
else {
|
||||
// Include it as part of the mail object.
|
||||
$mailer->Body = $body_part2;
|
||||
}
|
||||
$mailer->ContentType = 'multipart/mixed';
|
||||
}
|
||||
}
|
||||
@@ -403,14 +438,14 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
$mailer->ContentType = 'multipart/mixed';
|
||||
}
|
||||
// Add the attachment.
|
||||
elseif (strpos($body_part, 'Content-Disposition: attachment;')) {
|
||||
elseif (strpos($body_part, 'Content-Disposition: attachment;') && !isset($message['params']['attachments'])) {
|
||||
$file_path = $this->_get_substring($body_part, 'filename=', '"', '"');
|
||||
$file_name = $this->_get_substring($body_part, ' name=', '"', '"');
|
||||
$file_encoding = $this->_get_substring($body_part, 'Content-Transfer-Encoding', ' ', "\n");
|
||||
$file_type = $this->_get_substring($body_part, 'Content-Type', ' ', ';');
|
||||
|
||||
if (file_exists($file_path)) {
|
||||
if (!$mailer->AddAttachment($file_path, $file_name, $file_encoding, $filetype)) {
|
||||
if (!$mailer->AddAttachment($file_path, $file_name, $file_encoding, $file_type)) {
|
||||
drupal_set_message(t('Attahment could not be found or accessed.'));
|
||||
}
|
||||
}
|
||||
@@ -428,10 +463,11 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
$attachment = $body_part;
|
||||
}
|
||||
|
||||
$attachment_new_filename = tempnam(realpath(file_directory_temp()), 'smtp');
|
||||
$file_path = file_save_data($attachment, $attachment_new_filename, FILE_EXISTS_RENAME);
|
||||
$attachment_new_filename = drupal_tempnam('temporary://', 'smtp');
|
||||
$file_path = file_save_data($attachment, $attachment_new_filename, FILE_EXISTS_REPLACE);
|
||||
$real_path = drupal_realpath($file_path->uri);
|
||||
|
||||
if (!$mailer->AddAttachment($file_path, $file_name)) { // , $file_encoding, $filetype);
|
||||
if (!$mailer->AddAttachment($real_path, $file_name)) {
|
||||
drupal_set_message(t('Attachment could not be found or accessed.'));
|
||||
}
|
||||
}
|
||||
@@ -444,6 +480,19 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
break;
|
||||
}
|
||||
|
||||
// Process mimemail attachments, which are prepared in mimemail_mail().
|
||||
if (isset($message['params']['attachments'])) {
|
||||
foreach ($message['params']['attachments'] as $attachment) {
|
||||
if (isset($attachment['filecontent'])) {
|
||||
$mailer->AddStringAttachment($attachment['filecontent'], $attachment['filename'], 'base64', $attachment['filemime']);
|
||||
}
|
||||
if (isset($attachment['filepath'])) {
|
||||
$filename = isset($attachment['filename']) ? $attachment['filename'] : basename($attachment['filepath']);
|
||||
$filemime = isset($attachment['filemime']) ? $attachment['filemime'] : file_get_mimetype($attachment['filepath']);
|
||||
$mailer->AddAttachment($attachment['filepath'], $filename, 'base64', $filemime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the authentication settings.
|
||||
$username = variable_get('smtp_username', '');
|
||||
@@ -473,23 +522,130 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
|
||||
|
||||
// Set other connection settings.
|
||||
$mailer->Host = variable_get('smtp_host', '') . ';' . variable_get('smtp_hostbackup', '');
|
||||
$mailer->Port = variable_get('smtp_port', '25');
|
||||
$mailer->Host = variable_get('smtp_host', '') . ';' . variable_get('smtp_hostbackup', '');
|
||||
$mailer->Port = variable_get('smtp_port', '25');
|
||||
$mailer->Mailer = 'smtp';
|
||||
|
||||
// Integration with the Maillog module.
|
||||
if (module_exists('maillog')) {
|
||||
if (variable_get('maillog_log', TRUE)) {
|
||||
$record = new stdClass;
|
||||
|
||||
// Let the people know what is going on.
|
||||
watchdog('smtp', 'Sending mail to: @to', array('@to' => $to));
|
||||
// In case the subject/from/to is already encoded, decode with
|
||||
// mime_header_decode.
|
||||
$record->header_message_id = isset($mailer->MessageID) ? $mailer->MessageID : NULL;
|
||||
$record->subject = drupal_substr(mime_header_decode($mailer->Subject), 0, 255);
|
||||
$record->header_from = $from;
|
||||
$record->header_to = $to;
|
||||
$record->header_reply_to = isset($headers['Reply-To']) ? $headers['Reply-To'] : '';
|
||||
$record->header_all = serialize($headers);
|
||||
$record->sent_date = REQUEST_TIME;
|
||||
|
||||
// Try to send e-mail. If it fails, set watchdog entry.
|
||||
if (!$mailer->Send()) {
|
||||
watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', array('@from' => $from, '@to' => $to, '!error_message' => $mailer->ErrorInfo), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
// Used to separate different portions of the body string.
|
||||
$divider = str_repeat('-', 60) . "\n";
|
||||
|
||||
// Load the attachments.
|
||||
$attachments = $mailer->GetAttachments();
|
||||
|
||||
$record->body = '';
|
||||
|
||||
// If there's more than one item to display, add a divider.
|
||||
if (!empty($mailer->AltBody) || !empty($attachments)) {
|
||||
$record->body .= t('Body') . ":\n";
|
||||
$record->body .= $divider;
|
||||
}
|
||||
|
||||
// Add the body field.
|
||||
if (isset($mailer->Body)) {
|
||||
$record->body .= $mailer->Body;
|
||||
}
|
||||
else {
|
||||
$record->body .= t('*No message body*') . ":\n";
|
||||
}
|
||||
|
||||
// The AltBody value is optional.
|
||||
if (!empty($mailer->AltBody)) {
|
||||
$record->body .= "\n";
|
||||
$record->body .= $divider;
|
||||
$record->body .= t('Alternative body') . ":\n";
|
||||
$record->body .= $divider;
|
||||
$record->body .= $mailer->AltBody;
|
||||
}
|
||||
|
||||
// List the attachments.
|
||||
if (!empty($attachments)) {
|
||||
$record->body .= "\n";
|
||||
$record->body .= $divider;
|
||||
$record->body .= t('Attachments') . ":\n";
|
||||
$record->body .= $divider;
|
||||
foreach ($attachments as $file) {
|
||||
$record->body .= t('Filename') . ':' . $file[1] . "\n";
|
||||
$record->body .= t('Name') . ':' . $file[2] . "\n";
|
||||
$record->body .= t('Encoding') . ':' . $file[3] . "\n";
|
||||
$record->body .= t('Type') . ':' . $file[4] . "\n";
|
||||
$record->body .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
drupal_write_record('maillog', $record);
|
||||
}
|
||||
|
||||
// Display the e-mail using Devel module.
|
||||
if (variable_get('maillog_devel', TRUE) && function_exists('dpm')) {
|
||||
$devel_msg = array();
|
||||
$devel_msg[t('Subject')] = $mailer->Subject;
|
||||
$devel_msg[t('From')] = $from;
|
||||
$devel_msg[t('To')] = $to;
|
||||
$devel_msg[t('Reply-To')] = isset($headers['Reply-To']) ? $headers['Reply-To'] : NULL;
|
||||
$devel_msg[t('Headers')] = $headers;
|
||||
$devel_msg[t('Body')] = $mailer->Body;
|
||||
$devel_msg[t('Alternative body')] = $mailer->AltBody;
|
||||
$devel_msg[t('Attachments')] = $mailer->GetAttachments();
|
||||
|
||||
dpm($devel_msg, 'maillog');
|
||||
}
|
||||
}
|
||||
|
||||
$error = FALSE;
|
||||
|
||||
// Email delivery was disabled.
|
||||
if (!variable_get('smtp_deliver', TRUE)) {
|
||||
if ($logging) {
|
||||
$params = array(
|
||||
'@from' => $from,
|
||||
'@to' => $to,
|
||||
);
|
||||
watchdog('smtp', 'Email delivery is disabled, did not send email from @from to @to.', $params);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!$mailer->send()) {
|
||||
$params = array(
|
||||
'@from' => $from,
|
||||
'@to' => $to,
|
||||
'!error_message' => $mailer->ErrorInfo
|
||||
);
|
||||
|
||||
if (variable_get('smtp_queue_fail', FALSE)) {
|
||||
if ($logging) {
|
||||
watchdog('smtp', 'Error sending e-mail from @from to @to, will retry on cron run : !error_message.', $params, WATCHDOG_ERROR);
|
||||
}
|
||||
smtp_failed_messages($message);
|
||||
}
|
||||
elseif ($logging) {
|
||||
$error = TRUE;
|
||||
watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', $params, WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
elseif (variable_get('smtp_debugging', SMTP_LOGGING_ERRORS) == SMTP_LOGGING_ALL) {
|
||||
watchdog('smtp', 'Sent mail to: @to', array('@to' => $to));
|
||||
}
|
||||
}
|
||||
|
||||
$mailer->SmtpClose();
|
||||
return TRUE;
|
||||
return !$error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the input into parts based on the given boundary.
|
||||
*
|
||||
@@ -523,8 +679,6 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
return $parts;
|
||||
} // End of _smtp_boundary_split().
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Strips the headers from the body part.
|
||||
*
|
||||
@@ -536,20 +690,29 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
protected function _remove_headers($input) {
|
||||
$part_array = explode("\n", $input);
|
||||
|
||||
if (strpos($part_array[0], 'Content') !== FALSE) {
|
||||
if (strpos($part_array[1], 'Content') !== FALSE) {
|
||||
if (strpos($part_array[2], 'Content') !== FALSE) {
|
||||
array_shift($part_array);
|
||||
array_shift($part_array);
|
||||
array_shift($part_array);
|
||||
}
|
||||
else {
|
||||
array_shift($part_array);
|
||||
array_shift($part_array);
|
||||
// will strip these headers according to RFC2045
|
||||
$headers_to_strip = array( 'Content-Type', 'Content-Transfer-Encoding', 'Content-ID', 'Content-Disposition');
|
||||
$pattern = '/^(' . implode('|', $headers_to_strip) . '):/';
|
||||
|
||||
while (count($part_array) > 0) {
|
||||
|
||||
// ignore trailing spaces/newlines
|
||||
$line = rtrim($part_array[0]);
|
||||
|
||||
// if the line starts with a known header string
|
||||
if (preg_match($pattern, $line)) {
|
||||
$line = rtrim(array_shift($part_array));
|
||||
// remove line containing matched header.
|
||||
|
||||
// if line ends in a ';' and the next line starts with four spaces, it's a continuation
|
||||
// of the header split onto the next line. Continue removing lines while we have this condition.
|
||||
while (substr($line, -1) == ';' && count($part_array) > 0 && substr($part_array[0], 0, 4) == ' ') {
|
||||
$line = rtrim(array_shift($part_array));
|
||||
}
|
||||
}
|
||||
else {
|
||||
array_shift($part_array);
|
||||
// no match header, must be past headers; stop searching.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,8 +720,6 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
return $output;
|
||||
} // End of _smtp_remove_headers().
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string that is contained within another string.
|
||||
*
|
||||
@@ -588,6 +749,41 @@ class SmtpMailSystem implements MailSystemInterface {
|
||||
$substring = drupal_substr($substring, 0, $string_length);
|
||||
}
|
||||
|
||||
return $substring;
|
||||
return trim($substring);
|
||||
} // End of _smtp_get_substring().
|
||||
|
||||
/**
|
||||
* Returns an array of name and email address from a string.
|
||||
*
|
||||
* @param $input
|
||||
* A string that contains different possible combinations of names and
|
||||
* email address.
|
||||
* @return
|
||||
* An array containing a name and an email address.
|
||||
*/
|
||||
protected function _get_components($input) {
|
||||
$components = array(
|
||||
'input' => $input,
|
||||
'name' => '',
|
||||
'email' => '',
|
||||
);
|
||||
|
||||
// If the input is a valid email address in its entirety, then there is
|
||||
// nothing to do, just return that.
|
||||
if (valid_email_address($input)) {
|
||||
$components['email'] = trim($input);
|
||||
return $components;
|
||||
}
|
||||
|
||||
// Check if $input has one of the following formats, extract what we can:
|
||||
// some name <address@example.com>
|
||||
// "another name" <address@example.com>
|
||||
// <address@example.com>
|
||||
if (preg_match('/^"?([^"\t\n]*)"?\s*<([^>\t\n]*)>$/', $input, $matches)) {
|
||||
$components['name'] = trim($matches[1]);
|
||||
$components['email'] = trim($matches[2]);
|
||||
}
|
||||
|
||||
return $components;
|
||||
}
|
||||
}
|
||||
|
@@ -16,17 +16,33 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_help().
|
||||
* SMTP logging -- logging is disabled
|
||||
*/
|
||||
define('SMTP_LOGGING_NONE', 0);
|
||||
|
||||
/**
|
||||
* SMTP logging -- all messages are logged
|
||||
*/
|
||||
define('SMTP_LOGGING_ALL', 1);
|
||||
|
||||
/**
|
||||
* SMTP logging -- only errors are logged
|
||||
*/
|
||||
define('SMTP_LOGGING_ERRORS', 2);
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function smtp_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#smtp':
|
||||
return t('Allow for site emails to be sent through an SMTP server of your choice.');
|
||||
}
|
||||
} // End of smtp_help().
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_menu().
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function smtp_menu() {
|
||||
$items['admin/config/system/smtp'] = array(
|
||||
@@ -38,10 +54,10 @@ function smtp_menu() {
|
||||
'file' => 'smtp.admin.inc',
|
||||
);
|
||||
return $items;
|
||||
} // End of smtp_menu().
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_permission().
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function smtp_permission() {
|
||||
return array(
|
||||
@@ -49,15 +65,93 @@ function smtp_permission() {
|
||||
'title' => t('Administer SMTP Authentication Support module'),
|
||||
'description' => t('Perform administration tasks for SMTP Authentication Support module.'))
|
||||
);
|
||||
} // End of smtp_permission().
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hook_mail().
|
||||
* Implements hook_mail().
|
||||
*/
|
||||
function smtp_mail($key, &$message, $params) {
|
||||
if ($key == 'smtp-test') {
|
||||
$message['subject'] = $params['subject'];
|
||||
$message['body'] = $params['body'];
|
||||
$message['body'] = $params['body'];
|
||||
}
|
||||
} // End of smtp_mail().
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_cron_queue_info().
|
||||
*/
|
||||
function smtp_cron_queue_info() {
|
||||
$queues['smtp_send_queue'] = array(
|
||||
'worker callback' => 'smtp_send_queue_runner',
|
||||
'time' => 60,
|
||||
);
|
||||
|
||||
$queues['smtp_failure_queue'] = array(
|
||||
'worker callback' => 'smtp_failure_queue_runner',
|
||||
'time' => 30,
|
||||
);
|
||||
|
||||
return $queues;
|
||||
}
|
||||
|
||||
/**
|
||||
* smtp_send_queue queuer.
|
||||
*/
|
||||
function smtp_send_queue($mailerObj) {
|
||||
$queue = DrupalQueue::get('smtp_send_queue');
|
||||
$queue->createItem($mailerObj);
|
||||
}
|
||||
|
||||
function smtp_send_queue_runner($message) {
|
||||
$logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
|
||||
|
||||
// Legacy for mails queued before 7.x-v1.3
|
||||
// What was passed to the runner used to be a PHPMailer object, not a message array.
|
||||
if (!empty($message['mailer']) && is_object($message['mailer'])) {
|
||||
if (!$message['mailer']->Send()) {
|
||||
if ($logging == SMTP_LOGGING_ALL || $logging == SMTP_LOGGING_ERRORS) {
|
||||
watchdog('smtp', 'Error sending e-mail from @from to @to, will retry on cron run : !error_message.',
|
||||
array(
|
||||
'@from' => $message['from'],
|
||||
'@to' => $message['to'],
|
||||
'!error_message' => $message['mailer']->ErrorInfo,
|
||||
), WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the people know what is going on.
|
||||
if ($logging == SMTP_LOGGING_ALL) {
|
||||
watchdog('smtp', 'Sending mail to: @to', array('@to' => $message['to']));
|
||||
}
|
||||
|
||||
// Send the message.
|
||||
$mail_system = new SmtpMailSystem();
|
||||
$mail_system->mailWithoutQueue($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store failed messages for later.
|
||||
*
|
||||
* @param array $new_message
|
||||
*
|
||||
* @return array
|
||||
* All messages that have been saved.
|
||||
*/
|
||||
function smtp_failed_messages($message) {
|
||||
$queue = DrupalQueue::get('smtp_failure_queue');
|
||||
$queue->createItem($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue runner for smtp_failure_queue.
|
||||
*
|
||||
* @param $message
|
||||
* A drupal_mail-formatted message.
|
||||
*/
|
||||
function smtp_failure_queue_runner($message) {
|
||||
$queue = DrupalQueue::get('smtp_send_queue');
|
||||
$queue->createItem($message);
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*~ class.phpmailer.php
|
||||
Orginal release information:
|
||||
Original release information:
|
||||
.---------------------------------------------------------------------------.
|
||||
| Software: PHPMailer - PHP email class |
|
||||
| Version: 5.1 |
|
||||
@@ -325,6 +325,7 @@ class PHPMailer {
|
||||
private $sign_key_file = "";
|
||||
private $sign_key_pass = "";
|
||||
private $exceptions = FALSE;
|
||||
private $logging;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// CONSTANTS
|
||||
@@ -343,6 +344,7 @@ class PHPMailer {
|
||||
* @param boolean $exceptions Should we throw external exceptions?
|
||||
*/
|
||||
public function __construct($exceptions = FALSE) {
|
||||
$this->logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
|
||||
$this->exceptions = ($exceptions == TRUE);
|
||||
}
|
||||
|
||||
@@ -455,7 +457,9 @@ class PHPMailer {
|
||||
*/
|
||||
private function AddAnAddress($kind, $address, $name = '') {
|
||||
if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
|
||||
echo 'Invalid recipient array: ' . kind;
|
||||
if ($this->logging) {
|
||||
watchdog('smtp', 'Invalid recipient array: %kind', array('%kind' => $kind), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
$address = trim($address);
|
||||
@@ -465,7 +469,9 @@ class PHPMailer {
|
||||
if ($this->exceptions) {
|
||||
throw new phpmailerException(t('Invalid address') . ': ' . $address);
|
||||
}
|
||||
echo t('Invalid address') . ': ' . $address;
|
||||
if ($this->logging) {
|
||||
watchdog('smtp', 'Invalid address: %address', array('%address' => $address), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if ($kind != 'ReplyTo') {
|
||||
@@ -498,7 +504,9 @@ class PHPMailer {
|
||||
if ($this->exceptions) {
|
||||
throw new phpmailerException(t('Invalid address') . ': ' . $address);
|
||||
}
|
||||
echo t('Invalid address') . ': ' . $address;
|
||||
if ($this->logging) {
|
||||
watchdog('smtp', 'Invalid address: %address', array('%address' => $address), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
$this->From = $address;
|
||||
@@ -577,8 +585,6 @@ class PHPMailer {
|
||||
|
||||
// Choose the mailer and send through it
|
||||
switch ($this->Mailer) {
|
||||
case 'sendmail':
|
||||
return $this->SendmailSend($header, $body);
|
||||
case 'smtp':
|
||||
return $this->SmtpSend($header, $body);
|
||||
default:
|
||||
@@ -590,59 +596,13 @@ class PHPMailer {
|
||||
if ($this->exceptions) {
|
||||
throw $e;
|
||||
}
|
||||
echo $e->getMessage() . "\n";
|
||||
if ($this->logging) {
|
||||
watchdog_exception('smtp', $e);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends mail using the $Sendmail program.
|
||||
* @param string $header The message headers
|
||||
* @param string $body The message body
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function SendmailSend($header, $body) {
|
||||
if ($this->Sender != '') {
|
||||
$sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
|
||||
}
|
||||
else {
|
||||
$sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
|
||||
}
|
||||
if ($this->SingleTo === TRUE) {
|
||||
foreach ($this->SingleToArray as $key => $val) {
|
||||
if (!@$mail = popen($sendmail, 'w')) {
|
||||
throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
|
||||
}
|
||||
fputs($mail, "To: " . $val . "\n");
|
||||
fputs($mail, $header);
|
||||
fputs($mail, $body);
|
||||
$result = pclose($mail);
|
||||
// implement call back function if it exists
|
||||
$isSent = ($result == 0) ? 1 : 0;
|
||||
$this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
|
||||
if ($result != 0) {
|
||||
throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!@$mail = popen($sendmail, 'w')) {
|
||||
throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
|
||||
}
|
||||
fputs($mail, $header);
|
||||
fputs($mail, $body);
|
||||
$result = pclose($mail);
|
||||
// implement call back function if it exists
|
||||
$isSent = ($result == 0) ? 1 : 0;
|
||||
$this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
|
||||
if ($result != 0) {
|
||||
throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends mail using the PHP mail() function.
|
||||
* @param string $header The message headers
|
||||
@@ -662,7 +622,7 @@ class PHPMailer {
|
||||
$old_from = ini_get('sendmail_from');
|
||||
ini_set('sendmail_from', $this->Sender);
|
||||
if ($this->SingleTo === TRUE && count($toArr) > 1) {
|
||||
foreach ($toArr as $key => $val) {
|
||||
foreach ($toArr as $val) {
|
||||
$rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
|
||||
// implement call back function if it exists
|
||||
$isSent = ($rt == 1) ? 1 : 0;
|
||||
@@ -678,7 +638,7 @@ class PHPMailer {
|
||||
}
|
||||
else {
|
||||
if ($this->SingleTo === TRUE && count($toArr) > 1) {
|
||||
foreach ($toArr as $key => $val) {
|
||||
foreach ($toArr as $val) {
|
||||
$rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
|
||||
// implement call back function if it exists
|
||||
$isSent = ($rt == 1) ? 1 : 0;
|
||||
@@ -792,10 +752,11 @@ class PHPMailer {
|
||||
$hosts = explode(';', $this->Host);
|
||||
$index = 0;
|
||||
$connection = $this->smtp->Connected();
|
||||
$lastexception = NULL;
|
||||
|
||||
// Retry while there is no connection
|
||||
try {
|
||||
while ($index < count($hosts) && !$connection) {
|
||||
while ($index < count($hosts) && !$connection) {
|
||||
try {
|
||||
$hostinfo = array();
|
||||
if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
|
||||
$host = $hostinfo[1];
|
||||
@@ -830,14 +791,24 @@ class PHPMailer {
|
||||
}
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
if (!$connection) {
|
||||
throw new phpmailerException(t('SMTP Error: Could not connect to SMTP host.'));
|
||||
} catch (phpmailerException $e) {
|
||||
if ($connection) {
|
||||
$this->SmtpClose();
|
||||
$connection = FALSE;
|
||||
}
|
||||
|
||||
$lastexception = $e;
|
||||
}
|
||||
|
||||
$index++;
|
||||
}
|
||||
if (!$connection) {
|
||||
if ($lastexception != NULL) {
|
||||
throw $lastexception;
|
||||
}
|
||||
else {
|
||||
throw new phpmailerException(t('SMTP Error: Could not connect to SMTP host.'));
|
||||
}
|
||||
} catch (phpmailerException $e) {
|
||||
$this->smtp->Reset();
|
||||
throw $e;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1361,7 +1332,9 @@ class PHPMailer {
|
||||
if ($this->exceptions) {
|
||||
throw $e;
|
||||
}
|
||||
echo $e->getMessage() . "\n";
|
||||
if ($this->logging) {
|
||||
watchdog_exception('smtp', $e);
|
||||
}
|
||||
if ( $e->getCode() == self::STOP_CRITICAL ) {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1469,14 +1442,24 @@ class PHPMailer {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (PHP_VERSION < 6) {
|
||||
$magic_quotes = get_magic_quotes_runtime();
|
||||
set_magic_quotes_runtime(0);
|
||||
$magic_quotes = get_magic_quotes_runtime();
|
||||
if ($magic_quotes) {
|
||||
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
||||
set_magic_quotes_runtime(0);
|
||||
}
|
||||
else {
|
||||
ini_set('magic_quotes_runtime', 0);
|
||||
}
|
||||
}
|
||||
$file_buffer = file_get_contents($path);
|
||||
$file_buffer = $this->EncodeString($file_buffer, $encoding);
|
||||
if (PHP_VERSION < 6) {
|
||||
set_magic_quotes_runtime($magic_quotes);
|
||||
if ($magic_quotes) {
|
||||
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
||||
set_magic_quotes_runtime($magic_quotes);
|
||||
}
|
||||
else {
|
||||
ini_set('magic_quotes_runtime', $magic_quotes);
|
||||
}
|
||||
}
|
||||
return $file_buffer;
|
||||
} catch (Exception $e) {
|
||||
@@ -1731,27 +1714,41 @@ class PHPMailer {
|
||||
*/
|
||||
public function EncodeQ($str, $position = 'text') {
|
||||
// There should not be any EOL in the string
|
||||
$encoded = preg_replace('/[\r\n]*/', '', $str);
|
||||
|
||||
$pattern = '';
|
||||
$encoded = str_replace(array("\r", "\n"), '', $str);
|
||||
switch (strtolower($position)) {
|
||||
case 'phrase':
|
||||
$encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
|
||||
// RFC 2047 section 5.3
|
||||
$pattern = '^A-Za-z0-9!*+\/ -';
|
||||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'comment':
|
||||
$encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
|
||||
// RFC 2047 section 5.2
|
||||
$pattern = '\(\)"';
|
||||
// intentional fall-through
|
||||
// for this reason we build the $pattern without including delimiters and []
|
||||
case 'text':
|
||||
default:
|
||||
// Replace every high ascii, control =, ? and _ characters
|
||||
//TODO using /e (equivalent to eval()) is probably not a good idea
|
||||
$encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
|
||||
"'='.sprintf('%02X', ord('\\1'))", $encoded);
|
||||
// RFC 2047 section 5.1
|
||||
// Replace every high ascii, control, =, ? and _ characters
|
||||
$pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
|
||||
break;
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
|
||||
// If the string contains an '=', make sure it's the first thing we replace
|
||||
// so as to avoid double-encoding
|
||||
$s = array_search('=', $matches[0]);
|
||||
if ($s !== false) {
|
||||
unset($matches[0][$s]);
|
||||
array_unshift($matches[0], '=');
|
||||
}
|
||||
foreach (array_unique($matches[0]) as $char) {
|
||||
$encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
|
||||
}
|
||||
}
|
||||
// Replace every spaces to _ (more readable than =20)
|
||||
$encoded = str_replace(' ', '_', $encoded);
|
||||
|
||||
return $encoded;
|
||||
return str_replace(' ', '_', $encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2193,7 +2190,6 @@ class PHPMailer {
|
||||
* @param string $key_pass Password for private key
|
||||
*/
|
||||
public function DKIM_QP($txt) {
|
||||
$tmp="";
|
||||
$line="";
|
||||
for ($i=0;$i<strlen($txt);$i++) {
|
||||
$ord=ord($txt[$i]);
|
||||
@@ -2320,4 +2316,4 @@ class phpmailerException extends Exception {
|
||||
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
|
||||
return $errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
/*~ class.smtp.php
|
||||
Orginal release information:
|
||||
Original release information:
|
||||
.---------------------------------------------------------------------------.
|
||||
| Software: PHPMailer - PHP email class |
|
||||
| Version: 5.1 |
|
||||
@@ -141,7 +141,7 @@ class SMTP {
|
||||
"errno" => $errno,
|
||||
"errstr" => $errstr);
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @errstr (@errno)", array("@error" => $this->error["error"], "@errstr" => $errstr, "@errno" => $errno)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ class SMTP {
|
||||
$announce = $this->get_lines();
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @announce", array("@announce" => $announce)));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -184,7 +184,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 220) {
|
||||
@@ -193,7 +193,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -259,7 +259,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -278,7 +278,7 @@ class SMTP {
|
||||
if ($sock_status["eof"]) {
|
||||
// the socket is valid but we are not connected
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
|
||||
drupal_set_message(t("SMTP -> NOTICE: EOF caught while checking if connected"));
|
||||
}
|
||||
$this->Close();
|
||||
return FALSE;
|
||||
@@ -314,7 +314,7 @@ class SMTP {
|
||||
* finializing the mail transaction. $msg_data is the message
|
||||
* that is to be send with the headers. Each header needs to be
|
||||
* on a single line followed by a <CRLF> with the message headers
|
||||
* and the message body being seperated by and additional <CRLF>.
|
||||
* and the message body being separated by and additional <CRLF>.
|
||||
*
|
||||
* Implements rfc 821: DATA <CRLF>
|
||||
*
|
||||
@@ -343,7 +343,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 354) {
|
||||
@@ -352,7 +352,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -437,7 +437,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250) {
|
||||
@@ -446,7 +446,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -502,7 +502,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250) {
|
||||
@@ -511,7 +511,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -551,7 +551,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250) {
|
||||
@@ -560,7 +560,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -594,7 +594,7 @@ class SMTP {
|
||||
$byemsg = $this->get_lines();
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @byemsg", array("@rply" => $byemsg)));
|
||||
}
|
||||
|
||||
$rval = TRUE;
|
||||
@@ -608,7 +608,7 @@ class SMTP {
|
||||
"smtp_rply" => substr($byemsg, 4));
|
||||
$rval = FALSE;
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +646,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250 && $code != 251) {
|
||||
@@ -655,7 +655,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -689,7 +689,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250) {
|
||||
@@ -698,7 +698,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -736,7 +736,7 @@ class SMTP {
|
||||
$code = substr($rply, 0, 3);
|
||||
|
||||
if ($this->do_debug >= 2) {
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
|
||||
}
|
||||
|
||||
if ($code != 250) {
|
||||
@@ -745,7 +745,7 @@ class SMTP {
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -755,7 +755,7 @@ class SMTP {
|
||||
/**
|
||||
* This is an optional command for SMTP that this class does not
|
||||
* support. This method is here to make the RFC821 Definition
|
||||
* complete for this class and __may__ be implimented in the future
|
||||
* complete for this class and __may__ be implemented in the future
|
||||
*
|
||||
* Implements from rfc 821: TURN <CRLF>
|
||||
*
|
||||
@@ -768,7 +768,7 @@ class SMTP {
|
||||
public function Turn() {
|
||||
$this->error = array("error" => "This method, TURN, of the SMTP is not implemented");
|
||||
if ($this->do_debug >= 1) {
|
||||
echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> NOTICE: @error", array("@error" => $this->error["error"])));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -799,12 +799,12 @@ class SMTP {
|
||||
$data = "";
|
||||
while ($str = @fgets($this->smtp_conn, 515)) {
|
||||
if ($this->do_debug >= 4) {
|
||||
echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
|
||||
echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
|
||||
drupal_set_message(t("SMTP -> get_lines(): \$str is \"@str\"", array("@str" => $str)));
|
||||
}
|
||||
$data .= $str;
|
||||
if ($this->do_debug >= 4) {
|
||||
echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
|
||||
drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
|
||||
}
|
||||
// if 4th character is a space, we are done reading, break the loop
|
||||
if (substr($str, 3, 1) == " ") {
|
||||
@@ -813,4 +813,4 @@ class SMTP {
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
sites/all/modules/smtp/smtp.variable.inc
Normal file
40
sites/all/modules/smtp/smtp.variable.inc
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Custom integration with the Variable module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_variable_group_info().
|
||||
*/
|
||||
function smtp_variable_group_info() {
|
||||
$groups['smtp'] = array(
|
||||
'title' => t('SMTP Authentication Support'),
|
||||
'access' => 'administer smtp module',
|
||||
'description' => t('Configure SMTP server for site emails to be sent from different names.'),
|
||||
);
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_variable_info().
|
||||
*
|
||||
* Allows for the SMTP from name to be translated if/when the Variable module is
|
||||
* enabled.
|
||||
*
|
||||
* @link http://api.drupalhelp.net/api/variable/variable.api.php/function/hook_variable_info/7
|
||||
* @param array $options
|
||||
*/
|
||||
function smtp_variable_info($options) {
|
||||
$variable['smtp_fromname'] = array (
|
||||
'title' => t('Email from name (SMTP module)'),
|
||||
'type' => 'string',
|
||||
'description' => t('Allow for site emails to be sent from a different name.'),
|
||||
'group' => 'smtp',
|
||||
'multidomain' => TRUE,
|
||||
'localize' => TRUE,
|
||||
);
|
||||
|
||||
return $variable;
|
||||
}
|
200
sites/all/modules/smtp/tests/smtp.unit.test
Normal file
200
sites/all/modules/smtp/tests/smtp.unit.test
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Some tests for the SMTP module.
|
||||
*/
|
||||
|
||||
class SmtpUnitTest extends DrupalWebTestCase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'SMTP unit tests',
|
||||
'description' => 'Test the SMTP module.',
|
||||
'group' => 'SMTP',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function setUp(array $modules = array()) {
|
||||
// Requirements.
|
||||
$modules[] = 'smtp';
|
||||
|
||||
// Some extra logic for fully testing the module.
|
||||
$modules[] = 'smtp_tests';
|
||||
|
||||
// This module is used to log all emails so that the delivery can be
|
||||
// confirmed.
|
||||
$modules[] = 'maillog';
|
||||
|
||||
parent::setUp($modules);
|
||||
|
||||
// Take over the email system.
|
||||
variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
|
||||
|
||||
// Turn on the mail module.
|
||||
variable_set('smtp_on', TRUE);
|
||||
|
||||
// Do not actually deliver the emails.
|
||||
variable_set('smtp_deliver', FALSE);
|
||||
|
||||
// Use Maillog to log all emails.
|
||||
variable_set('maillog_log', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that SMTP has taken over the 'mail_system' variable.
|
||||
*/
|
||||
function testSetup() {
|
||||
$enabled = variable_get('mail_system', array());
|
||||
$should_be = array(
|
||||
'default-system' => 'SmtpMailSystem',
|
||||
);
|
||||
$this->assertEqual($enabled, $should_be, 'SMTP is controlling mail delivery.');
|
||||
|
||||
$delivery = variable_get('smtp_on', TRUE);
|
||||
$this->assertEqual($delivery, TRUE, 'SMTP is enabled.');
|
||||
|
||||
$delivery = variable_get('smtp_deliver', FALSE);
|
||||
$this->assertEqual($delivery, FALSE, 'Email delivery is disabled.');
|
||||
|
||||
$logging = variable_get('maillog_log', TRUE);
|
||||
$this->assertEqual($logging, TRUE, 'Email delivery is being logged.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests logging mail with maillog module.
|
||||
*/
|
||||
public function testLogging() {
|
||||
$langcode = language_default('language');
|
||||
|
||||
// This is automatically assigned by Simpletest.
|
||||
$sender = 'simpletest@example.com';
|
||||
|
||||
// Send an email.
|
||||
$to_email = 'to_test@example.com';
|
||||
$reply_email = 'reply_test@example.com';
|
||||
$params = array();
|
||||
drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
|
||||
|
||||
// The SMTP module controls the 'from' address but defaults to using the
|
||||
// site's system email address.
|
||||
$from_email = variable_get('site_mail', '');
|
||||
|
||||
// Compare the maillog db entry with the sent mail.
|
||||
$logged_email = $this->getLatestMaillogEntry();
|
||||
$this->assertTrue(!empty($logged_email), 'The test email was captured.');
|
||||
$this->assertEqual($to_email, $logged_email['header_to']);//, 'Email "to" address is correct.');
|
||||
$this->assertEqual($from_email, $logged_email['header_from']);//, 'Email "from" address is correct.');
|
||||
$this->assertEqual($from_email, $logged_email['header_all']['From']);//, 'Email "from" header is correct.');
|
||||
$this->assertEqual($sender, $logged_email['header_all']['Sender']);//, 'Email "sender" header is correct.');
|
||||
$this->assertEqual($sender, $logged_email['header_all']['Return-Path']);//, 'Email "return-path" header is correct.');
|
||||
$this->assertEqual('Drupal', $logged_email['header_all']['X-Mailer']);//, 'Email "x-mailer" header is correct.');
|
||||
$this->assertEqual(t('Test email subject'), $logged_email['subject']);//, 'Email subject is correct.');
|
||||
$this->assertEqual(t('Test email body.') . "\n", $logged_email['body']);//, 'Email body is correct.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm the queue works.
|
||||
*/
|
||||
public function testQueue() {
|
||||
// Turn on the queue.
|
||||
variable_set('smtp_queue', TRUE);
|
||||
|
||||
// Send a test message.
|
||||
$langcode = language_default('language');
|
||||
$sender = 'simpletest@example.com';
|
||||
$to_email = 'to_test@example.com';
|
||||
$reply_email = 'reply_test@example.com';
|
||||
$params = array();
|
||||
drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
|
||||
|
||||
// Check the queue for messages.
|
||||
$queue_count = $this->getQueueCount();
|
||||
$this->assertEqual($queue_count, 1, 'An email was found in the send queue.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm the queue works.
|
||||
*/
|
||||
public function testFailQueue() {
|
||||
// Turn on the queue failover.
|
||||
variable_set('smtp_queue_fail', TRUE);
|
||||
|
||||
// Make sure the queue is disabled.
|
||||
variable_set('smtp_queue', FALSE);
|
||||
|
||||
// Turn on email delivery.
|
||||
variable_set('smtp_deliver', TRUE);
|
||||
|
||||
// Set some fake values for the delivery, it should fail and then cause the
|
||||
// email to go in to the queue.
|
||||
variable_set('smtp_from', 'drupal@example.com');
|
||||
variable_set('smtp_fromname', 'Drupal Simpletest');
|
||||
variable_set('smtp_host', 'smtp.gmail.com');
|
||||
variable_set('smtp_hostbackup', '');
|
||||
variable_set('smtp_password', 'THIS WILL NOT WORK!');
|
||||
variable_set('smtp_port', '465');
|
||||
variable_set('smtp_protocol', 'ssl');
|
||||
variable_set('smtp_username', 'hello@example.com');
|
||||
|
||||
// Send a test message.
|
||||
$langcode = language_default('language');
|
||||
$sender = 'simpletest@example.com';
|
||||
$to_email = 'to_test@example.com';
|
||||
$reply_email = 'reply_test@example.com';
|
||||
$params = array();
|
||||
drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
|
||||
|
||||
// Check the queue for messages.
|
||||
$queue_count = $this->getQueueCount('smtp_failure_queue');
|
||||
$this->assertEqual($queue_count, 1, 'An email was found in the failure queue.');
|
||||
$queue_count = $this->getQueueCount();
|
||||
$this->assertEqual($queue_count, 0, 'An email was not found in the regular email queue.');
|
||||
|
||||
// Run the queue so that messages can be moved to the normal email queue.
|
||||
drupal_cron_run();
|
||||
|
||||
// Check the queue for messages.
|
||||
$queue_count = $this->getQueueCount();
|
||||
$this->assertEqual($queue_count, 1, 'An email was found in the regular email queue.');
|
||||
$queue_count = $this->getQueueCount('smtp_failure_queue');
|
||||
$this->assertEqual($queue_count, 0, 'An email was not found in the failure queue.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the latest Maillog entry.
|
||||
*
|
||||
* @return array
|
||||
* Maillog entry.
|
||||
*/
|
||||
protected function getLatestMaillogEntry() {
|
||||
$query = 'SELECT idmaillog, header_from, header_to, header_reply_to, header_all, subject, body FROM {maillog} ORDER BY idmaillog DESC';
|
||||
$result = db_query_range($query, 0, 1);
|
||||
|
||||
if ($maillog = $result->fetchAssoc()) {
|
||||
// Unserialize values.
|
||||
$maillog['header_all'] = unserialize($maillog['header_all']);
|
||||
}
|
||||
return $maillog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of emails in a specific queue.
|
||||
*
|
||||
* @param string $queue
|
||||
* The name of the queue to add the emails to.
|
||||
*
|
||||
* @return int
|
||||
* The number of messages found in the requested queue.
|
||||
*/
|
||||
protected function getQueueCount($queue = 'smtp_send_queue') {
|
||||
return db_query("SELECT count('name') FROM {queue} WHERE name = :queue",
|
||||
array(':queue' => $queue))
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
}
|
12
sites/all/modules/smtp/tests/smtp_tests.info
Normal file
12
sites/all/modules/smtp/tests/smtp_tests.info
Normal file
@@ -0,0 +1,12 @@
|
||||
name = SMTP tests
|
||||
description = Contains helper logic for the SMTP tests.
|
||||
package = Mail
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-27
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "smtp"
|
||||
datestamp = "1498593247"
|
||||
|
16
sites/all/modules/smtp/tests/smtp_tests.module
Normal file
16
sites/all/modules/smtp/tests/smtp_tests.module
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Primary hook implementations for the SMTP test helper module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_mail().
|
||||
*/
|
||||
function smtp_tests_mail($key, &$message, $params) {
|
||||
// A very rudimentary test.
|
||||
if ($key == 'smtp_basic_test') {
|
||||
$message['subject'] = t('Test email subject');
|
||||
$message['body'][] = t('Test email body.');
|
||||
}
|
||||
}
|
@@ -1,19 +1,50 @@
|
||||
CONTENTS OF THIS FILE
|
||||
---------------------
|
||||
|
||||
* Introduction
|
||||
* Requirements
|
||||
* Installation
|
||||
* Configuration
|
||||
* Recommended
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
|
||||
Welcome to Views 3. Please see the advanced help for more information.
|
||||
|
||||
If you're having trouble installing this module, please ensure that your
|
||||
tar program is not flattening the directory tree, truncating filenames
|
||||
or losing files.
|
||||
If you're having trouble installing this module, please ensure that your tar
|
||||
program is not flattening the directory tree, truncating filenames or losing
|
||||
files.
|
||||
|
||||
Installing Views:
|
||||
|
||||
Place the entirety of this directory in sites/all/modules/views
|
||||
You must also install the CTools module (http://www.drupal.org/project/ctools) to use Views.
|
||||
REQUIREMENTS
|
||||
------------
|
||||
|
||||
Navigate to administer >> build >> modules. Enable Views and Views UI.
|
||||
This module requires the following modules:
|
||||
|
||||
If you're new to Views, try the Simple Views module which can create some
|
||||
often used Views for you, this might save you some time.
|
||||
* Chaos tool suite (ctools) (https://drupal.org/project/ctools)
|
||||
|
||||
Here you can find many modules extending the functionality of Views:
|
||||
http://drupal.org/taxonomy/term/89
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Install as you would normally install a contributed Drupal module. See:
|
||||
https://drupal.org/documentation/install/modules-themes/modules-7 for further
|
||||
information.
|
||||
|
||||
Navigate to administer >> modules. Enable Views and Views UI.
|
||||
|
||||
|
||||
RECOMMENDED
|
||||
-----------
|
||||
|
||||
* SimpleViews (https://www.drupal.org/project/simpleviews):
|
||||
If you're new to Views, try the Simple Views which can create some often used
|
||||
Views for you, this might save you some time.
|
||||
|
||||
* Advanced help (https://www.drupal.org/project/advanced_help):
|
||||
If you enable the advanced help, Views will provide more and better help.
|
||||
|
||||
* Here you can find many modules extending the functionality of Views:
|
||||
http://drupal.org/taxonomy/term/89
|
||||
|
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
.form-actions {
|
||||
float: left;
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
@@ -61,7 +61,6 @@ class views_handler_area_result extends views_handler_area {
|
||||
// Calculate the page totals.
|
||||
$current_page = (int) $this->view->get_current_page() + 1;
|
||||
$per_page = (int) $this->view->get_items_per_page();
|
||||
$count = count($this->view->result);
|
||||
// @TODO: Maybe use a possible is views empty functionality.
|
||||
// Not every view has total_rows set, use view->result instead.
|
||||
$total = isset($this->view->total_rows) ? $this->view->total_rows : count($this->view->result);
|
||||
|
@@ -589,8 +589,11 @@ class views_handler_filter extends views_handler {
|
||||
form_error($form['expose']['identifier'], t('The identifier is required if the filter is exposed.'));
|
||||
}
|
||||
|
||||
if (!empty($form_state['values']['options']['expose']['identifier']) && $form_state['values']['options']['expose']['identifier'] == 'value') {
|
||||
form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
|
||||
if (!empty($form_state['values']['options']['expose']['identifier'])) {
|
||||
$illegal_identifiers = array('value', 'q');
|
||||
if (in_array($form_state['values']['options']['expose']['identifier'], $illegal_identifiers)) {
|
||||
form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->view->display_handler->is_identifier_unique($form_state['id'], $form_state['values']['options']['expose']['identifier'])) {
|
||||
@@ -607,8 +610,11 @@ class views_handler_filter extends views_handler {
|
||||
form_error($form['group_info']['identifier'], t('The identifier is required if the filter is exposed.'));
|
||||
}
|
||||
|
||||
if (!empty($form_state['values']['options']['group_info']['identifier']) && $form_state['values']['options']['group_info']['identifier'] == 'value') {
|
||||
form_error($form['group_info']['identifier'], t('This identifier is not allowed.'));
|
||||
if (!empty($form_state['values']['options']['group_info']['identifier'])) {
|
||||
$illegal_identifiers = array('value', 'q');
|
||||
if (in_array($form_state['values']['options']['group_info']['identifier'], $illegal_identifiers)) {
|
||||
form_error($form['group_info']['identifier'], t('This identifier is not allowed.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->view->display_handler->is_identifier_unique($form_state['id'], $form_state['values']['options']['group_info']['identifier'])) {
|
||||
|
@@ -18,6 +18,7 @@ function yourmodule_views_data() {
|
||||
'handler' => 'yourmodule_handler_collapsible_area_text',
|
||||
),
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
@@ -994,7 +994,7 @@ function views_ui_edit_form($form, &$form_state, $view, $display_id = NULL) {
|
||||
// @todo When more functionality is added to this form, cloning here may be
|
||||
// too soon. But some of what we do with $view later in this function
|
||||
// results in making it unserializable due to PDO limitations.
|
||||
$form_state['view'] = clone($view);
|
||||
$form_state['view'] = clone $view;
|
||||
|
||||
$form['#attached']['library'][] = array('system', 'ui.tabs');
|
||||
$form['#attached']['library'][] = array('system', 'ui.dialog');
|
||||
|
@@ -40,15 +40,18 @@ function views_ajax() {
|
||||
|
||||
// Load the view.
|
||||
$view = views_get_view($name);
|
||||
if ($view && $view->access($display_id)) {
|
||||
if ($view && $view->access($display_id) && $view->set_display($display_id) && $view->display_handler->use_ajax()) {
|
||||
// Fix 'q' for paging.
|
||||
if (!empty($path)) {
|
||||
$_GET['q'] = $path;
|
||||
}
|
||||
|
||||
// Add all $_POST data, because AJAX is always a post and many things,
|
||||
// If page parameter is in the $_POST exclude it from $_GET,
|
||||
// otherwise support views_ajax requests using $_GET.
|
||||
$exclude = isset($_POST['page']) ? array('page') : array();
|
||||
// Add all $_POST data to $_GET as many things,
|
||||
// such as tablesorts, exposed filters and paging assume $_GET.
|
||||
$_GET = $_POST + drupal_get_query_parameters($_GET, array('page'));
|
||||
$_GET = $_POST + drupal_get_query_parameters($_GET, $exclude);
|
||||
|
||||
// Overwrite the destination.
|
||||
// @see drupal_get_destination()
|
||||
@@ -343,7 +346,7 @@ function views_ajax_autocomplete_taxonomy($vid, $tags_typed = '') {
|
||||
|
||||
$query = db_select('taxonomy_term_data', 't');
|
||||
$query->addTag('translatable');
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
|
||||
// Do not select already entered terms.
|
||||
if (!empty($tags_typed)) {
|
||||
|
@@ -1544,9 +1544,16 @@ class views_join {
|
||||
|
||||
// Tack on the extra.
|
||||
if (isset($this->extra)) {
|
||||
if (is_array($this->extra)) {
|
||||
$extras = array();
|
||||
foreach ($this->extra as $info) {
|
||||
// If extra has been provided as string instead of an array, convert it
|
||||
// to an array.
|
||||
if (!is_array($this->extra)) {
|
||||
$this->extra = array($this->extra);
|
||||
}
|
||||
|
||||
$extras = array();
|
||||
foreach ($this->extra as $info) {
|
||||
if (is_array($info)) {
|
||||
$extra = '';
|
||||
// Figure out the table name. Remember, only use aliases provided
|
||||
// if at all possible.
|
||||
$join_table = '';
|
||||
@@ -1564,76 +1571,49 @@ class views_join {
|
||||
}
|
||||
}
|
||||
|
||||
// If left_field is set use it for a field-to-field condition.
|
||||
if (!empty($info['left_field'])) {
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : '=';
|
||||
$left_table = (isset($info['left_table'])) ? $info['left_table'] : $left['alias'];
|
||||
$extras[] = "$join_table$info[field] $operator $left_table.$info[left_field]";
|
||||
}
|
||||
// Else if formula is set, us it for a flexible on clause.
|
||||
elseif (!empty($info['formula'])) {
|
||||
// If a field is given, we build a "$field $op $formula".
|
||||
// Without it would only be "$formula".
|
||||
$extra = '';
|
||||
if (isset($info['field'])) {
|
||||
// With a single value, the '=' operator is implicit.
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : '=';
|
||||
$extra .= "$join_table$info[field] $operator ";
|
||||
}
|
||||
$extra .= $info['formula'];
|
||||
// Add placeholder arguments.
|
||||
if (isset($info['formula_arguments']) && is_array($info['formula_arguments'])) {
|
||||
$arguments = array_merge($arguments, $info['formula_arguments']);
|
||||
}
|
||||
$extras[] = $extra;
|
||||
}
|
||||
// Otherwise - and if we have a value - use it for a field-to-value condition.
|
||||
elseif (!empty($info['value'])) {
|
||||
// Convert a single-valued array of values to the single-value case,
|
||||
// and transform from IN() notation to = notation
|
||||
if (is_array($info['value']) && count($info['value']) == 1) {
|
||||
if (empty($info['operator'])) {
|
||||
$operator = '=';
|
||||
}
|
||||
else {
|
||||
$operator = $info['operator'] == 'NOT IN' ? '!=' : '=';
|
||||
}
|
||||
$info['value'] = array_shift($info['value']);
|
||||
}
|
||||
|
||||
if (is_array($info['value'])) {
|
||||
// With an array of values, we need multiple placeholders and the
|
||||
// 'IN' operator is implicit.
|
||||
foreach ($info['value'] as $value) {
|
||||
$placeholder_i = ':views_join_condition_' . $select_query->nextPlaceholder();
|
||||
$arguments[$placeholder_i] = $value;
|
||||
}
|
||||
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : 'IN';
|
||||
$placeholder = '( ' . implode(', ', array_keys($arguments)) . ' )';
|
||||
// Convert a single-valued array of values to the single-value case,
|
||||
// and transform from IN() notation to = notation
|
||||
if (is_array($info['value']) && count($info['value']) == 1) {
|
||||
if (empty($info['operator'])) {
|
||||
$operator = '=';
|
||||
}
|
||||
else {
|
||||
// With a single value, the '=' operator is implicit.
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : '=';
|
||||
$placeholder = ':views_join_condition_' . $select_query->nextPlaceholder();
|
||||
$arguments[$placeholder] = $info['value'];
|
||||
$operator = $info['operator'] == 'NOT IN' ? '!=' : '=';
|
||||
}
|
||||
$info['value'] = array_shift($info['value']);
|
||||
}
|
||||
|
||||
if (is_array($info['value'])) {
|
||||
// With an array of values, we need multiple placeholders and the
|
||||
// 'IN' operator is implicit.
|
||||
foreach ($info['value'] as $value) {
|
||||
$placeholder_i = $view_query->placeholder('views_join_condition_');
|
||||
$arguments[$placeholder_i] = $value;
|
||||
}
|
||||
|
||||
$extras[] = "$join_table$info[field] $operator $placeholder";
|
||||
}
|
||||
}
|
||||
|
||||
if ($extras) {
|
||||
if (count($extras) == 1) {
|
||||
$condition .= ' AND ' . array_shift($extras);
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : 'IN';
|
||||
$placeholder = '( ' . implode(', ', array_keys($arguments)) . ' )';
|
||||
}
|
||||
else {
|
||||
$condition .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
|
||||
// With a single value, the '=' operator is implicit.
|
||||
$operator = !empty($info['operator']) ? $info['operator'] : '=';
|
||||
$placeholder = $view_query->placeholder('views_join_condition_');
|
||||
$arguments[$placeholder] = $info['value'];
|
||||
}
|
||||
$extras[] = "$join_table$info[field] $operator $placeholder";
|
||||
}
|
||||
elseif (is_string($info)) {
|
||||
$extras[] = $info;
|
||||
}
|
||||
}
|
||||
elseif ($this->extra && is_string($this->extra)) {
|
||||
$condition .= " AND ($this->extra)";
|
||||
|
||||
if ($extras) {
|
||||
if (count($extras) == 1) {
|
||||
$condition .= ' AND ' . array_shift($extras);
|
||||
}
|
||||
else {
|
||||
$condition .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1681,11 +1661,19 @@ class views_join_subquery extends views_join {
|
||||
$arguments = array();
|
||||
|
||||
// Tack on the extra.
|
||||
// This is just copied verbatim from the parent class, which itself has a bug: http://drupal.org/node/1118100
|
||||
// This is just copied verbatim from the parent class, which itself has a
|
||||
// bug: http://drupal.org/node/1118100
|
||||
if (isset($this->extra)) {
|
||||
if (is_array($this->extra)) {
|
||||
$extras = array();
|
||||
foreach ($this->extra as $info) {
|
||||
// If extra has been provided as string instead of an array, convert it
|
||||
// to an array.
|
||||
if (!is_array($this->extra)) {
|
||||
$this->extra = array($this->extra);
|
||||
}
|
||||
|
||||
$extras = array();
|
||||
foreach ($this->extra as $info) {
|
||||
if (is_array($info)) {
|
||||
$extra = '';
|
||||
// Figure out the table name. Remember, only use aliases provided
|
||||
// if at all possible.
|
||||
$join_table = '';
|
||||
@@ -1713,18 +1701,18 @@ class views_join_subquery extends views_join {
|
||||
$extras[] = "$join_table$info[field] $operator $placeholder";
|
||||
$arguments[$placeholder] = $info['value'];
|
||||
}
|
||||
|
||||
if ($extras) {
|
||||
if (count($extras) == 1) {
|
||||
$condition .= ' AND ' . array_shift($extras);
|
||||
}
|
||||
else {
|
||||
$condition .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
|
||||
}
|
||||
elseif (is_string($info)) {
|
||||
$extras[] = $info;
|
||||
}
|
||||
}
|
||||
elseif ($this->extra && is_string($this->extra)) {
|
||||
$condition .= " AND ($this->extra)";
|
||||
|
||||
if ($extras) {
|
||||
if (count($extras) == 1) {
|
||||
$condition .= ' AND ' . array_shift($extras);
|
||||
}
|
||||
else {
|
||||
$condition .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -411,18 +411,8 @@ class view extends views_db_object {
|
||||
* Figure out what the exposed input for this view is.
|
||||
*/
|
||||
function get_exposed_input() {
|
||||
// Fill our input either from $_GET or from something previously set on the
|
||||
// view.
|
||||
if (empty($this->exposed_input)) {
|
||||
$this->exposed_input = $_GET;
|
||||
// unset items that are definitely not our input:
|
||||
foreach (array('page', 'q') as $key) {
|
||||
if (isset($this->exposed_input[$key])) {
|
||||
unset($this->exposed_input[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no input at all, check for remembered input via session.
|
||||
$this->exposed_input = array();
|
||||
|
||||
// If filters are not overridden, store the 'remember' settings on the
|
||||
// default display. If they are, store them on this display. This way,
|
||||
@@ -430,9 +420,17 @@ class view extends views_db_object {
|
||||
// remember settings.
|
||||
$display_id = ($this->display_handler->is_defaulted('filters')) ? 'default' : $this->current_display;
|
||||
|
||||
if (empty($this->exposed_input) && !empty($_SESSION['views'][$this->name][$display_id])) {
|
||||
// Start with remembered input via session.
|
||||
if (!empty($_SESSION['views'][$this->name][$display_id])) {
|
||||
$this->exposed_input = $_SESSION['views'][$this->name][$display_id];
|
||||
}
|
||||
|
||||
// Fetch exposed input values from $_GET. Overwrite if clashing.
|
||||
foreach ($_GET as $key => $value) {
|
||||
if (!in_array($key, array('page', 'q'))) {
|
||||
$this->exposed_input[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->exposed_input;
|
||||
@@ -685,6 +683,10 @@ class view extends views_db_object {
|
||||
*/
|
||||
function init_pager() {
|
||||
if (empty($this->query->pager)) {
|
||||
// If the query doesn't exist, initialize it.
|
||||
if (empty($this->query)) {
|
||||
$this->init_query();
|
||||
}
|
||||
$this->query->pager = $this->display_handler->get_plugin('pager');
|
||||
|
||||
if ($this->query->pager->use_pager()) {
|
||||
@@ -1282,7 +1284,7 @@ class view extends views_db_object {
|
||||
foreach ($GLOBALS['base_theme_info'] as $base) {
|
||||
$function = $base->name . '_views_post_render';
|
||||
if (function_exists($function)) {
|
||||
$function($this);
|
||||
$function($this, $this->display_handler->output, $cache);
|
||||
}
|
||||
}
|
||||
$function = $GLOBALS['theme'] . '_views_post_render';
|
||||
@@ -1478,7 +1480,7 @@ class view extends views_db_object {
|
||||
* this sets the display handler if it hasn't been.
|
||||
*/
|
||||
function access($displays = NULL, $account = NULL) {
|
||||
// Noone should have access to disabled views.
|
||||
// No one should have access to disabled views.
|
||||
if (!empty($this->disabled)) {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1960,12 +1962,12 @@ class view extends views_db_object {
|
||||
* The cloned view.
|
||||
*/
|
||||
function clone_view() {
|
||||
$clone = version_compare(phpversion(), '5.0') < 0 ? $this : clone($this);
|
||||
$clone = clone $this;
|
||||
|
||||
$keys = array('current_display', 'display_handler', 'build_info', 'built', 'executed', 'attachment_before', 'attachment_after', 'field', 'argument', 'filter', 'sort', 'relationship', 'header', 'footer', 'empty', 'query', 'inited', 'style_plugin', 'plugin_name', 'exposed_data', 'exposed_input', 'exposed_widgets', 'many_to_one_tables', 'feed_icon');
|
||||
foreach ($keys as $key) {
|
||||
if (isset($clone->$key)) {
|
||||
unset($clone->$key);
|
||||
if (isset($clone->{$key})) {
|
||||
unset($clone->{$key});
|
||||
}
|
||||
}
|
||||
$clone->built = $clone->executed = FALSE;
|
||||
@@ -1994,7 +1996,7 @@ class view extends views_db_object {
|
||||
*/
|
||||
function destroy() {
|
||||
foreach (array_keys($this->display) as $display_id) {
|
||||
if (isset($this->display[$display_id]->handler)) {
|
||||
if (isset($this->display[$display_id]->handler) && is_object($this->display[$display_id]->handler)) {
|
||||
$this->display[$display_id]->handler->destroy();
|
||||
unset($this->display[$display_id]->handler);
|
||||
}
|
||||
|
@@ -60,6 +60,9 @@ Drupal.views.ajaxView = function(settings) {
|
||||
this.$exposed_form = $('#views-exposed-form-'+ settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'));
|
||||
this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this));
|
||||
|
||||
// Store Drupal.ajax objects here for all pager links.
|
||||
this.links = [];
|
||||
|
||||
// Add the ajax to pagers.
|
||||
this.$view
|
||||
// Don't attach to nested views. Doing so would attach multiple behaviors
|
||||
@@ -123,6 +126,7 @@ Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function(id, link) {
|
||||
|
||||
this.element_settings.submit = viewData;
|
||||
this.pagerAjax = new Drupal.ajax(false, $link, this.element_settings);
|
||||
this.links.push(this.pagerAjax);
|
||||
};
|
||||
|
||||
Drupal.ajax.prototype.commands.viewsScrollTop = function (ajax, response, status) {
|
||||
|
@@ -64,6 +64,11 @@ Drupal.Views.parseQueryString = function (query) {
|
||||
* Helper function to return a view's arguments based on a path.
|
||||
*/
|
||||
Drupal.Views.parseViewArgs = function (href, viewPath) {
|
||||
|
||||
// Provide language prefix.
|
||||
if (Drupal.settings.pathPrefix) {
|
||||
var viewPath = Drupal.settings.pathPrefix + viewPath;
|
||||
}
|
||||
var returnObj = {};
|
||||
var path = Drupal.Views.getPath(href);
|
||||
// Ensure we have a correct path.
|
||||
@@ -99,7 +104,7 @@ Drupal.Views.getPath = function (href) {
|
||||
href = href.substring(3, href.length);
|
||||
}
|
||||
var chars = ['#', '?', '&'];
|
||||
for (i in chars) {
|
||||
for (var i in chars) {
|
||||
if (href.indexOf(chars[i]) > -1) {
|
||||
href = href.substr(0, href.indexOf(chars[i]));
|
||||
}
|
||||
|
@@ -168,6 +168,59 @@ function comment_views_data() {
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_fulldata'] = array(
|
||||
'title' => t('Created date'),
|
||||
'help' => t('Date in the form of CCYYMMDD.'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_fulldate',
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_year_month'] = array(
|
||||
'title' => t('Created year + month'),
|
||||
'help' => t('Date in the form of YYYYMM.'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_year_month',
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_year'] = array(
|
||||
'title' => t('Created year'),
|
||||
'help' => t('Date in the form of YYYY.'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_year',
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_month'] = array(
|
||||
'title' => t('Created month'),
|
||||
'help' => t('Date in the form of MM (01 - 12).'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_month',
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_day'] = array(
|
||||
'title' => t('Created day'),
|
||||
'help' => t('Date in the form of DD (01 - 31).'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_day',
|
||||
),
|
||||
);
|
||||
|
||||
$data['comment']['created_week'] = array(
|
||||
'title' => t('Created week'),
|
||||
'help' => t('Date in the form of WW (01 - 53).'),
|
||||
'argument' => array(
|
||||
'field' => 'created',
|
||||
'handler' => 'views_handler_argument_node_created_week',
|
||||
),
|
||||
);
|
||||
|
||||
// Language field
|
||||
if (module_exists('locale')) {
|
||||
@@ -209,7 +262,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_fulldate']['moved to'] = array('comment', 'changed_fulldata');
|
||||
$data['comment']['changed_fulldata'] = array(
|
||||
'title' => t('Created date'),
|
||||
'title' => t('Changed date'),
|
||||
'help' => t('Date in the form of CCYYMMDD.'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
@@ -219,7 +272,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_year_month']['moved to'] = array('comment', 'changed_year_month');
|
||||
$data['comment']['changed_year_month'] = array(
|
||||
'title' => t('Created year + month'),
|
||||
'title' => t('Changed year + month'),
|
||||
'help' => t('Date in the form of YYYYMM.'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
@@ -229,7 +282,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_year']['moved to'] = array('comment', 'changed_year');
|
||||
$data['comment']['changed_year'] = array(
|
||||
'title' => t('Created year'),
|
||||
'title' => t('Changed year'),
|
||||
'help' => t('Date in the form of YYYY.'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
@@ -239,7 +292,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_month']['moved to'] = array('comment', 'changed_month');
|
||||
$data['comment']['changed_month'] = array(
|
||||
'title' => t('Created month'),
|
||||
'title' => t('Changed month'),
|
||||
'help' => t('Date in the form of MM (01 - 12).'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
@@ -249,7 +302,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_day']['moved to'] = array('comment', 'changed_day');
|
||||
$data['comment']['changed_day'] = array(
|
||||
'title' => t('Created day'),
|
||||
'title' => t('Changed day'),
|
||||
'help' => t('Date in the form of DD (01 - 31).'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
@@ -259,7 +312,7 @@ function comment_views_data() {
|
||||
|
||||
$data['comments']['timestamp_week']['moved to'] = array('comment', 'changed_week');
|
||||
$data['comment']['changed_week'] = array(
|
||||
'title' => t('Created week'),
|
||||
'title' => t('Changed week'),
|
||||
'help' => t('Date in the form of WW (01 - 53).'),
|
||||
'argument' => array(
|
||||
'field' => 'changed',
|
||||
|
@@ -733,7 +733,7 @@ function node_row_node_view_preprocess_node(&$vars) {
|
||||
unset($vars['content']['links']);
|
||||
}
|
||||
|
||||
if (!empty($options['comments']) && user_access('access comments') && $node->comment) {
|
||||
if (module_exists('comment') && !empty($options['comments']) && user_access('access comments') && $node->comment) {
|
||||
$vars['content']['comments'] = comment_node_page_additions($node);
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,10 @@ class views_handler_argument_node_created_fulldate extends views_handler_argumen
|
||||
* Provide a link to the next level of the view
|
||||
*/
|
||||
function title() {
|
||||
return format_date(strtotime($this->argument . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
|
||||
$timestamp = strtotime($this->argument . " 00:00:00 UTC");
|
||||
if ($timestamp !== FALSE) {
|
||||
return format_date($timestamp, 'custom', $this->format, 'UTC');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +80,10 @@ class views_handler_argument_node_created_year_month extends views_handler_argum
|
||||
* Provide a link to the next level of the view
|
||||
*/
|
||||
function title() {
|
||||
return format_date(strtotime($this->argument . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
|
||||
$timestamp = strtotime($this->argument . "15" . " 00:00:00 UTC");
|
||||
if ($timestamp !== FALSE) {
|
||||
return format_date($timestamp, 'custom', $this->format, 'UTC');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +114,10 @@ class views_handler_argument_node_created_month extends views_handler_argument_d
|
||||
*/
|
||||
function title() {
|
||||
$month = str_pad($this->argument, 2, '0', STR_PAD_LEFT);
|
||||
return format_date(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
|
||||
$timestamp = strtotime("2005" . $month . "15" . " 00:00:00 UTC");
|
||||
if ($timestamp !== FALSE) {
|
||||
return format_date($timestamp, 'custom', $this->format, 'UTC');
|
||||
}
|
||||
}
|
||||
|
||||
function summary_argument($data) {
|
||||
@@ -145,7 +154,10 @@ class views_handler_argument_node_created_day extends views_handler_argument_dat
|
||||
*/
|
||||
function title() {
|
||||
$day = str_pad($this->argument, 2, '0', STR_PAD_LEFT);
|
||||
return format_date(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
|
||||
$timestamp = strtotime("2005" . "05" . $day . " 00:00:00 UTC");
|
||||
if ($timestamp !== FALSE) {
|
||||
return format_date($timestamp, 'custom', $this->format, 'UTC');
|
||||
}
|
||||
}
|
||||
|
||||
function summary_argument($data) {
|
||||
|
@@ -61,6 +61,7 @@ class views_plugin_row_node_view extends views_plugin_row {
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Display comments'),
|
||||
'#default_value' => $this->options['comments'],
|
||||
'#access' => module_exists('comment'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -107,4 +108,4 @@ class views_plugin_row_node_view extends views_plugin_row {
|
||||
return drupal_render($build);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,14 +43,14 @@ function search_views_data() {
|
||||
'left_table' => 'search_index',
|
||||
'left_field' => 'sid',
|
||||
'field' => 'sid',
|
||||
'extra' => 'search_index.type = search_dataset.type',
|
||||
'extra' => array('search_index.type = search_dataset.type'),
|
||||
'type' => 'INNER',
|
||||
),
|
||||
'users' => array(
|
||||
'left_table' => 'search_index',
|
||||
'left_field' => 'sid',
|
||||
'field' => 'sid',
|
||||
'extra' => 'search_index.type = search_dataset.type',
|
||||
'extra' => array('search_index.type = search_dataset.type'),
|
||||
'type' => 'INNER',
|
||||
),
|
||||
);
|
||||
|
@@ -42,7 +42,7 @@ class views_handler_argument_search extends views_handler_argument {
|
||||
}
|
||||
}
|
||||
if ($required) {
|
||||
if ($this->operator == 'required') {
|
||||
if (isset($this->operator) && ($this->operator == 'required')) {
|
||||
$this->query->add_where(0, 'FALSE');
|
||||
}
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ class views_handler_filter_search extends views_handler_filter {
|
||||
$form['remove_score'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Remove search score'),
|
||||
'#description' => t('Check this box to remove the search score from the query. This can help reduce help reduce duplicate search results when using this filter.'),
|
||||
'#description' => t('Check this box to remove the search score from the query. This can help reduce duplicate search results when using this filter.'),
|
||||
'#default_value' => $this->options['remove_score'],
|
||||
);
|
||||
}
|
||||
|
@@ -114,7 +114,7 @@ function taxonomy_views_data() {
|
||||
'field' => 'tid',
|
||||
'title' => t('Term'),
|
||||
'help' => t('Taxonomy terms are attached to nodes.'),
|
||||
'access query tag' => 'term_access',
|
||||
'access query tag' => 'taxonomy_term_access',
|
||||
);
|
||||
$data['taxonomy_term_data']['table']['entity type'] = 'taxonomy_term';
|
||||
|
||||
|
@@ -38,6 +38,7 @@ class views_handler_argument_term_node_tid extends views_handler_argument_many_t
|
||||
function title_query() {
|
||||
$titles = array();
|
||||
$result = db_select('taxonomy_term_data', 'td')
|
||||
->addTag('taxonomy_term_access')
|
||||
->fields('td', array('name'))
|
||||
->condition('td.tid', $this->value)
|
||||
->execute();
|
||||
|
@@ -22,6 +22,7 @@ class views_handler_field_taxonomy extends views_handler_field {
|
||||
parent::construct();
|
||||
$this->additional_fields['vid'] = 'vid';
|
||||
$this->additional_fields['tid'] = 'tid';
|
||||
$this->additional_fields['name'] = 'name';
|
||||
$this->additional_fields['vocabulary_machine_name'] = array(
|
||||
'table' => 'taxonomy_vocabulary',
|
||||
'field' => 'machine_name',
|
||||
@@ -65,10 +66,18 @@ class views_handler_field_taxonomy extends views_handler_field {
|
||||
$term = new stdClass();
|
||||
$term->tid = $tid;
|
||||
$term->vid = $this->get_value($values, 'vid');
|
||||
$term->name = $this->get_value($values, 'name');
|
||||
$term->vocabulary_machine_name = $values->{$this->aliases['vocabulary_machine_name']};
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
$uri = entity_uri('taxonomy_term', $term);
|
||||
if (isset($uri['options'])) {
|
||||
$this->options['alter'] = array_merge($this->options['alter'], $uri['options']);
|
||||
}
|
||||
$this->options['alter']['path'] = $uri['path'];
|
||||
// If entity_uri() returned an options array, use it.
|
||||
if (isset($uri['options'])) {
|
||||
$this->options['alter'] = $uri['options'] + $this->options['alter'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->options['convert_spaces'])) {
|
||||
|
@@ -104,7 +104,7 @@ class views_handler_field_term_node_tid extends views_handler_field_prerender_li
|
||||
$query->orderby('td.weight');
|
||||
$query->orderby('td.name');
|
||||
$query->condition('tn.nid', $nids);
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$vocabs = array_filter($this->options['vocabularies']);
|
||||
if (!empty($this->options['limit']) && !empty($vocabs)) {
|
||||
$query->condition('tv.machine_name', $vocabs);
|
||||
|
@@ -140,7 +140,7 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
|
||||
$query->orderby('tv.name');
|
||||
$query->orderby('td.weight');
|
||||
$query->orderby('td.name');
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
if ($this->options['limit']) {
|
||||
$query->condition('tv.machine_name', $vocabulary->machine_name);
|
||||
}
|
||||
@@ -275,7 +275,7 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
|
||||
|
||||
// We only validate if they've chosen the text field style.
|
||||
if ($this->options['type'] != 'textfield') {
|
||||
if ($form_state['values'][$identifier] != 'All') {
|
||||
if (isset($form_state['values'][$identifier]) && $form_state['values'][$identifier] != 'All') {
|
||||
$this->validated_exposed_input = (array) $form_state['values'][$identifier];
|
||||
}
|
||||
return;
|
||||
@@ -328,7 +328,7 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
|
||||
$query->fields('td');
|
||||
$query->condition('td.name', $names);
|
||||
$query->condition('tv.machine_name', $this->options['vocabulary']);
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$result = $query->execute();
|
||||
foreach ($result as $term) {
|
||||
unset($missing[strtolower($term->name)]);
|
||||
|
@@ -76,7 +76,7 @@ class views_handler_relationship_node_term_data extends views_handler_relationsh
|
||||
$query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
|
||||
$query->condition('tv.machine_name', array_filter($this->options['vocabularies']));
|
||||
if (empty($this->query->options['disable_sql_rewrite'])) {
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
}
|
||||
$query->fields('td');
|
||||
$query->fields('tn', array('nid'));
|
||||
|
@@ -97,7 +97,7 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
|
||||
$query->leftJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
|
||||
$query->fields('td');
|
||||
$query->condition('td.tid', $argument);
|
||||
$query->addTag('term_access');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$term = $query->execute()->fetchObject();
|
||||
if (!$term) {
|
||||
return FALSE;
|
||||
@@ -139,6 +139,7 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
|
||||
// if unverified tids left - verify them and cache results
|
||||
if (count($test)) {
|
||||
$query = db_select('taxonomy_term_data', 'td');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->leftJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
|
||||
$query->fields('td');
|
||||
$query->fields('tv', array('machine_name'));
|
||||
@@ -167,6 +168,7 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
|
||||
case 'name':
|
||||
case 'convert':
|
||||
$query = db_select('taxonomy_term_data', 'td');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->leftJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
|
||||
$query->fields('td');
|
||||
$query->fields('tv', array('machine_name'));
|
||||
@@ -202,6 +204,7 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
|
||||
$arg_keys = array_flip($args);
|
||||
|
||||
$query = db_select('taxonomy_term_data', 'td');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->condition('tid', $args);
|
||||
$query->addField('td', 'tid', 'tid');
|
||||
if (!empty($vocabularies)) {
|
||||
|
@@ -74,7 +74,7 @@ class views_handler_field_user_name extends views_handler_field_user {
|
||||
}
|
||||
}
|
||||
// If we want a formatted username, do that.
|
||||
if (!empty($this->options['format_username'])) {
|
||||
if (!empty($this->options['format_username']) && !is_null($account->uid)) {
|
||||
return format_username($account);
|
||||
}
|
||||
// Otherwise, there's no special handling, so return the data directly.
|
||||
|
@@ -34,7 +34,7 @@ class views_plugin_row_user_view extends views_plugin_row {
|
||||
'#title' => t('View mode'),
|
||||
'#default_value' => $this->options['view_mode'],
|
||||
);
|
||||
$form['help']['#markup'] = t("Display the user with standard user view. It might be necessary to add a user-profile.tpl.php in your themes template folder, because the default <a href=\"@user-profile-api-link\">user-profile</a>e template don't show the username per default.", array('@user-profile-api-link' => url('http://api.drupal.org/api/drupal/modules--user--user-profile.tpl.php/7')));
|
||||
$form['help']['#markup'] = t("Display the user with standard user view. It might be necessary to add a user-profile.tpl.php in your theme's template folder, because the default <a href=\"@user-profile-api-link\">user-profile</a> template doesn't show the username by default.", array('@user-profile-api-link' => url('http://api.drupal.org/api/drupal/modules--user--user-profile.tpl.php/7')));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -109,7 +109,7 @@ function views_views_data() {
|
||||
|
||||
$data['views']['combine'] = array(
|
||||
'title' => t('Combine fields filter'),
|
||||
'help' => t('Combine two fields together and search by them.'),
|
||||
'help' => t('Combine multiple fields together and search by them.'),
|
||||
'filter' => array(
|
||||
'handler' => 'views_handler_filter_combine',
|
||||
),
|
||||
|
@@ -289,7 +289,14 @@ class views_plugin_cache extends views_plugin {
|
||||
|
||||
function get_results_key() {
|
||||
if (!isset($this->_results_key)) {
|
||||
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . $this->get_cache_key();
|
||||
$key_data = array();
|
||||
foreach (array('exposed_info', 'page', 'sort', 'order', 'items_per_page', 'offset') as $key) {
|
||||
if (isset($_GET[$key])) {
|
||||
$key_data[$key] = $_GET[$key];
|
||||
}
|
||||
}
|
||||
|
||||
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . $this->get_cache_key($key_data);
|
||||
}
|
||||
|
||||
return $this->_results_key;
|
||||
@@ -298,6 +305,7 @@ class views_plugin_cache extends views_plugin {
|
||||
function get_output_key() {
|
||||
if (!isset($this->_output_key)) {
|
||||
$key_data = array(
|
||||
'result' => $this->view->result,
|
||||
'theme' => $GLOBALS['theme'],
|
||||
);
|
||||
$this->_output_key = $this->view->name . ':' . $this->display->id . ':output:' . $this->get_cache_key($key_data);
|
||||
|
@@ -41,7 +41,7 @@ class views_plugin_cache_time extends views_plugin_cache {
|
||||
'#maxlength' => '30',
|
||||
'#description' => t('Length of time in seconds raw query results should be cached.'),
|
||||
'#default_value' => $this->options['results_lifespan_custom'],
|
||||
'#process' => array('form_process_select','ctools_dependent_process'),
|
||||
'#process' => array('ctools_dependent_process'),
|
||||
'#dependency' => array(
|
||||
'edit-cache-options-results-lifespan' => array('custom'),
|
||||
),
|
||||
@@ -60,7 +60,7 @@ class views_plugin_cache_time extends views_plugin_cache {
|
||||
'#maxlength' => '30',
|
||||
'#description' => t('Length of time in seconds rendered HTML output should be cached.'),
|
||||
'#default_value' => $this->options['output_lifespan_custom'],
|
||||
'#process' => array('form_process_select','ctools_dependent_process'),
|
||||
'#process' => array('ctools_dependent_process'),
|
||||
'#dependency' => array(
|
||||
'edit-cache-options-output-lifespan' => array('custom'),
|
||||
),
|
||||
|
@@ -365,6 +365,19 @@ class views_plugin_display extends views_plugin {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the enabled display more link being opened in an new window?
|
||||
*
|
||||
* @codingStandardsIgnoreStart
|
||||
*/
|
||||
function use_more_open_new_window() {
|
||||
// @codingStandardsIgnoreEnd
|
||||
if (!empty($this->definition['use more'])) {
|
||||
return $this->get_option('open_new_window');
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the display have custom link text?
|
||||
*/
|
||||
@@ -414,9 +427,29 @@ class views_plugin_display extends views_plugin {
|
||||
'hide_admin_links' => array('hide_admin_links'),
|
||||
'group_by' => array('group_by'),
|
||||
'query' => array('query'),
|
||||
'use_more' => array('use_more', 'use_more_always', 'use_more_text'),
|
||||
'use_more_always' => array('use_more', 'use_more_always', 'use_more_text'),
|
||||
'use_more_text' => array('use_more', 'use_more_always', 'use_more_text'),
|
||||
'use_more' => array('use_more',
|
||||
'use_more_always',
|
||||
'open_new_window',
|
||||
'use_more_text',
|
||||
),
|
||||
'use_more_always' => array(
|
||||
'use_more',
|
||||
'use_more_always',
|
||||
'open_new_window',
|
||||
'use_more_text',
|
||||
),
|
||||
'use_more_text' => array(
|
||||
'use_more',
|
||||
'use_more_always',
|
||||
'open_new_window',
|
||||
'use_more_text',
|
||||
),
|
||||
'open_new_window' => array(
|
||||
'use_more',
|
||||
'use_more_always',
|
||||
'open_new_window',
|
||||
'use_more_text',
|
||||
),
|
||||
'link_display' => array('link_display', 'link_url'),
|
||||
|
||||
// Force these to cascade properly.
|
||||
@@ -481,6 +514,7 @@ class views_plugin_display extends views_plugin {
|
||||
'pager_options' => TRUE,
|
||||
'use_more' => TRUE,
|
||||
'use_more_always' => TRUE,
|
||||
'open_new_window' => FALSE,
|
||||
'use_more_text' => TRUE,
|
||||
'exposed_form' => TRUE,
|
||||
'exposed_form_options' => TRUE,
|
||||
@@ -1061,6 +1095,11 @@ class views_plugin_display extends views_plugin {
|
||||
$title = $text;
|
||||
}
|
||||
|
||||
// Truncate the path as it is displayed as a link.
|
||||
if ($section == 'path') {
|
||||
$text = views_ui_truncate($text, 24);
|
||||
}
|
||||
|
||||
return l($text, 'admin/structure/views/nojs/display/' . $this->view->name . '/' . $this->display->id . '/' . $section, array('attributes' => array('class' => 'views-ajax-link ' . $class, 'title' => $title, 'id' => drupal_html_id('views-' . $this->display->id . '-' . $section)), 'html' => TRUE));
|
||||
}
|
||||
|
||||
@@ -1468,7 +1507,7 @@ class views_plugin_display extends views_plugin {
|
||||
$form['#title'] .= t('The title of this view');
|
||||
$form['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#description' => t('This title will be displayed with the view, wherever titles are normally displayed; i.e, as the page title, block title, etc.'),
|
||||
'#description' => t('This title will be displayed with the view, wherever titles are normally displayed; i.e, as the page title, block title, etc. Use <none> to not assign a title; this can allow other modules to control the page title.'),
|
||||
'#default_value' => $this->get_option('title'),
|
||||
);
|
||||
break;
|
||||
@@ -1524,6 +1563,17 @@ class views_plugin_display extends views_plugin {
|
||||
'edit-use-more' => array(TRUE),
|
||||
),
|
||||
);
|
||||
|
||||
$form['open_new_window'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t("Open 'more' link in new window (target='blank')"),
|
||||
'#description' => t("Leave this unchecked to open the more link in the same window."),
|
||||
'#default_value' => $this->get_option('open_new_window'),
|
||||
'#dependency' => array(
|
||||
'edit-use-more' => array(TRUE),
|
||||
),
|
||||
);
|
||||
|
||||
$form['use_more_text'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('More link text'),
|
||||
@@ -2381,6 +2431,7 @@ class views_plugin_display extends views_plugin {
|
||||
case 'use_more':
|
||||
$this->set_option($section, intval($form_state['values'][$section]));
|
||||
$this->set_option('use_more_always', !intval($form_state['values']['use_more_always']));
|
||||
$this->set_option('open_new_window', $form_state['values']['open_new_window']) == '1';
|
||||
$this->set_option('use_more_text', $form_state['values']['use_more_text']);
|
||||
case 'distinct':
|
||||
$this->set_option($section, $form_state['values'][$section]);
|
||||
@@ -2594,7 +2645,7 @@ class views_plugin_display extends views_plugin {
|
||||
|
||||
$path = check_url(url($path, $url_options));
|
||||
|
||||
return theme($theme, array('more_url' => $path, 'link_text' => check_plain($this->use_more_text()), 'view' => $this->view));
|
||||
return theme($theme, array('more_url' => $path, 'new_window' => $this->use_more_open_new_window(), 'link_text' => check_plain($this->use_more_text()), 'view' => $this->view));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2798,7 +2849,7 @@ class views_plugin_display extends views_plugin {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($id != $key && $identifier == $handler->options['expose']['identifier']) {
|
||||
if ($id != $key && isset($handler->options['expose']['identifier']) && $identifier == $handler->options['expose']['identifier']) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@@ -52,7 +52,8 @@ class views_plugin_display_block extends views_plugin_display {
|
||||
// Prior to this being called, the $view should already be set to this
|
||||
// display, and arguments should be set on the view.
|
||||
$info['content'] = $this->view->render();
|
||||
$info['subject'] = filter_xss_admin($this->view->get_title());
|
||||
$title = $this->view->get_title();
|
||||
$info['subject'] = ($title == '<none>') ? '' : filter_xss_admin($title);
|
||||
if (!empty($this->view->result) || $this->get_option('empty') || !empty($this->view->style_plugin->definition['even empty'])) {
|
||||
return $info;
|
||||
}
|
||||
|
@@ -118,6 +118,8 @@ class views_plugin_display_page extends views_plugin_display {
|
||||
'access arguments' => $access_arguments,
|
||||
// Identify URL embedded arguments and correlate them to a handler
|
||||
'load arguments' => array($this->view->name, $this->display->id, '%index'),
|
||||
// Make sure the menu router knows where views_page is.
|
||||
'module' => 'views',
|
||||
);
|
||||
$menu = $this->get_option('menu');
|
||||
if (empty($menu)) {
|
||||
@@ -182,6 +184,8 @@ class views_plugin_display_page extends views_plugin_display {
|
||||
'title' => $tab_options['title'],
|
||||
'description' => $tab_options['description'],
|
||||
'menu_name' => $tab_options['name'],
|
||||
// Make sure the menu router knows where views_page is.
|
||||
'module' => 'views',
|
||||
);
|
||||
switch ($tab_options['type']) {
|
||||
default:
|
||||
@@ -231,7 +235,13 @@ class views_plugin_display_page extends views_plugin_display {
|
||||
|
||||
// First execute the view so it's possible to get tokens for the title.
|
||||
// And the title, which is much easier.
|
||||
drupal_set_title(filter_xss_admin($this->view->get_title()), PASS_THROUGH);
|
||||
$title = $this->view->get_title();
|
||||
// Support the core method of using '<none>' to indicate nothing should be
|
||||
// assigned to the title, so only process the title value if it is not that
|
||||
// value.
|
||||
if ($title != '<none>') {
|
||||
drupal_set_title(filter_xss_admin($title), PASS_THROUGH);
|
||||
}
|
||||
return $render;
|
||||
}
|
||||
|
||||
@@ -263,7 +273,7 @@ class views_plugin_display_page extends views_plugin_display {
|
||||
$options['path'] = array(
|
||||
'category' => 'page',
|
||||
'title' => t('Path'),
|
||||
'value' => views_ui_truncate($path, 24),
|
||||
'value' => $path,
|
||||
);
|
||||
|
||||
$menu = $this->get_option('menu');
|
||||
|
@@ -417,7 +417,7 @@ class views_plugin_pager_full extends views_plugin_pager {
|
||||
function exposed_form_validate(&$form, &$form_state) {
|
||||
if (!empty($form_state['values']['offset']) && trim($form_state['values']['offset'])) {
|
||||
if (!is_numeric($form_state['values']['offset']) || $form_state['values']['offset'] < 0) {
|
||||
form_set_error('offset', t('Offset must be an number greather or equal than 0.'));
|
||||
form_set_error('offset', t('Offset must be an number greater or equal than 0.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,6 +39,9 @@ class views_plugin_query extends views_plugin {
|
||||
*
|
||||
* @param $get_count
|
||||
* Provide a countquery if this is true, otherwise provide a normal query.
|
||||
*
|
||||
* @return SelectQuery
|
||||
* A SelectQuery object.
|
||||
*/
|
||||
function query($get_count = FALSE) { }
|
||||
|
||||
|
@@ -1244,6 +1244,9 @@ class views_plugin_query_default extends views_plugin_query {
|
||||
*
|
||||
* @param $get_count
|
||||
* Provide a countquery if this is true, otherwise provide a normal query.
|
||||
*
|
||||
* @return SelectQuery
|
||||
* A SelectQuery object.
|
||||
*/
|
||||
function query($get_count = FALSE) {
|
||||
// Check query distinct value.
|
||||
@@ -1367,7 +1370,7 @@ class views_plugin_query_default extends views_plugin_query {
|
||||
}
|
||||
|
||||
// Add all query substitutions as metadata.
|
||||
$query->addMetaData('views_substitutions', module_invoke_all('views_query_substitutions', $this));
|
||||
$query->addMetaData('views_substitutions', module_invoke_all('views_query_substitutions', $this->view));
|
||||
|
||||
if (!$get_count) {
|
||||
if (!empty($this->limit) || !empty($this->offset)) {
|
||||
|
@@ -130,7 +130,7 @@ class views_plugin_style extends views_plugin {
|
||||
// Explode the value by whitespace, this allows the function to handle
|
||||
// a single class name and multiple class names that are then tokenized.
|
||||
foreach(explode(' ', $class) as $token_class) {
|
||||
$classes[] = strip_tags($this->tokenize_value($token_class, $row_index));
|
||||
$classes = array_merge($classes, explode(' ', strip_tags($this->tokenize_value($token_class, $row_index))));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -139,7 +139,7 @@ class views_plugin_style extends views_plugin {
|
||||
|
||||
// Convert whatever the result is to a nice clean class name
|
||||
foreach ($classes as &$class) {
|
||||
$class = drupal_html_class($class);
|
||||
$class = drupal_clean_css_identifier($class);
|
||||
}
|
||||
return implode(' ', $classes);
|
||||
}
|
||||
@@ -237,6 +237,7 @@ class views_plugin_style extends views_plugin {
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Remove tags from rendered output'),
|
||||
'#default_value' => $grouping['rendered_strip'],
|
||||
'#description' => t('Some modules add HTML to the rendered output and prevent the rows from grouping correctly. Stripping the HTML tags should correct this.'),
|
||||
'#dependency' => array(
|
||||
'edit-style-options-grouping-' . $i . '-field' => array_keys($field_labels),
|
||||
)
|
||||
|
@@ -146,7 +146,7 @@ class views_plugin_style_jump_menu extends views_plugin_style {
|
||||
$lookup_options = array();
|
||||
// We need to check if the path is absolute
|
||||
// or else language is not taken in account.
|
||||
if ($this->view->display[$this->view->current_display]->display_options['fields'][$this->options['path']]['absolute']) {
|
||||
if (!empty($this->view->display[$this->view->current_display]->display_options['fields'][$this->options['path']]['absolute'])) {
|
||||
$lookup_options['absolute'] = TRUE;
|
||||
}
|
||||
$lookup_url = url($_GET['q'], $lookup_options);
|
||||
|
@@ -84,7 +84,8 @@ abstract class views_plugin_style_mapping extends views_plugin_style {
|
||||
// Optionally filter the available fields.
|
||||
if (isset($mapping[$key]['#filter'])) {
|
||||
$this->view->init_handlers();
|
||||
$this::$mapping[$key]['#filter']($field_options);
|
||||
$filter = $mapping[$key]['#filter'];
|
||||
$this::$filter($field_options);
|
||||
unset($mapping[$key]['#filter']);
|
||||
}
|
||||
|
||||
|
@@ -252,11 +252,11 @@ class ViewsPluginStyleTestCase extends ViewsPluginStyleTestBase {
|
||||
foreach ($rows as $row) {
|
||||
$attributes = $row->attributes();
|
||||
$class = (string) $attributes['class'][0];
|
||||
$this->assertTrue(strpos($class, $random_name) !== FALSE, 'Take sure that a custom css class is added to the output.');
|
||||
$this->assertTrue(strpos($class, $random_name) !== FALSE, 'Make sure that a custom css class is added to the output.');
|
||||
|
||||
// Check token replacement.
|
||||
$name = drupal_html_class($view->field['name']->get_value($view->result[$count]));
|
||||
$this->assertTrue(strpos($class, "test-token-$name") !== FALSE, 'Take sure that a token in custom css class is replaced.');
|
||||
$name = drupal_clean_css_identifier($view->field['name']->get_value($view->result[$count]));
|
||||
$this->assertTrue(strpos($class, "test-token-$name") !== FALSE, 'Make sure that a token in custom css class is replaced.');
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
109
sites/all/modules/views/tests/views_ajax.test
Normal file
109
sites/all/modules/views/tests/views_ajax.test
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Definition of ViewsAjaxTest.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests views ajax display.
|
||||
*/
|
||||
class ViewsAjaxTest extends ViewsSqlTest {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Ajax',
|
||||
'description' => 'Test views with and without ajax enabled.',
|
||||
'group' => 'Views Handlers',
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp('views', 'views_test');
|
||||
// Create a second node.
|
||||
$this->drupalCreateNode(array('type' => 'article', 'status' => NODE_PUBLISHED));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a simple AJAX POST HTTP request.
|
||||
*
|
||||
* @param string $path
|
||||
* Drupal path where the request should be POSTed.
|
||||
* @param string $accept
|
||||
* The value for the "Accept" header. Usually either 'application/json' or
|
||||
* 'application/vnd.drupal-ajax'.
|
||||
* @param array $post
|
||||
* The POST data. When making a 'application/vnd.drupal-ajax' request, the
|
||||
* Ajax page state data should be included. Use getAjaxPageStatePostData()
|
||||
* for that.
|
||||
*
|
||||
* @return
|
||||
* The content returned from the call to curl_exec().
|
||||
*/
|
||||
public function simpleAjaxPost($path, $accept, $post = array()) {
|
||||
$options['absolute'] = TRUE;
|
||||
foreach ($post as $key => $value) {
|
||||
// Encode according to application/x-www-form-urlencoded
|
||||
// Both names and values needs to be urlencoded, according to
|
||||
// http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
|
||||
$post[$key] = urlencode($key) . '=' . urlencode($value);
|
||||
}
|
||||
$postfields = implode('&', $post);
|
||||
$headers = array(
|
||||
'Accept: ' . $accept,
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
);
|
||||
return $this->curlExec(array(
|
||||
CURLOPT_URL => url($path, $options),
|
||||
CURLOPT_POST => TRUE,
|
||||
CURLOPT_POSTFIELDS => $postfields,
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an ajax and non-ajax view.
|
||||
*/
|
||||
public function testAjaxView() {
|
||||
$this->drupalCreateNode();
|
||||
$this->drupalGet('test_ajax_view');
|
||||
$drupal_settings = $this->drupalGetSettings();
|
||||
$this->assertTrue(isset($drupal_settings['views']['ajax_path']), 'The Ajax callback path is set in drupalSettings.');
|
||||
$this->assertEqual(count($drupal_settings['views']['ajaxViews']), 1);
|
||||
$view_entry = current(array_keys($drupal_settings['views']['ajaxViews']));
|
||||
$this->assertEqual($drupal_settings['views']['ajaxViews'][$view_entry]['view_name'], 'test_ajax_view', 'The view\'s ajaxViews array entry has the correct \'view_name\' key.');
|
||||
$this->assertEqual($drupal_settings['views']['ajaxViews'][$view_entry]['view_display_id'], 'page_1', 'The view\'s ajaxViews array entry has the correct \'view_display_id\' key.');
|
||||
|
||||
$post = array(
|
||||
'view_name' => 'test_ajax_view',
|
||||
'view_display_id' => 'page_1',
|
||||
);
|
||||
|
||||
$response = $this->simpleAjaxPost('views/ajax', 'application/json', $post);
|
||||
$data = drupal_json_decode($response);
|
||||
|
||||
$this->assertTrue(isset($data[0]['settings']['views']['ajaxViews']));
|
||||
|
||||
// Ensure that the view insert command is part of the result.
|
||||
$this->assertEqual($data[1]['command'], 'insert');
|
||||
$this->assertTrue(strpos($data[1]['selector'], '.view-dom-id-') === 0);
|
||||
|
||||
$this->drupalSetContent($data[1]['data']);
|
||||
$result = $this->xpath('//div[contains(@class, "views-row")]');
|
||||
$this->assertEqual(count($result), 2, 'Ensure that two items are rendered in the HTML.');
|
||||
|
||||
$post = array(
|
||||
'view_name' => 'test_noajax_view',
|
||||
'view_display_id' => 'default',
|
||||
);
|
||||
|
||||
$response = $this->simpleAjaxPost('views/ajax', 'application/json', $post);
|
||||
$data = drupal_json_decode($response);
|
||||
// In Drupal 7 we get an ajax response with no commands instead of a 403 if
|
||||
// the view cannot be accessed.
|
||||
foreach ($data as $item) {
|
||||
$this->assertIdentical('settings', $item['command']);
|
||||
$this->assertTrue(empty($item['data']));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -56,6 +56,38 @@ class ViewsExposedFormTest extends ViewsSqlTest {
|
||||
$this->helperButtonHasLabel('edit-reset', $expected_label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that exposed values are correctly stored.
|
||||
*/
|
||||
public function testRemember() {
|
||||
$account = $this->drupalCreateUser();
|
||||
$this->drupalLogin($account);
|
||||
// Create some random nodes.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
// Set the exposed filter.
|
||||
$this->drupalGet('test_exposed_remember', array('query' => array('type' => 'page')));
|
||||
$this->assertFieldByName('type', 'page');
|
||||
|
||||
// Request the page again, should still be set.
|
||||
$this->drupalGet('test_exposed_remember');
|
||||
$this->assertFieldByName('type', 'page');
|
||||
|
||||
// Request the page with an unrelated GET argument, filter should still be set.
|
||||
$this->drupalGet('test_exposed_remember', array('query' => array('argument' => 'value')));
|
||||
$this->assertFieldByName('type', 'page');
|
||||
|
||||
// Change the remembered exposed value.
|
||||
$this->drupalGet('test_exposed_remember', array('query' => array('type' => 'article')));
|
||||
$this->assertFieldByName('type', 'article');
|
||||
|
||||
// Request the page again, should have remembered the new value.
|
||||
$this->drupalGet('test_exposed_remember');
|
||||
$this->assertFieldByName('type', 'article');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the admin interface of exposed filter and sort items.
|
||||
*/
|
||||
|
@@ -5,9 +5,9 @@ core = 7.x
|
||||
dependencies[] = views
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-06-15
|
||||
version = "7.x-3.14"
|
||||
; Information added by Drupal.org packaging script on 2017-08-23
|
||||
version = "7.x-3.18"
|
||||
core = "7.x"
|
||||
project = "views"
|
||||
datestamp = "1466019588"
|
||||
datestamp = "1503495103"
|
||||
|
||||
|
@@ -218,5 +218,113 @@ function views_test_views_default_views() {
|
||||
|
||||
$views[$view->name] = $view;
|
||||
|
||||
$view = new view();
|
||||
$view->name = 'test_exposed_remember';
|
||||
$view->description = '';
|
||||
$view->tag = '';
|
||||
$view->base_table = 'node';
|
||||
$view->human_name = 'test_exposed_remember';
|
||||
$view->core = 0;
|
||||
$view->api_version = '3.0';
|
||||
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
|
||||
|
||||
/* Display: Master */
|
||||
$handler = $view->new_display('default', 'Master', 'default');
|
||||
$handler->display->display_options['use_more_always'] = FALSE;
|
||||
$handler->display->display_options['access']['type'] = 'none';
|
||||
$handler->display->display_options['cache']['type'] = 'none';
|
||||
$handler->display->display_options['query']['type'] = 'views_query';
|
||||
$handler->display->display_options['exposed_form']['type'] = 'basic';
|
||||
$handler->display->display_options['exposed_form']['options']['reset_button'] = TRUE;
|
||||
$handler->display->display_options['pager']['type'] = 'none';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'node';
|
||||
/* Sort criterion: Content: Post date */
|
||||
$handler->display->display_options['sorts']['created']['id'] = 'created';
|
||||
$handler->display->display_options['sorts']['created']['table'] = 'node';
|
||||
$handler->display->display_options['sorts']['created']['field'] = 'created';
|
||||
/* Filter criterion: Content: Type */
|
||||
$handler->display->display_options['filters']['type']['id'] = 'type';
|
||||
$handler->display->display_options['filters']['type']['table'] = 'node';
|
||||
$handler->display->display_options['filters']['type']['field'] = 'type';
|
||||
$handler->display->display_options['filters']['type']['exposed'] = TRUE;
|
||||
$handler->display->display_options['filters']['type']['expose']['operator_id'] = 'type_op';
|
||||
$handler->display->display_options['filters']['type']['expose']['label'] = 'Type';
|
||||
$handler->display->display_options['filters']['type']['expose']['operator'] = 'type_op';
|
||||
$handler->display->display_options['filters']['type']['expose']['identifier'] = 'type';
|
||||
$handler->display->display_options['filters']['type']['expose']['remember'] = TRUE;
|
||||
$handler->display->display_options['filters']['type']['expose']['remember_roles'] = array(
|
||||
2 => '2',
|
||||
);
|
||||
|
||||
/* Display: Page */
|
||||
$handler = $view->new_display('page', 'Page', 'page_1');
|
||||
$handler->display->display_options['path'] = 'test_exposed_remember';
|
||||
$translatables['test_exposed_remember'] = array(
|
||||
t('Master'),
|
||||
t('more'),
|
||||
t('Apply'),
|
||||
t('Reset'),
|
||||
t('Sort by'),
|
||||
t('Asc'),
|
||||
t('Desc'),
|
||||
t('Type'),
|
||||
t('Page'),
|
||||
);
|
||||
|
||||
$views[$view->name] = $view;
|
||||
|
||||
$view = new view();
|
||||
$view->name = 'test_ajax_view';
|
||||
$view->description = '';
|
||||
$view->tag = '';
|
||||
$view->base_table = 'node';
|
||||
$view->human_name = '';
|
||||
$view->core = 0;
|
||||
$view->api_version = '3.0';
|
||||
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
|
||||
|
||||
/* Display: Master */
|
||||
$handler = $view->new_display('default', 'Master', 'default');
|
||||
$handler->display->display_options['use_ajax'] = TRUE;
|
||||
$handler->display->display_options['use_more_always'] = FALSE;
|
||||
$handler->display->display_options['access']['type'] = 'none';
|
||||
$handler->display->display_options['cache']['type'] = 'none';
|
||||
$handler->display->display_options['query']['type'] = 'views_query';
|
||||
$handler->display->display_options['exposed_form']['type'] = 'basic';
|
||||
$handler->display->display_options['pager']['type'] = 'none';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'node';
|
||||
|
||||
/* Display: Page */
|
||||
$handler = $view->new_display('page', 'Page', 'page_1');
|
||||
$handler->display->display_options['path'] = 'test_ajax_view';
|
||||
|
||||
$views[$view->name] = $view;
|
||||
|
||||
$view = new view();
|
||||
$view->name = 'test_noajax_view';
|
||||
$view->description = '';
|
||||
$view->tag = '';
|
||||
$view->base_table = 'node';
|
||||
$view->human_name = '';
|
||||
$view->core = 0;
|
||||
$view->api_version = '3.0';
|
||||
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
|
||||
|
||||
/* Display: Master */
|
||||
$handler = $view->new_display('default', 'Master', 'default');
|
||||
$handler->display->display_options['use_ajax'] = FALSE;
|
||||
$handler->display->display_options['use_more_always'] = FALSE;
|
||||
$handler->display->display_options['access']['type'] = 'none';
|
||||
$handler->display->display_options['cache']['type'] = 'none';
|
||||
$handler->display->display_options['query']['type'] = 'views_query';
|
||||
$handler->display->display_options['exposed_form']['type'] = 'basic';
|
||||
$handler->display->display_options['pager']['type'] = 'none';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'node';
|
||||
|
||||
$views[$view->name] = $view;
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
@@ -7,8 +7,11 @@
|
||||
|
||||
/**
|
||||
* Views class tests.
|
||||
*
|
||||
* @codingStandardsIgnoreStart
|
||||
*/
|
||||
class ViewsViewTest extends ViewsSqlTest {
|
||||
// @codingStandardsIgnoreEnd
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Test the view class',
|
||||
@@ -227,6 +230,8 @@ class ViewsViewTest extends ViewsSqlTest {
|
||||
'default' => 'default',
|
||||
'page_1' => 'page_1',
|
||||
);
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
$translatables['test_destroy'] = array(
|
||||
t('Master'),
|
||||
t('more'),
|
||||
@@ -272,6 +277,8 @@ class ViewsViewTest extends ViewsSqlTest {
|
||||
$handler->display->display_options['pager']['type'] = 'full';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'fields';
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
$translatables['test_view_delete'] = array(
|
||||
t('Defaults'),
|
||||
t('more'),
|
||||
|
@@ -86,7 +86,7 @@ function template_preprocess_views_view(&$vars) {
|
||||
$vars['title'] = !empty($view->views_ui_context) ? filter_xss_admin($view->get_title()) : '';
|
||||
|
||||
if ($view->display_handler->render_pager()) {
|
||||
$exposed_input = isset($view->exposed_raw_input) ? $view->exposed_raw_input : NULL;
|
||||
$exposed_input = $view->get_exposed_input();
|
||||
$vars['pager'] = $view->query->render_pager($exposed_input);
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ function template_preprocess_views_view(&$vars) {
|
||||
),
|
||||
),
|
||||
),
|
||||
// Support for AJAX path validation in core 7.39.
|
||||
'urlIsAjaxTrusted' => array(
|
||||
url('views/ajax') => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
drupal_add_js($settings, 'setting');
|
||||
|
@@ -7,13 +7,16 @@
|
||||
* - $view: The view object.
|
||||
* - $more_url: the url for the more link.
|
||||
* - $link_text: the text for the more link.
|
||||
* - $new_window: The flag that indicates if link should be opened in a new
|
||||
* window.
|
||||
*
|
||||
* @ingroup views_templates
|
||||
*/
|
||||
?>
|
||||
|
||||
<div class="more-link">
|
||||
<a href="<?php print $more_url ?>">
|
||||
<a href="<?php print $more_url ?>"<?php if (!empty($new_window)) { ?> target="_blank"<?php
|
||||
} ?>>
|
||||
<?php print $link_text; ?>
|
||||
</a>
|
||||
</div>
|
||||
|
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This template handles the printing of fields/filters/sort criteria/arguments or relationships.
|
||||
*/
|
||||
?>
|
||||
<?php print $rearrange; ?>
|
||||
<?php print $add; ?>
|
||||
<div class="views-category-title<?php
|
||||
if ($overridden) {
|
||||
print ' overridden';
|
||||
}
|
||||
if ($defaulted) {
|
||||
print ' defaulted';
|
||||
}
|
||||
?>">
|
||||
<?php print $item_help_icon; ?>
|
||||
<?php print $title; ?>
|
||||
</div>
|
||||
|
||||
<div class="views-category-content<?php
|
||||
if ($overridden) {
|
||||
print ' overridden';
|
||||
}
|
||||
if ($defaulted) {
|
||||
print ' defaulted';
|
||||
}
|
||||
?>">
|
||||
<?php if (!empty($no_fields)): ?>
|
||||
<div><?php print t('The style selected does not utilize fields.'); ?></div>
|
||||
<?php elseif (empty($fields)): ?>
|
||||
<div><?php print t('None defined'); ?></div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($fields as $pid => $field): ?>
|
||||
<?php if (!empty($field['links'])): ?>
|
||||
<?php print $field['links']; ?>
|
||||
<?php endif; ?>
|
||||
<div class="<?php print $field['class']; if (!empty($field['changed'])) { print ' changed'; } ?>">
|
||||
<?php print $field['title']; ?>
|
||||
<?php print $field['info']; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
@@ -87,7 +87,7 @@
|
||||
* $this->value_title = t('Node type');
|
||||
* $types = node_get_types();
|
||||
* foreach ($types as $type => $info) {
|
||||
* $options[$type] = $info->name;
|
||||
* $options[$type] = $info->name;
|
||||
* }
|
||||
* $this->value_options = $options;
|
||||
* }
|
||||
|
@@ -2,7 +2,6 @@ name = Views
|
||||
description = Create customized lists and queries from your database.
|
||||
package = Views
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
|
||||
; Always available CSS
|
||||
stylesheets[all][] = css/views.css
|
||||
@@ -302,6 +301,7 @@ files[] = tests/styles/views_plugin_style_unformatted.test
|
||||
files[] = tests/views_access.test
|
||||
files[] = tests/views_analyze.test
|
||||
files[] = tests/views_basic.test
|
||||
files[] = tests/views_ajax.test
|
||||
files[] = tests/views_argument_default.test
|
||||
files[] = tests/views_argument_validator.test
|
||||
files[] = tests/views_exposed_form.test
|
||||
@@ -328,9 +328,9 @@ files[] = tests/views_cache.test
|
||||
files[] = tests/views_view.test
|
||||
files[] = tests/views_ui.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-06-15
|
||||
version = "7.x-3.14"
|
||||
; Information added by Drupal.org packaging script on 2017-08-23
|
||||
version = "7.x-3.18"
|
||||
core = "7.x"
|
||||
project = "views"
|
||||
datestamp = "1466019588"
|
||||
datestamp = "1503495103"
|
||||
|
||||
|
@@ -44,13 +44,12 @@ function views_schema($caller_function = FALSE) {
|
||||
// Generate a sorted list of available schema update functions.
|
||||
if ($get_current || empty($schemas)) {
|
||||
$get_current = FALSE;
|
||||
$functions = get_defined_functions();
|
||||
foreach ($functions['user'] as $function) {
|
||||
if (strpos($function, 'views_schema_') === 0) {
|
||||
$version = substr($function, strlen('views_schema_'));
|
||||
if (is_numeric($version)) {
|
||||
$schemas[] = $version;
|
||||
}
|
||||
// Provide a worst-case scenario range.
|
||||
$start_schema = 6000;
|
||||
$end_schema = 7999;
|
||||
for ($i = $start_schema; $i <= $end_schema; $i++) {
|
||||
if (function_exists('views_schema_' . $i)) {
|
||||
$schemas[] = $i;
|
||||
}
|
||||
}
|
||||
if ($schemas) {
|
||||
@@ -253,8 +252,7 @@ function views_schema_6000() {
|
||||
),
|
||||
);
|
||||
|
||||
// $schema['cache_views_data'] added in views_schema_6006()
|
||||
|
||||
// $schema['cache_views_data'] added in views_schema_6006().
|
||||
return $schema;
|
||||
}
|
||||
|
||||
@@ -296,8 +294,10 @@ function views_update_6001() {
|
||||
update_sql("UPDATE {blocks} SET delta = CONCAT(delta, '-block_1') WHERE module = 'views'");
|
||||
}
|
||||
|
||||
// NOTE: Update 6002 removed because it did not always work.
|
||||
// Update 6004 implements the change correctly.
|
||||
/*
|
||||
* NOTE: Update 6002 removed because it did not always work.
|
||||
* Update 6004 implements the change correctly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add missing unique key.
|
||||
@@ -488,7 +488,7 @@ function views_update_6011() {
|
||||
*/
|
||||
function views_update_6012() {
|
||||
// There is only one simple query to run.
|
||||
$update = db_update('blocks')
|
||||
db_update('blocks')
|
||||
->condition('module', 'views')
|
||||
->condition('delta', db_like('-exp-') . '%', 'LIKE')
|
||||
->fields(array('cache' => DRUPAL_NO_CACHE));
|
||||
|
@@ -9,6 +9,32 @@
|
||||
* incoming page and block requests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function views_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#views':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Views module provides a back end to fetch information from content, user accounts, taxonomy terms, and other entities from the database and present it to the user as a grid, HTML list, table, unformatted list, etc. The resulting displays are known generally as views.') . '</p>';
|
||||
$output .= '<p>' . t('For more information, see the <a href="@views" target="blank">online documentation for the Views</a>.', array('@views' => 'https://www.drupal.org/documentation/modules/views')) . '</p>';
|
||||
$output .= '<p>' . t('In order to create and modify your own views using the administration and configuration user interface, you will need to enable either the Views UI module in core or a contributed module that provides a user interface for Views. See the <a href="/admin/structure/views">Views UI module help page</a> for more information.') . '</p>';
|
||||
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Adding functionality to administrative pages') . '</dt>';
|
||||
$output .= '<dd>' . t('The Views module adds functionality to some core administration pages. For example, <em>admin/content</em> uses Views to filter and sort content. With Views uninstalled, <em>admin/content</em> is more limited.') . '</dd>';
|
||||
|
||||
$output .= '<dt>' . t('Expanding Views functionality') . '</dt>';
|
||||
$output .= '<dd>' . t('Contributed projects that support the Views module can be found in the <a href="@views-related" target="blank">online documentation for Views-related contributed modules.</a>.', array('@views-related' => 'https://www.drupal.org/documentation/modules/views/add-ons')) . '</dd>';
|
||||
|
||||
$output .= '<dt>' . t('Improving table accessibility') . '</dt>';
|
||||
$output .= '<dd>' . t('Views tables include semantic markup to improve accessibility. Data cells are automatically associated with header cells through id and header attributes. To improve the accessibility of your tables you can add descriptive elements within the Views table settings. The caption element can introduce context for a table, making it easier to understand. The summary element can provide an overview of how the data has been organized and how to navigate the table. Both the caption and summary are visible by default and also implemented according to HTML5 guidelines.') . '</dd>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advertise the current views api version
|
||||
*/
|
||||
@@ -377,7 +403,7 @@ function views_menu() {
|
||||
'file' => 'includes/ajax.inc',
|
||||
);
|
||||
// Define another taxonomy autocomplete because the default one of drupal
|
||||
// does not support a vid a argument anymore
|
||||
// does not support a vid a argument anymore.
|
||||
$items['admin/views/ajax/autocomplete/taxonomy'] = array(
|
||||
'page callback' => 'views_ajax_autocomplete_taxonomy',
|
||||
'theme callback' => 'ajax_base_page_theme',
|
||||
|
@@ -48,7 +48,6 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
|
||||
$url_options['language'] = $options['language'];
|
||||
}
|
||||
$sanitize = !empty($options['sanitize']);
|
||||
$langcode = isset($options['language']) ? $options['language']->language : NULL;
|
||||
|
||||
$replacements = array();
|
||||
|
||||
|
@@ -4,12 +4,13 @@ package = Views
|
||||
core = 7.x
|
||||
configure = admin/structure/views
|
||||
dependencies[] = views
|
||||
# @codingStandardsIgnoreLine
|
||||
files[] = views_ui.module
|
||||
files[] = plugins/views_wizard/views_ui_base_views_wizard.class.php
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-06-15
|
||||
version = "7.x-3.14"
|
||||
; Information added by Drupal.org packaging script on 2017-08-23
|
||||
version = "7.x-3.18"
|
||||
core = "7.x"
|
||||
project = "views"
|
||||
datestamp = "1466019588"
|
||||
datestamp = "1503495103"
|
||||
|
||||
|
@@ -5,6 +5,29 @@
|
||||
* Provide structure for the administrative interface to Views.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function views_ui_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#views_ui':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Views UI module provides an interface for managing views for the Views module. For more information, see the <a href="@views" target="blank">online documentation for the Views UI module</a>.', array('@views' => 'https://www.drupal.org/documentation/modules/views')) . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Creating and managing views') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be created from the <a href="/admin/structure/views">Views list page</a> by using the "Add view" action. Existing views can be managed from the <a href="/admin/structure/views">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".') . '</dd>';
|
||||
|
||||
$output .= '<dt>' . t('Enabling and disabling views') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be enabled or disabled from the <a href="/admin/structure/views">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.') . '</dd>';
|
||||
|
||||
$output .= '<dt>' . t('Exporting and importing views') . '</dt>';
|
||||
$output .= '<dd>' . t('Views can be exported and imported as configuration files by using the Configuration Manager module.') . '</dd>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
@@ -96,7 +119,6 @@ function views_ui_menu() {
|
||||
) + $base;
|
||||
|
||||
// Additional pages for acting on a View.
|
||||
|
||||
$items['admin/structure/views/view/%views_ui_cache/break-lock'] = array(
|
||||
'title' => 'Break lock',
|
||||
'page callback' => 'drupal_get_form',
|
||||
@@ -143,7 +165,7 @@ function views_ui_menu() {
|
||||
'type' => MENU_CALLBACK,
|
||||
) + $base;
|
||||
|
||||
// A page in the Reports section to show usage of fields in all views
|
||||
// A page in the Reports section to show usage of fields in all views.
|
||||
$items['admin/reports/fields/list'] = array(
|
||||
'title' => 'List',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
@@ -175,9 +197,17 @@ function views_ui_theme() {
|
||||
require_once DRUPAL_ROOT . "/$path/includes/admin.inc";
|
||||
|
||||
return array(
|
||||
// edit a view
|
||||
// Edit a view.
|
||||
'views_ui_display_tab_setting' => array(
|
||||
'variables' => array('description' => '', 'link' => '', 'settings_links' => array(), 'overridden' => FALSE, 'defaulted' => FALSE, 'description_separator' => TRUE, 'class' => array()),
|
||||
'variables' => array(
|
||||
'description' => '',
|
||||
'link' => '',
|
||||
'settings_links' => array(),
|
||||
'overridden' => FALSE,
|
||||
'defaulted' => FALSE,
|
||||
'description_separator' => TRUE,
|
||||
'class' => array(),
|
||||
),
|
||||
'template' => 'views-ui-display-tab-setting',
|
||||
'path' => "$path/theme",
|
||||
),
|
||||
@@ -186,11 +216,6 @@ function views_ui_theme() {
|
||||
'template' => 'views-ui-display-tab-bucket',
|
||||
'path' => "$path/theme",
|
||||
),
|
||||
'views_ui_edit_item' => array(
|
||||
'variables' => array('type' => NULL, 'view' => NULL, 'display' => NULL, 'no_fields' => FALSE),
|
||||
'template' => 'views-ui-edit-item',
|
||||
'path' => "$path/theme",
|
||||
),
|
||||
'views_ui_rearrange_form' => array(
|
||||
'render element' => 'form',
|
||||
),
|
||||
@@ -203,7 +228,7 @@ function views_ui_theme() {
|
||||
'file' => 'includes/admin.inc',
|
||||
),
|
||||
|
||||
// list views
|
||||
// List views.
|
||||
'views_ui_view_info' => array(
|
||||
'variables' => array('view' => NULL, 'base' => NULL),
|
||||
'file' => "includes/admin.inc",
|
||||
@@ -215,7 +240,7 @@ function views_ui_theme() {
|
||||
'file' => 'includes/admin.inc',
|
||||
),
|
||||
|
||||
// tab themes
|
||||
// Tab themes.
|
||||
'views_tabset' => array(
|
||||
'variables' => array('tabs' => NULL),
|
||||
),
|
||||
@@ -227,15 +252,19 @@ function views_ui_theme() {
|
||||
'file' => 'includes/admin.inc',
|
||||
),
|
||||
|
||||
|
||||
// On behalf of a plugin
|
||||
// On behalf of a plugin.
|
||||
'views_ui_style_plugin_table' => array(
|
||||
'render element' => 'form',
|
||||
),
|
||||
|
||||
// When previewing a view.
|
||||
'views_ui_view_preview_section' => array(
|
||||
'variables' => array('view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''),
|
||||
'variables' => array(
|
||||
'view' => NULL,
|
||||
'section' => NULL,
|
||||
'content' => NULL,
|
||||
'links' => '',
|
||||
),
|
||||
),
|
||||
|
||||
// Generic container wrapper, to use instead of theme_container when an id
|
||||
@@ -279,10 +308,10 @@ function views_ui_edit_page_title($view) {
|
||||
/**
|
||||
* Specialized menu callback to load a view and check its locked status.
|
||||
*
|
||||
* @param $name
|
||||
* @param string $name
|
||||
* The machine name of the view.
|
||||
*
|
||||
* @return
|
||||
* @return object
|
||||
* The view object, with a "locked" property indicating whether or not
|
||||
* someone else is already editing the view.
|
||||
*/
|
||||
@@ -320,6 +349,8 @@ function views_ui_cache_load($name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache set.
|
||||
*
|
||||
* Specialized cache function to add a flag to our view, include an appropriate
|
||||
* include, and cache more easily.
|
||||
*/
|
||||
@@ -329,7 +360,8 @@ function views_ui_cache_set(&$view) {
|
||||
return;
|
||||
}
|
||||
ctools_include('object-cache');
|
||||
$view->changed = TRUE; // let any future object know that this view has changed.
|
||||
// Let any future object know that this view has changed.
|
||||
$view->changed = TRUE;
|
||||
|
||||
if (isset($view->current_display)) {
|
||||
// Add the knowledge of the changed display, too.
|
||||
@@ -337,7 +369,7 @@ function views_ui_cache_set(&$view) {
|
||||
unset($view->current_display);
|
||||
}
|
||||
|
||||
// Unset handlers; we don't want to write these into the cache
|
||||
// Unset handlers; we don't want to write these into the cache.
|
||||
unset($view->display_handler);
|
||||
unset($view->default_display);
|
||||
$view->query = NULL;
|
||||
@@ -348,8 +380,9 @@ function views_ui_cache_set(&$view) {
|
||||
ctools_object_cache_set('view', $view->name, $view);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default Load.
|
||||
*
|
||||
* Specialized menu callback to load a view that is only a default
|
||||
* view.
|
||||
*/
|
||||
@@ -369,7 +402,21 @@ function views_ui_preprocess_views_view(&$vars) {
|
||||
$view = $vars['view'];
|
||||
if (!empty($view->views_ui_context) && module_exists('contextual')) {
|
||||
$view->hide_admin_links = TRUE;
|
||||
foreach (array('title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before') as $section) {
|
||||
|
||||
$sections = array(
|
||||
'title',
|
||||
'header',
|
||||
'exposed',
|
||||
'rows',
|
||||
'pager',
|
||||
'more',
|
||||
'footer',
|
||||
'empty',
|
||||
'attachment_after',
|
||||
'attachment_before',
|
||||
);
|
||||
|
||||
foreach ($sections as $section) {
|
||||
if (!empty($vars[$section])) {
|
||||
$vars[$section] = array(
|
||||
'#theme' => 'views_ui_view_preview_section',
|
||||
@@ -397,40 +444,49 @@ function template_preprocess_views_ui_view_preview_section(&$vars) {
|
||||
$vars['title'] = t('Title');
|
||||
$links = views_ui_view_preview_section_display_category_links($vars['view'], 'title', $vars['title']);
|
||||
break;
|
||||
|
||||
case 'header':
|
||||
$vars['title'] = t('Header');
|
||||
$links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
|
||||
break;
|
||||
|
||||
case 'empty':
|
||||
$vars['title'] = t('No results behavior');
|
||||
$links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
|
||||
break;
|
||||
|
||||
case 'exposed':
|
||||
// @todo Sorts can be exposed too, so we may need a better title.
|
||||
$vars['title'] = t('Exposed Filters');
|
||||
$links = views_ui_view_preview_section_display_category_links($vars['view'], 'exposed_form_options', $vars['title']);
|
||||
break;
|
||||
|
||||
case 'rows':
|
||||
// @todo The title needs to depend on what is being viewed.
|
||||
$vars['title'] = t('Content');
|
||||
$links = views_ui_view_preview_section_rows_links($vars['view']);
|
||||
break;
|
||||
|
||||
case 'pager':
|
||||
$vars['title'] = t('Pager');
|
||||
$links = views_ui_view_preview_section_display_category_links($vars['view'], 'pager_options', $vars['title']);
|
||||
break;
|
||||
|
||||
case 'more':
|
||||
$vars['title'] = t('More');
|
||||
$links = views_ui_view_preview_section_display_category_links($vars['view'], 'use_more', $vars['title']);
|
||||
break;
|
||||
|
||||
case 'footer':
|
||||
$vars['title'] = t('Footer');
|
||||
$links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
|
||||
break;
|
||||
|
||||
case 'attachment_before':
|
||||
// @todo: Add links to the attachment configuration page.
|
||||
$vars['title'] = t('Attachment before');
|
||||
break;
|
||||
|
||||
case 'attachment_after':
|
||||
// @todo: Add links to the attachment configuration page.
|
||||
$vars['title'] = t('Attachment after');
|
||||
@@ -459,18 +515,18 @@ function template_preprocess_views_ui_view_preview_section(&$vars) {
|
||||
function theme_views_ui_view_preview_section($vars) {
|
||||
return '<h1 class="section-title">' . $vars['title'] . '</h1>'
|
||||
. $vars['links']
|
||||
. '<div class="preview-section">'. $vars['content'] . '</div>';
|
||||
. '<div class="preview-section">' . $vars['content'] . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns contextual links for each handler of a certain section.
|
||||
*
|
||||
* @param string $title
|
||||
* Add a bolded title of this section.
|
||||
*
|
||||
* @TODO
|
||||
* Bring in relationships
|
||||
* Refactor this function to use much stuff of views_ui_edit_form_get_bucket.
|
||||
*
|
||||
* @param $title
|
||||
* Add a bolded title of this section.
|
||||
*/
|
||||
function views_ui_view_preview_section_handler_links($view, $type, $title = FALSE) {
|
||||
$display = $view->display_handler->display;
|
||||
@@ -521,8 +577,9 @@ function views_ui_view_preview_section_display_category_links($view, $type, $tit
|
||||
* Returns all contextual links for the main content part of the view.
|
||||
*/
|
||||
function views_ui_view_preview_section_rows_links($view) {
|
||||
$display = $view->display_handler->display;
|
||||
|
||||
$links = array();
|
||||
|
||||
$links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
|
||||
$links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
|
||||
$links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
|
||||
@@ -532,7 +589,6 @@ function views_ui_view_preview_section_rows_links($view) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implments hook_ctools_plugin_directory().
|
||||
*
|
||||
@@ -547,10 +603,10 @@ function views_ui_ctools_plugin_directory($module, $plugin) {
|
||||
/**
|
||||
* Fetch metadata on a specific views ui wizard plugin.
|
||||
*
|
||||
* @param $wizard_type
|
||||
* @param string $wizard_type
|
||||
* Name of a wizard, or name of a base table.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array with information about the requested wizard type.
|
||||
*/
|
||||
function views_ui_get_wizard($wizard_type) {
|
||||
@@ -576,14 +632,14 @@ function views_ui_get_wizard($wizard_type) {
|
||||
/**
|
||||
* Fetch metadata for all content_type plugins.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of arrays with information about all available views wizards.
|
||||
*/
|
||||
function views_ui_get_wizards() {
|
||||
ctools_include('plugins');
|
||||
$wizard_plugins = ctools_get_plugins('views_ui', 'views_wizard');
|
||||
$wizard_tables = array();
|
||||
foreach ($wizard_plugins as $name => $info) {
|
||||
foreach ($wizard_plugins as $info) {
|
||||
$wizard_tables[$info['base_table']] = TRUE;
|
||||
}
|
||||
$base_tables = views_fetch_base_tables();
|
||||
@@ -604,7 +660,7 @@ function views_ui_get_wizards() {
|
||||
/**
|
||||
* Helper function to define the default values for a Views wizard plugin.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of defaults for a views wizard.
|
||||
*/
|
||||
function views_ui_views_wizard_defaults() {
|
||||
@@ -612,7 +668,7 @@ function views_ui_views_wizard_defaults() {
|
||||
// The children may, for example, be a different variant for each node type.
|
||||
'get children' => NULL,
|
||||
'get child' => NULL,
|
||||
// title and base table must be populated. They are empty here just
|
||||
// Title and base table must be populated. They are empty here just
|
||||
// so they are documented.
|
||||
'title' => '',
|
||||
'base_table' => NULL,
|
||||
@@ -641,6 +697,9 @@ function views_ui_ctools_plugin_type() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form wizard instance.
|
||||
*/
|
||||
function views_ui_get_form_wizard_instance($wizard) {
|
||||
if (isset($wizard['form_wizard_class']['class'])) {
|
||||
$class = $wizard['form_wizard_class']['class'];
|
||||
@@ -710,7 +769,7 @@ function views_ui_contextual_links_suppress($set = NULL) {
|
||||
* @see views_ui_contextual_links_suppress_pop()
|
||||
*/
|
||||
function views_ui_contextual_links_suppress_push() {
|
||||
views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())+1);
|
||||
views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -719,13 +778,16 @@ function views_ui_contextual_links_suppress_push() {
|
||||
* @see views_ui_contextual_links_suppress_push()
|
||||
*/
|
||||
function views_ui_contextual_links_suppress_pop() {
|
||||
views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())-1);
|
||||
views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; handles AJAX form submissions similar to ajax_form_callback(), but can be used for uncached forms.
|
||||
* Menu callback.
|
||||
*
|
||||
* ajax_form_callback(), the menu callback for the system/ajax path, requires
|
||||
* Handles AJAX form submissions similar to ajax_form_callback(), but can be
|
||||
* used for uncached forms.
|
||||
*
|
||||
* Ajax_form_callback(), the menu callback for the system/ajax path, requires
|
||||
* the form to be retrievable from the form cache, because it lacks a trusted
|
||||
* $form_id argument with which to call drupal_retrieve_form(). When AJAX is
|
||||
* wanted on a non-cacheable form, #ajax['path'] can be set to a path whose
|
||||
@@ -765,16 +827,18 @@ function views_ui_ajax_get_form($form_id) {
|
||||
return $callback($form, $form_state);
|
||||
}
|
||||
}
|
||||
// @todo move these when we can
|
||||
|
||||
/**
|
||||
* @todo move these when we can
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function to get a list of paths assigned to a view.
|
||||
*
|
||||
* @param $view
|
||||
* @param object $view
|
||||
* The view.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of links to this view's display paths.
|
||||
*/
|
||||
function _views_ui_get_paths($view) {
|
||||
@@ -783,14 +847,14 @@ function _views_ui_get_paths($view) {
|
||||
$all_paths[] = t('Edit this view to add a display.');
|
||||
}
|
||||
else {
|
||||
$view->init_display(); // Make sure all the handlers are set up
|
||||
// Make sure all the handlers are set up.
|
||||
$view->init_display();
|
||||
foreach ($view->display as $display) {
|
||||
if (!empty($display->handler) && $display->handler->has_path()) {
|
||||
$one_path = $display->handler->get_option('path');
|
||||
if (empty($path_sort)) {
|
||||
$path_sort = strtolower($one_path);
|
||||
}
|
||||
|
||||
if (empty($view->disabled) && strpos($one_path, '%') === FALSE) {
|
||||
// @codingStandardsIgnoreLine
|
||||
$all_paths[] = l('/' . $one_path, $one_path);
|
||||
}
|
||||
else {
|
||||
@@ -806,10 +870,10 @@ function _views_ui_get_paths($view) {
|
||||
/**
|
||||
* Helper function to get a list of displays included in a view.
|
||||
*
|
||||
* @param $view
|
||||
* @param object $view
|
||||
* The view.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of display types that this view includes.
|
||||
*/
|
||||
function _views_ui_get_displays_list($view) {
|
||||
@@ -828,21 +892,22 @@ function _views_ui_get_displays_list($view) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is part of a patch to address a jQueryUI bug. The bug is responsible
|
||||
* for the inability to scroll a page when a modal dialog is active. If the content
|
||||
* of the dialog extends beyond the bottom of the viewport, the user is only able
|
||||
* to scroll with a mousewheel or up/down keyboard keys.
|
||||
* This is part of a patch to address a jQueryUI bug.
|
||||
*
|
||||
* The bug is responsible
|
||||
* for the inability to scroll a page when a modal dialog is active. If the
|
||||
* content of the dialog extends beyond the bottom of the viewport, the user is
|
||||
* only able to scroll with a mousewheel or up/down keyboard keys.
|
||||
*
|
||||
* @see http://bugs.jqueryui.com/ticket/4671
|
||||
* @see https://bugs.webkit.org/show_bug.cgi?id=19033
|
||||
* @see /js/jquery.ui.dialog.patch.js
|
||||
* @see /js/jquery.ui.dialog.min.js
|
||||
*
|
||||
* The javascript patch overwrites the $.ui.dialog.overlay.events object to remove
|
||||
* the mousedown, mouseup and click events from the list of events that are bound
|
||||
* in $.ui.dialog.overlay.create.
|
||||
* The javascript patch overwrites the $.ui.dialog.overlay.events object to
|
||||
* remove the mousedown, mouseup and click events from the list of events that
|
||||
* are bound in $.ui.dialog.overlay.create.
|
||||
*/
|
||||
|
||||
function views_ui_library_alter(&$libraries, $module) {
|
||||
if ($module == 'system' && isset($libraries['ui.dialog'])) {
|
||||
// Only apply the fix, if we don't have an up to date jQueryUI version.
|
||||
|
Reference in New Issue
Block a user