updated node_export, mimemail, menu_attributes

This commit is contained in:
Bachir Soussi Chiadmi 2016-11-05 17:09:40 +01:00
parent 2b028cf376
commit fdefc824d8
50 changed files with 1598 additions and 1555 deletions

View File

@ -6,9 +6,9 @@ configure = admin/structure/menu/settings
files[] = menu_attributes.test
; Information added by Drupal.org packaging script on 2015-01-02
version = "7.x-1.0-rc3+1-dev"
; Information added by Drupal.org packaging script on 2016-02-15
version = "7.x-1.0"
core = "7.x"
project = "menu_attributes"
datestamp = "1420231982"
datestamp = "1455568740"

View File

@ -16,7 +16,7 @@ function menu_attributes_permission() {
return array(
'administer menu attributes' => array(
'title' => t('Administer menu attributes'),
'description' => t('Administer menu attributes.'),
'description' => t('Administer menu attributes configuration.'),
),
);
}
@ -255,6 +255,9 @@ function _menu_attributes_form_alter(array &$form, array $item = array(), array
$has_visible_children = (bool) element_get_visible_children($form['options']['attributes']);
$user_has_access = user_access('administer menu attributes');
$form['options']['attributes']['#access'] = ($has_visible_children && $user_has_access);
$has_visible_children = (bool) element_get_visible_children($form['options']['item_attributes']);
$form['options']['item_attributes']['#access'] = ($has_visible_children && $user_has_access);
}
/**
@ -337,7 +340,7 @@ function menu_attributes_preprocess_menu_link(&$variables) {
// Class get's special treatment, as it's an array and it should not
// replace existing values.
if ($attribute == 'class') {
$value = explode(' ', $value);
$value = !is_array($value) ? explode(' ', $value) : $value;
if (isset($attributes[$attribute])) {
$value = array_merge($attributes[$attribute], $value);
}

View File

@ -88,6 +88,6 @@ Regarding the Node export features module which integrates with the Features
module, any nodes to be used with this must have a UUID (universally unique
ID). To export older nodes that don't have UUID make sure you have selected
the content type and click on 'create missings uuids' from
'admin/settings/uuid' under the fieldset 'Synchronize'. Then you should be
'admin/config/system/uuid' under the fieldset 'Synchronize'. Then you should be
able to see more nodes under the feature component, If you don't see the node
export component, that means no nodes has been configured with UUID.

View File

@ -18,7 +18,7 @@ function node_export_dsv_settings($form, $form_state) {
'Select how your DSV output will be formatted - this must be configured the
same on both sites. By default this is configured to RFC4180 CSV format
where the delimiter is a comma (,), the enclosure is a double-quote ("),
and the seperator is CRLF (\r\n). Not all configurations may be possible,
and the separator is CRLF (\r\n). Not all configurations may be possible,
use wisely. Enclosure will only be used to escape values that contain any
of the configured strings. Additionally single-quotes will be used to
escape values that are equivalent to reserved words (NULL, TRUE, FALSE).'
@ -45,12 +45,12 @@ function node_export_dsv_settings($form, $form_state) {
'#required' => TRUE,
);
$settings['dsv']['node_export_dsv_seperator'] = array(
$settings['dsv']['node_export_dsv_separator'] = array(
'#type' => 'textfield',
'#title' => t('Record seperator'),
'#title' => t('Record separator'),
'#size' => 5,
'#maxlength' => 255,
'#default_value' => variable_get('node_export_dsv_seperator', '\r\n'),
'#default_value' => variable_get('node_export_dsv_separator', '\r\n'),
'#required' => TRUE,
);
@ -82,15 +82,15 @@ function node_export_dsv_string($string) {
function node_export_dsv_export($nodes, $format) {
$delimiter = node_export_dsv_string(variable_get('node_export_dsv_delimiter', ','));
$enclosure = node_export_dsv_string(variable_get('node_export_dsv_enclosure', '"'));
$seperator = node_export_dsv_string(variable_get('node_export_dsv_seperator', '\r\n'));
$separator = node_export_dsv_string(variable_get('node_export_dsv_separator', '\r\n'));
$escape_eol = variable_get('node_export_dsv_escape_eol', 1);
return node_export_dsv_encode($nodes, $delimiter, $enclosure, $seperator, $escape_eol);
return node_export_dsv_encode($nodes, $delimiter, $enclosure, $separator, $escape_eol);
}
/**
* Build DSV string.
*/
function node_export_dsv_encode($nodes, $delimiter, $enclosure, $seperator, $escape_eol) {
function node_export_dsv_encode($nodes, $delimiter, $enclosure, $separator, $escape_eol) {
$encoded_nodes = array();
$dsv_lines = array();
@ -110,7 +110,7 @@ function node_export_dsv_encode($nodes, $delimiter, $enclosure, $seperator, $esc
}
}
return node_export_dsv_array_to_dsv($dsv_lines, $delimiter, $enclosure, $seperator, $escape_eol);
return node_export_dsv_array_to_dsv($dsv_lines, $delimiter, $enclosure, $separator, $escape_eol);
}
/**
@ -199,16 +199,16 @@ function node_export_dsv_encode_header_value($parents, $var, $k) {
function node_export_dsv_import($code_string) {
$delimiter = node_export_dsv_string(variable_get('node_export_dsv_delimiter', ','));
$enclosure = node_export_dsv_string(variable_get('node_export_dsv_enclosure', '"'));
$seperator = node_export_dsv_string(variable_get('node_export_dsv_seperator', '\r\n'));
return node_export_dsv_decode($code_string, $delimiter, $enclosure, $seperator);
$separator = node_export_dsv_string(variable_get('node_export_dsv_separator', '\r\n'));
return node_export_dsv_decode($code_string, $delimiter, $enclosure, $separator);
}
/**
* Interpret a DSV string.
*/
function node_export_dsv_decode($code_string, $delimiter, $enclosure, $seperator) {
function node_export_dsv_decode($code_string, $delimiter, $enclosure, $separator) {
// Get array data from DSV.
$array = @node_export_dsv_dsv_to_array($code_string, $delimiter, $enclosure, $seperator);
$array = @node_export_dsv_dsv_to_array($code_string, $delimiter, $enclosure, $separator);
// If the first two rows are of equal length, we can assume this is a DSV.
// Also checks there are a decent number of fields.
@ -235,7 +235,7 @@ function node_export_dsv_decode($code_string, $delimiter, $enclosure, $seperator
/**
* Encode DSV.
*/
function node_export_dsv_array_to_dsv($array, $delimiter, $enclosure, $seperator, $escape_eol) {
function node_export_dsv_array_to_dsv($array, $delimiter, $enclosure, $separator, $escape_eol) {
$lines = array();
foreach ($array as $line) {
$out_item = array();
@ -246,7 +246,7 @@ function node_export_dsv_array_to_dsv($array, $delimiter, $enclosure, $seperator
if (
(stripos($item, $delimiter) !== FALSE)
|| (stripos($item, $enclosure) !== FALSE)
|| (stripos($item, $seperator) !== FALSE)
|| (stripos($item, $separator) !== FALSE)
|| ($escape_eol && stripos($item, "\n") !== FALSE)
) {
$item = $enclosure . $item . $enclosure;
@ -255,13 +255,13 @@ function node_export_dsv_array_to_dsv($array, $delimiter, $enclosure, $seperator
}
$lines[] = implode($delimiter, $out_item);
}
return implode($seperator, $lines);
return implode($separator, $lines);
}
/**
* Decode DSV.
*/
function node_export_dsv_dsv_to_array($string, $delimiter, $enclosure, $seperator) {
function node_export_dsv_dsv_to_array($string, $delimiter, $enclosure, $separator) {
$lines = array();
$out_item = array();
$count = strlen($string);
@ -269,15 +269,15 @@ function node_export_dsv_dsv_to_array($string, $delimiter, $enclosure, $seperato
$double_escape = FALSE;
$position = 0;
$i = 0;
$seperators = str_split($seperator);
$separators = str_split($separator);
while ($i < $count) {
$c = $string[$i];
// Determine whether this is an EOL.
$is_eol = TRUE;
for ($j = 0; $j < count($seperators); $j++) {
if (!isset($string[$i + $j]) || $string[$i + $j] != $seperators[$j]) {
for ($j = 0; $j < count($separators); $j++) {
if (!isset($string[$i + $j]) || $string[$i + $j] != $separators[$j]) {
$is_eol = FALSE;
break;
}
@ -288,7 +288,7 @@ function node_export_dsv_dsv_to_array($string, $delimiter, $enclosure, $seperato
$out_item[$position] .= $c;
}
else {
$i += count($seperators);
$i += count($separators);
$lines[] = $out_item;
$out_item = array();
$position = 0;

View File

@ -189,6 +189,9 @@ class NodeExportXmlDecoder {
return NULL;
}
}
elseif (!empty($stack['attributes']['_NUMERIC_KEYS'])) {
return array();
}
return htmlspecialchars_decode(trim($stack['data']));
}
else {
@ -229,4 +232,4 @@ class NodeExportXmlDecoder {
*/
function node_export_xml_action_form($context, &$form_state) {
return node_export_action_form($context, $form_state, 'xml');
}
}

View File

@ -0,0 +1,17 @@
name = "Node export book"
description = "Adds Book support to Node export"
core = 7.x
dependencies[] = book
dependencies[] = node_export
files[] = node_export_book.module
files[] = node_export_book_utils.inc
package = "Node export"
project = node_export
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1457077222"

View File

@ -0,0 +1,212 @@
<?php
/**
* @file
* Adds Book support to the Node export module.
*/
/**
* Implements hook_node_export_node_alter().
*/
function node_export_book_node_export_node_alter(&$node, $original_node) {
module_load_include('inc', 'node_export_book', 'node_export_book_utils');
// Throw errors if the node doesn't have a UUID
if (module_exists('uuid') and drupal_strlen(_node_export_book_nid_to_uuid($node->nid)) < 1) {
drupal_set_message(t('The node %nid does not have a UUID; unable to export!', array('%nid' => $node->nid)), 'error');
watchdog('node_export_book', 'Unable to export %nid because it is missing a UUID.', array('%nid' => $node->nid), WATCHDOG_CRITICAL);
}
elseif (module_exists('book') and property_exists($original_node, 'book')) {
// Create a namespace for our export info in the book node
if (!property_exists($node, 'node_export_book')) {
$node->node_export_book = array();
}
// Dereference the Parent Link ID (PLID) and write the parent node's UUID
if (array_key_exists('plid', $original_node->book) and menu_link_load($original_node->book['plid'])) {
$node->node_export_book['#parent_uuid'] = _node_export_book_mlid_to_uuid($original_node->book['plid']);
}
// Dereference the Book ID (BID) and write the book node's UUID
if (array_key_exists('bid', $original_node->book) and node_load($original_node->book['bid'])) {
$node->node_export_book['#book_uuid'] = _node_export_book_nid_to_uuid($original_node->book['bid']);
}
// Add the weight of this page in the book heirarchy
if (array_key_exists('weight', $original_node->book)) {
$node->node_export_book['weight'] = intval($original_node->book['weight']);
}
if ($original_node->book['bid'] == $original_node->nid) {
$node->node_export_book['#is_root'] = TRUE;
}
else {
$node->node_export_book['#is_root'] = FALSE;
}
// When we're done, unset the book info in the node, so it isn't exported
// and book.module on the destination site can't get confused
unset($node->book);
}
}
/**
* Implements hook_node_export_after_import_alter().
*/
function node_export_book_node_export_after_import_alter(&$nodes, $format, $save) {
module_load_include('inc', 'node_export_book', 'node_export_book_utils');
if (module_exists('book')) {
// A smaller array of child nodes to parse later
$child_nodes = array();
// Loop through all the nodes, process books, and build a smaller array of nodes to parse later
foreach ($nodes as &$node) {
if (book_type_is_allowed($node->type) and property_exists($node, 'node_export_book')) {
// If this is a root book node, create the book
if (array_key_exists('#is_root', $node->node_export_book) and $node->node_export_book['#is_root']) {
$node->book = array('bid' => 'new');
book_node_update($node);
}
// Otherwise, it's a child node, so add it to a smaller array of nodes to parse
else {
$child_nodes[] = &$node;
}
}
}
// Add each child node to the book as a root item
foreach ($child_nodes as &$node) {
// Find the root book node
$book_nid = _node_export_book_uuid_to_nid($node->node_export_book['#book_uuid']);
// Set up the data we need to make this node a child of the root book node
$node->book = array();
$node->book['bid'] = $book_nid;
$node->book['plid'] = _node_export_book_nid_to_mlid($book_nid);
// Also set up the weight
$node->book['weight'] = $node->node_export_book['weight'];
// Add this node to the book
book_node_update($node);
// Derefernce the parent node's UUID to a nid
$node->node_export_book['#parent_nid'] = _node_export_book_uuid_to_nid($node->node_export_book['#parent_uuid']);
}
// Re-structure the book as it was on the source site
foreach ($child_nodes as &$node) {
// Force a reload of the node
$updated_node = node_load($node->nid, NULL, TRUE);
// Update this node's Parent Link ID (PLID)
$updated_node->book['plid'] = _node_export_book_nid_to_mlid($node->node_export_book['#parent_nid']);
// Update the node
book_node_update($updated_node);
}
}
}
/**
* Implements hook_menu().
*/
function node_export_book_menu() {
$items = array();
$items['admin/content/book/node_export_book/%node'] = array(
'title' => 'Export book',
'page callback' => '_node_export_book_run_export',
'page arguments' => array(4),
'access arguments' => array('export bulk nodes'),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Helper function to export a book.
*/
function _node_export_book_run_export($book_root) {
if (module_exists('node_export') and module_exists('book')) {
$nids = array();
// Include some useful utilities
module_load_include('inc', 'node_export_book', 'node_export_book_utils');
module_load_include('inc', 'node_export', 'node_export.pages');
// Get a list of all nodes in this book
$tree = book_menu_subtree_data(menu_link_load(_node_export_book_nid_to_mlid($book_root->nid)));
$nids = _node_export_book_get_nids($tree);
return node_export_gui($nids);
}
}
/**
* Helper function to return the node ID of a book page
*/
function _node_export_book_get_nids($tree) {
$answer = array();
foreach ($tree as $key => $value) {
// Base case: menu item is a node
if (is_numeric($tree[$key]['link']['nid'])) {
$answer[] = $tree[$key]['link']['nid'];
}
// Recursive case: menu item has children
if ($tree[$key]['below']) {
$sub_nids = _node_export_book_get_nids($tree[$key]['below']);
$answer = array_merge($answer, $sub_nids);
}
}
return $answer;
}
/**
* Implements hook_menu_alter().
*/
function node_export_book_menu_alter(&$items) {
// Alter the page callback for the book overview page
$items['admin/content/book']['page callback'] = '_node_export_book_book_admin_overview';
}
/**
* Helper function to override the book overview page and add an Export book
* operation.
*
* @see book_admin_overview()
*/
function _node_export_book_book_admin_overview() {
$rows = array();
$headers = array(t('Book'), t('Operations'));
// Add any recognized books to the table list.
foreach (book_get_books() as $book) {
$operations = array(
'links' => array(
'edit' => array(
'title' => t('edit order and titles'),
'href' => 'admin/content/book/' . $book['nid'],
),
'export' => array(
'title' => t('export book'),
'href' => 'admin/content/book/node_export_book/' . $book['nid'],
),
),
'attributes' => array('class' => array('links', 'inline')),
);
$rows[] = array(
l($book['title'], $book['href'], $book['options']),
theme('links', $operations)
);
}
return theme('table', array(
'header' => $headers,
'rows' => $rows,
'empty' => t('No books available.')
));
}

View File

@ -0,0 +1,132 @@
<?php
/**
* @file
* A bunch of utility functions to help with importing and exporting books.
*/
/**
* Return the Node ID of a node with a given Menu Link ID.
*
* @param $mlid
* The MLID of a node.
*
* @return
* The NID of the node with the given MLID; xor NULL if the MLID is not
* pointing to a node.
*
* @see menu_link_load()
*/
function _node_export_book_mlid_to_nid($mlid) {
// Load the menu link
$menu_item = menu_link_load($mlid);
if ($menu_item != FALSE) {
$path = explode('/', $menu_item['link_path']);
// Return the node ID if it's a valid node path
if ($path[0] == 'node' and is_numeric($path[1])) {
return intval($path[1]);
}
}
// If we get here, the node wasn't valid
return NULL;
}
/**
* Return the Universally Unique ID of a node with a given Menu Link ID.
*
* @param $mlid
* The MLID of a node.
*
* @return
* The UUID of the node with the given MLID; xor NULL if the node has not been
* assigned a UUID.
*
* @see _node_export_book_mlid_to_nid()
* @see _node_export_book_nid_to_uuid()
*/
function _node_export_book_mlid_to_uuid($mlid) {
return _node_export_book_nid_to_uuid(_node_export_book_mlid_to_nid($mlid));
}
/**
* Return the Menu Link ID of a node with a given Node ID.
*
* @pre
* The node must be in a book.
*
* @param $nid
* The NID of a node.
*
* @return
* The MLID of the node with the given NID; xor NULL if the node has no book
* MLID (i.e.: is not in a book).
*
* @see menu_get_item()
*/
function _node_export_book_nid_to_mlid($nid) {
$node_path = 'node/' . intval($nid);
$query = db_select('menu_links', 'ml');
$query->addField('ml', 'mlid');
$query->condition('link_path', $node_path);
$result = $query->execute()->fetchAssoc();
if ($result == FALSE) {
return NULL;
}
return $result['mlid'];
}
/**
* Return the Universally Unique ID of a node with a given Node ID.
*
* @param $nid
* The NID of a node.
*
* @return
* The UUID of the node with the given NID; xor (FALSE if the node doesn't
* exist OR there the node has not been assigned a UUID yet).
*
* @see entity_get_uuid_by_id()
*/
function _node_export_book_nid_to_uuid($nid) {
$uuid = entity_get_uuid_by_id('node', array($nid), FALSE);
return array_pop($uuid);
}
/**
* Return the Node ID of a node with a given Universally-Unique ID.
*
* @param $uuid
* The UUID of a node.
*
* @return
* The NID of the node with the given UUID; xor NULL if there are no nodes
* with that UUID.
*
* @see entity_get_id_by_uuid()
*/
function _node_export_book_uuid_to_nid($uuid) {
$nid = entity_get_id_by_uuid('node', array($uuid), FALSE);
return array_pop($nid);
}
/**
* Return the Menu Link ID of a node with a given Universally-Unique ID.
*
* @param $uuid
* The UUID of a node.
*
* @return
* The MLID of the node with the given UUID; xor NULL if there are no nodes
* with that UUID.
*
* @see _node_export_book_uuid_to_nid()
* @see _node_export_book_nid_to_mlid()
*/
function _node_export_book_uuid_to_mlid($uuid) {
return _node_export_book_nid_to_mlid(_node_export_book_uuid_to_nid($uuid));
}

View File

@ -217,6 +217,25 @@ function entityreference_node_export_dependency_field($entity_type, $entity, $fi
function field_collection_node_export_dependency_field($entity_type, $entity, $field, $instance, $langcode, $items) {
$dependencies = array();
node_export_dependency_add($dependencies, $items, 'field_collection_item', 'value');
// Loop all items to add their data for export.
foreach($items as $index => $item) {
if ($field_collection_item = field_collection_item_load($item['value'])) {
// Add file field data for export.
node_export_file_field_export($field_collection_item,
$field_collection_item);
// Add the field collection item data to the exported data. Mimics
// EntityAPIController::export() without the JSON conversion.
$dependencies[$index]['node_export_field_collection_data']
= get_object_vars($field_collection_item);
// Support nested fields and field collections too.
$dependencies = array_merge($dependencies, field_node_export_dependency(
$field_collection_item, 'field_collection_item'));
}
}
return $dependencies;
}

View File

@ -4,9 +4,9 @@ dependencies[] = node_export
dependencies[] = uuid
core = 7.x
package = "Node export"
; Information added by drupal.org packaging script on 2012-08-20
version = "7.x-3.0"
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1345435979"
datestamp = "1457077222"

View File

@ -100,7 +100,7 @@ function node_export_dependency_node_export_alter(&$nodes, $format) {
/**
* Recursively load dependencies.
*/
function node_export_dependency_load_dependencies(&$nodes, $nid) {
function node_export_dependency_load_dependencies(&$nodes, $nid, $reset = FALSE) {
$node = &$nodes[$nid];
$dependencies = node_export_dependency_get_dependencies('node', $node);
foreach ($dependencies as $dep_key => &$dependency) {
@ -114,8 +114,8 @@ function node_export_dependency_load_dependencies(&$nodes, $nid) {
if ($dependency['type'] == 'node' && variable_get('node_export_dependency_attach_nodes', 1)) {
// It the node doesn't exist in keyed nodes, add it.
if (!isset($nodes[$dependency['id']])) {
$new_node = node_load($dependency['id']);
if (node_export_access_export($new_node)) {
$new_node = node_load($dependency['id'], NULL, $reset);
if (node_export_access_export($new_node, $reset)) {
$new_node = node_export_prepare_node($new_node);
$nodes[$new_node->nid] = $new_node;
// Recursively load dependent nodes.
@ -140,20 +140,16 @@ function node_export_dependency_load_dependencies(&$nodes, $nid) {
/**
* Implements hook_node_export_import_alter().
*/
function node_export_dependency_node_export_import_alter($nodes, $format) {
function node_export_dependency_node_export_after_import_alter($nodes, $format, $save) {
$node_export_dependency = variable_get('node_export_dependency', array());
foreach ($nodes as $node) {
if (isset($node->node_export_dependency)) {
foreach ($node->node_export_dependency as $dep_key => $dependency) {
// Try to handle this dependency now, and unset if successfull.
// Try to handle this dependency now, and unset if successful.
// Only do this now if maintaining dependency to original node, because
// if that setting is turned off, doing this at this stage will break
// things.
if (
variable_get('node_export_dependency_existing', 1) &&
node_export_dependency_handle_dependency($node, $dependency)
) {
if (variable_get('node_export_dependency_existing', 1) && node_export_dependency_handle_dependency($node, $dependency)) {
unset($node->node_export_dependency[$dep_key]);
}
else {
@ -164,6 +160,7 @@ function node_export_dependency_node_export_import_alter($nodes, $format) {
}
}
unset($node->node_export_dependency);
node_save($node);
}
}
@ -185,8 +182,10 @@ function node_export_dependency_node_export_import_alter($nodes, $format) {
* How many iterations to run.
* @param $seconds
* How long to lock others from processing (will release upon completion).
* @param $reset
* Whether to reset the node_load_multiple cache.
*/
function node_export_dependency_process_outstanding_dependencies($iterations, $seconds = 240) {
function node_export_dependency_process_outstanding_dependencies($iterations, $seconds = 240, $reset = FALSE) {
if (REQUEST_TIME - variable_get('node_export_dependency_lock', REQUEST_TIME) >= 0) {
variable_set('node_export_dependency_lock', REQUEST_TIME + $seconds);
$node_export_dependency = variable_get('node_export_dependency', array());
@ -206,9 +205,9 @@ function node_export_dependency_process_outstanding_dependencies($iterations, $s
$dependencies = &$node_export_dependency[$node_uuid];
foreach ($dependencies as $dep_key => &$dependency) {
$nids = entity_get_id_by_uuid('node', array($node_uuid));
$node = node_load($nids[$node_uuid]);
$node = node_load($nids[$node_uuid], $reset);
if (!empty($node)) {
// Try to handle this dependency now, and unset if successfull.
// Try to handle this dependency now, and unset if successful.
if (node_export_dependency_handle_dependency($node, $dependency)) {
unset($dependencies[$dep_key]);
node_save($node);
@ -257,10 +256,25 @@ function node_export_dependency_init() {
}
/**
* Attempt to handle a dependency.
* Attempt to handle a dependency.
*
* @return
* TRUE or FALSE whether the dependency was handled.
* Handles field collection items excluding file/image fields (not supported
* yet) and adds the data to the given node.
*
* Passes all dependencies to hook_node_export_dependency_alter() for external
* handling.
*
* @param $node
* Node object before importing it.
* @param $dependency
* Associative array with data for the given dependency as exported under the
* 'node_export_dependency' key.
*
* @return
* TRUE or FALSE whether the dependency was handled.
*
* @todo
* Implement file/image field handling for field collection items.
*/
function node_export_dependency_handle_dependency(&$node, $dependency) {
$handled = FALSE;
@ -269,6 +283,111 @@ function node_export_dependency_handle_dependency(&$node, $dependency) {
// We're not handling it, so it is 'handled'.
return TRUE;
}
// Handle exported field collection items.
if ($dependency['type'] == 'field_collection_item' &&
isset($dependency['node_export_field_collection_data'])) {
$entity_controller = new EntityAPIController("field_collection_item");
$field_collection_item = $entity_controller
->create($dependency['node_export_field_collection_data']);
// The import of file/image field data is not yet supported. Thus we need
// to remove any file data from the field collection item's fields to avoid
// errors about non-existent files during import.
$supported_file_fields = array_map('trim', explode(',',
variable_get('node_export_file_supported_fields', 'file, image')));
// Gather information about the field collection item's individual fields.
$field_info = field_info_instances('field_collection_item',
$dependency['field_name']);
// Loop all fields to remove possibly contained file data.
foreach ($field_info as $field_name => $info) {
// If this is some file field.
if (in_array($info['widget']['module'], $supported_file_fields) && is_array($field_collection_item->{$field_name})) {
// Import the files, similar to node_export_file_field_import().
foreach ($field_collection_item->{$field_name} as $language => $files) {
if (is_array($files)) {
foreach ($files as $i => $field_value) {
$file = (object) $field_value;
$result = _node_export_file_field_import_file($file);
// The file was saved successfully, update the file field (by reference).
if ($result == TRUE && isset($file->fid)) {
// Retain any special properties from the original field value.
$field_collection_item->{$field_name}[$language][$i] = array_merge($field_value, (array) $file);
}
}
}
}
}
}
// Get the nid of the host node in the target system, if it already exits.
$nid = db_query('SELECT nid FROM {node} WHERE uuid = :uuid',
array(':uuid' => $node->uuid))->fetchField();
if ($nid) {
// Find the field collection item's current ID if it already exists.
$item_id = db_query('
SELECT d.' . $dependency['field_name'] . '_value
FROM {field_data_' . $dependency['field_name'] . '} d
INNER JOIN {field_collection_item} ci ON
ci.item_id = d.' . $dependency['field_name'] . '_value
AND ci.revision_id = d.' . $dependency['field_name'] . '_revision_id
WHERE d.entity_id = :nid AND d.delta = :delta
AND ci.field_name = :field_name',
array(
':nid' => $nid,
':delta' => $dependency['delta'],
':field_name' => $dependency['field_name'])
)->fetchField();
$field_collection_item->item_id = $item_id ? $item_id : NULL;
}
else {
$field_collection_item->item_id = NULL;
}
if ($field_collection_item->item_id) {
// The item already exists in the DB, so we need its uuid and revision_id
// to overwrite exactly the existing one with the new data.
$data = db_query('
SELECT revision_id, uuid
FROM {field_collection_item}
WHERE item_id = :item_id',
array(':item_id' => $field_collection_item->item_id))->fetchAssoc();
$field_collection_item->uuid = $data['uuid'];
$field_collection_item->revision_id = $data['revision_id'];
// Property is not needed.
if (property_exists($field_collection_item, 'is_new')) {
unset($field_collection_item->is_new);
}
}
// If there is no item_id, i.e. this is a new field collection item.
else {
$field_collection_item->is_new = TRUE;
$field_collection_item->revision_id = NULL;
// Remove the old uuid, a new one will be created.
unset($field_collection_item->uuid);
}
// Add the field collection item data to the node where node_save() expects
// it. It will save the new data later.
$node->{$dependency['field_name']}[$dependency['langcode']]
[$dependency['delta']]['entity'] = $field_collection_item;
$handled = TRUE;
}
if (!isset($dependency['relationship'])) {
// Entity id.
$entity_ids = entity_get_id_by_uuid($dependency['type'], array($dependency['uuid']));

View File

@ -5,9 +5,9 @@ dependencies[] = uuid
dependencies[] = features
core = 7.x
package = "Node export"
; Information added by drupal.org packaging script on 2012-08-20
version = "7.x-3.0"
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1345435979"
datestamp = "1457077222"

View File

@ -85,12 +85,38 @@ function node_export_features_features_export($data, &$export, $module_name = ''
return $pipe;
}
/**
* Implements hook_node_export_alter().
*/
function node_export_features_node_export_alter(&$nodes, $format) {
if (_node_export_features_currently_exporting()) {
foreach ($nodes as $key => $node) {
// Perform cleaning of the node before creating the export for features.
// This can help strip volatile attributes like 'created' and 'changed'.
$nodes[$key] = node_export_node_clone($node);
}
}
}
/**
* Check if the code is currently running a feature export.
*/
function _node_export_features_currently_exporting($set = FALSE, $value = NULL) {
$exporting = &drupal_static(__FUNCTION__, FALSE);
if ($set) {
$exporting = $value;
}
return $exporting;
}
/**
* Implements hook_features_export_render().
*/
function node_export_features_features_export_render($module, $data, $export = NULL) {
$nids = entity_get_id_by_uuid('node', $data);
_node_export_features_currently_exporting(TRUE, TRUE);
$result = node_export($nids);
_node_export_features_currently_exporting(TRUE, FALSE);
if ($result['success']) {
$node_export['code_string'] = $result['output'];
$node_export_code = ' $node_export = ' . features_var_export($node_export) . ';';
@ -125,8 +151,10 @@ function node_export_features_features_rebuild($module) {
}
}
else {
foreach ($result['output'] as $status) {
drupal_set_message($status);
if (!isset($_GET['profile'])) {
foreach ($result['output'] as $status) {
drupal_set_message($status);
}
}
}
}

View File

@ -0,0 +1,59 @@
Node Export Features UI
=======================
This module works with the Node Export Features module to provide an easy to
use method of selecting nodes to export. It is based on this Node Export
issue: http://drupal.org/node/1626360
Currently, the feature module's UI does not support listing a large number of
nodes to select from. Sites with large numbers of nodes caused major UI and
server performance problems. Because of this, the node_export_feature module
currently limits the number of nodes in the Feature UI to only the first 250
nodes.
The current solution for changing what nodes to display is to write a custom
module. This module is for people who don't want to write a custom module.
When enabled, it adds a "Feature Configuration" tab on the Node Export settings
page. ( Admin->Configure->Content Authoring->Node Export )
In the Feature Configuration tab, you can select from a set of filters to
control what nodes get listed in the Feature modules UI. The filter are:
* Number of nodes to List:
Expand or shrink beyond the build in 250 nodes.
NOTE: Using a large number can cause server and UI performance problems.
* Filter By Content Type:
Only show nodes of the selected content types.
* Filter By Publishing Options:
Filter by published, promoted, and sticky status.
* Filter by Title:
Filter by title using an SQL 'LIKE' statement. E.g, %Test%One%
* Filter by UUID:
Supply a specific list of node UUIDs to show.
These filters are 'additive' so each one is an "AND" condition on the query.
Installation:
Install Node Export, then enable via the modules page (or drush or...)
Features Notes:
If you need to recreate a feature created with one or more of the filters set,
you will need to make sure that the Node Export Feature filters are the
same.

View File

@ -0,0 +1,15 @@
name = Node Export Features UI
description = Supply some common filter options to define node available to be exported.
core = 7.x
package = "Node export"
configure = admin/config/content/node_export/features
dependencies[] = node_export_features
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1457077222"

View File

@ -0,0 +1,24 @@
<?php
/**
* @file
* The Node export features ui install/uninstall code.
*/
/**
* Implements hook_uninstall().
*/
function node_export_features_ui_uninstall() {
$settings = array(
'node_export_features_ui_range',
'node_export_features_ui_content_types',
'node_export_features_ui_status',
'node_export_features_ui_promote',
'node_export_features_ui_sticky',
'node_export_features_ui_title',
'node_export_features_ui_uuids',
);
foreach ( $settings as $setting ) {
variable_del($setting);
}
}

View File

@ -0,0 +1,85 @@
<?php
/**
* @file
* Node Export Features UI main module file
*/
/**
* Implements hook_menu().
*/
function node_export_features_ui_menu() {
$items = array();
$items['admin/config/content/node_export/features'] = array(
'access arguments' => array('administer site configuration'),
'page callback' => 'drupal_get_form',
'page arguments' => array('node_export_features_ui_settings'),
'title' => 'Features Configuration',
'description' => 'Configure filters for nodes available to be exported by node export features',
'file' => 'node_export_features_ui.pages.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
return $items;
}
/**
* Implements hook_query_alter().
*/
function node_export_features_ui_query_alter(QueryAlterableInterface $query) {
if ($query->hasTag('node_export_features')) {
$range = variable_get('node_export_features_ui_range', 250);
$types = variable_get('node_export_features_ui_content_types', array());
$status = variable_get('node_export_features_ui_status', 0);
$promote = variable_get('node_export_features_ui_promote', 0);
$sticky = variable_get('node_export_features_ui_sticky', 0);
$title = trim(variable_get('node_export_features_ui_title', ''));
$uuids = node_export_features_ui_textarea_to_array(variable_get('node_export_features_ui_uuids', ''));
// Add in the specified conditions.
if ( $range ) {
$query->range(0, $range);
}
if ( ! empty($types) ) {
$query->condition('type', $types, 'IN');
}
if ( $status ) {
$query->condition('status', $status-1);
}
if ( $promote ) {
$query->condition('promote', $promote-1);
}
if ( $sticky ) {
$query->condition('sticky', $sticky-1);
}
if ( $title ) {
$query->condition('title', $title, 'LIKE');
}
if ( ! empty($uuids) ) {
$query->condition('uuid', $uuids, 'IN');
}
}
}
/**
* Utility function to convert a text area into a array of trimmed non-blank lines.
*
* @param string $area
* The text area value to parse.
* @return array
* The parsed array of non-blank trimmed lines found in the area.
* An empty array is returned if no information found.
*/
function node_export_features_ui_textarea_to_array( $area ) {
$area = trim($area);
$results = array();
if ( $area ) {
$lines = explode("\r\n", $area);
foreach ( $lines as $key => $value ) {
$result = trim($value);
if ( $result ) {
$results[] = $result;
}
}
}
return $results;
}

View File

@ -0,0 +1,167 @@
<?php
/**
* @file
* The Node export features ui pages file.
*/
/**
* Admin settings form.
*
* @param array $form
* The current form array.
* @param array $form_state
* The current form array
* @return array
* A form array
*/
function node_export_features_ui_settings($form, &$form_state) {
$types = node_type_get_names();
$filter_types = variable_get('node_export_features_ui_content_types', array());
$default_types = array();
if ( ! empty($filter_types) ) {
foreach ( $types as $key => $value ) {
if ( in_array($key, $filter_types)) {
$default_types[$key] = $key;
}
else {
$default_type[$key] = 0;
}
}
}
$form = array();
$form['info'] = array(
'#pre' => '<div id="node-export-features-ui-info">',
'#markup' => t('The settings below will effect what nodes will get listed in the Node Export section of the Features UI. Note that each of these is an AND condition and so the limiting effect is additive. Also, when rebuilding a feature, the same filter settings will need to be applied.'),
'#suffix' => '</div>',
);
$form['node_export_features_ui_range'] = array(
'#type' => 'textfield',
'#title' => t('Number of nodes to list'),
'#default_value' => variable_get('node_export_features_ui_range', 250),
'#size' => 6,
'#element_validate' => array('element_validate_integer_positive'),
'#description' => t("The Features' UI and system can become unusable if a a large number of nodes are listed to be exported. This value is the maximum number of nodes tht will be displayed." ),
);
// Content types
$form['content types'] = array(
'#type' => 'fieldset',
'#title' => t('Filter by Content Type'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array(
'class' => array('node-form-options'),
),
);
$form['content types']['node_export_features_ui_content_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Content types to display'),
'#default_value' => $default_types,
'#options' => $types,
'#description' => t('Which content types should be listed?'),
);
// Node options
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Filter by Publishing options'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array(
'class' => array('node-form-options'),
),
);
$form['options']['node_export_features_ui_status'] = array(
'#type' => 'select',
'#options' => array('Any', 'Unpublished', 'Published'),
'#title' => t('Published'),
'#default_value' => variable_get('node_export_features_ui_status', 0),
);
$form['options']['node_export_features_ui_promote'] = array(
'#type' => 'select',
'#options' => array('Any', 'Unpromoted', 'Promoted'),
'#title' => t('Promoted to front page'),
'#default_value' => variable_get('node_export_features_ui_promote', 0),
);
$form['options']['node_export_features_ui_sticky'] = array(
'#type' => 'select',
'#options' => array('Any', 'Not Sticky', 'Sticky'),
'#title' => t('Sticky at top of lists'),
'#default_value' => variable_get('node_export_features_ui_sticky', 0),
);
// Specific node filters
$form['node info'] = array(
'#type' => 'fieldset',
'#title' => t('Filter by Specific Node Info'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array(
'class' => array('node-form-options'),
),
);
$form['node info']['node_export_features_ui_title'] = array(
'#type' => 'textfield',
'#title' => t('Title match'),
'#default_value' => variable_get('node_export_features_ui_title', ''),
'#size' => 60,
'#description' => t("An SQL 'LIKE' match for titles. Use % to match any substring and _ to match a single character. For example, %Test_Node% to find any title like A Test Node for... or A Test-Node for..." ),
);
$form['node info']['node_export_features_ui_uuids'] = array(
'#type' => 'textarea',
'#title' => t('Specific node UUIDs to display'),
'#default_value' => variable_get('node_export_features_ui_uuids', ''),
'#description' => t('Enter node UUIDs to list. One uuid per line.'),
'#cols' => 20,
'#rows' => 10,
);
return system_settings_form($form);
}
/**
* Validate and normalize some of the inputs.
*
* @param array $form
* The form array
* @param array $form_state
* The current form state.
*/
function node_export_features_ui_settings_validate($form, &$form_state ) {
module_load_include('inc', 'uuid');
$values = $form_state['values'];
$field = 'node_export_features_ui_uuids';
$uuids = node_export_features_ui_textarea_to_array($values[$field]);
$invalid_uuids = array();
foreach ( $uuids as $uuid ) {
if ( ! uuid_is_valid($uuid) ) {
$invalid_uuids[] = $uuid;
}
}
if ( empty($invalid_uuids) ) {
$form_state['values'][$field] = implode("\r\n", $uuids);
}
else {
form_set_error($field, t("Invalid UUID(s) found: ") . check_plain(implode(',', $invalid_uuids)));
}
// Convert type options to wanted type array
$field = 'node_export_features_ui_content_types';
$types = array();
foreach ( $values[$field] as $type ) {
if ( $type ) {
$types[] = $type;
}
}
$form_state['values'][$field] = $types;
}

View File

@ -98,7 +98,10 @@ class FeedsNodeExportProcessor extends FeedsNodeProcessor {
node_export_save($node);
$this->new_nodes[$node->nid] = $node;
// @todo: Is this what we should do with output messages?
drupal_set_message(t("Imported node !nid: !node", array('!nid' => $node->nid, '!node' => l($node->title, 'node/' . $node->nid))));
drupal_set_message(t("Imported node !nid: !node", array(
'!nid' => $node->nid,
'!node' => l($node->title, 'node/' . $node->nid)
)));
}
}

View File

@ -6,9 +6,9 @@ dependencies[] = "feeds"
dependencies[] = "node_export"
files[] = FeedsNodeExportParser.inc
files[] = FeedsNodeExportProcessor.inc
; Information added by drupal.org packaging script on 2012-08-20
version = "7.x-3.0"
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1345435979"
datestamp = "1457077222"

View File

@ -8,7 +8,11 @@
* Implementation of hook_ctools_plugin_api().
*/
function node_export_feeds_ctools_plugin_api($module = '', $api = '') {
if ($module == 'feeds' && in_array($api, array('feeds_importer_default', 'plugins'))) {
if ($module == 'feeds' && in_array($api, array(
'feeds_importer_default',
'plugins'
))
) {
return array('version' => 1);
}
}

View File

@ -4,9 +4,9 @@ dependencies[] = node_export
dependencies[] = uuid
core = 7.x
package = "Node export"
; Information added by drupal.org packaging script on 2012-08-20
version = "7.x-3.0"
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1345435979"
datestamp = "1457077222"

View File

@ -61,7 +61,7 @@ function node_export_relation_node_reference_update($nodes) {
/**
* Recursively load node references.
*/
function node_export_relation_node_reference_load(&$nodes, $nid) {
function node_export_relation_node_reference_load(&$nodes, $nid, $reset = FALSE) {
// Alias for easy referencing.
$node = &$nodes[$nid];
@ -76,12 +76,12 @@ function node_export_relation_node_reference_load(&$nodes, $nid) {
// Load the referenced nodes only if its not already loaded
// This will save if from infinite loop of back references
if (!isset($nodes[$node_reference['nid']])) {
$new_node = node_load($node_reference['nid']);
if (node_export_access_export($new_node)) {
$new_node = node_load($node_reference['nid'], NULL, $reset);
if (node_export_access_export($new_node, $reset)) {
$new_node = node_export_prepare_node($new_node);
$nodes[$new_node->nid] = $new_node;
// Recursively load references of new nodes
node_export_relation_node_reference_load($nodes, $new_node->nid);
node_export_relation_node_reference_load($nodes, $new_node->nid, $reset);
}
elseif (!variable_get('node_export_node_reference_skip', TRUE)) {
// Set this node to FALSE to trigger an error in node export.

View File

@ -1,13 +0,0 @@
Index: node_export.module
===================================================================
--- node_export.module (revision 172)
+++ node_export.module (working copy)
@@ -1146,7 +1146,7 @@
if (!empty($query)) {
watchdog('node_export', 'kept existing managed file at uri "%uri"', array('%uri' => $file->uri), WATCHDOG_NOTICE);
- $file = file_load(array_shift($query));
+ $file = (object) array_merge((array) $file, (array) file_load(array_shift($query)));
}
$file = file_save($file);

View File

@ -5,9 +5,11 @@ core = 7.x
package = "Node export"
configure = admin/config/content/node_export
files[]=views/views_handler_field_node_link_export.inc
; Information added by drupal.org packaging script on 2012-08-20
version = "7.x-3.0"
files[]=node_export.test
; Information added by Drupal.org packaging script on 2016-03-04
version = "7.x-3.1"
core = "7.x"
project = "node_export"
datestamp = "1345435979"
datestamp = "1457077222"

View File

@ -35,12 +35,9 @@ function node_export_uninstall() {
// DSV format.
variable_del('node_export_dsv_delimiter');
variable_del('node_export_dsv_enclosure');
variable_del('node_export_dsv_seperator');
variable_del('node_export_dsv_separator');
variable_del('node_export_dsv_escape_eol');
// Old vars.
variable_del('node_export_reset_' . $type);
variable_del('node_export_nodes_without_confirm');
}
@ -133,3 +130,21 @@ function node_export_update_7303() {
}
return 'Node export format modules removed, functionality moved to Node export.';
}
/**
* Remove and rename vars.
*/
function node_export_update_7304() {
$types = node_type_get_names();
foreach ($types as $type => $name) {
variable_del('node_export_reset_' . $type);
}
$sep = variable_get('node_export_dsv_seperator', '\r\n');
variable_set('node_export_dsv_separator', $sep);
variable_del('node_export_nodes_without_confirm');
variable_del('node_export_dsv_seperator');
}

View File

@ -38,6 +38,12 @@ function node_export_menu() {
'description' => 'Configure the settings for Node export.',
'file' => 'node_export.pages.inc',
);
// Allow other modules to add local task tabs.
$items['admin/config/content/node_export/settings'] = array(
'title' => 'Settings',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
if (count(array_filter($selected_formats)) > 1) {
$format_handlers = node_export_format_handlers();
@ -93,10 +99,10 @@ function node_export_menu() {
/**
* Check access to export a node.
*/
function node_export_access_export($node) {
function node_export_access_export($node, $reset = FALSE) {
global $user;
if (is_int($node)) {
$node = node_load($node);
if (is_numeric($node)) {
$node = node_load($node, NULL, $reset);
}
if (function_exists('drush_main')) {
@ -257,31 +263,32 @@ function node_export_bulk_operation($nodes = NULL, $format = NULL, $delivery = N
*/
function node_export_action_info() {
$actions = array();
if (user_access('export nodes')) {
$selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
$format_handlers = node_export_format_handlers();
foreach ($format_handlers as $format_handler => $format) {
if (!empty($selected_formats[$format_handler])) {
// @todo: should formats be able to define their own actions?
if (!empty($format['#file']) && is_file($format['#file'])) {
require_once $format['#file'];
}
$format_action = 'node_export_' . $format_handler . '_action';
if (function_exists($format_action . '_form')) {
$actions[$format_action] = array(
'type' => 'node',
'label' => t('Node export') . " (" . $format['#title'] . ")",
'behavior' => array('changes_property'),
// This action only works when invoked through VBO. That's why it's
// declared as non-configurable to prevent it from being shown in the
// "Create an advanced action" dropdown on admin/config/system/actions.
'configurable' => FALSE,
'vbo_configurable' => TRUE,
);
}
$selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
$format_handlers = node_export_format_handlers();
foreach ($format_handlers as $format_handler => $format) {
if (in_array($format_handler, $selected_formats)) {
// @todo: should formats be able to define their own actions?
if (!empty($format['#file']) && is_file($format['#file'])) {
require_once $format['#file'];
}
$format_action = 'node_export_' . $format_handler . '_action';
if (function_exists($format_action . '_form')) {
$actions[$format_action] = array(
'type' => 'node',
'label' => t('Node export') . " (" . $format['#title'] . ")",
'behavior' => array('changes_property'),
// This action only works when invoked through VBO. That's why it's
// declared as non-configurable to prevent it from being shown in the
// "Create an advanced action" dropdown on admin/config/system/actions.
'configurable' => FALSE,
'vbo_configurable' => TRUE,
'triggers' => array('any'),
);
}
}
}
return $actions;
}
@ -314,12 +321,14 @@ function node_export_action_form($context, &$form_state, $format = NULL) {
* The format to use for export.
* @param $msg_t
* Function used to translate.
* @param $reset
* Whether to reset the node_load_multiple cache.
* @return
* An array with keys 'success' which is a boolean value representing whether
* the export was successful and 'output' which contains the code string or an
* array of translated error messages to be shown to the user.
*/
function node_export($nids, $format = NULL, $msg_t = 't') {
function node_export($nids, $format = NULL, $msg_t = 't', $reset = FALSE) {
global $user;
// Make $nids an array if it isn't.
@ -332,9 +341,9 @@ function node_export($nids, $format = NULL, $msg_t = 't') {
$nodes = array();
foreach ($nids as $nid) {
$original_node = node_load($nid);
$original_node = node_load($nid, NULL, $reset);
if (!node_export_access_export($original_node)) {
if (!node_export_access_export($original_node, $reset)) {
// Halt exporting.
$error = $msg_t("You do not have permission to perform a Node export on one or more of these nodes. No nodes exported.");
return array(
@ -418,7 +427,7 @@ function node_export_prepare_node(&$original_node) {
}
}
if (isset($new_taxonomy['tags']) && count($new_taxonomy['tags'])) {
// Comma seperate the tags
// Comma separate the tags
foreach ($new_taxonomy['tags'] as $vid => $tags) {
$new_taxonomy['tags'][$vid] = implode(', ', $tags);
}
@ -571,11 +580,13 @@ function node_export_import($code_string, $msg_t = 't', $save = TRUE) {
$messages = array();
foreach ($nodes as $original_node) {
$node = node_export_node_clone($original_node);
$tnid_to_reset = node_export_node_clone_set_tnid($node, $original_node);
// Import file fields.
node_export_file_field_import($node, $original_node);
// Handle existing nodes.
$save_node = $save;
$nids = entity_get_id_by_uuid('node', array($node->uuid));
if (!empty($nids[$node->uuid])) {
$existing = variable_get('node_export_existing', 'new');
@ -588,17 +599,27 @@ function node_export_import($code_string, $msg_t = 't', $save = TRUE) {
$node->nid = $nids[$node->uuid];
$node->is_new = FALSE;
$node->revision = 1;
$tnid_to_reset = 0;
break;
case 'skip':
$save = FALSE;
$save_node = FALSE;
break;
}
}
// Let other modules do special fixing up.
drupal_alter('node_export_node_import', $node, $original_node, $save);
drupal_alter('node_export_node_import', $node, $original_node, $save_node);
if ($save_node) {
if (!empty($tnid_to_reset) && empty($node->tnid)) {
node_export_save($node);
$node->tnid = $node->nid;
// Update the tnid map for other nodes referencing this tnid.
$tnid_map = &drupal_static('node_export_import_tnid_map', array());
$tnid_map[$tnid_to_reset] = $node->tnid;
}
if ($save) {
node_export_save($node);
$new_nodes[$node->nid] = $node;
$messages[] = $msg_t("Imported node !nid: !node", array('!nid' => $node->nid, '!node' => l($node->title, 'node/' . $node->nid)));
@ -609,7 +630,7 @@ function node_export_import($code_string, $msg_t = 't', $save = TRUE) {
}
}
if ($save) {
if ($count) {
drupal_alter('node_export_after_import', $new_nodes, $used_format, $save);
$messages[] = $msg_t("!count of !total nodes were imported. Some values may have been reset depending on Node export's configuration.", array('!total' => $total, '!count' => $count));
@ -676,6 +697,7 @@ function node_export_save(&$node) {
// Let modules modify the node before it is saved to the database.
module_invoke_all('node_presave', $node);
module_invoke_all('entity_presave', $node, 'node');
if ($node->is_new || !empty($node->revision)) {
// When inserting either a new node or a new node revision, $node->log
@ -787,6 +809,12 @@ function node_export_node_clone($original_node) {
if (variable_get('node_export_reset_author_' . $node->type, TRUE)) {
$node->name = !empty($user->name) ? $user->name : (!empty($user->uid) ? NULL : variable_get('anonymous', t('Anonymous')));
$node->uid = $user->uid;
$node->revision_uid = $user->uid;
}
// note: a uid of 0 is erroneous in any case, reset it to 1 (admin user)
if ($node->revision_uid == 0) {
$node->revision_uid = 1;
}
if (variable_get('node_export_reset_created_' . $node->type, TRUE)) {
@ -841,10 +869,76 @@ function node_export_node_clone($original_node) {
$node->sticky = FALSE;
}
// check for a data casting error
if ($node->data == 'b:0;') { // data has been serialized as a FALSE instead of NULL
$node->data = NULL;
}
// sort the node keys, so that there is a consistent representation for
// (drupal_)var_export
$array_node = (array) $node;
ksort( $array_node);
$node = (object) $array_node;
return $node;
}
/**
* Update the tnid value on the new node based on the tnid value from the old node.
*
* If the original node has a tnid that matches its nid, then we can deduce that this
* tnid needs to be changed to match the node's nid (which will only be set after
* first saving the node).
*
* If the original node has a tnid that does not match its nid, we first check to see
* if we have already updated the tnid on another node that had this tnid originally.
* If so, we will use that tnid. Otherwise, we leave the tnid specified in the import
* unchanged.
*
* As such, when importing a set of nodes that are all linked via tnid, it is necessary
* that the first node where nid = tnid is imported prior to any of the other nodes
* that share that tnid.
*
* @return number
* original tnid if the tnid on this node needs to be set equal to the node's nid
* when it is saved, otherwise NULL
*/
function node_export_node_clone_set_tnid(&$node, $original_node) {
if (!empty($original_node->tnid)) {
$tnid_map = drupal_static('node_export_import_tnid_map', array());
if (!empty($tnid_map[$original_node->tnid])) {
$node->tnid = $tnid_map[$original_node->tnid];
}
elseif (!empty($original_node->nid) && $original_node->tnid == $original_node->nid) {
$node->tnid = 0;
return $original_node->tnid;
}
}
return NULL;
}
/**
* Implements hook_node_export_alter().
* In case when node translation is enabled we have to ensure that original nodes
* appear in export before their translations. This is done to properly assign tnid
* to translations, because we don't know until the first node in the set is saved.
*/
function node_export_node_export_alter(&$nodes, $format_handler) {
if (module_exists('translation')) {
$source_nodes = array();
foreach ($nodes as $i => $node) {
if ($node->nid == $node->tnid) {
$source_nodes[] = $node;
unset($nodes[$i]);
}
}
if ($source_nodes) {
$nodes = array_merge($source_nodes, $nodes);
}
}
}
/**
* Create a new menu entry with title, parent and weight exported from
* another nodes menu. Returns NULL if the node has no menu title.
@ -967,16 +1061,51 @@ function node_export_format_handlers() {
if (empty($format_handlers)) {
$format_handlers = module_invoke_all('node_export_format_handlers');
}
drupal_alter('node_export_format_handlers', $format_handlers);
return $format_handlers;
}
/**
* Get entity type and bundle of the given entity. Works for nodes and field
* collection items.
*
* @param $entity
* Entity to get information of.
*
* @return
* Associative array with the 'type' and 'bundle' fields.
*/
function _node_export_entity_info($entity) {
$info = array();
if (method_exists($entity, 'entityType')
&& $entity->entityType() == 'field_collection_item') {
$info['type'] = $entity->entityType();
// Field the collection is attached to.
$info['bundle'] = $entity->field_name;
}
else {
$info['type'] = 'node';
$info['bundle'] = $entity->type;
}
return $info;
}
/**
* Handle exporting file fields.
*
* @param $entity
* Node or field_collection_item object.
* @param $original_entity
* Unused...
*/
function node_export_file_field_export(&$node, $original_node) {
function node_export_file_field_export(&$entity, $original_entity) {
$entity_info = _node_export_entity_info($entity);
$types = array_filter(variable_get('node_export_file_types', array()));
if (in_array($node->type, $types)) {
if ($entity_info['type'] != 'node' || in_array($entity->type, $types)) {
$assets_path = variable_get('node_export_file_assets_path', '');
$export_mode = variable_get('node_export_file_mode', 'inline');
@ -1011,11 +1140,11 @@ function node_export_file_field_export(&$node, $original_node) {
}
// get all fields from this node type
$fields = field_info_instances('node', $node->type);
$fields = field_info_instances($entity_info['type'],
$entity_info['bundle']);
foreach($fields as $field_instance) {
// load field infos to check the type
$field = &$node->{$field_instance['field_name']};
$field = &$entity->{$field_instance['field_name']};
$info = field_info_field($field_instance['field_name']);
$supported_fields = array_map('trim', explode(',', variable_get('node_export_file_supported_fields', 'file, image')));
@ -1032,6 +1161,13 @@ function node_export_file_field_export(&$node, $original_node) {
// convert file to array to stay into the default node_export_file format
$file = (object) $file;
// media field type doesn't load file the whole file on node_load
// it loads only fid, title and data associated with file, so in this case we need
// to load it by ourselves.
if (empty($file->uri) && !empty($file->fid) && $file = file_load($file->fid)) {
$field[$language][$i] = (array) $file;
}
// Check the file
if (!isset($file->uri) || !is_file($file->uri)) {
drupal_set_message(t("File field found on node, but file doesn't exist on disk? '!path'", array('!path' => $file->uri)), 'error');
@ -1052,7 +1188,8 @@ function node_export_file_field_export(&$node, $original_node) {
}
// Remote export mode
elseif ($export_mode == 'remote') {
$export_data = url($file->uri, array('absolute' => TRUE));
// NOTE: This is patched with info from https://drupal.org/node/2046431
$export_data = file_create_url($file->uri);
}
// Default is 'inline' export mode
else {
@ -1074,14 +1211,20 @@ function node_export_file_field_export(&$node, $original_node) {
/**
* Handle importing file fields.
*
* @param $entity
* Node or field_collection_item object.
* @param $original_entity
* Unused...
*/
function node_export_file_field_import(&$node, $original_node) {
// Get all fields from this node type.
$fields = field_info_instances('node', $node->type);
foreach($fields as $field_instance) {
function node_export_file_field_import(&$entity, $original_entity) {
$entity_info = _node_export_entity_info($entity);
// Get all fields from this node type.
$fields = field_info_instances($entity_info['type'], $entity_info['bundle']);
foreach($fields as $field_instance) {
// Load field info to check the type.
$field = &$node->{$field_instance['field_name']};
$field = &$entity->{$field_instance['field_name']};
$info = field_info_field($field_instance['field_name']);
$supported_fields = array_map('trim', explode(',', variable_get('node_export_file_supported_fields', 'file, image')));
@ -1093,17 +1236,17 @@ function node_export_file_field_import(&$node, $original_node) {
// fields with different language than the node one.
foreach($field as $language => $files) {
if (is_array($files)) {
foreach($files as $i => $file) {
foreach($files as $i => $field_value) {
// Convert file to array to stay into the default node_export_file format.
$file = (object)$file;
$file = (object) $field_value;
$result = _node_export_file_field_import_file($file);
// The file was saved successfully, update the file field (by reference).
if ($result == TRUE && isset($file->fid)) {
$field[$language][$i] = (array)$file;
// Retain any special properties from the original field value.
$field[$language][$i] = array_merge($field_value, (array) $file);
}
}
}
}
@ -1149,6 +1292,9 @@ function _node_export_file_field_import_file(&$file) {
if (!empty($query)) {
watchdog('node_export', 'kept existing managed file at uri "%uri"', array('%uri' => $file->uri), WATCHDOG_NOTICE);
$file = file_load(array_shift($query));
} elseif(isset($file->fid)) {
unset($file->fid);
$file = (object) array_merge((array) $file, (array) file_load(array_shift($query)));
}
@ -1158,7 +1304,13 @@ function _node_export_file_field_import_file(&$file) {
$directory = drupal_dirname($file->uri);
if (file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
if (file_put_contents($file->uri, base64_decode($file->node_export_file_data))) {
$file = file_save($file);
$files = file_load_multiple(array(), array('uri' => $file->uri));
// Only attempt to save the file if a record doesn't already exist in
// the file_managed table.
if (count($files) == 0) {
$file = file_save($file);
}
}
}
}
@ -1260,12 +1412,11 @@ if (!function_exists('uuid_set_uuid')) {
return FALSE;
}
$query = db_query("UPDATE {" . $table . "} SET uuid = :uuid WHERE " . $key . " = :id", array(':uuid' => $uuid, ':id' => $serial_id));
/*
if (!$query->rowCount()) {
@db_query("INSERT INTO {" . $table . "} (" . $key . ", uuid) VALUES (:id, :uuid)", array(':uuid' => $uuid, ':id' => $serial_id));
}
*/
$query = db_update($table)
->fields(array('uuid' => $uuid))
->condition($key, $serial_id, '=')
->execute();
return $uuid;
}

View File

@ -268,7 +268,7 @@ function node_export_settings($form, &$form_state) {
'#title' => t('Supported file field types'),
'#default_value' => variable_get('node_export_file_supported_fields', 'file, image'),
'#maxlength' => 512,
'#description' => t('Comma seperated list of file field types to detect for export/import.'),
'#description' => t('Comma separated list of file field types to detect for export/import.'),
);
return system_settings_form($form);

View File

@ -0,0 +1,109 @@
<?php
/**
* @file
* Node export/import tests.
*/
define('ORIGINAL_TITLE', 'Original node title');
define('CHANGED_TITLE', 'Changed node title');
define('ORIGINAL_BODY', 'This is some original test text for the node body.');
define('CHANGED_BODY', 'Changed test text for the node body.');
/**
* Test XML export and import.
*/
class NodeExportXMLTestCase extends DrupalWebTestCase {
protected $user;
public static function getInfo() {
return array(
'name' => 'Node Export XML export/import test',
'description' => 'Test exporting a node as XML, changing the exported XML, then importing the changed XML.',
'group' => 'Node Export',
);
}
function setUp() {
parent::setUp('node_export');
// Make sure the export gives back a file.
variable_set('node_export_code', 'file');
// We want to test XML export.
variable_set('node_export_format', array('xml'));
variable_set('node_export_existing', 'revision');
$this->user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access', 'export nodes', 'export own nodes', 'use PHP to import nodes'));
$this->drupalLogin($this->user);
}
/**
* Test XML export and import.
*/
function testNodeExportXMLExportImport() {
$langcode = LANGUAGE_NONE;
$title_key = 'title';
$body_key = "body[{$langcode}][0][value]";
$original_title = ORIGINAL_TITLE;
$changed_title = CHANGED_TITLE;
$original_body = ORIGINAL_BODY;
$changed_body = CHANGED_BODY;
$settings = array(
'type' => 'page',
'title' => $original_title,
'body' => array($langcode => array(array('value' => $original_body))),
);
$node = $this->drupalCreateNode($settings);
$this->verbose('Node created: ' . var_export($node, TRUE));
$this->drupalGet("node/{$node->nid}/edit");
$this->assertFieldByName($title_key, $original_title, "Found original title in edit form.");
$this->assertFieldByName($body_key, $original_body, "Found original body in edit form.");
// Test export.
$xml_file = $this->drupalGet("node/{$node->nid}/node_export");
// Check if the export is valid XML.
$this->assertResponse(200, 'Export was successful.');
$this->assertTrue(simplexml_load_string($xml_file), 'XML is valid.');
$node_export = simplexml_load_string($xml_file);
debug($node_export->asXml(), 'Before changing the XML');
// Find the original title in the XML.
$original_title_value = $node_export->xpath("node[1]/title[text() = '{$original_title}']");
$title_found = !empty($original_title_value);
$this->assertTrue($title_found, 'Original title was found in the XML.');
if ($title_found) {
// Change the title value.
$original_title_value[0][0] = $changed_title;
}
// Find the original body in the XML.
$original_body_value = $node_export->xpath("node[1]//body//n0//*[text() = '{$original_body}']");
$body_found = !empty($original_body_value);
$this->assertTrue($body_found, 'Original body was found in the XML.');
if ($body_found) {
// Change the body value.
$original_body_value[0][0] = $changed_body;
}
// Find the changed title in the XML.
$changed_title_value = $node_export->xpath("node[1]/title[text() = '{$changed_title}']");
$this->assertTrue(!empty($changed_title_value), 'Changed title was found in the XML.');
// Find the changed body in the XML.
$changed_body_value = $node_export->xpath("node[1]//body//n0//*[text() = '{$changed_body}']");
$this->assertTrue(!empty($changed_body_value), 'Changed body was found in the XML.');
if ($title_found || $body_found) {
debug($node_export->asXml(), 'After changing the XML');
}
// Test import.
$import_info = node_export_import($node_export->asXml());
$this->assertTrue($import_info['success'], 'Import was succesful.');
if ($import_info['success']) {
$this->assertEqual($import_info['format'], 'xml', 'XML was imported.');
}
$this->drupalGet("node/{$node->nid}/edit");
$this->assertFieldByName($title_key, $changed_title, "Found changed title in edit form.");
$this->assertFieldByName($body_key, $changed_body, "Found changed body in edit form.");
}
}

View File

@ -55,7 +55,7 @@ function node_export_token_info() {
'node_export_filename' => array(
'nid-list' => array(
'name' => t("Node ID list"),
'description' => t("Comma seperated list of Node IDs in square brackets (if available)."),
'description' => t("Comma separated list of Node IDs in square brackets (if available)."),
),
'node-count' => array(
'name' => t("Node count"),

View File

@ -13,19 +13,14 @@
class views_handler_field_node_link_export extends views_handler_field_node_link {
function construct() {
parent::construct();
$this->additional_fields['uid'] = 'uid';
$this->additional_fields['type'] = 'type';
$this->additional_fields['format'] = array('table' => 'node_revisions', 'field' => 'format');
$this->additional_fields['nid'] = 'nid';
}
function render($values) {
// Insure that user has access to export this node.
// Ensure that user has access to export this node.
$node = new stdClass();
$node->nid = $values->{$this->aliases['nid']};
$node->uid = $values->{$this->aliases['uid']};
$node->type = $values->{$this->aliases['type']};
$node->format = $values->{$this->aliases['format']};
if (!node_export_access_check($node)) {
if (!node_export_access_export($node->nid)) {
return;
}

View File

@ -1,56 +0,0 @@
diff --git a/node_export.module b/node_export.module
index 8bdadb9..052fa6c 100755
--- a/node_export.module
+++ b/node_export.module
@@ -38,7 +38,7 @@ function node_export_menu() {
'description' => 'Configure the settings for Node export.',
'file' => 'node_export.pages.inc',
);
- $selected_formats = variable_get('node_export_format', array('drupal'));
+ $selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
if (count(array_filter($selected_formats)) > 1) {
$format_handlers = node_export_format_handlers();
foreach ($format_handlers as $format_handler => $format) {
@@ -218,7 +218,7 @@ function node_export_node_operations() {
$operations = array();
if (user_access('export nodes')) {
- $selected_formats = variable_get('node_export_format', array('drupal'));
+ $selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
if (count(array_filter($selected_formats)) > 1) {
$format_handlers = node_export_format_handlers();
foreach ($format_handlers as $format_handler => $format) {
@@ -258,7 +258,7 @@ function node_export_bulk_operation($nodes = NULL, $format = NULL, $delivery = N
function node_export_action_info() {
$actions = array();
if (user_access('export nodes')) {
- $selected_formats = variable_get('node_export_format', array('drupal'));
+ $selected_formats = variable_get('node_export_format', array('drupal' => 'drupal'));
$format_handlers = node_export_format_handlers();
foreach ($format_handlers as $format_handler => $format) {
if (!empty($selected_formats[$format_handler])) {
@@ -296,10 +296,13 @@ function node_export_action_info() {
function node_export_action_form($context, &$form_state, $format = NULL) {
// Get the name of the vbo views field
$vbo = _views_bulk_operations_get_field($form_state['build_info']['args'][0]);
+
// Adjust the selection in case the user chose 'select all'
- _views_bulk_operations_adjust_selection($form_state['selection'], $form_state['select_all_pages'], $vbo);
+ if (!empty($form_state['select_all_pages'])) {
+ views_bulk_operations_direct_adjust($form_state['selection'], $vbo);
+ }
$nodes = array_combine($form_state['selection'], $form_state['selection']);
- return node_export_bulk_operation($nodes);
+ return node_export_bulk_operation($nodes, $format);
}
/**
@@ -347,7 +350,7 @@ function node_export($nids, $format = NULL, $msg_t = 't') {
// Get the node code from the format handler
$format_handlers = node_export_format_handlers();
- $node_export_format = variable_get('node_export_format', array('drupal'));
+ $node_export_format = variable_get('node_export_format', array('drupal' => 'drupal'));
$format_handler = $format ? $format : reset($node_export_format);
if (!isset($format_handlers[$format_handler])) {
$format_handler = 'drupal';

View File

@ -1,6 +1,22 @@
Mime Mail 7.x-1.x, xxxx-xx-xx
-----------------------
Mime Mail 7.x-1.0-beta4, 2015-08-02
-----------------------
- #2413495 by sgabe, siggi_kid: Public images not embedded when file default scheme is private
- #2312747 by Lukas von Blarer: Remove 'itok' token from image URL
- #2366659 by david_garcia: Attachments created by content generate warnings
- #2404719 by alexp999: Missing space in RFC headers breaks DKIM
- #1908318 by jvieille, zionduc, bisonbleu | anrkaid: Sender is double encoded.
- #2359771 by PascalAnimateur: Support for OG membership tokens.
- #2218037 by sgabe | pinkonomy: Fixed integrity constraint violation.
- #2219609 by mitrpaka, sgabe: Convert float properties just for images.
- #2057703 by New Zeal, sgabe: Warning: is_file() expects a valid path.
- #2202127 by k.skarlatos: Added List-Unsubscribe header field for bulk mails.
- #2297135 by tobiasb: Language prefix with absolute-path reference.
- #2297091 by cameron1729: TLDs in Return-Path trimmed to 4 characters.
- #2237109 by Dane Powell: Indicate text format for body in Rules.
Mime Mail 7.x-1.0-beta3, 2014-03-05
-----------------------
- Public files test incorrect if similar path is not below root.

View File

@ -84,6 +84,12 @@
the mail.css file found anywhere in your theme folder or
the combined CSS style sheets of your theme if enabled.
Since some email clients (namely Outlook 2007 and GMail) is tend to only regard
inline CSS, you can use the Compressor to convert CSS styles into inline style
attributes. It transmogrifies the HTML source by parsing the CSS and inserting the
CSS definitions into tags within the HTML based on the CSS selectors. To use the
Compressor, just enable it.
To create a custom mail template copy the mimemail-message.tpl.php file from
the mimemail/theme directory into your default theme's folder. Both general and
by-mailkey theming can be performed:
@ -100,17 +106,15 @@
or any other active theme.
Images with absolute URL will be available as remote content. To embed images
into emails you have to use a relative URL or an internal path.
into emails you have to use a relative URL or an internal path. Due to security
concerns, only files residing in the public file system (e.g sites/default/files)
can be used by default.
For example:
instead of http://www.mysite.com/sites/default/files/mypicture.jpg
use /home/www/public_html/drupal/sites/default/files/mypicture.jpg
or /sites/default/files/mypicture.jpg
Since some email clients (namely Outlook 2007 and GMail) is tend to only regard
inline CSS, you can use the Compressor to convert CSS styles into inline style
attributes. It transmogrifies the HTML source by parsing the CSS and inserting the
CSS definitions into tags within the HTML based on the CSS selectors. To use the
Compressor, just enable it.
or public://mypicture.jpg
The 'send arbitrary files' permission allows you to attach or embed files located
outside Drupal's public files directory. Note that this has security implications:

View File

@ -84,6 +84,10 @@ function mimemail_admin_settings() {
'#default_value' => variable_get('mimemail_format', filter_fallback_format()),
'#access' => count($formats) > 1,
'#attributes' => array('class' => array('filter-list')),
'#description' => t('The filter set that will be applied to the message body.
If you are using Mime Mail as default mail sytem, make sure to enable
"Convert line breaks into HTML" and "Convert URLs into links" with a long
enough maximum length for e.g. password reset URLs!'),
);
$form['mimemail']['advanced'] = array(

View File

@ -37,7 +37,7 @@ function mimemail_rfc_headers($headers) {
$value = wordwrap($value, 50, "$crlf ", FALSE);
}
}
$header .= $key . ":" . $value . $crlf;
$header .= $key . ": " . $value . $crlf;
}
return trim($header);
}
@ -66,7 +66,8 @@ function mimemail_headers($headers, $from = NULL) {
}
// This may not work. The MTA may rewrite the Return-Path.
if (!isset($headers['Return-Path']) || $headers['Return-Path'] == $default_from) {
if (preg_match('/[a-z\d\-\.\+_]+@(?:[a-z\d\-]+\.)+[a-z\d]{2,4}/i', $from, $matches)) {
// According to IANA the current longest TLD is 23 characters.
if (preg_match('/[a-z\d\-\.\+_]+@(?:[a-z\d\-]+\.)+[a-z\d]{2,23}/i', $from, $matches)) {
$headers['Return-Path'] = "<$matches[0]>";
}
}
@ -80,7 +81,10 @@ function mimemail_headers($headers, $from = NULL) {
// Run all headers through mime_header_encode() to convert non-ascii
// characters to an rfc compliant string, similar to drupal_mail().
foreach ($headers as $key => $value) {
$headers[$key] = mime_header_encode($value);
// According to RFC 2047 addresses MUST NOT be encoded.
if ($key !== 'From' && $key !== 'Sender') {
$headers[$key] = mime_header_encode($value);
}
}
return $headers;
@ -187,19 +191,22 @@ function _mimemail_file($url = NULL, $content = NULL, $name = '', $type = '', $d
$file = $content;
}
if (isset($file) && (@is_file($file) || $content)) {
$public_path = file_default_scheme() . '://';
$no_access = !user_access('send arbitrary files');
$not_in_public_path = strpos(drupal_realpath($file), drupal_realpath($public_path)) !== 0;
if (@is_file($file) && $not_in_public_path && $no_access) {
return $url;
if (isset($file)) {
$is_file = @is_file($file);
if ($is_file) {
$access = user_access('send arbitrary files');
$in_public_path = strpos(@drupal_realpath($file), drupal_realpath('public://')) === 0;
if (!$in_public_path && !$access) {
return $url;
}
}
if (!$name) {
$name = (@is_file($file)) ? basename($file) : 'attachment.dat';
$name = $is_file ? basename($file) : 'attachment.dat';
}
if (!$type) {
$type = ($name) ? file_get_mimetype($name) : file_get_mimetype($file);
$type = $is_file ? file_get_mimetype($file) : file_get_mimetype($name);
}
$id = md5($file) .'@'. $_SERVER['HTTP_HOST'];
@ -322,7 +329,7 @@ function mimemail_multipart_body($parts, $content_type = 'multipart/mixed; chars
}
if (isset($part['file'])) {
$file = (is_file($part['file'])) ? file_get_contents($part['file']) : $part['file'];
$file = (@is_file($part['file'])) ? file_get_contents($part['file']) : $part['file'];
$part_body = chunk_split(base64_encode($file), 76, variable_get('mimemail_crlf', "\n"));
}
@ -457,17 +464,14 @@ function _mimemail_url($url, $to_embed = NULL) {
else {
$url = preg_replace('!^' . base_path() . '!', '', $url, 1);
if ($is_image) {
// Remove security token from URL, this allows for styled image embedding.
// @see https://drupal.org/drupal-7.20-release-notes
$url = preg_replace('/\\?itok=.*$/', '', $url);
if ($to_link) {
// Exclude images from embedding if needed.
$url = file_create_url($url);
$url = str_replace(' ', '%20', $url);
}
else {
// Remove security token from URL, this allows for styled image embedding.
// @see https://drupal.org/drupal-7.20-release-notes
$url = preg_replace('/\\?itok=.*$/', '', $url);
}
}
return $url;
}
@ -490,9 +494,10 @@ function _mimemail_url($url, $to_embed = NULL) {
$language = language_default();
// Check for language prefix.
$path = trim($path, '/');
$args = explode('/', $path);
foreach ($languages as $lang) {
if ($args[0] == $lang->prefix) {
if (!empty($args) && $args[0] == $lang->prefix) {
$prefix = array_shift($args);
$language = $lang;
$path = implode('/', $args);

View File

@ -14,9 +14,9 @@ files[] = tests/mimemail.test
files[] = tests/mimemail_rules.test
files[] = tests/mimemail_compress.test
; Information added by Drupal.org packaging script on 2014-03-05
version = "7.x-1.0-beta3"
; Information added by Drupal.org packaging script on 2015-08-02
version = "7.x-1.0-beta4"
core = "7.x"
project = "mimemail"
datestamp = "1394018015"
datestamp = "1438530555"

View File

@ -5,13 +5,6 @@
* Install, update and uninstall functions for Mime Mail module.
*/
/**
* Implements hook_install().
*/
function mimemail_install() {
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('edit mimemail user settings'));
}
/**
* Implements hook_enable().
*/
@ -23,6 +16,8 @@ function mimemail_enable() {
'mimemail' => 'MimeMailSystem',
)
);
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('edit mimemail user settings'));
}
/**

View File

@ -157,6 +157,7 @@ function mimemail_mail($key, &$message, $params) {
'cc' => 'Cc',
'bcc' => 'Bcc',
'reply-to' => 'Reply-to',
'list-unsubscribe' => 'List-Unsubscribe',
);
foreach ($address_headers as $param_key => $address_header) {
$params[$param_key] = empty($params[$param_key]) ? array() : explode(',', $params[$param_key]);

View File

@ -57,6 +57,12 @@ function mimemail_rules_action_info() {
'description' => t("The address to reply to. Leave it empty to use the sender's address."),
'optional' => TRUE,
),
'list_unsubscribe' => array(
'type' => 'text',
'label' => t('Unsubscription e-mail and/or URL'),
'description' => t("An e-mail address and/or a URL which can be used for unsubscription. Values must be enclosed by angel brackets and separated by a comma."),
'optional' => TRUE,
),
'subject' => array(
'type' => 'text',
'label' => t('Subject'),
@ -66,7 +72,7 @@ function mimemail_rules_action_info() {
'body' => array(
'type' => 'text',
'label' => t('Body'),
'description' => t("The mail's message HTML body."),
'description' => t('The mail\'s HTML body. Will be formatted using the text format selected on the <a href="@url">settings</a> page.', array('@url' => url('admin/config/system/mimemail'))),
'sanitize' => TRUE,
'optional' => TRUE,
'translatable' => TRUE,
@ -74,7 +80,7 @@ function mimemail_rules_action_info() {
'plaintext' => array(
'type' => 'text',
'label' => t('Plain text body'),
'description' => t("The mail's message plaintext body."),
'description' => t("The mail's plaintext body."),
'optional' => TRUE,
'translatable' => TRUE,
),
@ -238,7 +244,7 @@ function mimemail_rules_action_mail_to_users_of_role_upgrade($element, RulesPlug
/**
* Action Implementation: Send HTML mail.
*/
function rules_action_mimemail($key, $to, $cc = NULL, $bcc = NULL, $from_name = NULL, $from_mail = NULL, $reply_to = NULL, $subject, $body, $plaintext = NULL, $attachments = array(), $langcode, $settings, RulesState $state, RulesPlugin $element) {
function rules_action_mimemail($key, $to, $cc = NULL, $bcc = NULL, $from_name = NULL, $from_mail = NULL, $reply_to = NULL, $list_unsubscribe = NULL, $subject, $body, $plaintext = NULL, $attachments = array(), $langcode, $settings, RulesState $state, RulesPlugin $element) {
module_load_include('inc', 'mimemail');
// Set the sender name and from address.
@ -268,6 +274,7 @@ function rules_action_mimemail($key, $to, $cc = NULL, $bcc = NULL, $from_name =
'cc' => $cc,
'bcc' => $bcc,
'reply-to' => $reply_to,
'list-unsubscribe' => $list_unsubscribe,
'plaintext' => $plaintext,
'attachments' => $attachments,
);

View File

@ -6,9 +6,9 @@ dependencies[] = trigger
core = 7.x
; Information added by Drupal.org packaging script on 2014-03-05
version = "7.x-1.0-beta3"
; Information added by Drupal.org packaging script on 2015-08-02
version = "7.x-1.0-beta4"
core = "7.x"
project = "mimemail"
datestamp = "1394018015"
datestamp = "1438530555"

View File

@ -24,7 +24,11 @@ function mimemail_action_info() {
*/
function mimemail_send_email_action($entity, $context) {
if (empty($context['node'])) {
$context['node'] = $entity;
if (get_class($entity) == 'OgMembership') {
$context['user'] = user_load($entity->etid);
} else {
$context['node'] = $entity;
}
}
$to = token_replace($context['to'], $context);

View File

@ -145,7 +145,7 @@ class mimemail_compress {
// Convert float to align for images.
$float = preg_match ('/float:(left|right)/', $style, $matches);
if ($float) {
if ($node->nodeName == 'img' && $float) {
$node->setAttribute('align', $matches[1]);
$node->setAttribute('vspace', 5);
$node->setAttribute('hspace', 5);

View File

@ -6,9 +6,9 @@ core = 7.x
files[] = mimemail_compress.inc
; Information added by Drupal.org packaging script on 2014-03-05
version = "7.x-1.0-beta3"
; Information added by Drupal.org packaging script on 2015-08-02
version = "7.x-1.0-beta4"
core = "7.x"
project = "mimemail"
datestamp = "1394018015"
datestamp = "1438530555"

View File

@ -0,0 +1,12 @@
name = Mime Mail Example
description = Example of how to use the Mime Mail module.
dependencies[] = mimemail
package = Example modules
core = 7.x
; Information added by Drupal.org packaging script on 2015-08-02
version = "7.x-1.0-beta4"
core = "7.x"
project = "mimemail"
datestamp = "1438530555"

View File

@ -0,0 +1,20 @@
<?php
/**
* @file
* Install, update and uninstall functions for Mime Mail Example module.
*/
/**
* Implements hook_enable().
*/
function mimemail_example_enable() {
mailsystem_set(array('mimemail_example' => 'MimeMailSystem'));
}
/**
* Implements hook_disable().
*/
function mimemail_example_disable() {
mailsystem_clear(array('mimemail_example' => 'MimeMailSystem'));
}

View File

@ -0,0 +1,170 @@
<?php
/**
* @file
* Core and contrib hook implementations for Mime Mail Example module.
*/
/**
* Implements hook_menu().
*/
function mimemail_example_menu() {
$items['example/mimemail_example'] = array(
'title' => 'Mime Mail Example',
'page callback' => 'drupal_get_form',
'page arguments' => array('mimemail_example_form'),
'access arguments' => array('access content'),
);
return $items;
}
/**
* Implements hook_mail().
*/
function mimemail_example_mail($key, &$message, $params) {
$message['subject'] = $params['subject'];
$message['body'][] = $params['body'];
}
/**
* The example email contact form.
*/
function mimemail_example_form() {
global $user;
$form['intro'] = array(
'#markup' => t('Use this form to send a HTML message to an e-mail address. No spamming!'),
);
$form['key'] = array(
'#type' => 'textfield',
'#title' => t('Key'),
'#default_value' => 'test',
'#required' => TRUE,
);
$form['to'] = array(
'#type' => 'textfield',
'#title' => t('To'),
'#default_value' => $user->mail,
'#required' => TRUE,
);
$form['from'] = array(
'#type' => 'textfield',
'#title' => t('Sender name'),
);
$form['from_mail'] = array(
'#type' => 'textfield',
'#title' => t('Sender e-mail address'),
);
$form['params'] = array(
'#tree' => TRUE,
'headers' => array(
'Cc' => array(
'#type' => 'textfield',
'#title' => t('Cc'),
),
'Bcc' => array(
'#type' => 'textfield',
'#title' => t('Bcc'),
),
'Reply-to' => array(
'#type' => 'textfield',
'#title' => t('Reply to'),
),
'List-unsubscribe' => array(
'#type' => 'textfield',
'#title' => t('List-unsubscribe'),
),
),
'subject' => array(
'#type' => 'textfield',
'#title' => t('Subject'),
),
'body' => array(
'#type' => 'textarea',
'#title' => t('HTML message'),
),
'plain' => array(
'#type' => 'hidden',
'#states' => array(
'value' => array(
':input[name="body"]' => array('value' => ''),
),
),
),
'plaintext' => array(
'#type' => 'textarea',
'#title' => t('Plain text message'),
),
'attachments' => array(
'#name' => 'files[attachment]',
'#type' => 'file',
'#title' => t('Choose a file to send as attachment'),
),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Send message'),
);
return $form;
}
/**
* Form validation logic for the email contact form.
*/
function mimemail_example_form_validate($form, &$form_state) {
$values = &$form_state['values'];
if (!valid_email_address($values['to'])) {
form_set_error('to', t('That e-mail address is not valid.'));
}
$file = file_save_upload('attachment');
if ($file) {
$file = file_move($file, 'public://');
$values['params']['attachments'][] = array(
'filepath' => $file->uri,
);
}
}
/**
* Form submission logic for the email contact form.
*/
function mimemail_example_form_submit($form, &$form_state) {
$values = $form_state['values'];
$module = 'mimemail_example';
$key = $values['key'];
$to = $values['to'];
$language = language_default();
$params = $values['params'];
if (!empty($values['from_mail'])) {
module_load_include('inc', 'mimemail');
$from = mimemail_address(array(
'name' => $values['from'],
'mail' => $values['from_mail'],
));
}
else {
$from = $values['from'];
}
$send = TRUE;
$result = drupal_mail($module, $key, $to, $language, $params, $from, $send);
if ($result['result'] == TRUE) {
drupal_set_message(t('Your message has been sent.'));
}
else {
drupal_set_message(t('There was a problem sending your message and it was not sent.'), 'error');
}
}

View File

@ -71,12 +71,16 @@ class MimeMailWebTestCase extends DrupalWebTestCase {
public function setUp() {
parent::setUp('mailsystem', 'mimemail');
// Create and login user.
$this->adminUser = $this->drupalCreateUser(array(
$permissions = array(
'access administration pages',
'administer site configuration',
));
);
// Check to make sure that the array of permissions are valid.
$this->checkPermissions($permissions, TRUE);
// Create and login user.
$this->adminUser = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->adminUser);
}

View File

@ -24,15 +24,20 @@ class MimeMailRulesTestCase extends DrupalWebTestCase {
public function setUp() {
parent::setUp('mailsystem', 'locale', 'entity', 'entity_token', 'rules', 'mimemail');
// Create and login user.
$this->adminUser = $this->drupalCreateUser(array(
$permissions = array(
'access administration pages',
'edit mimemail user settings',
'administer languages',
'administer rules',
'bypass rules access',
'access rules debug',
));
);
// Check to make sure that the array of permissions are valid.
$this->checkPermissions($permissions, TRUE);
// Create and login user.
$this->adminUser = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->adminUser);
// Enable another language too.