From a16354296623864024c70f130acb555dbaa6f1ef Mon Sep 17 00:00:00 2001
From: Bachir Soussi Chiadmi Thank you for helping test the XML sitemap module rewrite. Please consider helping offset developer free time by donating or if your company is interested in sponsoring the rewrite or a specific feature, please contact the developer. Thank you to the following current sponsors: ' . implode(', ', $sponsors) . ', and all the individuals that have donated. This message will not be seen in the stable versions.
It is recommended that you use the temporary file system (temporary://) if your server configuration allows for that.'),
+ '#element_validate' => array('filefield_paths_settings_form_temp_location_validate'),
+ );
+
+ return system_settings_form($form);
+}
+
+/**
+ * Validation callback for 'Temporary file location' setting.
+ *
+ * @param $element
+ * @param $form_state
+ * @return bool
+ */
+function filefield_paths_settings_form_temp_location_validate($element, $form_state) {
+ $scheme = file_uri_scheme($element['#value']);
+ if (!$scheme) {
+ form_error($element, t('Invalid file location. You must include a file stream wrapper (e.g., public://).'));
+ return FALSE;
+ }
+
+ if (!file_stream_wrapper_valid_scheme($scheme)) {
+ form_error($element, t('Invalid file stream wrapper.'));
+ return FALSE;
+ }
+
+ if ((!is_dir($element['#value']) || !is_writable($element['#value'])) && !file_prepare_directory($element['#value'], FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+ form_error($element, t('File location can not be created or is not writable.'));
+ return FALSE;
+ }
+}
\ No newline at end of file
diff --git a/sites/all/modules/filefield_paths/filefield_paths.api.php b/sites/all/modules/filefield_paths/filefield_paths.api.php
new file mode 100644
index 0000000..5c53b6e
--- /dev/null
+++ b/sites/all/modules/filefield_paths/filefield_paths.api.php
@@ -0,0 +1,71 @@
+ array(
+ 'title' => 'File path',
+ 'form' => array(
+ 'value' => array(
+ '#type' => 'textfield',
+ '#title' => t('File path'),
+ '#maxlength' => 512,
+ '#size' => 128,
+ '#element_validate' => array('_file_generic_settings_file_directory_validate'),
+ '#default_value' => $instance['settings']['file_directory'],
+ ),
+ ),
+ ),
+ );
+}
+
+/**
+ * Declare a compatible field type for use with File (Field) Paths.
+ *
+ * @return array
+ */
+function hook_filefield_paths_field_type_info() {
+ return array('file');
+}
+
+/**
+ * Process the uploaded files.
+ *
+ * @param $type
+ * The entity type containing the files for processing.
+ * @param $entity
+ * The entity containing the files for processing.
+ * @param $field
+ * The definition of the field containing the files for processing.
+ * @param $instance
+ * The instance of the field containing the files for processing.
+ * @param $langcode
+ * The language code of the field containing the files for processing.
+ * @param $items
+ * A pass-by-reference array of all the files for processing.
+ *
+ * @see filefield_paths_filefield_paths_process_file().
+ */
+function hook_filefield_paths_process_file($type, $entity, $field, $instance, $langcode, &$items) {
+}
\ No newline at end of file
diff --git a/sites/all/modules/filefield_paths/modules/filefield_paths.drush.inc b/sites/all/modules/filefield_paths/filefield_paths.drush.inc
similarity index 82%
rename from sites/all/modules/filefield_paths/modules/filefield_paths.drush.inc
rename to sites/all/modules/filefield_paths/filefield_paths.drush.inc
index 0ee45bc..0e2bff1 100644
--- a/sites/all/modules/filefield_paths/modules/filefield_paths.drush.inc
+++ b/sites/all/modules/filefield_paths/filefield_paths.drush.inc
@@ -1,4 +1,5 @@
'Retroactively updates all File (Field) Paths of a chosen field instance.',
- 'arguments' => array(
+ 'arguments' => array(
'entity_type' => 'Entity type.',
'bundle_name' => 'Bundle name.',
- 'field_name' => 'Field name.'
+ 'field_name' => 'Field name.'
),
- 'options' => array(
+ 'options' => array(
'all' => 'Retroactively update all File (Field) Paths.',
),
- 'examples' => array(
- 'drush ffp-update' => 'Retroactively updates the File (Field) Paths of the instances choosen via an interactive menu.',
+ 'examples' => array(
+ 'drush ffp-update' => 'Retroactively updates the File (Field) Paths of the instances choosen via an interactive menu.',
'drush ffp-update node article field_image' => 'Retroactively updates the File (Field) Paths of all instances of the Article content types Image field.',
- 'drush ffp-update --all' => 'Retroactively update all File (Field) Paths.',
+ 'drush ffp-update --all' => 'Retroactively update all File (Field) Paths.',
),
- 'aliases' => array('ffpu'),
+ 'aliases' => array('ffpu'),
);
return $items;
@@ -33,17 +34,23 @@ function filefield_paths_drush_command() {
/**
* Retroactively updates all File (Field) Paths of a chosen field instance.
+ *
+ * @param null $entity_type
+ * @param null $bundle_name
+ * @param null $field_name
+ *
+ * @return string
*/
function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NULL, $field_name = NULL) {
// Build array of information of all entity types, bundle names and field
// names.
$field_types = array_keys(_filefield_paths_get_field_types());
- $info = array();
+ $info = array();
foreach (field_info_fields() as $field) {
if (in_array($field['type'], $field_types)) {
foreach ($field['bundles'] as $entity_type_name => $bundles) {
if (!isset($info[$entity_type_name])) {
- $entity_type_info = entity_get_info($entity_type_name);
+ $entity_type_info = entity_get_info($entity_type_name);
$info[$entity_type_name] = array(
'#label' => "{$entity_type_info['label']} ({$entity_type_name})",
);
@@ -56,6 +63,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
);
}
$field = field_info_instance($entity_type_name, $field['field_name'], $bundle);
+
$info[$entity_type_name][$bundle][$field['field_name']] = "{$field['label']} ({$field['field_name']})";
}
}
@@ -72,6 +80,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
+
return '';
}
@@ -96,6 +105,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
+
return '';
}
@@ -118,6 +128,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
}
}
_filefield_paths_drush_ffp_update($instances);
+
return '';
}
@@ -138,6 +149,7 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
$instances[] = field_info_instance($entity_type, $field_name, $bundle_name);
}
_filefield_paths_drush_ffp_update($instances);
+
return '';
}
@@ -148,13 +160,16 @@ function drush_filefield_paths_ffp_update($entity_type = NULL, $bundle_name = NU
/**
* Helper function; Invokes File (Field) Paths Retroactive updates.
+ *
+ * @param $instances
*/
function _filefield_paths_drush_ffp_update($instances) {
foreach ($instances as $instance) {
- filefield_paths_batch_update($instance);
- $batch =& batch_get();
- $batch['progressive'] = FALSE;
- drush_backend_batch_process();
- drush_log(dt('!field_name File (Field) Paths updated.', array('!field_name' => "{$instance['label']} ({$instance['entity_type']}-{$instance['bundle']}-{$instance['field_name']})")), 'success');
+ if (filefield_paths_batch_update($instance)) {
+ $batch =& batch_get();
+ $batch['progressive'] = FALSE;
+ drush_backend_batch_process();
+ drush_log(dt('!field_name File (Field) Paths updated.', array('!field_name' => "{$instance['label']} ({$instance['entity_type']}-{$instance['bundle']}-{$instance['field_name']})")), 'success');
+ }
}
}
diff --git a/sites/all/modules/filefield_paths/filefield_paths.info b/sites/all/modules/filefield_paths/filefield_paths.info
index cdf6a81..2f12c95 100644
--- a/sites/all/modules/filefield_paths/filefield_paths.info
+++ b/sites/all/modules/filefield_paths/filefield_paths.info
@@ -1,25 +1,28 @@
name = File (Field) Paths
description = Adds improved Token based file sorting and renaming functionalities.
-dependencies[] = token
package = Fields
+test_dependencies[] = pathauto
+test_dependencies[] = redirect
+test_dependencies[] = token
+test_dependencies[] = transliteration
+configure = admin/config/media/file-system/filefield-paths
core = 7.x
-files[] = filefield_paths.install
-files[] = filefield_paths.module
-files[] = modules/features.inc
-files[] = modules/file.inc
-files[] = modules/filefield_paths.drush.inc
-files[] = modules/filefield_paths.inc
-files[] = modules/image.inc
-files[] = modules/token.inc
-files[] = modules/video.inc
-;files[] = tests/filefield_paths.test
+; Simpletest files.
-; Information added by drupal.org packaging script on 2012-02-07
-version = "7.x-1.0-beta3"
+files[] = tests/filefield_paths.test
+files[] = tests/filefield_paths.general.test
+files[] = tests/filefield_paths.text_replace.test
+files[] = tests/filefield_paths.tokens.test
+files[] = tests/filefield_paths.update.test
+files[] = tests/pathauto.test
+files[] = tests/redirect.test
+files[] = tests/transliteration.test
+
+; Information added by Drupal.org packaging script on 2018-08-14
+version = "7.x-1.1"
core = "7.x"
project = "filefield_paths"
-datestamp = "1328655041"
-
+datestamp = "1534256584"
diff --git a/sites/all/modules/filefield_paths/filefield_paths.install b/sites/all/modules/filefield_paths/filefield_paths.install
index a52c41a..b0608ed 100644
--- a/sites/all/modules/filefield_paths/filefield_paths.install
+++ b/sites/all/modules/filefield_paths/filefield_paths.install
@@ -1,4 +1,5 @@
'Original name of the file.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
);
}
@@ -28,14 +29,12 @@ function filefield_paths_install() {
// filenames.
db_add_field('file_managed', 'origname', array(
'description' => 'Original name of the file with no path components. Used by the filefield_paths module.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
));
- db_update('file_managed')
- ->expression('origname', 'filename')
- ->execute();
+ db_update('file_managed')->expression('origname', 'filename')->execute();
}
/**
@@ -76,10 +75,10 @@ function filefield_paths_update_7103() {
if (!db_field_exists('file_managed', 'origname')) {
db_add_field('file_managed', 'origname', array(
'description' => 'Original name of the file with no path components. Used by the filefield_paths module.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
));
}
db_update('file_managed')
@@ -93,10 +92,10 @@ function filefield_paths_update_7103() {
*/
function filefield_paths_update_7104() {
db_add_field('filefield_paths', 'active_updating', array(
- 'type' => 'int',
- 'size' => 'tiny',
+ 'type' => 'int',
+ 'size' => 'tiny',
'not null' => TRUE,
- 'default' => '0'
+ 'default' => '0'
));
// migrate variable to filefield_paths table
@@ -123,10 +122,10 @@ function filefield_paths_update_7104() {
*/
function filefield_paths_update_7105() {
db_change_field('filefield_paths', 'active_updating', 'active_updating', array(
- 'type' => 'int',
- 'size' => 'tiny',
+ 'type' => 'int',
+ 'size' => 'tiny',
'not null' => TRUE,
- 'default' => 0
+ 'default' => 0
));
}
@@ -135,16 +134,16 @@ function filefield_paths_update_7105() {
*/
function filefield_paths_update_7106() {
db_change_field('filefield_paths', 'type', 'type', array(
- 'type' => 'varchar',
- 'length' => 128,
+ 'type' => 'varchar',
+ 'length' => 128,
'not null' => TRUE,
- 'default' => ''
+ 'default' => ''
));
db_change_field('filefield_paths', 'field', 'field', array(
- 'type' => 'varchar',
- 'length' => 128,
+ 'type' => 'varchar',
+ 'length' => 128,
'not null' => TRUE,
- 'default' => ''
+ 'default' => ''
));
}
@@ -152,33 +151,57 @@ function filefield_paths_update_7106() {
* Removed filefield_paths table/schema.
*/
function filefield_paths_update_7107() {
+ $results = db_select('filefield_paths', 'ffp')->fields('ffp')->execute();
+ foreach ($results as $result) {
+ $instance = field_info_instance('node', $result->field, $result->type);
+ if (!is_null($instance) && isset($instance["ffp_{$result->field}}"])) {
+ $filepath = unserialize($result->filepath);
+ $filename = unserialize($result->filename);
+
+ $instance["ffp_{$result->field}"] = array(
+ 'file_path' => $filepath['value'],
+ 'file_path_cleanup' => array(
+ 'file_path_pathauto' => $filepath['pathauto'],
+ 'file_path_transliterate' => $filepath['transliterate'],
+ ),
+ 'file_name' => $filename['value'],
+ 'file_name_cleanup' => array(
+ 'file_name_pathauto' => $filename['pathauto'],
+ 'file_name_transliterate' => $filename['transliterate'],
+ ),
+ 'active_updating' => $result->active_updating,
+ );
+ field_update_instance($instance);
+ }
+ }
+
// Remove filefield_paths table/schema.
db_drop_table('filefield_paths');
// Update field instance settings.
+ drupal_load('module', 'filefield_paths');
$field_types = array_keys(_filefield_paths_get_field_types());
foreach (field_info_fields() as $field) {
if (in_array($field['type'], $field_types)) {
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle_name) {
$instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
- if ($instance["ffp_{$field['field_name']}"] && !isset($instance['settings']['filefield_paths'])) {
+ if (isset($instance["ffp_{$field['field_name']}"]) && !isset($instance['settings']['filefield_paths'])) {
$instance['settings']['filefield_paths'] = array(
- 'file_path' => array(
- 'value' => $instance["ffp_{$field['field_name']}"]['file_path'],
+ 'file_path' => array(
+ 'value' => $instance["ffp_{$field['field_name']}"]['file_path'],
'options' => array(
- 'pathauto' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_pathauto'],
+ 'pathauto' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_pathauto'],
'transliterate' => $instance["ffp_{$field['field_name']}"]['file_path_cleanup']['file_path_transliterate'],
),
),
- 'file_name' => array(
- 'value' => $instance["ffp_{$field['field_name']}"]['file_name'],
+ 'file_name' => array(
+ 'value' => $instance["ffp_{$field['field_name']}"]['file_name'],
'options' => array(
- 'pathauto' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_pathauto'],
+ 'pathauto' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_pathauto'],
'transliterate' => $instance["ffp_{$field['field_name']}"]['file_name_cleanup']['file_name_transliterate'],
),
),
- 'retroactive_update' => $instance["ffp_{$field['field_name']}"]['retroactive_update'],
'active_updating' => $instance["ffp_{$field['field_name']}"]['active_updating'],
);
unset($instance["ffp_{$field['field_name']}"]);
diff --git a/sites/all/modules/filefield_paths/filefield_paths.module b/sites/all/modules/filefield_paths/filefield_paths.module
index eb2e990..cca12b7 100644
--- a/sites/all/modules/filefield_paths/filefield_paths.module
+++ b/sites/all/modules/filefield_paths/filefield_paths.module
@@ -1,4 +1,5 @@
t('File (Field) Paths settings'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('filefield_paths_settings_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'type' => MENU_NORMAL_ITEM,
+ 'file' => 'filefield_paths.admin.inc',
+ );
+
+ return $items;
+}
+
+/**
+ * Implements hook_form_alter().
+ *
+ * @param $form
+ */
+function filefield_paths_form_alter(&$form) {
+ // Force all File (Field) Paths uploads to go to the temporary file system
+ // prior to being processed.
+ if (isset($form['#entity']) && isset($form['#entity_type']) && isset($form['#bundle']) && $form['#type'] == 'form') {
+ filefield_paths_temporary_upload_location($form);
+ }
+
$field_types = _filefield_paths_get_field_types();
if (isset($form['#field']) && in_array($form['#field']['type'], array_keys($field_types))) {
$entity_info = entity_get_info($form['#instance']['entity_type']);
- $settings = isset($form['#instance']['settings']['filefield_paths']) ? $form['#instance']['settings']['filefield_paths'] : array();
+ $settings = isset($form['#instance']['settings']['filefield_paths']) ? $form['#instance']['settings']['filefield_paths'] : array();
+
+ $form['instance']['settings']['filefield_paths_enabled'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable File (Field) Paths?'),
+ '#default_value' => isset($form['#instance']['settings']['filefield_paths_enabled']) ? $form['#instance']['settings']['filefield_paths_enabled'] : TRUE,
+ '#weight' => 2,
+ );
// Hide standard File directory field.
- $form['instance']['settings']['file_directory']['#access'] = FALSE;
+ $form['instance']['settings']['file_directory']['#states'] = array(
+ 'visible' => array(
+ ':input[name="instance[settings][filefield_paths_enabled]"]' => array('checked' => FALSE),
+ ),
+ );
// File (Field) Paths fieldset element.
$form['instance']['settings']['filefield_paths'] = array(
- '#type' => 'fieldset',
- '#title' => t('File (Field) Path settings'),
+ '#type' => 'fieldset',
+ '#title' => t('File (Field) Path settings'),
'#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#weight' => 1,
- '#tree' => TRUE,
+ '#collapsed' => TRUE,
+ '#weight' => 3,
+ '#tree' => TRUE,
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="instance[settings][filefield_paths_enabled]"]' => array('checked' => TRUE),
+ ),
+ ),
);
// Additional File (Field) Paths widget fields.
- $fields = module_invoke_all('filefield_paths_field_settings');
+ $fields = module_invoke_all('filefield_paths_field_settings', $form['#field'], $form['#instance']);
foreach ($fields as $name => $field) {
// Attach widget fields.
$form['instance']['settings']['filefield_paths'][$name] = array(
@@ -46,13 +89,14 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
// Attach widget field form elements.
if (isset($field['form']) && is_array($field['form'])) {
foreach (array_keys($field['form']) as $delta => $key) {
- $form['instance']['settings']['filefield_paths'][$name][$key] = array_merge(
- $field['form'][$key],
- array(
- '#element_validate' => array('token_element_validate'),
- '#token_types' => array('file', $entity_info['token type']),
- )
- );
+ $form['instance']['settings']['filefield_paths'][$name][$key] = $field['form'][$key];
+ if (module_exists('token')) {
+ $form['instance']['settings']['filefield_paths'][$name][$key]['#element_validate'][] = 'token_element_validate';
+ $form['instance']['settings']['filefield_paths'][$name][$key]['#token_types'] = array(
+ 'file',
+ $entity_info['token type']
+ );
+ }
// Fetch stored value from instance.
if (isset($settings[$name][$key])) {
@@ -62,67 +106,82 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
// Field options.
$form['instance']['settings']['filefield_paths'][$name]['options'] = array(
- '#type' => 'fieldset',
- '#title' => t('@title options', array('@title' => $field['title'])),
+ '#type' => 'fieldset',
+ '#title' => t('@title options', array('@title' => t($field['title']))),
'#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#weight' => 1,
- '#attributes' => array(
+ '#collapsed' => TRUE,
+ '#weight' => 1,
+ '#attributes' => array(
'class' => array("{$name} cleanup")
),
);
- // @TODO - Make this more modular.
+ // Cleanup slashes (/).
+ $form['instance']['settings']['filefield_paths'][$name]['options']['slashes'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Remove slashes (/) from tokens'),
+ '#default_value' => isset($settings[$name]['options']['slashes']) ? $settings[$name]['options']['slashes'] : FALSE,
+ '#description' => t('If checked, any slashes (/) in tokens will be removed from %title.', array('%title' => t($field['title']))),
+ );
+
// Cleanup field with Pathauto module.
$form['instance']['settings']['filefield_paths'][$name]['options']['pathauto'] = array(
- '#type' => 'checkbox',
- '#title' => t('Cleanup using Pathauto') . '.',
- '#default_value' => isset($settings[$name]['options']['pathauto']) && module_exists('pathauto')
- ? $settings[$name]['options']['pathauto']
- : FALSE,
- '#description' => t('Cleanup @title using', array('@title' => $field['title'])) . ' ' . l(t('Pathauto settings'), 'admin/config/search/path/settings'),
- '#disabled' => !module_exists('pathauto'),
+ '#type' => 'checkbox',
+ '#title' => t('Cleanup using Pathauto'),
+ '#default_value' => isset($settings[$name]['options']['pathauto']) && module_exists('pathauto') ? $settings[$name]['options']['pathauto'] : FALSE,
+ '#description' => t('Cleanup %title using Pathauto settings.', array(
+ '%title' => t($field['title']),
+ '@pathauto' => url('admin/config/search/path/settings')
+ )),
+ '#disabled' => !module_exists('pathauto'),
);
// Transliterate field with Transliteration module.
$form['instance']['settings']['filefield_paths'][$name]['options']['transliterate'] = array(
- '#type' => 'checkbox',
- '#title' => t('Transliterate') . '.',
- '#default_value' => isset($settings[$name]['options']['transliterate']) && module_exists('transliteration')
- ? $settings[$name]['options']['transliterate']
- : 0,
- '#description' => t('Transliterate @title', array('@title' => $field['title'])) . '.',
- '#disabled' => !module_exists('transliteration'),
+ '#type' => 'checkbox',
+ '#title' => t('Transliterate'),
+ '#default_value' => isset($settings[$name]['options']['transliterate']) && module_exists('transliteration') ? $settings[$name]['options']['transliterate'] : 0,
+ '#description' => t('Provides one-way string transliteration (romanization) and cleans the %title during upload by replacing unwanted characters.', array('%title' => t($field['title']))),
+ '#disabled' => !module_exists('transliteration'),
);
// Replacement patterns for field.
- $form['instance']['settings']['filefield_paths']['token_tree'] = array(
- '#type' => 'fieldset',
- '#title' => t('Replacement patterns'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => theme('token_tree', array('token_types' => array('file', $entity_info['token type']))),
- '#weight' => 10,
+ if (module_exists('token')) {
+ $form['instance']['settings']['filefield_paths']['token_tree'] = array(
+ '#theme' => 'token_tree',
+ '#token_types' => array('file', $entity_info['token type']),
+ '#dialog' => TRUE,
+ '#weight' => 10,
+ );
+ }
+
+ // Redirect
+ $form['instance']['settings']['filefield_paths']['redirect'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create Redirect'),
+ '#description' => t('Create a redirect to the new location when a previously uploaded file is moved.'),
+ '#default_value' => isset($settings['redirect']) ? $settings['redirect'] : FALSE,
+ '#weight' => 11,
);
+ if (!module_exists('redirect')) {
+ $form['instance']['settings']['filefield_paths']['redirect']['#disabled'] = TRUE;
+ $form['instance']['settings']['filefield_paths']['redirect']['#description'] .= '
' . t('Requires the Redirect module.');
+ }
// Retroactive updates.
$form['instance']['settings']['filefield_paths']['retroactive_update'] = array(
- '#type' => 'checkbox',
- '#title' => t('Retroactive update'),
- '#description' => t('Move and rename previously uploaded files') . '.' .
- '
' . t('Warning') . ': ' .
- t('This feature should only be used on developmental servers or with extreme caution') . '.',
- '#weight' => 11,
+ '#type' => 'checkbox',
+ '#title' => t('Retroactive update'),
+ '#description' => t('Move and rename previously uploaded files.') . '
' . t('Warning') . ': ' .
- t('This feature should only be used on developmental servers or with extreme caution') . '.',
- '#weight' => 12
+ '#description' => t('Actively move and rename previously uploaded files as required.') . '
It is recommended that you use the temporary file system (temporary://) if your server configuration allows for that.'),
+ 'validate callback' => 'filefield_paths_variable_temp_location_validate',
+ 'group' => 'filefield_paths',
+ );
+
+ return $variables;
+}
+
+/**
+ * Validate callback for 'Temporary file location' variable.
+ *
+ * @param $element
+ */
+function filefield_paths_variable_temp_location_validate($element) {
+ // Add FAPI element keys for standard validation callback.
+ $element['#parents'] = array('filefield_paths_temp_location');
+ $element['#value'] = $element['value'];
+
+ // Pass element through standard validation callback.
+ module_load_include('admin.inc', 'filefield_paths');
+ filefield_paths_settings_form_temp_location_validate($element);
+}
+
+/**
+ * Implements hook_variable_group_info().
+ *
+ * @return mixed
+ */
+function filefield_paths_variable_group_info() {
+ $groups['filefield_paths'] = array(
+ 'title' => t('File (Field) Paths'),
+ 'description' => t('File (Field) Paths settings.'),
+ 'access' => 'administer site configuration',
+ 'path' => array(
+ 'admin/config/media/file-system/filefield-paths'
+ ),
+ );
+
+ return $groups;
+}
\ No newline at end of file
diff --git a/sites/all/modules/filefield_paths/modules/features.inc b/sites/all/modules/filefield_paths/modules/features.inc
index fcd6f01..264b671 100644
--- a/sites/all/modules/filefield_paths/modules/features.inc
+++ b/sites/all/modules/filefield_paths/modules/features.inc
@@ -1,16 +1,21 @@
array(
'title' => 'File path',
- 'sql' => 'filepath',
-
- 'form' => array(
+ 'form' => array(
'value' => array(
- '#type' => 'textfield',
- '#title' => t('File path'),
- '#maxlength' => 512,
- '#size' => 128,
+ '#type' => 'textfield',
+ '#title' => t('File path'),
+ '#maxlength' => 512,
+ '#size' => 128,
+ '#element_validate' => array('_file_generic_settings_file_directory_validate'),
+ '#default_value' => $instance['settings']['file_directory'],
),
),
),
-
'file_name' => array(
'title' => 'File name',
- 'sql' => 'filename',
-
- 'form' => array(
+ 'form' => array(
'value' => array(
- '#type' => 'textfield',
- '#title' => t('File name'),
+ '#type' => 'textfield',
+ '#title' => t('File name'),
+ '#maxlength' => 512,
+ '#size' => 128,
'#default_value' => '[file:ffp-name-only-original].[file:ffp-extension-original]',
),
),
@@ -40,42 +45,86 @@ function filefield_paths_filefield_paths_field_settings() {
/**
* Implements hook_filefield_paths_process_file().
+ *
+ * @param $type
+ * @param $entity
+ * @param $field
+ * @param $instance
+ * @param $langcode
+ * @param $items
*/
function filefield_paths_filefield_paths_process_file($type, $entity, $field, $instance, $langcode, &$items) {
- $settings = $instance['settings']['filefield_paths'];
- foreach ($items as &$file) {
- if ($file['timestamp'] == REQUEST_TIME || $settings['active_updating']) {
- $token_data = array(
- 'file' => (object) $file,
- $type => $entity
- );
+ if (isset($instance['settings']['filefield_paths'])) {
+ $settings = $instance['settings']['filefield_paths'];
- // Copy the original file for comparision purposes.
- $old_file = $file;
-
- // Process filename.
- $file['filename'] = !empty($settings['file_name']['value'])
- ? filefield_paths_process_string($settings['file_name']['value'], $token_data, $settings['file_name']['options'])
- : $file['filename'];
-
- // Process filepath.
- $file['uri'] = "{$field['settings']['uri_scheme']}://" . filefield_paths_process_string($settings['file_path']['value'] . "/{$file['filename']}", $token_data, $settings['file_path']['options']);
-
- // Finalize file if necessary.
- if ($file !== $old_file) {
- if (file_prepare_directory(drupal_dirname($file['uri']), FILE_CREATE_DIRECTORY) && file_move((object) $old_file, $file['uri'])) {
- // Process regular expression.
- _filefield_paths_replace_path($old_file['uri'], $file['uri'], $entity);
-
- // Remove any old empty directories.
- $scheme = file_uri_scheme($old_file['uri']);
- $paths = explode('/', str_replace("{$scheme}://", '', drupal_dirname($old_file['uri'])));
- while ($paths) {
- if (@drupal_rmdir("{$scheme}://" . implode('/', $paths)) == TRUE) {
- array_pop($paths);
- continue;
+ // Check that the destination is writeable.
+ $wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE);
+ foreach ($items as &$file) {
+ $source_scheme = file_uri_scheme($file['uri']);
+ $temporary_scheme = file_uri_scheme(variable_get('filefield_paths_temp_location', 'public://filefield_paths'));
+ $destination_scheme = $field['settings']['uri_scheme'];
+ if (in_array($source_scheme, array($temporary_scheme, $destination_scheme)) && !empty($wrappers[$destination_scheme])) {
+ // Process file if this is a new entity, 'Active updating' is set or
+ // file wasn't previously attached to the entity.
+ if (isset($entity->original) && empty($settings['active_updating']) && !empty($entity->original->{$field['field_name']}[$langcode])) {
+ foreach ($entity->original->{$field['field_name']}[$langcode] as $original_file) {
+ if ($original_file['fid'] == $file['fid']) {
+ continue(2);
}
- break;
+ }
+ }
+
+ $token_data = array(
+ 'file' => (object) $file,
+ $type => $entity
+ );
+
+ // Copy the original file for comparison purposes.
+ $old_file = $file;
+
+ // Process filename.
+ $settings['file_name']['options']['context'] = 'file_name';
+ $file['filename'] = !empty($settings['file_name']['value']) ? filefield_paths_process_string($settings['file_name']['value'], $token_data, $settings['file_name']['options']) : $file['filename'];
+
+ // Process filepath.
+ $settings['file_path']['options']['context'] = 'file_path';
+ $path = filefield_paths_process_string($settings['file_path']['value'], $token_data, $settings['file_path']['options']);
+ $file['uri'] = file_stream_wrapper_uri_normalize("{$destination_scheme}://{$path}/{$file['filename']}");
+
+ // Ensure file uri is no more than 255 characters.
+ if (drupal_strlen($file['uri']) > 255) {
+ watchdog('filefield_paths', 'File path was truncated.', array(), WATCHDOG_INFO);
+ $pathinfo = pathinfo($file['uri']);
+ $file['uri'] = drupal_substr($file['uri'], 0, 254 - drupal_strlen($pathinfo['extension'])) . ".{$pathinfo['extension']}";
+ }
+
+ // Finalize file if necessary.
+ if ($file !== $old_file) {
+ $dirname = drupal_dirname($file['uri']);
+ if (file_prepare_directory($dirname, FILE_CREATE_DIRECTORY) && $new_file = file_move((object) $old_file, $file['uri'])) {
+ // Process regular expression.
+ _filefield_paths_replace_path($old_file['uri'], $file['uri'], $entity);
+
+ // Create redirect from old location.
+ if (module_exists('redirect') && !empty($settings['redirect']) && $settings['active_updating']) {
+ _filefield_paths_create_redirect($old_file['uri'], $new_file->uri);
+ }
+
+ // Remove any old empty directories.
+ $paths = explode('/', str_replace("{$source_scheme}://", '', drupal_dirname($old_file['uri'])));
+ while ($paths) {
+ if (@drupal_rmdir("{$source_scheme}://" . implode('/', $paths)) == TRUE) {
+ array_pop($paths);
+ continue;
+ }
+ break;
+ }
+ }
+ else {
+ watchdog('filefield_paths', 'The file %old could not be moved to the destination of %new. Ensure your permissions are set correctly.', array(
+ '%old' => $old_file['uri'],
+ '%new' => $file['uri'],
+ ));
}
}
}
diff --git a/sites/all/modules/filefield_paths/modules/image.inc b/sites/all/modules/filefield_paths/modules/image.inc
index acf14bb..65462d1 100644
--- a/sites/all/modules/filefield_paths/modules/image.inc
+++ b/sites/all/modules/filefield_paths/modules/image.inc
@@ -1,4 +1,5 @@
t("File name"),
- 'description' => t("File name without extension."),
- );
- $info['tokens']['file']['ffp-name-only-original'] = array(
- 'name' => t("File name - original"),
- 'description' => t("File name without extension - original."),
- );
- $info['tokens']['file']['ffp-extension-original'] = array(
- 'name' => t("File extension - original"),
- 'description' => t("File extension - original."),
- );
-
- return $info;
-}
-
-/**
- * Implements hook_tokens().
- */
-function filefield_paths_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $url_options = array('absolute' => TRUE);
- if (isset($language)) {
- $url_options['language'] = $language;
- }
- $sanitize = !empty($options['sanitize']);
-
- $replacements = array();
-
- if ($type == 'file' && !empty($data['file'])) {
- $file = $data['file'];
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'ffp-name-only':
- $info = pathinfo($file->filename);
- $replacements[$original] = $info['filename'];
- break;
-
- case 'ffp-name-only-original':
- $info = pathinfo($file->origname);
- $replacements[$original] = $info['filename'];
- break;
-
- case 'ffp-extension-original':
- $info = pathinfo($file->origname);
- $replacements[$original] = $info['extension'];
- break;
- }
- }
- }
-
- return $replacements;
-}
diff --git a/sites/all/modules/filefield_paths/modules/video.inc b/sites/all/modules/filefield_paths/modules/video.inc
index 72ca7e9..a392631 100644
--- a/sites/all/modules/filefield_paths/modules/video.inc
+++ b/sites/all/modules/filefield_paths/modules/video.inc
@@ -1,4 +1,5 @@
'General functionality',
+ 'description' => 'Test general functionality.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Test that the File (Field) Paths UI works as expected.
+ */
+ public function testAddField() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings = array('file_directory' => "fields/{$field_name}");
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Ensure File (Field) Paths settings are present.
+ $this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
+ $this->assertText('Enable File (Field) Paths?', t('File (Field) Path settings are present.'));
+
+ // Ensure that 'Enable File (Field) Paths?' is a direct sibling of
+ // 'File (Field) Path settings'.
+ $element = $this->xpath('//div[contains(@class, :class)]/following-sibling::*[1]/@id', array(':class' => 'form-item-instance-settings-filefield-paths-enabled'));
+ $this->assert(isset($element[0]) && 'edit-instance-settings-filefield-paths' == (string) $element[0], t('Enable checkbox is next to settings fieldset.'));
+
+ // Ensure that the File path used the File directory as it's default value.
+ $this->assertFieldByName('instance[settings][filefield_paths][file_path][value]', "fields/{$field_name}");
+ }
+
+ /**
+ * Test File (Field) Paths works as normal when no file uploaded.
+ */
+ public function testNoFile() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node without a file attached.
+ $this->drupalCreateNode(array('type' => $this->content_type));
+ }
+
+ /**
+ * Test a basic file upload with File (Field) Paths.
+ */
+ public function testUploadFile() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field with 'node/[node:nid]' as the File path and
+ // '[node:nid].[file:ffp-extension-original]' as the File name.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ $schemes = array('public', 'private');
+ foreach ($schemes as $scheme) {
+ // Set the field URI scheme.
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", array('field[settings][uri_scheme]' => $scheme), t('Save settings'));
+
+ // Upload a file to a node.
+ $test_file = $this->getTestFile('text');
+ $this->drupalGet("node/add/{$this->content_type}");
+ $edit['title'] = $this->randomName();
+ $edit["files[{$field_name}_{$langcode}_0]"] = $test_file->uri;
+ $this->drupalPost(NULL, $edit, t('Upload'));
+
+ // Ensure that the file was put into the Temporary file location.
+ $temp_location = variable_get('filefield_paths_temp_location', 'public://filefield_paths');
+ $this->assertRaw(file_create_url("{$temp_location}/{$test_file->filename}"), t('File has been uploaded to the temporary file location.'));
+
+ // Save the node.
+ $this->drupalPost(NULL, array(), t('Save'));
+
+ // Get created Node ID.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ $nid = $matches[1];
+
+ // Ensure that the File path has been processed correctly.
+ $uri = file_create_url("{$scheme}://node/{$nid}/{$nid}.txt");
+ $this->assertRaw($uri, t('The File path has been processed correctly.'));
+
+ // Delete the node so we can change the URI scheme.
+ node_delete($nid);
+ }
+ }
+
+ /**
+ * Tests a multivalue file upload with File (Field) Paths.
+ */
+ public function testUploadFileMultivalue() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a multivalue File field with 'node/[node:nid]' as the File path
+ // and '[file:fid].txt' as the File name.
+ $field_name = drupal_strtolower($this->randomName());
+ $field_settings['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[file:fid].txt';
+ $this->createFileField($field_name, $this->content_type, $field_settings, $instance_settings);
+
+ // Create a node with three (3) test files.
+ $text_files = $this->drupalGetTestFiles('text');
+ $this->drupalGet("node/add/{$this->content_type}");
+ $this->drupalPost(NULL, array("files[{$field_name}_{$langcode}_0]" => drupal_realpath($text_files[0]->uri)), t('Upload'));
+ $this->drupalPost(NULL, array("files[{$field_name}_{$langcode}_1]" => drupal_realpath($text_files[1]->uri)), t('Upload'));
+ $edit = array(
+ 'title' => $this->randomName(),
+ "files[{$field_name}_{$langcode}_2]" => drupal_realpath($text_files[1]->uri),
+ );
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ // Get created Node ID.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ $nid = $matches[1];
+
+ // Ensure that the File path has been processed correctly.
+ $this->assertRaw("{$this->public_files_directory}/node/{$nid}/1.txt", t('The first File path has been processed correctly.'));
+ $this->assertRaw("{$this->public_files_directory}/node/{$nid}/2.txt", t('The second File path has been processed correctly.'));
+ $this->assertRaw("{$this->public_files_directory}/node/{$nid}/3.txt", t('The third File path has been processed correctly.'));
+ }
+
+ /**
+ * Test File (Field) Paths with a very long path.
+ */
+ public function testLongPath() {
+ // Create a File field with 'node/[random:hash:sha256]' as the File path.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[random:hash:sha512]/[random:hash:sha512]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+ $nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
+
+ // Ensure file path is no more than 255 characters.
+ $node = node_load($nid, NULL, TRUE);
+ $this->assert(drupal_strlen($node->{$field_name}[LANGUAGE_NONE][0]['uri']) <= 255, t('File path is no more than 255 characters'));
+ }
+
+ /**
+ * Test File (Field) Paths on a programmatically added file.
+ */
+ public function testProgrammaticAttach() {
+ // Create a File field with 'node/[node:nid]' as the File path and
+ // '[node:nid].[file:ffp-extension-original]' as the File name.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].[file:ffp-extension-original]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node without an attached file.
+ $node = $this->drupalCreateNode(array('type' => $this->content_type));
+
+ // Create a file object.
+ $test_file = $this->getTestFile('text');
+
+ $file = new stdClass();
+ $file->fid = NULL;
+ $file->uri = $test_file->uri;
+ $file->filename = basename($file->uri);
+ $file->filemime = file_get_mimetype($file->uri);
+ $file->uid = $GLOBALS['user']->uid;
+ $file->status = FILE_STATUS_PERMANENT;
+ $file->display = TRUE;
+ file_save($file);
+
+ // Adjust timestamp to simulate real-world experience.
+ $file->timestamp = REQUEST_TIME - 60;
+
+ // Attach the file to the node.
+ $node->{$field_name}[LANGUAGE_NONE][0] = (array) $file;
+ node_save($node);
+
+ // Ensure that the File path has been processed correctly.
+ $node = node_load($node->nid, NULL, TRUE);
+ $this->assertEqual("public://node/{$node->nid}/{$node->nid}.txt", $node->{$field_name}[LANGUAGE_NONE][0]['uri'], t('The File path has been processed correctly.'));
+ }
+
+ /**
+ * Test File (Field) Paths slashes cleanup functionality.
+ */
+ public function testSlashes() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field with 'node/[node:title]' as the File path and
+ // '[node:title].[file:ffp-extension-original]' as the File name.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+
+ $title = "{$this->randomName()}/{$this->randomName()}";
+ $edit['title'] = $title;
+ $edit["body[{$langcode}][0][value]"] = '';
+ $edit["files[{$field_name}_{$langcode}_0]"] = drupal_realpath($test_file->uri);
+ $this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
+
+ // Get created Node ID.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ $nid = $matches[1];
+
+ // Ensure slashes are present in file path and name.
+ $node = node_load($nid);
+ $this->assertEqual("public://node/{$title}/{$title}.txt", $node->{$field_name}[$langcode][0]['uri']);
+
+ // Remove slashes.
+ $edit = array(
+ 'instance[settings][filefield_paths][file_path][options][slashes]' => TRUE,
+ 'instance[settings][filefield_paths][file_name][options][slashes]' => TRUE,
+ 'instance[settings][filefield_paths][retroactive_update]' => TRUE,
+ );
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
+
+ // Ensure slashes are not present in file path and name.
+ $node = node_load($nid, NULL, TRUE);
+ $title = str_replace('/', '', $title);
+ $this->assertEqual("public://node/{$title}/{$title}.txt", $node->{$field_name}[$langcode][0]['uri']);
+ }
+
+ /**
+ * Test a file usage of a basic file upload with File (Field) Paths.
+ */
+ public function testFileUsage() {
+ // Create a File field with 'node/[node:nid]' as the File path.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+ $nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
+
+ // Get file usage for uploaded file.
+ $node = node_load($nid, NULL, TRUE);
+ $items = field_get_items('node', $node, $field_name);
+ $file = file_load($items[0]['fid']);
+ $usage = file_usage_list($file);
+
+ // Ensure file usage count for new node is correct.
+ $this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 1, t('File usage count for new node is correct.'));
+
+ // Update node.
+ $this->drupalPost("node/{$nid}/edit", array(), t('Save'));
+ $usage = file_usage_list($file);
+
+ // Ensure file usage count for updated node is correct.
+ $this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 1, t('File usage count for updated node is correct.'));
+
+ // Update node with revision.
+ $this->drupalPost("node/{$nid}/edit", array('revision' => TRUE), t('Save'));
+ $usage = file_usage_list($file);
+
+ // Ensure file usage count for updated node with revision is correct.
+ $this->assert(isset($usage['file']['node'][$nid]) && $usage['file']['node'][$nid] == 2, t('File usage count for updated node with revision is correct.'));
+ }
+
+ /**
+ * Test File (Field) Paths works with read-only stream wrappers.
+ */
+ public function testReadOnly() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $field_settings = array('uri_scheme' => 'ffp');
+ $instance_settings = array('file_directory' => "fields/{$field_name}");
+ $this->createFileField($field_name, $this->content_type, $field_settings, $instance_settings);
+
+ // Get a test file.
+ $file = $this->getTestFile('image');
+
+ // Prepare the file for the test 'ffp://' read-only stream wrapper.
+ $file->uri = str_replace('public', 'ffp', $file->uri);
+ $uri = file_stream_wrapper_uri_normalize($file->uri);
+
+ // Create a file object.
+ $file = new stdClass();
+ $file->fid = NULL;
+ $file->uri = $uri;
+ $file->filename = basename($file->uri);
+ $file->filemime = file_get_mimetype($file->uri);
+ $file->uid = $GLOBALS['user']->uid;
+ $file->status = FILE_STATUS_PERMANENT;
+ $file->display = TRUE;
+ file_save($file);
+
+ // Attach the file to a node.
+ $node = array();
+ $node['type'] = $this->content_type;
+ $node[$field_name][LANGUAGE_NONE][0] = (array) $file;
+
+ $node = $this->drupalCreateNode($node);
+
+ // Ensure file has been attached to a node.
+ $this->assert(isset($node->{$field_name}[LANGUAGE_NONE][0]) && !empty($node->{$field_name}[LANGUAGE_NONE][0]), t('Read-only file is correctly attached to a node.'));
+
+ $edit = array();
+ $edit['instance[settings][filefield_paths][retroactive_update]'] = TRUE;
+ $edit['instance[settings][filefield_paths][file_path][value]'] = 'node/[node:nid]';
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
+
+ // Ensure file is still in original location.
+ $this->drupalGet("node/{$node->nid}");
+ $this->assertRaw("{$this->public_files_directory}/{$file->filename}", t('Read-only file not affected by Retroactive updates.'));
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths.test b/sites/all/modules/filefield_paths/tests/filefield_paths.test
new file mode 100644
index 0000000..fe5d5be
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths.test
@@ -0,0 +1,90 @@
+drupalCreateContentType();
+ $this->content_type = $content_type->name;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function createFileField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
+ parent::createFileField($name, $type_name, $field_settings, $instance_settings, $widget_settings);
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$name}", array(), t('Save settings'));
+ }
+
+ /**
+ * Creates a new image field.
+ *
+ * @param $name
+ * The name of the new field (all lowercase), exclude the "field_" prefix.
+ * @param $type_name
+ * The node type that this field will be added to.
+ * @param $field_settings
+ * A list of field settings that will be added to the defaults.
+ * @param $instance_settings
+ * A list of instance settings that will be added to the instance defaults.
+ * @param $widget_settings
+ * A list of widget settings that will be added to the widget defaults.
+ */
+ function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
+ $field = array(
+ 'field_name' => $name,
+ 'type' => 'image',
+ 'settings' => array(),
+ 'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
+ );
+ $field['settings'] = array_merge($field['settings'], $field_settings);
+ field_create_field($field);
+
+ $instance = array(
+ 'field_name' => $name,
+ 'label' => $name,
+ 'entity_type' => 'node',
+ 'bundle' => $type_name,
+ 'required' => !empty($instance_settings['required']),
+ 'settings' => array(),
+ 'widget' => array(
+ 'type' => 'image_image',
+ 'settings' => array(),
+ ),
+ );
+ $instance['settings'] = array_merge($instance['settings'], $instance_settings);
+ $instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings);
+ field_create_instance($instance);
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$name}", array(), t('Save settings'));
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths.text_replace.test b/sites/all/modules/filefield_paths/tests/filefield_paths.text_replace.test
new file mode 100644
index 0000000..6652905
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths.text_replace.test
@@ -0,0 +1,104 @@
+ 'Text replace functionality',
+ 'description' => 'Tests text replace functionality.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Generates all variations of the URI for text replacement.
+ *
+ * @param $uri
+ * @param string $type
+ *
+ * @return mixed
+ */
+ protected function getPathVariations($uri, $type = 'image') {
+ // Force clean urls on.
+ $GLOBALS['conf']['clean_url'] = TRUE;
+
+ $variations['uri'] = $uri;
+ $variations['absolute'] = urldecode(file_create_url($uri));
+ $variations['relative'] = parse_url($variations['absolute'], PHP_URL_PATH);
+
+ if ($type == 'image') {
+ $variations['image_style'] = urldecode(image_style_url('thumbnail', $uri));
+ $variations['image_style_relative'] = parse_url($variations['image_style'], PHP_URL_PATH) . '?' . parse_url($variations['image_style'], PHP_URL_QUERY);
+ }
+
+ foreach ($variations as $key => $value) {
+ $variations["{$key}_urlencode"] = urlencode($value);
+ $variations["{$key}_drupal_encode_path"] = drupal_encode_path($value);
+ }
+
+ return $variations;
+ }
+
+ /**
+ * Test text replace with multiple file uploads.
+ */
+ public function testTextReplace() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field with 'node/[node:nid]' as the File path and
+ // '[node:nid].png’ as the File name,
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:nid]';
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:nid].png';
+ $this->createImageField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Prepare test files.
+ $test_files['basic_image'] = $this->getTestFile('image');
+ $test_files['complex_image'] = $this->getTestFile('image');
+ file_unmanaged_copy($test_files['complex_image']->uri, 'public://test image.png');
+ $files = file_scan_directory('public://', '/test image\.png/');
+ $test_files['complex_image'] = current($files);
+
+ // Iterate over each test file.
+ foreach ($test_files as $type => $test_file) {
+ // Get the available file paths for the test file.
+ $uri = str_replace('public://', variable_get('filefield_paths_temp_location', 'public://filefield_paths') . '/', $test_file->uri);
+ $source_paths = $this->getPathVariations($uri);
+
+ // Upload a file and reference the original path(s) to the file in the body
+ // field.
+ $edit['title'] = $this->randomName();
+ $edit["body[{$langcode}][0][value]"] = '';
+ $edit["files[{$field_name}_{$langcode}_0]"] = drupal_realpath($test_file->uri);
+ foreach ($source_paths as $key => $value) {
+ $edit["body[{$langcode}][0][value]"] .= "{$key}: {$value}\n";
+ }
+ $this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
+
+ // Get created Node ID.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ $nid = $matches[1];
+
+ // Ensure body field has updated file path.
+ $node = node_load($nid);
+ $destination_paths = $this->getPathVariations($node->{$field_name}[$langcode][0]['uri']);
+ foreach ($destination_paths as $key => $value) {
+ $this->assert($source_paths[$key] !== $destination_paths[$key] && strpos($node->body[$langcode][0]['value'], "{$key}: {$value}") !== FALSE, t('@type %key file path replaced successfully.', array(
+ '@type' => str_replace('_', ' ', drupal_ucfirst($type)),
+ '%key' => $key
+ )));
+ }
+ }
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths.tokens.test b/sites/all/modules/filefield_paths/tests/filefield_paths.tokens.test
new file mode 100644
index 0000000..c5bda9a
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths.tokens.test
@@ -0,0 +1,103 @@
+ 'Token functionality',
+ 'description' => 'Tests File (Field) Paths tokens.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * @param $token
+ * @param $value
+ * @param $data
+ */
+ public function assertToken($token, $value, $data) {
+ $result = token_replace($token, $data);
+ $this->assertEqual($result, $value, t('Token @token equals @value', array(
+ '@token' => $token,
+ '@value' => $value
+ )));
+ }
+
+ /**
+ * Test token values with a text file.
+ */
+ public function testTokensBasic() {
+ // Prepare a test text file.
+ $text_file = $this->getTestFile('text');
+ file_save($text_file);
+
+ // Ensure tokens are processed correctly.
+ $data = array('file' => $text_file);
+ $this->assertToken('[file:ffp-name-only]', 'text-0', $data);
+ $this->assertToken('[file:ffp-name-only-original]', 'text-0', $data);
+ $this->assertToken('[file:ffp-extension-original]', 'txt', $data);
+ }
+
+ /**
+ * Test token values with a moved text file.
+ */
+ public function testTokensMoved() {
+ // Prepare a test text file.
+ $text_file = $this->getTestFile('text');
+ file_save($text_file);
+
+ // Move the text file.
+ $moved_file = file_move($text_file, 'public://moved.diff');
+
+ // Ensure tokens are processed correctly.
+ $data = array('file' => $moved_file);
+ $this->assertToken('[file:ffp-name-only]', 'moved', $data);
+ $this->assertToken('[file:ffp-name-only-original]', 'text-0', $data);
+ $this->assertToken('[file:ffp-extension-original]', 'txt', $data);
+ }
+
+ /**
+ * Test token values with a multi-extension text file.
+ */
+ public function testTokensMultiExtension() {
+ // Prepare a test text file.
+ $text_file = $this->getTestFile('text');
+ file_unmanaged_copy($text_file->uri, 'public://text.multiext.txt');
+ $files = file_scan_directory('public://', '/text\.multiext\.txt/');
+ $multiext_file = current($files);
+ file_save($multiext_file);
+
+ // Ensure tokens are processed correctly.
+ $data = array('file' => $multiext_file);
+ $this->assertToken('[file:ffp-name-only]', 'text.multiext', $data);
+ $this->assertToken('[file:ffp-name-only-original]', 'text.multiext', $data);
+ $this->assertToken('[file:ffp-extension-original]', 'txt', $data);
+ }
+
+ /**
+ * Test token value with a UTF file.
+ * @see https://www.drupal.org/node/1292436
+ */
+ public function testTokensUTF() {
+ // Prepare a test text file.
+ $text_file = $this->getTestFile('text');
+ file_unmanaged_copy($text_file->uri, 'public://тест.txt');
+ $files = file_scan_directory('public://', '/тест\.txt/');
+ $utf_file = current($files);
+ file_save($utf_file);
+
+ // Ensure tokens are processed correctly.
+ $data = array('file' => $utf_file);
+ $this->assertToken('[file:ffp-name-only]', 'тест', $data);
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths.update.test b/sites/all/modules/filefield_paths/tests/filefield_paths.update.test
new file mode 100644
index 0000000..968b8a1
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths.update.test
@@ -0,0 +1,81 @@
+ 'Update functionality',
+ 'description' => 'Tests retroactive and active updates functionality.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Test behaviour of Retroactive updates when no updates are needed.
+ */
+ public function testRetroEmpty() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $this->createFileField($field_name, $this->content_type);
+
+ // Trigger retroactive updates.
+ $edit = array(
+ 'instance[settings][filefield_paths][retroactive_update]' => TRUE
+ );
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
+
+ // Ensure no errors are thrown.
+ $this->assertNoText('Error', t('No errors were found.'));
+ }
+
+ /**
+ * Test basic Retroactive updates functionality.
+ */
+ public function testRetroBasic() {
+ // Create an Image field.
+ $field_name = drupal_strtolower($this->randomName());
+ $this->createImageField($field_name, $this->content_type, array());
+
+ // Modify instance settings.
+ $instance = field_info_instance('node', $field_name, $this->content_type);
+
+ $instance['display']['default']['settings']['image_style'] = 'thumbnail';
+ $instance['display']['default']['settings']['image_link'] = 'content';
+ field_update_instance($instance);
+ $this->drupalGet("admin/structure/types/manage/{$this->content_type}/display");
+ $original_instance = field_info_instance('node', $field_name, $this->content_type);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('image');
+ $nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
+
+ // Ensure that the file is in the default path.
+ $this->drupalGet("node/{$nid}");
+ $this->assertRaw("{$this->public_files_directory}/styles/thumbnail/public/{$test_file->name}", t('The File is in the default path.'));
+
+ // Trigger retroactive updates.
+ $edit['instance[settings][filefield_paths][retroactive_update]'] = TRUE;
+ $edit['instance[settings][filefield_paths][file_path][value]'] = 'node/[node:nid]';
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
+
+ // Ensure instance display settings haven't changed.
+ // @see https://www.drupal.org/node/2276435
+ drupal_static_reset('_field_info_field_cache');
+ $instance = field_info_instance('node', $field_name, $this->content_type);
+ $this->assert($original_instance['display'] === $instance['display'], t('Instance settings have not changed.'));
+
+ // Ensure that the file path has been retroactively updated.
+ $this->drupalGet("node/{$nid}");
+ $this->assertRaw("{$this->public_files_directory}/styles/thumbnail/public/node/{$nid}/{$test_file->name}", t('The File path has been retroactively updated.'));
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths_test.info b/sites/all/modules/filefield_paths/tests/filefield_paths_test.info
new file mode 100644
index 0000000..38decbd
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths_test.info
@@ -0,0 +1,12 @@
+name = File (Field) Paths tests
+description = Support module for File (Field) Paths related testing.
+package = Testing
+dependencies[] = filefield_paths
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2018-08-14
+version = "7.x-1.1"
+core = "7.x"
+project = "filefield_paths"
+datestamp = "1534256584"
diff --git a/sites/all/modules/filefield_paths/tests/filefield_paths_test.module b/sites/all/modules/filefield_paths/tests/filefield_paths_test.module
new file mode 100644
index 0000000..b1c897e
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/filefield_paths_test.module
@@ -0,0 +1,16 @@
+ 'Pathauto integration',
+ 'description' => 'Tests the Pathauto module integration.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Test File (Field) Paths Pathauto UI.
+ */
+ public function testUI() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $this->createFileField($field_name, $this->content_type);
+
+ // Ensure File (Field) Paths Pathauto settings are present and available.
+ $this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
+ foreach (array('path', 'name') as $field) {
+ $this->assertField("instance[settings][filefield_paths][file_{$field}][options][pathauto]", t('Pathauto checkbox is present in File @field settings.', array('@field' => drupal_ucfirst($field))));
+
+ $element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => "instance[settings][filefield_paths][file_{$field}][options][pathauto]"));
+ $this->assert(empty($element), t('Pathauto checkbox is not disabled in File @field settings.', array('@field' => drupal_ucfirst($field))));
+ }
+ }
+
+ /**
+ * Test Pathauto cleanup in File (Field) Paths.
+ */
+ public function testPathauto() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
+ $instance_settings['filefield_paths']['file_path']['options']['pathauto'] = TRUE;
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
+ $instance_settings['filefield_paths']['file_name']['options']['pathauto'] = TRUE;
+
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+ $edit['title'] = $this->randomString() . ' ' . $this->randomString();
+
+ $edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($test_file->uri);
+ $this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
+
+ // Ensure that file path/name have been processed correctly by Pathauto.
+ $node = node_load(1);
+
+ module_load_include('inc', 'pathauto');
+ $parts = explode('/', $node->title);
+ foreach ($parts as &$part) {
+ $part = pathauto_cleanstring($part);
+ }
+ $title = implode('/', $parts);
+
+ $this->assertEqual($node->{$field_name}[$langcode][0]['uri'], "public://node/{$title}/{$title}.txt", t('File path/name has been processed correctly by Pathauto'));
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/redirect.test b/sites/all/modules/filefield_paths/tests/redirect.test
new file mode 100644
index 0000000..fd321db
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/redirect.test
@@ -0,0 +1,90 @@
+ 'Redirect module integration',
+ 'description' => 'Test redirect module integration.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Test File (Field) Paths Redirect UI.
+ */
+ public function testUI() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $this->createFileField($field_name, $this->content_type);
+
+ // Ensure File (Field) Paths Pathauto settings are present and available.
+ $this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
+
+ $this->assertField('instance[settings][filefield_paths][redirect]', t('Redirect checkbox is present in File (Field) Path settings.'));
+
+ $element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => 'instance[settings][filefield_paths][redirect]'));
+ $this->assert(empty($element), t('Redirect checkbox is not disabled.'));
+ }
+
+ /**
+ * Test File (Field) Paths Redirect functionality.
+ */
+ public function testRedirect() {
+ global $base_path;
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field with a random File path.
+ $field_name = drupal_strtolower($this->randomName());
+ $instance_settings['filefield_paths']['file_path']['value'] = $this->randomName();
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+ $nid = $this->uploadNodeFile($test_file, $field_name, $this->content_type);
+
+ // Get processed source file uri.
+ $node = node_load($nid, NULL, TRUE);
+ $source = $node->{$field_name}[$langcode][0]['uri'];
+
+ // Update file path and create redirect.
+ $edit = array(
+ 'instance[settings][filefield_paths][file_path][value]' => $this->randomName(),
+ 'instance[settings][filefield_paths][redirect]' => TRUE,
+ 'instance[settings][filefield_paths][retroactive_update]' => TRUE,
+ );
+ $this->drupalPost("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}", $edit, t('Save settings'));
+
+ // Get processed destination file uri.
+ $node = node_load($nid, NULL, TRUE);
+ $destination = $node->{$field_name}[$langcode][0]['uri'];
+
+ // Ensure that the source uri redirects to the destination uri.
+ $parsed_source = parse_url(file_create_url($source), PHP_URL_PATH);
+ $redirect_source = drupal_substr(urldecode($parsed_source), drupal_strlen($base_path));
+
+ $parsed_destination = parse_url(file_create_url($destination), PHP_URL_PATH);
+ $redirect_destination = drupal_substr(urldecode($parsed_destination), drupal_strlen($base_path));
+
+ $redirect = redirect_load_by_source($redirect_source);
+ $this->assert(is_object($redirect) && $redirect->redirect == $redirect_destination, t('Redirect created for relocated file.'));
+ }
+}
diff --git a/sites/all/modules/filefield_paths/tests/transliteration.test b/sites/all/modules/filefield_paths/tests/transliteration.test
new file mode 100644
index 0000000..09e1844
--- /dev/null
+++ b/sites/all/modules/filefield_paths/tests/transliteration.test
@@ -0,0 +1,82 @@
+ 'Transliteration integration',
+ 'description' => 'Tests the Transliteration module integration.',
+ 'group' => 'File (Field) Paths',
+ );
+ }
+
+ /**
+ * Test File (Field) Paths Transliteration UI.
+ */
+ public function testUI() {
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+ $this->createFileField($field_name, $this->content_type);
+
+ // Ensure File (Field) Paths Transliteration settings are present and available.
+ $this->drupalGet("admin/structure/types/manage/{$this->content_type}/fields/{$field_name}");
+ foreach (array('path', 'name') as $field) {
+ $this->assertField("instance[settings][filefield_paths][file_{$field}][options][transliterate]", t('Transliteration checkbox is present in File @field settings.', array('@field' => drupal_ucfirst($field))));
+
+ $element = $this->xpath('//input[@name=:name]/@disabled', array(':name' => "instance[settings][filefield_paths][file_{$field}][options][transliterate]"));
+ $this->assert(empty($element), t('Transliteration checkbox is not disabled in File @field settings.', array('@field' => drupal_ucfirst($field))));
+ }
+ }
+
+ /**
+ * Test Transliteration cleanup in File (Field) Paths.
+ */
+ public function testTransliteration() {
+ $langcode = LANGUAGE_NONE;
+
+ // Create a File field.
+ $field_name = drupal_strtolower($this->randomName());
+
+ $instance_settings['filefield_paths']['file_path']['value'] = 'node/[node:title]';
+ $instance_settings['filefield_paths']['file_path']['options']['transliterate'] = TRUE;
+ $instance_settings['filefield_paths']['file_name']['value'] = '[node:title].[file:ffp-extension-original]';
+ $instance_settings['filefield_paths']['file_name']['options']['transliterate'] = TRUE;
+
+ $this->createFileField($field_name, $this->content_type, array(), $instance_settings);
+
+ // Create a node with a test file.
+ $test_file = $this->getTestFile('text');
+ $edit['title'] = 'тест';
+
+ $edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($test_file->uri);
+ $this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
+
+ // Get created Node ID.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ $nid = $matches[1];
+
+ // Ensure that file path/name have been processed correctly by
+ // Transliteration.
+ $node = node_load($nid);
+ $this->assertEqual($node->{$field_name}[$langcode][0]['uri'], "public://node/test/test.txt", t('File path/name has been processed correctly by Transliteration'));
+ }
+}
diff --git a/sites/all/modules/uuid/.travis.yml b/sites/all/modules/uuid/.travis.yml
new file mode 100644
index 0000000..a4c6346
--- /dev/null
+++ b/sites/all/modules/uuid/.travis.yml
@@ -0,0 +1,74 @@
+language: php
+sudo: false
+
+php:
+ - 5.5
+ - 5.6
+ - 7.0
+ - hhvm
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: hhvm
+
+mysql:
+ database: drupal
+ username: root
+ encoding: utf8
+
+install:
+ # add composer's global bin directory to the path
+ # see: https://github.com/drush-ops/drush#install---composer
+ - export PATH="$HOME/.composer/vendor/bin:$PATH"
+
+ # install drush globally
+ - composer global require drush/drush:7.*
+
+ # Install PHP_CodeSniffer and Drupal config
+ - composer global require drupal/coder
+ - phpcs --config-set installed_paths ~/.composer/vendor/drupal/coder/coder_sniffer
+
+ # Create the database
+ - mysql -e 'create database drupal;'
+
+before_script:
+
+ # Disable sendmail
+ - echo sendmail_path=`which true` >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
+
+ # Increase the MySQL connection timeout on the PHP end.
+ - echo "mysql.connect_timeout=3000" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
+ - echo "default_socket_timeout=3000" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
+
+ # Increase the MySQL server timetout and packet size.
+ - mysql -e "SET GLOBAL wait_timeout = 36000;"
+ - mysql -e "SET GLOBAL max_allowed_packet = 33554432;"
+
+ # Download Drupal 7.x
+ - drush pm-download drupal-7 --destination=/tmp --drupal-project-rename=drupal
+
+ # Add our module
+ - ln -s $(pwd) /tmp/drupal/sites/all/modules/
+
+ # Switch to the drupal site directory
+ - cd /tmp/drupal
+
+ # Install site and dependencies
+ - drush -vv --yes site-install --db-url=mysql://root:@127.0.0.1/drupal
+ - drush pm-download entity
+ - drush pm-enable simpletest entity uuid --yes
+
+ # Use the PHP builtin webserver to serve the site.
+ #- drush runserver 8080 > /dev/null 2>&1 &
+ - drush runserver 127.0.0.1:8888 > ~/server.log 2>&1 &
+ - export counter=0; until nc -zv localhost 8888; do if [ $counter -ge 12 ]; then echo "Failed to start server."; exit 1; fi; echo "Waiting for web server to start on port 8888..."; sleep 5; counter=$[$counter +1]; done
+
+script:
+ - cd /tmp/drupal
+ - php ./scripts/run-tests.sh --verbose --color --php "$(which php)" --url http://127.0.0.1:8888 UUID | tee ~/tests.log
+ - phpcs --standard=Drupal --extensions=php,module,inc,install,test,profile,theme sites/all/modules/uuid
+
+after_failure:
+ # See what happened with the server.
+ - cat ~/server.log
diff --git a/sites/all/modules/uuid/README.txt b/sites/all/modules/uuid/README.txt
index 33bca3d..b1ea8a2 100644
--- a/sites/all/modules/uuid/README.txt
+++ b/sites/all/modules/uuid/README.txt
@@ -11,6 +11,7 @@ FEATURES
* Automatic UUID generation:
UUIDs will be generated for all core entities. An API is provided for other
modules to enable support for custom entities.
+ See https://www.drupal.org/node/2387671
* UUID API for entities, properties and fields:
With this unified API you can load entities with entity_uuid_load() so that
all supported properties and fields are made with UUID references. You can
diff --git a/sites/all/modules/uuid/plugins/arguments/entity_uuid.inc b/sites/all/modules/uuid/plugins/arguments/entity_uuid.inc
index 703abbd..bc9a824 100644
--- a/sites/all/modules/uuid/plugins/arguments/entity_uuid.inc
+++ b/sites/all/modules/uuid/plugins/arguments/entity_uuid.inc
@@ -6,8 +6,7 @@
*/
/**
- * Plugins are described by creating a $plugin array which will be used
- * by the system that includes this file.
+ * CTools UUID entity context plugin definition.
*/
$plugin = array(
'title' => t("Entity: UUID"),
@@ -17,11 +16,27 @@ $plugin = array(
'get children' => 'uuid_entity_uuid_get_children',
);
+/**
+ * Fetches the "child" information for a given parent entity.
+ *
+ * @todo document me properly.
+ *
+ * @return array
+ * The children.
+ */
function uuid_entity_uuid_get_child($plugin, $parent, $child) {
$plugins = uuid_entity_uuid_get_children($plugin, $parent);
return $plugins[$parent . ':' . $child];
}
+/**
+ * Fetches all children types for a given parent entity.
+ *
+ * @todo document me properly.
+ *
+ * @return array
+ * All the children.
+ */
function uuid_entity_uuid_get_children($original_plugin, $parent) {
$entities = entity_get_info();
$plugins = array();
diff --git a/sites/all/modules/uuid/uuid.admin.inc b/sites/all/modules/uuid/uuid.admin.inc
index 679aea4..e388d22 100644
--- a/sites/all/modules/uuid/uuid.admin.inc
+++ b/sites/all/modules/uuid/uuid.admin.inc
@@ -42,7 +42,9 @@ function uuid_devel_load_by_uuid($entity_type, $entity) {
// Get the keys for local ID and UUID.
$uuid_key = $info['entity keys']['uuid'];
$uuid_entities = entity_uuid_load($entity_type, array($entity->{$uuid_key}));
+ // @codingStandardsIgnoreStart
return kdevel_print_object(reset($uuid_entities), '$' . $entity_type . '->');
+ // @codingStandardsIgnoreEnd
}
else {
return t("This entity doesn't support UUID.");
diff --git a/sites/all/modules/uuid/uuid.api.php b/sites/all/modules/uuid/uuid.api.php
index 1b6b63b..18c8012 100644
--- a/sites/all/modules/uuid/uuid.api.php
+++ b/sites/all/modules/uuid/uuid.api.php
@@ -5,26 +5,6 @@
* Hooks provided by the UUID module.
*/
-/**
- * Defines one or more UUID generators exposed by a module.
- *
- * @return
- * An associative array with the key being the machine name for the
- * implementation and the values being an array with the following keys:
- * - title: The human readable name for the generator.
- * - callback: The function to be called for generating the UUID.
- *
- * @see uuid_get_info()
- */
-function hook_uuid_info() {
- $generators = array();
- $generators['my_module'] = array(
- 'title' => t('My module UUID generator'),
- 'callback' => 'my_module_generate_uuid',
- );
- return $generators;
-}
-
/**
* Ensures all records have a UUID assigned to them.
*
@@ -38,39 +18,35 @@ function hook_uuid_sync() {
}
/**
- * Let modules transform their properties with local IDs to UUIDs when an
- * entity is loaded.
+ * Transform entity properties from local IDs to UUIDs when they are loaded.
*/
function hook_entity_uuid_load(&$entities, $entity_type) {
}
/**
- * Let modules transform their fields with local IDs to UUIDs when an entity
- * is loaded.
+ * Transform field values from local IDs to UUIDs when an entity is loaded.
*/
function hook_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
}
/**
- * Let modules transform their properties with UUIDs to local IDs when an
- * entity is saved.
+ * Transform entity properties from UUIDs to local IDs before entity is saved.
*/
function hook_entity_uuid_presave(&$entity, $entity_type) {
}
/**
- * Let modules transform their fields with UUIDs to local IDs when an entity
- * is saved.
+ * Transform field values from UUIDs to local IDs before an entity is saved.
*/
function hook_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
}
/**
- * Let modules transform their properties when an entity is saved.
+ * Transform entity properties after an entity is saved.
*/
function hook_entity_uuid_save($entity, $entity_type) {
@@ -78,20 +54,24 @@ function hook_entity_uuid_save($entity, $entity_type) {
/**
* Let modules act when an entity is deleted.
+ *
+ * Generally hook_entity_delete() should be used instead of this hook.
+ *
+ * @see hook_entity_delete()
*/
function hook_entity_uuid_delete($entity, $entity_type) {
}
/**
- * Let modules modify paths when they are being converted to UUID ones.
+ * Modifies paths when they are being converted to UUID ones.
*/
function hook_uuid_menu_path_to_uri_alter($path, &$uri) {
}
/**
- * Let modules modify paths when they are being converted from UUID ones.
+ * Modifies paths when they are being converted from UUID ones.
*/
function hook_uuid_menu_uri_to_path(&$path, $uri) {
@@ -121,14 +101,14 @@ function hook_uuid_entities_post_rebuild($plan_name) {
/**
* Let other modules do things before default entities are created on revert.
*/
-function hook_uuid_entities_pre_rebuild($plan_name) {
+function hook_uuid_entities_pre_revert($plan_name) {
}
/**
* Let other modules do things after default entities are created on revert.
*/
-function hook_uuid_entities_post_rebuild($plan_name) {
+function hook_uuid_entities_post_revert($plan_name) {
}
@@ -152,12 +132,6 @@ function hook_uuid_entities_features_export_field_alter($entity_type, &$entity,
function hook_uuid_uri_data($data) {
}
-/**
- * Alter UUID URI data after processing.
- */
-function hook_uuid_uri_data($data) {
-}
-
/**
* Alter entity URI before creating UUID URI.
*/
diff --git a/sites/all/modules/uuid/uuid.core.inc b/sites/all/modules/uuid/uuid.core.inc
index e54b556..cc70a2e 100644
--- a/sites/all/modules/uuid/uuid.core.inc
+++ b/sites/all/modules/uuid/uuid.core.inc
@@ -32,6 +32,31 @@ function node_entity_uuid_presave(&$entity, $entity_type) {
if ($entity_type == 'node') {
entity_property_uuid_to_id($entity, 'user', array('uid', 'revision_uid'));
entity_property_uuid_to_id($entity, 'node', 'tnid');
+
+ // A node always must have an author.
+ if (empty($entity->uid)) {
+ global $user;
+ $entity->uid = $user->uid;
+ }
+ }
+}
+
+/**
+ * Implements hook_entity_uuid_save().
+ */
+function node_entity_uuid_save(&$entity, $entity_type) {
+ /*
+ * When a node is translated, the source node's tnid is set to it's own nid.
+ * When deploying the node for the first time the tnid can't be translated
+ * to an nid until after the node has been saved. So if the entity's tnid
+ * is still a uuid at this point it needs to be translated to an nid.
+ */
+ if ($entity_type == 'node' && uuid_is_valid($entity->tnid)) {
+ entity_property_uuid_to_id($entity, 'node', 'tnid');
+ db_update('node')
+ ->fields(array('tnid' => $entity->tnid))
+ ->condition('nid', $entity->nid)
+ ->execute();
}
}
@@ -64,17 +89,33 @@ function book_entity_uuid_presave(&$entity, $entity_type) {
* Implements hook_entity_uuid_presave().
*/
function user_entity_uuid_presave(&$entity, $entity_type) {
- if ($entity_type == 'user') {
- if (!empty($entity->picture)) {
- $uuids = entity_get_id_by_uuid('file', array($entity->picture['uuid']));
- $fid = current($uuids);
- if (!$entity->is_new) {
- $entity->picture = file_load($fid);
- }
- else {
- $entity->picture = $fid;
- }
- }
+ if ($entity_type != 'user') {
+ return;
+ }
+
+ /*
+ * We need to ensure new user's passwords are encrypted. The Services module
+ * transparently encrypts the password for new users. md5() is used by
+ * users who's accounts were migrated from Drupal 6 and who haven't updated
+ * their password.
+ */
+ if (isset($entity->pass)
+ && (!('$S$D' == substr($entity->pass, 0, 4)) || preg_match('/^[a-f0-9]{32}$/', $entity->pass))) {
+ // Ensure user's password is hashed.
+ $entity->pass = user_hash_password($entity->pass);
+ }
+
+ if (empty($entity->picture)) {
+ return;
+ }
+
+ $uuids = entity_get_id_by_uuid('file', array($entity->picture['uuid']));
+ $fid = current($uuids);
+ if (!$entity->is_new) {
+ $entity->picture = file_load($fid);
+ }
+ else {
+ $entity->picture = $fid;
}
}
@@ -104,6 +145,10 @@ function comment_entity_uuid_presave(&$entity, $entity_type) {
break;
case 'comment':
+ // entity_make_entity_local() may have unset cid, add back if necessary.
+ if (!isset($entity->cid)) {
+ $entity->cid = NULL;
+ }
entity_property_uuid_to_id($entity, 'user', array('uid', 'u_uid'));
entity_property_uuid_to_id($entity, 'node', 'nid');
break;
@@ -124,11 +169,58 @@ function file_entity_uuid_load(&$entities, $entity_type) {
*/
function file_entity_uuid_presave(&$entity, $entity_type) {
if ($entity_type == 'file') {
+ // entity_make_entity_local() may have unset fid, add back if necessary.
+ if (!isset($entity->fid)) {
+ $entity->fid = NULL;
+ }
entity_property_uuid_to_id($entity, 'user', 'uid');
- if (isset($entity->file_contents)) {
- $directory = drupal_dirname($entity->uri);
- file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
- file_unmanaged_save_data(base64_decode($entity->file_contents), $entity->uri, FILE_EXISTS_REPLACE);
+
+ // Write the new file to the local filesystem.
+ if (isset($entity->file_contents) && !empty($entity->filesize)) {
+ // Don't try to write it if it uses a stream wrapper that isn't writeable
+ // (for example, if it is a remotely-hosted video).
+ $scheme = file_uri_scheme($entity->uri);
+ $wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE);
+ if (empty($wrappers[$scheme])) {
+ return;
+ }
+
+ // Check for an existing file with the same URI.
+ $existing_files = file_load_multiple(array(), array('uri' => $entity->uri));
+ $existing = (object) array('uri' => NULL, 'uuid' => NULL);
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ }
+
+ // If this is a new file and there is an existing file with the same URI,
+ // but a different uuid then rename this file.
+ if ($entity->is_new && $entity->uri == $existing->uri && $entity->uuid != $existing->uuid) {
+ $uri = $entity->uri;
+ $replace = FILE_EXISTS_RENAME;
+ }
+ // If this has an id, meaning UUID has already matched the uuid to an
+ // existing file, but it has a URI that matches a file with a different
+ // uuid, then load the file with the matching uuid and use the URI from
+ // that file. The existing file with the matching uuid is most likely a
+ // file that was previously renamed, e.g. as in the condition above, to
+ // avoid conflict. The uuid matches because they are the same file, but
+ // the URI does not because an incrementing number was added as part of
+ // the renaming.
+ elseif ($entity->uri == $existing->uri && $entity->uuid != $existing->uuid) {
+ $file = file_load($entity->fid);
+ $uri = $file->uri;
+ $replace = FILE_EXISTS_REPLACE;
+ }
+ // Otherwise create a new file or replace the existing file contents.
+ else {
+ $uri = $entity->uri;
+ $replace = FILE_EXISTS_REPLACE;
+ }
+
+ $directory = drupal_dirname($uri);
+ if (!empty($directory) && file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
+ $entity->uri = file_unmanaged_save_data(base64_decode($entity->file_contents), $uri, $replace);
+ }
}
}
}
@@ -172,7 +264,7 @@ function taxonomy_entity_uuid_presave(&$entity, $entity_type) {
* Implements hook_entity_uuid_load().
*/
function field_entity_uuid_load(&$entities, $entity_type) {
- foreach ($entities as $i => $entity) {
+ foreach ($entities as $entity) {
list(, , $bundle_name) = entity_extract_ids($entity_type, $entity);
$instances = field_info_instances($entity_type, $bundle_name);
@@ -269,34 +361,8 @@ function image_field_uuid_presave($entity_type, $entity, $field, $instance, $lan
/**
* 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');
-}
-
-/**
- * Implements hook_field_uuid_load().
+ *
+ * Kept here because it is in D8 core.
*/
function entityreference_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
// TODO: This is not really good, but as of now 'entity_property_id_to_uuid()'
@@ -306,6 +372,8 @@ function entityreference_field_uuid_load($entity_type, $entity, $field, $instanc
/**
* Implements hook_field_uuid_presave().
+ *
+ * Kept here because it is in D8 core.
*/
function entityreference_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
// TODO: This is not really good, but as of now 'entity_property_id_to_uuid()'
@@ -313,38 +381,6 @@ function entityreference_field_uuid_presave($entity_type, $entity, $field, $inst
entity_property_uuid_to_id($items, $field['settings']['target_type'], 'target_id');
}
-/**
- * Implements hook_entity_uuid_load().
- */
-function field_collection_entity_uuid_load(&$entities, $entity_type) {
- if ($entity_type == 'field_collection_item') {
- entity_property_id_to_uuid($entities, 'field_collection_item', 'value');
- }
-}
-
-/**
- * Implements hook_entity_uuid_presave().
- */
-function field_collection_entity_uuid_presave(&$entity, $entity_type) {
- if ($entity_type == 'field_collection_item') {
- entity_property_uuid_to_id($entity, 'field_collection_item', 'value');
- }
-}
-
-/**
- * Implements hook_field_uuid_load().
- */
-function field_collection_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
- entity_property_id_to_uuid($items, 'field_collection_item', 'value');
-}
-
-/**
- * Implements hook_field_uuid_presave().
- */
-function field_collection_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
- entity_property_uuid_to_id($items, 'field_collection_item', 'value');
-}
-
/**
* @} End of "Field implementations"
*/
@@ -358,24 +394,35 @@ function field_collection_field_uuid_presave($entity_type, $entity, $field, $ins
* Implements hook_uuid_entities_features_export_entity_alter().
*/
function node_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
- if ($entity_type == 'node') {
- foreach (array('data', 'name', 'picture', 'revision_uid', 'last_comment_timestamp') as $property) {
- if (property_exists($entity, $property)) {
- unset($entity->{$property});
- }
+ if ('node' != $entity_type) {
+ return;
+ }
+
+ $properties = array(
+ 'data',
+ 'name',
+ 'picture',
+ 'revision_uid',
+ 'last_comment_timestamp',
+ );
+ foreach ($properties as $property) {
+ if (property_exists($entity, $property)) {
+ unset($entity->{$property});
}
}
}
/**
- * Implementation of hook_uuid_entities_features_export_entity_alter().
+ * Implements hook_uuid_entities_features_export_entity_alter().
*/
function user_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
- if ($entity_type == 'user') {
- foreach (array('data', 'access', 'login') as $property) {
- if (property_exists($entity, $property)) {
- unset($entity->{$property});
- }
+ if ('user' != $entity_type) {
+ return;
+ }
+
+ foreach (array('data', 'access', 'login') as $property) {
+ if (property_exists($entity, $property)) {
+ unset($entity->{$property});
}
}
}
@@ -391,17 +438,6 @@ function file_uuid_entities_features_export_field_alter($entity_type, $entity, $
}
}
-/**
- * Implements hook_uuid_entities_features_export_entity_alter().
- */
-function workbench_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
- foreach (array('workbench_moderation', 'my_revision', 'workbench_access', 'workbench_access_scheme', 'workbench_access_by_role') as $property) {
- if (isset($entity->{$property})) {
- unset($entity->{$property});
- }
- }
-}
-
/**
* @} End of "Export alterations"
*/
diff --git a/sites/all/modules/uuid/uuid.drush.inc b/sites/all/modules/uuid/uuid.drush.inc
index afb44ad..c3641e8 100644
--- a/sites/all/modules/uuid/uuid.drush.inc
+++ b/sites/all/modules/uuid/uuid.drush.inc
@@ -6,7 +6,7 @@
*/
/**
- * Implementats hook_drush_command().
+ * Implements hook_drush_command().
*/
function uuid_drush_command() {
$items = array();
@@ -18,7 +18,7 @@ function uuid_drush_command() {
}
/**
- * Implementats of hook_drush_help().
+ * Implements hook_drush_help().
*/
function uuid_drush_help($section) {
switch ($section) {
diff --git a/sites/all/modules/uuid/uuid.entity.inc b/sites/all/modules/uuid/uuid.entity.inc
index 50081c3..4306339 100644
--- a/sites/all/modules/uuid/uuid.entity.inc
+++ b/sites/all/modules/uuid/uuid.entity.inc
@@ -11,8 +11,7 @@
class UuidEntityException extends Exception {}
/**
- * Helper function that returns entity info for all supported core modules,
- * relevant for UUID functionality.
+ * Returns entity info for all supported core entities.
*
* @see uuid_entity_info()
* @see uuid_schema_alter()
@@ -76,9 +75,9 @@ function uuid_get_core_entity_info() {
*/
/**
- * Implements of hook_entity_info_alter().
+ * Implements hook_entity_info_alter().
*
- * @see uuid_core_entity_info().
+ * @see uuid_core_entity_info()
*/
function uuid_entity_info_alter(&$info) {
foreach (uuid_get_core_entity_info() as $entity_type => $core_info) {
@@ -91,21 +90,24 @@ function uuid_entity_info_alter(&$info) {
}
/**
- * Implements of hook_entity_property_info_alter().
+ * Implements hook_entity_property_info_alter().
*
* This adds the UUID as an entity property for all UUID-enabled entities
* which automatically gives us token and Rules integration.
*/
function uuid_entity_property_info_alter(&$info) {
foreach (entity_get_info() as $entity_type => $entity_info) {
- if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE && !empty($entity_info['entity keys']['uuid'])) {
+ if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE
+ && !empty($entity_info['entity keys']['uuid'])
+ && empty($info[$entity_type]['properties'][$entity_info['entity keys']['uuid']])) {
$info[$entity_type]['properties'][$entity_info['entity keys']['uuid']] = array(
'label' => t('UUID'),
'type' => 'text',
'description' => t('The universally unique ID.'),
'schema field' => $entity_info['entity keys']['uuid'],
);
- if (!empty($entity_info['entity keys']['revision uuid'])) {
+ if (!empty($entity_info['entity keys']['revision uuid'])
+ && empty($info[$entity_type]['properties'][$entity_info['entity keys']['revision uuid']])) {
$info[$entity_type]['properties'][$entity_info['entity keys']['revision uuid']] = array(
'label' => t('Revision UUID'),
'type' => 'text',
@@ -118,7 +120,7 @@ function uuid_entity_property_info_alter(&$info) {
}
/**
- * Implements of hook_entity_presave().
+ * Implements hook_entity_presave().
*
* This is where all UUID-enabled entities get their UUIDs.
*/
@@ -131,7 +133,19 @@ function uuid_entity_presave($entity, $entity_type) {
}
if (!empty($info['entity keys']['revision uuid'])) {
$vuuid_key = $info['entity keys']['revision uuid'];
- if ((isset($entity->revision) && $entity->revision == TRUE) || empty($entity->{$vuuid_key})) {
+ // If this entity comes from a remote environment and have a revision UUID
+ // that exists locally we should not create a new revision. Because
+ // otherwise revisions won't be tracked universally.
+ // TODO: Move code dependent on the uuid_services module into it's own
+ // implementation of hook_entity_presave().
+ if (!empty($entity->uuid_services) && isset($entity->{$vuuid_key})) {
+ $vuuid_exists = (bool) entity_get_id_by_uuid($entity_type, array($entity->{$vuuid_key}), TRUE);
+ if ($vuuid_exists) {
+ $entity->revision = FALSE;
+ }
+ }
+
+ if ((isset($entity->revision) && $entity->revision == TRUE && empty($entity->uuid_services)) || empty($entity->{$vuuid_key})) {
$entity->{$vuuid_key} = uuid_generate();
}
}
@@ -151,12 +165,26 @@ function uuid_entity_presave($entity, $entity_type) {
/**
* Load entities by their UUID, that only should containing UUID references.
*
+ * Optionally load revisions by their VUUID by passing it into $conditions.
+ * Ex. $conditions['vuuid'][$vuuid]
+ *
* This function is mostly useful if you want to load an entity from the local
* database that only should contain UUID references.
*
* @see entity_load()
*/
function entity_uuid_load($entity_type, $uuids = array(), $conditions = array(), $reset = FALSE) {
+ // Allow Revision UUID to be passed in $conditions and translate.
+ $entity_info[$entity_type] = entity_get_info($entity_type);
+ $revision_key = $entity_info[$entity_type]['entity keys']['revision'];
+ if (isset($entity_info[$entity_type]['entity keys']['revision uuid'])) {
+ $revision_uuid_key = $entity_info[$entity_type]['entity keys']['revision uuid'];
+ }
+ if (isset($revision_uuid_key) && isset($conditions[$revision_uuid_key])) {
+ $revision_id = entity_get_id_by_uuid($entity_type, array($conditions[$revision_uuid_key]), TRUE);
+ $conditions[$revision_key] = $revision_id[$conditions[$revision_uuid_key]];
+ unset($conditions[$revision_uuid_key]);
+ }
$ids = entity_get_id_by_uuid($entity_type, $uuids);
$results = entity_load($entity_type, $ids, $conditions, $reset);
$entities = array();
@@ -209,10 +237,27 @@ function entity_uuid_save($entity_type, $entity) {
throw new UuidEntityException(t('Calling %function requires the Entity API module (!link).', array('%function' => __FUNCTION__, '!link' => 'http://drupal.org/project/entity')));
}
+ $info = entity_get_info($entity_type);
+ $uuid_key = $info['entity keys']['uuid'];
+ if (empty($entity->{$uuid_key}) || !uuid_is_valid($entity->{$uuid_key})) {
+ watchdog('Entity UUID', 'Attempted to save an entity with an invalid UUID', array(), WATCHDOG_ERROR);
+ return FALSE;
+ }
+
+ // Falling back on the variable node_options_[type] is not something an API
+ // function should take care of. With normal (non UUID) nodes this is dealt
+ // with in the form submit handler, i.e. not in node_save().
+ // But since using entity_uuid_save() usually means you're trying to manage
+ // entities remotely we do respect this variable here to make it work as the
+ // node form, but only if we explicitly haven't set $node->revision already.
+ if ($entity_type == 'node' && !isset($entity->revision) && in_array('revision', variable_get('node_options_' . $entity->type, array()))) {
+ $entity->revision = 1;
+ }
+
entity_make_entity_local($entity_type, $entity);
// Save the entity.
- entity_save($entity_type, $entity);
+ $result = entity_save($entity_type, $entity);
$hook = 'entity_uuid_save';
foreach (module_implements($hook) as $module) {
@@ -221,6 +266,7 @@ function entity_uuid_save($entity_type, $entity) {
$function($entity, $entity_type);
}
}
+ return $result;
}
/**
@@ -259,6 +305,10 @@ function entity_make_entity_local($entity_type, $entity) {
$vid = NULL;
// Fetch the local revision ID by its UUID.
if (isset($entity->{$vuuid_key})) {
+ // It's important to note that the revision UUID might be set here but
+ // there might not exist a correspondant local revision ID in which case
+ // we should unset the assigned revision ID to not confuse anyone with
+ // revision IDs that might come from other environments.
$vids = entity_get_id_by_uuid($entity_type, array($entity->{$vuuid_key}), TRUE);
$vid = reset($vids);
}
@@ -268,9 +318,10 @@ function entity_make_entity_local($entity_type, $entity) {
elseif (!empty($vid)) {
$entity->{$vid_key} = $vid;
}
- // Nodes need this when trying to save an existing node without a vid.
+ // If the revision ID was unset before this (or just missing for some
+ // reason) we fetch the current revision ID to build a better
+ // representation of the node object we're working with.
if ($entity_type == 'node' && !isset($entity->vid) && !$entity->is_new) {
- $entity->revision = 0;
$entity->vid = db_select('node', 'n')
->condition('n.nid', $entity->nid)
->fields('n', array('vid'))
@@ -289,7 +340,7 @@ function entity_make_entity_local($entity_type, $entity) {
}
}
else {
- throw new UuidEntityException(t('Trying to operate on a @type entity, which doesn\'t support UUIDs.', array('@type' => $info['label'])));
+ throw new UuidEntityException(t("Trying to operate on a @type entity, which doesn\'t support UUIDs.", array('@type' => $info['label'])));
}
}
@@ -312,6 +363,7 @@ function entity_uuid_delete($entity_type, $uuid) {
// Fetch the local ID by its UUID.
$ids = entity_get_id_by_uuid($entity_type, array($uuid));
$id = reset($ids);
+ $entity = entity_load($entity_type, array($id));
// Let other modules transform UUID references to local ID references.
$hook = 'entity_uuid_delete';
@@ -322,11 +374,14 @@ function entity_uuid_delete($entity_type, $uuid) {
}
}
+ if (empty($entity)) {
+ return FALSE;
+ }
// Delete the entity.
return entity_delete($entity_type, $id);
}
else {
- throw new UuidEntityException(t('Trying to delete a @type entity, which doesn\'t support UUIDs.', array('@type' => $info['label'])));
+ throw new UuidEntityException(t("Trying to delete a @type entity, which doesn\'t support UUIDs.", array('@type' => $info['label'])));
}
}
@@ -334,24 +389,34 @@ function entity_uuid_delete($entity_type, $uuid) {
* Helper function that retrieves entity IDs by their UUIDs.
*
* @todo
- * Statically cache as many IDs as possible and limit the query.
+ * Limit the query.
*
- * @param $entity_type
+ * @param string $entity_type
* The entity type we should be dealing with.
- * @param $uuids
- * An array of UUIDs for which we should find their entity IDs. If $revision
+ * @param array $uuids
+ * List of UUIDs for which we should find their entity IDs. If $revision
* is TRUE this should be revision UUIDs instead.
- * @param $revision
+ * @param bool $revision
* If TRUE the revision IDs is returned instead.
- * @return
- * Array of entity IDs keyed by their UUIDs. If $revision is TRUE revision
+ *
+ * @return array
+ * List of entity IDs keyed by their UUIDs. If $revision is TRUE revision
* IDs and UUIDs are returned instead.
*/
function entity_get_id_by_uuid($entity_type, $uuids, $revision = FALSE) {
if (empty($uuids)) {
return array();
}
+ $cached_ids = entity_uuid_id_cache($entity_type, $uuids, $revision);
+ if (count($cached_ids) == count($uuids)) {
+ return $cached_ids;
+ }
+ $uuids = array_diff($uuids, $cached_ids);
$info = entity_get_info($entity_type);
+ // Some contrib entities has no support for UUID, let's skip them.
+ if (empty($info['uuid'])) {
+ return array();
+ }
// Find out what entity keys to use.
if (!$revision) {
$table = $info['base table'];
@@ -369,35 +434,61 @@ function entity_get_id_by_uuid($entity_type, $uuids, $revision = FALSE) {
}
// Get all UUIDs in one query.
- return db_select($table, 't')
+ $result = db_select($table, 't')
->fields('t', array($uuid_key, $id_key))
->condition($uuid_key, array_values($uuids), 'IN')
->execute()
->fetchAllKeyed();
+ $cache = &drupal_static('entity_uuid_id_cache', array());
+ $cache[$entity_type][(int) $revision] += $result;
+ return $result + $cached_ids;
+}
+
+/**
+ * Helper caching function.
+ */
+function entity_uuid_id_cache($entity_type, $ids, $revision) {
+ $cache = &drupal_static(__FUNCTION__, array());
+ if (empty($cache[$entity_type][(int) $revision])) {
+ $cache[$entity_type][(int) $revision] = array();
+ }
+ $cached_ids = $cache[$entity_type][(int) $revision];
+ return array_intersect_key($cached_ids, array_flip($ids));
}
/**
* Helper function that retrieves UUIDs by their entity IDs.
*
* @todo
- * Statically cache as many IDs as possible and limit the query.
+ * Limit the query.
*
- * @param $entity_type
+ * @param string $entity_type
* The entity type we should be dealing with.
- * @param $ids
- * An array of entity IDs for which we should find their UUIDs. If $revision
+ * @param array $ids
+ * List of entity IDs for which we should find their UUIDs. If $revision
* is TRUE this should be revision IDs instead.
- * @param $revision
+ * @param bool $revision
* If TRUE the revision UUIDs is returned instead.
- * @return
- * Array of entity UUIDs keyed by their IDs. If $revision is TRUE revision
+ *
+ * @return array
+ * List of entity UUIDs keyed by their IDs. If $revision is TRUE revision
* IDs and UUIDs are returned instead.
*/
function entity_get_uuid_by_id($entity_type, $ids, $revision = FALSE) {
if (empty($ids)) {
return array();
}
+ $cached_ids = array_flip(entity_uuid_id_cache($entity_type, $ids, $revision));
+ if (count($cached_ids) == count($ids)) {
+ return $cached_ids;
+ }
+ $ids = array_diff($ids, $cached_ids);
+
$info = entity_get_info($entity_type);
+ // Some contrib entities has no support for UUID, let's skip them.
+ if (empty($info['uuid'])) {
+ return array();
+ }
// Find out what entity keys to use.
if (!$revision) {
$table = $info['base table'];
@@ -415,11 +506,14 @@ function entity_get_uuid_by_id($entity_type, $ids, $revision = FALSE) {
}
// Get all UUIDs in one query.
- return db_select($table, 't')
+ $result = db_select($table, 't')
->fields('t', array($id_key, $uuid_key))
->condition($id_key, array_values($ids), 'IN')
->execute()
->fetchAllKeyed();
+ $cache = &drupal_static('entity_uuid_id_cache', array());
+ $cache[$entity_type][(int) $revision] += array_flip($result);
+ return $result + $cached_ids;
}
/**
@@ -432,12 +526,12 @@ function entity_get_uuid_by_id($entity_type, $ids, $revision = FALSE) {
* @todo
* Add tests for this function.
*
- * @param $objects
- * An array of objects that should get $properties changed. Can be either an
+ * @param array $objects
+ * List of objects that should get $properties changed. Can be either an
* entity object or a field items array.
- * @param $entity_type
+ * @param string $entity_type
* The type of entity that all $properties refers to.
- * @param $properties
+ * @param array $properties
* An array of properties that should be changed. All properties must refer to
* the same type of entity (the one referenced in $entity_type).
*/
@@ -488,12 +582,12 @@ function entity_property_id_to_uuid(&$objects, $entity_type, $properties) {
* @todo
* Add tests for this function.
*
- * @param $objects
- * An array of objects that should get $properties changed. Can be either an
+ * @param array $objects
+ * List of objects that should get $properties changed. Can be either an
* entity object or a field items array.
- * @param $entity_type
+ * @param string $entity_type
* The type of entity that all $properties refers to.
- * @param $properties
+ * @param array $properties
* An array of properties that should be changed. All properties must refer to
* the same type of entity (the one referenced in $entity_type).
*/
diff --git a/sites/all/modules/uuid/uuid.features.inc b/sites/all/modules/uuid/uuid.features.inc
index 1dfa70d..93b418e 100644
--- a/sites/all/modules/uuid/uuid.features.inc
+++ b/sites/all/modules/uuid/uuid.features.inc
@@ -84,7 +84,15 @@ function uuid_entities_features_export_render($module_name, $components, $export
}
// We unset some common timestamp properties, since those will change and
// constantly leave the feature overidden.
- $keys = array('created', 'updated', 'changed', 'revision_timestamp', 'timestamp', 'stamp', 'current');
+ $keys = array(
+ 'created',
+ 'updated',
+ 'changed',
+ 'revision_timestamp',
+ 'timestamp',
+ 'stamp',
+ 'current',
+ );
foreach ($keys as $key) {
if (isset($entity->{$key})) {
unset($entity->{$key});
@@ -93,7 +101,7 @@ function uuid_entities_features_export_render($module_name, $components, $export
// Let other modules alter exported entities.
drupal_alter('uuid_entities_features_export_entity', $entity, $entity_type);
// Field handling.
- list(,, $bundle_name) = entity_extract_ids($entity_type, $entity);
+ list(, , $bundle_name) = entity_extract_ids($entity_type, $entity);
$instances = field_info_instances($entity_type, $bundle_name);
foreach ($instances as $field_name => $instance) {
$field = field_info_field($field_name);
@@ -121,7 +129,10 @@ function uuid_entities_features_export_render($module_name, $components, $export
}
uuid_entities_features_clean($entity);
- // Convert entities to array to avoid having them in JSON, returned from standard implementation of $entity->export().
+ /*
+ * Convert entities to array to avoid having them in JSON, returned
+ * from standard implementation of $entity->export().
+ */
if (is_object($entity) && method_exists($entity, 'export')) {
$entity = get_object_vars($entity);
}
@@ -134,14 +145,14 @@ function uuid_entities_features_export_render($module_name, $components, $export
}
/**
- * Implements [component]_features_export_rebuild().
+ * Implements [component]_features_rebuild().
*/
function uuid_entities_features_rebuild($module_name) {
uuid_entities_rebuild($module_name, 'rebuild');
}
/**
- * Implements [component]_features_export_revert().
+ * Implements [component]_features_revert().
*/
function uuid_entities_features_revert($module_name) {
uuid_entities_rebuild($module_name, 'revert');
@@ -157,6 +168,7 @@ function uuid_entities_rebuild($module_name = '', $op = 'rebuild') {
foreach ($entities as $plan_name => $entities) {
// Let other modules do things before default entities are created.
module_invoke_all("uuid_entities_pre_$op", $plan_name);
+ drupal_alter("uuid_entities_pre_$op", $entities, $plan_name);
foreach ($entities as $entity) {
entity_uuid_save($entity->__metadata['type'], $entity);
}
diff --git a/sites/all/modules/uuid/uuid.inc b/sites/all/modules/uuid/uuid.inc
index 4b0042d..d2a3d8f 100644
--- a/sites/all/modules/uuid/uuid.inc
+++ b/sites/all/modules/uuid/uuid.inc
@@ -8,7 +8,7 @@
/**
* Pattern for detecting a valid UUID.
*/
-define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+define('UUID_PATTERN', '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}');
/**
* Generates an universally unique identifier.
@@ -17,7 +17,7 @@ define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
* universally unique identifiers. If that doesn't exist, then it falls back on
* PHP for generating that.
*
- * @return
+ * @return string
* An UUID, made up of 32 hex digits and 4 hyphens.
*/
function uuid_generate() {
@@ -37,6 +37,61 @@ function uuid_generate() {
return $callback();
}
+/**
+ * Generates a version 5 compliant UUID.
+ *
+ * @param string $namespace
+ * Namespace UUID as a hex encoded string.
+ * @param string $name
+ * The name for the generating the UUID.
+ *
+ * @return string
+ * UUID as a hex encoded string.
+ *
+ * @link http://www.php.net/manual/en/function.uniqid.php#94959 Code lifted from
+ * PHP manual comment by Andrew Moore. @endlink
+ */
+function uuid_generate_v5($namespace, $name) {
+ if (!uuid_is_valid($namespace)) {
+ return FALSE;
+ }
+
+ // Get hexadecimal components of namespace.
+ $nhex = str_replace(array('-', '{', '}'), '', $namespace);
+
+ // Binary Value.
+ $nstr = '';
+
+ // Convert Namespace UUID to bits.
+ for ($i = 0; $i < strlen($nhex); $i += 2) {
+ $nstr .= chr(hexdec($nhex[$i] . $nhex[$i + 1]));
+ }
+
+ // Calculate hash value.
+ $hash = sha1($nstr . $name);
+
+ return sprintf('%08s-%04s-%04x-%04x-%12s',
+
+ // 32 bits for "time_low".
+ substr($hash, 0, 8),
+
+ // 16 bits for "time_mid".
+ substr($hash, 8, 4),
+
+ // 16 bits for "time_hi_and_version",
+ // four most significant bits holds version number 5.
+ (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
+
+ // 16 bits, 8 bits for "clk_seq_hi_res",
+ // 8 bits for "clk_seq_low",
+ // two most significant bits holds zero and one for variant DCE1.1.
+ (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
+
+ // 48 bits for "node".
+ substr($hash, 20, 12)
+ );
+}
+
/**
* Generate all missing UUIDs.
*/
@@ -53,7 +108,7 @@ function uuid_sync_all() {
* The type of entity being used.
*
* @return string
- * The generated UUID URI or normal URI if entity doesn't support UUIDs.
+ * The generated UUID URI or normal URI if entity doesn't support UUIDs.
*/
function uuid_entity_uuid_uri($entity, $entity_type) {
$entity_info = entity_get_info($entity_type);
@@ -73,13 +128,13 @@ function uuid_entity_uuid_uri($entity, $entity_type) {
/**
* Converts an ID URI string to an entity data array.
*
- * @see uuid_id_uri_array_to_data()
- *
* @param string $uri
- * The URI to convert.
+ * The URI to convert.
*
* @return array
- * The entity data.
+ * The entity data.
+ *
+ * @see uuid_id_uri_array_to_data()
*/
function uuid_id_uri_to_data($uri) {
$parts = explode('/', $uri);
@@ -90,10 +145,10 @@ function uuid_id_uri_to_data($uri) {
* Converts a URI array to entity data array.
*
* @param array $uri
- * The URI parts, often taken from arg().
+ * The URI parts, often taken from arg().
*
* @return array
- * The entity data.
+ * The entity data.
*/
function uuid_id_uri_array_to_data($uri) {
$data = array(
@@ -110,13 +165,13 @@ function uuid_id_uri_array_to_data($uri) {
/**
* Converts a UUID URI string to an entity data array.
*
- * @see uuid_uri_array_to_data()
- *
* @param string $uri
- * The URI to convert.
+ * The URI to convert.
*
* @return array
- * The entity data.
+ * The entity data.
+ *
+ * @see uuid_uri_array_to_data()
*/
function uuid_uri_to_data($uri, $strip_uuid = TRUE) {
return uuid_uri_array_to_data(explode('/', $uri));
@@ -126,10 +181,10 @@ function uuid_uri_to_data($uri, $strip_uuid = TRUE) {
* Converts a URI array to entity data array.
*
* @param array $uri
- * The URI parts, often taken from arg().
+ * The URI parts, often taken from arg().
*
* @return array
- * The entity data.
+ * The entity data.
*/
function uuid_uri_array_to_data($uri, $strip_uuid = TRUE) {
if ($strip_uuid) {
@@ -138,8 +193,8 @@ function uuid_uri_array_to_data($uri, $strip_uuid = TRUE) {
$data = array(
'request' => $uri,
- 'entity_type' => $uri[0],
- 'uuid' => $uri[1],
+ 'entity_type' => isset($uri[0]) ? $uri[0] : NULL,
+ 'uuid' => isset($uri[1]) ? $uri[1] : NULL,
);
drupal_alter('uuid_uri_data', $data);
@@ -165,40 +220,56 @@ function _uuid_generate_pecl() {
}
/**
- * Generates a UUID v4 using PHP code.
- *
- * Based on code from @see http://php.net/uniqid#65879 , but corrected.
+ * Generates a UUID v4 (RFC 4122 section 4.4) using PHP code.
+ *
+ * @see http://www.rfc-editor.org/rfc/rfc4122.txt
+ *
+ * The UUID layout and fields are defined in section 4.1.2.
+ *
+ * Note that there are inconsistencies in the RFC with respect to
+ * bit numbering. Network Order is correct, so the most significant bit
+ * always appears first (in left-to-right sequence). See errata 3546:
+ * http://www.rfc-editor.org/errata_search.php?rfc=4122&eid=3546
+ *
+ * Based on code from http://php.net/uniqid
*/
function _uuid_generate_php() {
- // The field names refer to RFC 4122 section 4.1.2.
+ // We limit each generated number to 16 bits (maximum value 0xffff)
+ // because mt_rand() returns a *signed* integer, and hence a 32-bit
+ // value can only have a 31-bit magnitude. Constructing a 32-bit
+ // number from two 16-bit random numbers guarantees that all 32 bits
+ // are random.
return sprintf('%04x%04x-%04x-4%03x-%04x-%04x%04x%04x',
// 32 bits for "time_low".
- mt_rand(0, 65535), mt_rand(0, 65535),
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid".
- mt_rand(0, 65535),
- // 12 bits after the 0100 of (version) 4 for "time_hi_and_version".
- mt_rand(0, 4095),
- bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '10', 0, 2)),
- // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
- // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
- // 8 bits for "clk_seq_low" 48 bits for "node".
- mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535)
+ mt_rand(0, 0xffff),
+ // 12 bits after the initial 0100 (version 4) for "time_hi_and_version".
+ mt_rand(0, 0x0fff),
+ // 16 bits in total for "clk_seq_hi_res" and "clk_seq_low", with the
+ // most significant 2 bits of clk_seq_hi_res set to '10'. We do a
+ // bitwise OR of a random 14-bit value (maximum 0x3fff) with 0x8000
+ // (a 16-bit integer with only the most significant bit set).
+ mt_rand(0, 0x3fff) | 0x8000,
+ // 48 bits for "node".
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
-
-// This is wrapped in an if block to avoid conflicts with PECL's uuid_is_valid().
-/**
- * Check that a string appears to be in the format of a UUID.
- *
- * @param $uuid
- * The string to test.
- *
- * @return
- * TRUE if the string is well formed.
- */
+// The if block avoids conflicts with PECL's uuid_is_valid().
if (!function_exists('uuid_is_valid')) {
+
+ /**
+ * Check that a string appears to be in the format of a UUID.
+ *
+ * @param string $uuid
+ * The string to test.
+ *
+ * @return bool
+ * TRUE if the string is well formed.
+ */
function uuid_is_valid($uuid) {
return preg_match('/^' . UUID_PATTERN . '$/', $uuid);
}
+
}
diff --git a/sites/all/modules/uuid/uuid.info b/sites/all/modules/uuid/uuid.info
index fa55812..cefaf29 100644
--- a/sites/all/modules/uuid/uuid.info
+++ b/sites/all/modules/uuid/uuid.info
@@ -4,10 +4,11 @@ core = 7.x
package = UUID
configure = admin/config/system/uuid
files[] = uuid.test
+dependencies[] = node
+dependencies[] = user
-; Information added by drupal.org packaging script on 2013-02-03
-version = "7.x-1.0-alpha3+52-dev"
+; Information added by Drupal.org packaging script on 2018-07-19
+version = "7.x-1.2"
core = "7.x"
project = "uuid"
-datestamp = "1359858369"
-
+datestamp = "1531990689"
diff --git a/sites/all/modules/uuid/uuid.install b/sites/all/modules/uuid/uuid.install
index 751f7b5..f1e0bac 100644
--- a/sites/all/modules/uuid/uuid.install
+++ b/sites/all/modules/uuid/uuid.install
@@ -29,14 +29,28 @@ function uuid_schema_field_definition() {
}
/**
- * Implements of hook_schema_alter().
+ * Implements hook_schema_alter().
*/
-function uuid_schema_alter(&$schema = array()) {
- $field = uuid_schema_field_definition();
- foreach (uuid_get_core_entity_info() as $entity_type => $info) {
- $schema[$info['base table']]['fields'][$info['entity keys']['uuid']] = $field;
- if (!empty($info['revision table']) && !empty($info['entity keys']['revision uuid'])) {
- $schema[$info['revision table']]['fields'][$info['entity keys']['revision uuid']] = $field;
+function uuid_schema_alter(array &$schema) {
+ $field_info = uuid_schema_field_definition();
+ $key_names = array(
+ 'base table' => 'uuid',
+ 'revision table' => 'revision uuid',
+ );
+
+ foreach (uuid_get_core_entity_info() as $entity_info) {
+ foreach ($key_names as $table_type => $key_name) {
+ if (isset($entity_info[$table_type], $entity_info['entity keys'][$key_name])) {
+ $field_name = $entity_info['entity keys'][$key_name];
+ $properties = array(
+ 'fields' => $field_info,
+ 'indexes' => array($field_name),
+ );
+
+ foreach ($properties as $property => $value) {
+ $schema[$entity_info[$table_type]][$property][$field_name] = $value;
+ }
+ }
}
}
}
@@ -46,19 +60,20 @@ function uuid_schema_alter(&$schema = array()) {
*/
function uuid_install() {
_uuid_install_uuid_fields();
+ module_load_include('inc', 'uuid');
uuid_sync_all();
}
/**
- * Install the 'uuid' and 'vuuid' fields into Drupal core entity tables where needed.
+ * Install the uuid and vuuid fields for Drupal core entity tables where needed.
*
- * IMPORTANT: This function is called both at install and update time. If this method
- * is modified to add additional fields in the future, the update strategy must be
- * considered. See the comment in uuid_update_7102.
+ * IMPORTANT: This function is called both at install and update time. If this
+ * method is modified to add additional fields in the future, the update
+ * strategy must be considered. See the comment in uuid_update_7102.
*/
function _uuid_install_uuid_fields() {
$field = uuid_schema_field_definition();
- foreach (uuid_get_core_entity_info() as $entity_type => $info) {
+ foreach (uuid_get_core_entity_info() as $info) {
if (!db_field_exists($info['base table'], $info['entity keys']['uuid'])) {
db_add_field($info['base table'], $info['entity keys']['uuid'], $field);
db_add_index($info['base table'], $info['entity keys']['uuid'], array($info['entity keys']['uuid']));
@@ -76,7 +91,7 @@ function _uuid_install_uuid_fields() {
* Implements hook_uninstall().
*/
function uuid_uninstall() {
- foreach (uuid_get_core_entity_info() as $entity_type => $info) {
+ foreach (uuid_get_core_entity_info() as $info) {
if (db_field_exists($info['base table'], $info['entity keys']['uuid'])) {
db_drop_field($info['base table'], $info['entity keys']['uuid']);
db_drop_index($info['base table'], $info['entity keys']['uuid']);
@@ -112,8 +127,7 @@ function uuid_update_6001() {
}
/**
- * For each of out tables, drop the indexe on the UUID column and add a unique
- * key on that column.
+ * Make all uuid columns unique keys instead of indexes.
*/
function uuid_update_6002() {
$ret = array();
@@ -138,8 +152,7 @@ function uuid_update_6003() {
}
/**
- * Fix the column definitions for uuid columns in all tables
- * to use the more efficient char spec.
+ * Change column definitions for uuid columns to more efficient char spec.
*/
function uuid_update_6004() {
$ret = array();
@@ -158,6 +171,8 @@ function uuid_update_6004() {
}
/**
+ * Support deleting node revision.
+ *
* Modify existing uuid_node_revisions table to support revision deletion, and
* add in as much legacy data as possible.
*/
@@ -204,15 +219,17 @@ function uuid_update_7100() {
}
/**
- * Clear cache for installations that used alpha1. Modules that previously was
- * enabled in uuid_update_7100() doesn't exist anymore.
+ * Clear cache for installations that used alpha1.
+ *
+ * Modules previously enabled in uuid_update_7100() don't exist any more. We
+ * need to clear the cache so Drupal detects this change.
*/
function uuid_update_7101() {
drupal_flush_all_caches();
}
/**
- * Insure that the uuid and vuuid fields are added where needed.
+ * Ensure that the uuid and vuuid fields are added where needed.
*
* Note that update 7102 calls _uuid_install_uuid_fields(), which is an
* idempotent function. If _uuid_install_uuid_fields() is changed at some
@@ -220,8 +237,8 @@ function uuid_update_7101() {
* will have run update 7102, and some will not. A new uuid_update_7103()
* function would would therefore be necessary to update all users to
* the latest schema. At the same time, uuid_update_7102() could become
- * an empty function, as it would not be necessary to call _uuid_install_uuid_fields()
- * twice.
+ * an empty function, as it would not be necessary to call
+ * _uuid_install_uuid_fields() twice.
*/
function uuid_update_7102() {
// If the user have disabled the UUID module during upgrade (as UPGRADE.txt
@@ -230,3 +247,47 @@ function uuid_update_7102() {
_uuid_install_uuid_fields();
uuid_sync_all();
}
+
+/**
+ * Clean up entities created by uuid_default_entities_example module.
+ *
+ * Modify the labels of all example entities created by the now removed
+ * uuid_default_entities_example.module to make it clear they're examples. Also
+ * remove the administrator role of any example user.
+ */
+function uuid_update_7103() {
+ // These are UUIDs of all the example entities that might exist after having
+ // installed uuid_default_entities_example.module.
+ $info = entity_get_info();
+ $uuids = array(
+ 'node' => array(
+ 'b0558664-c94b-3674-d9df-3e1696b2e471',
+ '5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837',
+ ),
+ 'user' => array(
+ '7cf875e6-dc15-4404-f190-5a7c3e91d14c',
+ ),
+ );
+ // We can't assume taxonomy is enabled.
+ if (isset($info['taxonomy_term'])) {
+ $uuids['taxonomy_term'] = array(
+ 'bcb92ce8-2236-e264-65c8-0c163ae716d1',
+ '4293a15c-531a-6164-7d1b-668ed019a6bd',
+ 'af738a46-f278-cf84-d94d-9e03879fd71e',
+ );
+ }
+ foreach (array_keys($uuids) as $entity_type) {
+ $info = entity_get_info($entity_type);
+ $entity_ids = entity_get_id_by_uuid($entity_type, $uuids[$entity_type]);
+ $entities = entity_load($entity_type, $entity_ids);
+ foreach ($entities as $entity) {
+ // Update the label to make it clear this is example content.
+ $entity->{$info['entity keys']['label']} = $entity->{$info['entity keys']['label']} . ' (UUID example)';
+ // Remove the administrator role from any user.
+ if ($entity_type == 'user' && $rid = array_search('administrator', $entity->roles)) {
+ unset($entity->roles[$rid]);
+ }
+ entity_save($entity_type, $entity);
+ }
+ }
+}
diff --git a/sites/all/modules/uuid/uuid.module b/sites/all/modules/uuid/uuid.module
index e481203..4bbe97e 100644
--- a/sites/all/modules/uuid/uuid.module
+++ b/sites/all/modules/uuid/uuid.module
@@ -25,7 +25,7 @@ module_load_include('inc', 'uuid', 'uuid.entity');
module_load_include('inc', 'uuid', 'uuid.core');
/**
- * Implements of hook_menu().
+ * Implements hook_menu().
*/
function uuid_menu() {
$items = array();
@@ -34,6 +34,7 @@ function uuid_menu() {
'title' => 'UUID redirector',
'description' => 'Redirects requests for UUID URIs to the referenced entity.',
'page callback' => 'uuid_redirector',
+ // The access check is handled in the page callback.
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -44,7 +45,6 @@ function uuid_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('uuid_admin_form'),
'access arguments' => array('administer uuid'),
- 'type' => MENU_NORMAL_ITEM,
'file' => 'uuid.admin.inc',
);
@@ -72,7 +72,7 @@ function uuid_menu() {
}
/**
- * Implements of hook_ctools_plugin_directory().
+ * Implements hook_ctools_plugin_directory().
*/
function uuid_ctools_plugin_directory($module, $plugin) {
if ($module == 'ctools') {
@@ -81,7 +81,7 @@ function uuid_ctools_plugin_directory($module, $plugin) {
}
/**
- * Implements of hook_permission().
+ * Implements hook_permission().
*/
function uuid_permission() {
return array(
@@ -123,9 +123,8 @@ function uuid_hook_info() {
return array_fill_keys($hook_names, array('group' => 'uuid'));
}
-
/**
- * Implementation of hook_views_api().
+ * Implements hook_views_api().
*/
function uuid_views_api() {
return array(
@@ -135,27 +134,27 @@ function uuid_views_api() {
}
/**
- * Implements of hook_module_implements_alter().
+ * Implements hook_module_implements_alter().
*
- * Moves implementation of hook_entity_info_alter() to the bottom so it is
+ * Moves hook_entity_info_alter() implementation to the bottom so it is
* invoked after all modules relying on the entity API.
*
* @see uuid_entity_info_alter()
*/
-function uuid_module_implements_alter(&$Implementss, $hook) {
+function uuid_module_implements_alter(&$implementss, $hook) {
if ($hook == 'entity_info_alter') {
// Move our hook Implements to the bottom.
- $group = $Implementss['uuid'];
- unset($Implementss['uuid']);
- $Implementss['uuid'] = $group;
+ $group = $implementss['uuid'];
+ unset($implementss['uuid']);
+ $implementss['uuid'] = $group;
}
}
/**
- * Implements of hook_uuid_sync().
+ * Implements hook_uuid_sync().
*/
function uuid_uuid_sync() {
- foreach (entity_get_info() as $entity_type => $info) {
+ foreach (entity_get_info() as $info) {
if (isset($info['uuid']) && $info['uuid'] == TRUE && !empty($info['entity keys']['uuid'])) {
_uuid_sync_table($info['base table'], $info['entity keys']['id'], $info['entity keys']['uuid']);
if (!empty($info['entity keys']['revision uuid'])) {
@@ -185,7 +184,7 @@ function _uuid_sync_table($table, $id_field, $uuid_field) {
}
/**
- * Implementation of hook_features_api().
+ * Implements hook_features_api().
*
* The Features support consists of exporting entities from a Deploy
* fetch-only plan. Deploy is only required to generate the feature
@@ -202,7 +201,7 @@ function uuid_features_api() {
'default_hook' => 'uuid_default_entities',
'default_file' => FEATURES_DEFAULTS_INCLUDED,
'feature_source' => TRUE,
- 'file' => drupal_get_path('module', 'uuid') .'/uuid.features.inc',
+ 'file' => drupal_get_path('module', 'uuid') . '/uuid.features.inc',
),
);
}
@@ -212,18 +211,22 @@ function uuid_features_api() {
*/
function uuid_redirector() {
$entity_data = uuid_uri_array_to_data(arg());
-
+
$entity_info = entity_get_info($entity_data['entity_type']);
if (empty($entity_info['uuid'])) {
- return drupal_not_found();
+ return MENU_NOT_FOUND;
}
$entities = entity_uuid_load($entity_data['entity_type'], array($entity_data['uuid']));
if (!count($entities)) {
- return drupal_not_found();
+ return MENU_NOT_FOUND;
}
$uri = entity_uri($entity_data['entity_type'], current($entities));
- drupal_goto($uri['path'], array(), 301);
-}
+ if (!drupal_valid_path($uri['path'])) {
+ return MENU_ACCESS_DENIED;
+ }
+
+ drupal_goto($uri['path'], $uri['options'], 301);
+}
diff --git a/sites/all/modules/uuid/uuid.test b/sites/all/modules/uuid/uuid.test
index b6407b6..6c1481a 100644
--- a/sites/all/modules/uuid/uuid.test
+++ b/sites/all/modules/uuid/uuid.test
@@ -6,20 +6,28 @@
*/
/**
- * Base class with some helper methods.
+ * UUID test helper trait.
+ *
+ * Contains methods that assist with running UUID tests.
*/
-class UUIDTestCase extends DrupalWebTestCase {
-
- function setUp() {
- parent::setUp(func_get_args());
- }
+trait UUIDTestHelper {
/**
* Helper function that asserts a UUID.
*/
- function assertUUID($uuid, $message = NULL) {
+ protected function assertUuid($uuid, $message = NULL) {
$this->assertTrue(uuid_is_valid($uuid), $message);
}
+
+}
+
+/**
+ * Base class with some helper methods.
+ */
+abstract class UUIDTestCase extends DrupalWebTestCase {
+
+ use UUIDTestHelper;
+
}
/**
@@ -27,6 +35,9 @@ class UUIDTestCase extends DrupalWebTestCase {
*/
class UUIDAPITestCase extends UUIDTestCase {
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'UUID API',
@@ -35,26 +46,128 @@ class UUIDAPITestCase extends UUIDTestCase {
);
}
- function setUp() {
- parent::setUp('uuid');
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp(array('uuid'));
}
- function testAPIFunctions() {
+ /**
+ * Tests uuid function calls.
+ */
+ public function testApiFunctions() {
// This is a valid UUID, we know that.
$valid_uuid = '0ab26e6b-f074-4e44-9da6-1205fa0e9761';
// Test the uuid_is_valid() function.
- $this->assertUUID($valid_uuid, 'UUID validation works.');
+ $this->assertUuid($valid_uuid, 'UUID validation works.');
// The default generator is 'php'.
$uuid = uuid_generate();
- $this->assertUUID($uuid, 'PHP generator works.');
+ $this->assertUuid($uuid, 'PHP generator works.');
// Test the 'mysql' generator.
variable_set('uuid_generator', 'mysql');
drupal_static_reset('uuid_generate');
$uuid = uuid_generate();
- $this->assertUUID($uuid, 'MySQL generator works.');
+ $this->assertUuid($uuid, 'MySQL generator works.');
}
+
+ /**
+ * Checks that schema for tables of core entities is correctly defined.
+ */
+ public function testSchemas() {
+ module_load_include('install', 'uuid');
+
+ $schemas = drupal_get_schema();
+ $field_info = uuid_schema_field_definition();
+ $key_names = array(
+ 'base table' => 'uuid',
+ 'revision table' => 'revision uuid',
+ );
+
+ foreach (uuid_get_core_entity_info() as $entity_info) {
+ // Test the fields in "base" and "revision" tables.
+ foreach ($key_names as $table_type => $key_name) {
+ // Table or field is not defined in entity.
+ if (!isset($entity_info[$table_type], $entity_info['entity keys'][$key_name])) {
+ // Not all entities have a revisions table.
+ continue;
+ }
+
+ $field_name = $entity_info['entity keys'][$key_name];
+ $table_name = $entity_info[$table_type];
+
+ if (!isset($schemas[$table_name])) {
+ $this->fail(sprintf('Database schema does not have a "%s" table.', $table_name));
+ continue;
+ }
+
+ $properties = array(
+ 'field' => array('fields', $field_info),
+ 'index' => array('indexes', array($field_name)),
+ );
+
+ // Check integrity of the field and index definition.
+ foreach ($properties as $type => $data) {
+ list($property, $value) = $data;
+
+ $message = sprintf('Definition of the "%s" %s in the "%s" schema', $field_name, $type, $table_name);
+
+ if (isset($schemas[$table_name][$property][$field_name])) {
+ $this->assertIdentical($schemas[$table_name][$property][$field_name], $value, "$message is correct.");
+ }
+ else {
+ $this->fail("$message does not exist.");
+ }
+ }
+ }
+ }
+ }
+
+}
+
+/**
+ * Tests the UUID API functions.
+ */
+class UUIDV5TestCase extends UUIDTestCase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => 'UUID v5',
+ 'description' => 'Tests the UUID v5 function.',
+ 'group' => 'UUID',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp(array('uuid'));
+ }
+
+ /**
+ * Tests uuid function calls.
+ */
+ public function testV5Function() {
+ // DNS namespace UUID.
+ $dns_namespace = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
+
+ // Valid DNS generation test.
+ $uuid = uuid_generate_v5($dns_namespace, 'drupal.org');
+ $this->assertUuid($uuid, 'UUID for drupal.org is valid.');
+ $this->assertEqual($uuid, 'c809fd30-48df-52e3-a9f2-2cd78129b8b1', 'UUID for drupal.org is correct.');
+
+ // Invalid namespace test.
+ $invalid_namespace = '01234567-c7a9-feda-27e5-75d00dabc123';
+ $uuid = uuid_generate_v5($invalid_namespace, 'drupal.org');
+ $this->assertFalse($uuid, 'Invalid namespace UUID rejected.');
+ }
+
}
/**
@@ -62,6 +175,9 @@ class UUIDAPITestCase extends UUIDTestCase {
*/
class UUIDEntityTestCase extends UUIDTestCase {
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'Entity API functions',
@@ -70,14 +186,17 @@ class UUIDEntityTestCase extends UUIDTestCase {
);
}
- function setUp() {
- parent::setUp('uuid');
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp(array('uuid'));
}
/**
* Tests Entity API's UUID functions.
*/
- function testEntityAPIFunctions() {
+ public function testEntityApiFunctions() {
// Create some entities that we will work with.
$user = $this->drupalCreateUser();
$node = $this->drupalCreateNode(array('title' => 'original title', 'uid' => $user->uid));
@@ -94,6 +213,7 @@ class UUIDEntityTestCase extends UUIDTestCase {
$vuuids = entity_get_uuid_by_id('node', array($node->vid), TRUE);
$this->assertTrue(in_array($node->vuuid, $vuuids), 'Lookup of entity revision UUID works.');
}
+
}
/**
@@ -101,6 +221,9 @@ class UUIDEntityTestCase extends UUIDTestCase {
*/
class UUIDUserTestCase extends UUIDTestCase {
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'User implementation',
@@ -109,22 +232,26 @@ class UUIDUserTestCase extends UUIDTestCase {
);
}
- function setUp() {
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ $modules = array('uuid');
+
// Some tests depends on the optional Entity API module.
if (module_exists('entity')) {
- parent::setUp('uuid', 'entity');
- }
- else {
- parent::setUp('uuid');
+ $modules[] = 'entity';
}
+
+ parent::setUp($modules);
}
/**
* Test CRUD on users with UUID functions.
*/
- function testUserCRUD() {
+ public function testUserCrud() {
$user = $this->drupalCreateUser();
- $this->assertUUID($user->uuid, 'User UUID was generated.');
+ $this->assertUuid($user->uuid, 'User UUID was generated.');
// Test updating user.
$user_test = clone $user;
@@ -154,6 +281,7 @@ class UUIDUserTestCase extends UUIDTestCase {
$this->assertFalse($user_test, 'Deleting user with UUID worked.');
}
}
+
}
/**
@@ -161,6 +289,9 @@ class UUIDUserTestCase extends UUIDTestCase {
*/
class UUIDNodeTestCase extends UUIDTestCase {
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'Node implementation',
@@ -169,35 +300,46 @@ class UUIDNodeTestCase extends UUIDTestCase {
);
}
- function setUp() {
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ $modules = array('uuid');
+
// Some tests depends on the optional Entity API module.
if (module_exists('entity')) {
- parent::setUp('uuid', 'entity');
- }
- else {
- parent::setUp('uuid');
+ $modules[] = 'entity';
}
+
+ parent::setUp($modules);
}
/**
* Tests CRUD on nodes with UUID functions.
+ *
+ * @todo
+ * Break out into multiple test methods to loosen coupling between tests.
*/
- function testNodeCRUD() {
+ public function testNodeCrud() {
// Create some entities that we will work with.
$user = $this->drupalCreateUser();
$node = $this->drupalCreateNode(array('title' => 'original title', 'uid' => $user->uid));
- $this->assertUUID($node->uuid, 'Node UUID was generated.');
- $this->assertUUID($node->vuuid, 'Node revision UUID was generated.');
+ $this->assertUuid($node->uuid, 'Node UUID was generated.');
+ $this->assertUuid($node->vuuid, 'Node revision UUID was generated.');
// Test node update, without creating new revision.
$node_test = clone $node;
- $node_test->title = 'new title';
+ $node_test->title = 'original title';
$node_test->revision = FALSE;
node_save($node_test);
$node_test = node_load($node->nid, FALSE, TRUE);
$this->assertEqual($node_test->uuid, $node->uuid, 'Node UUID was intact after update, when not creating new revision.');
$this->assertEqual($node_test->vuuid, $node->vuuid, 'Node revision UUID was intact after updating, when not creating new revision.');
+ // Save the original revision IDs that we will test with later.
+ $vid_old = $node_test->vid;
+ $vuuid_old = $node_test->vuuid;
+ $uuid_old = $node_test->uuid;
// Test node update, with new revision.
$node_test = clone $node;
@@ -207,13 +349,31 @@ class UUIDNodeTestCase extends UUIDTestCase {
$node_test = node_load($node->nid, FALSE, TRUE);
$this->assertEqual($node_test->uuid, $node->uuid, 'Node UUID was intact after updating, when creating new revision.');
$this->assertNotEqual($node_test->vuuid, $node->vuuid, 'A new node revision UUID was generated, when creating new revision.');
- $this->assertUUID($node_test->vuuid, 'The new node revision UUID was valid.');
+ $this->assertUuid($node_test->vuuid, 'The new node revision UUID was valid.');
// Test entity_uuid_load().
+ // Save some variables that we will test against.
+ $nid_test = $node_test->nid;
+ $vid_test = $node_test->vid;
+ $uid_test = $user->uuid;
+ $uuid_test = $node_test->uuid;
+ $vuuid_test = $node_test->vuuid;
$nodes = entity_uuid_load('node', array($node->uuid), array(), TRUE);
$node_test = reset($nodes);
- $this->assertEqual($node_test->nid, $node->nid, 'Node was correctly loaded with UUID.');
- $this->assertEqual($node_test->uid, $user->uuid, "Node property 'uid' was transformed to UUID when loaded with UUID.");
+ $this->assertEqual($node_test->nid, $nid_test, 'Node ID was correct when loading with UUID.');
+ $this->assertEqual($node_test->vid, $vid_test, 'Node revision ID was correct when loading with UUID.');
+ $this->assertEqual($node_test->uid, $uid_test, "Node author ID was transformed to UUID when loaded with UUID.");
+ $this->assertEqual($node_test->uuid, $uuid_test, 'Node UUID was correct when loading with UUID.');
+ $this->assertEqual($node_test->vuuid, $vuuid_test, 'Node revision UUID was correct when loading with UUID.');
+
+ // Test entity_uuid_load() with conditions.
+ // Load the previous revision UUID that we saved earlier.
+ $nodes = entity_uuid_load('node', array($uuid_test), array('vuuid' => $vuuid_old));
+ $node_test = reset($nodes);
+ $this->assertTrue((($node_test->uuid == $uuid_test) && ($node_test->nid && $node->nid)), 'The correct entity was loaded when loading a universal entity with a revision UUID condition.');
+ $this->assertEqual($node_test->vuuid, $vuuid_old, 'Correct revision UUID was loaded when loading a universal entity with a revision UUID condition.');
+ $this->assertEqual($node_test->vid, $vid_old, 'Correct revision ID was loaded when loading a universal entity with a revision UUID condition.');
+ $this->assertEqual($node_test->title, 'original title', 'Correct title was loaded when loading a universal entity with a revision UUID condition.');
// The following tests depends on the optional Entity API module.
if (module_exists('entity')) {
@@ -245,15 +405,79 @@ class UUIDNodeTestCase extends UUIDTestCase {
$this->assertEqual($node_test->title, 'newer title', 'Saving node with UUID mapped to correct node, when creating new revision.');
$this->assertEqual($node_test->uuid, $node->uuid, 'Node UUID was intact after saving with UUID, when creating new revision.');
$this->assertNotEqual($node_test->vuuid, $node->vuuid, 'A new node revison UUID was generated after saving with UUID, when creating new revision.');
- $this->assertUUID($node_test->vuuid, 'New node revision UUID was valid.');
+ $this->assertUuid($node_test->vuuid, 'New node revision UUID was valid.');
$this->assertEqual($node_test->uid, $node->uid, "Node property 'uid' was intact after saving with UUID, when creating new revision.");
+ // Test the same thing again, but now triggering a new revision from a
+ // remote environment.
+ // TODO: Move this test to the uuid_services module.
+ $nodes = entity_uuid_load('node', array($node->uuid), array(), TRUE);
+ $node_test = reset($nodes);
+ // Store the current local revision ID to test with later.
+ $vid_old1 = $node_test->vid;
+ // Simulate this node coming from a remote environment by generating
+ // IDs that won't match. Only the UUID match at this point.
+ $node_test->uuid_services = TRUE;
+ $vuuid_test = uuid_generate();
+ $node_test->nid = $nid_test;
+ $node_test->vid = $vid_test;
+ $node_test->vuuid = $vuuid_test;
+ $node_test->revision = TRUE;
+ entity_uuid_save('node', $node_test);
+ $node_test = node_load($node->nid, FALSE, TRUE);
+ $this->assertNotEqual($node_test->vid, $vid_old1, 'A new revision was created, when trying to create new revision with new revision UUID from remote site');
+ $this->assertEqual($node_test->vuuid, $vuuid_test, 'The revison UUID was preserved after saving with UUID, when trying to create new revision with new revision UUID from remote site.');
+
+ // Test the same thing again from a remote environment, but now with the
+ // same vuuid as once previosuly. This should not trigger a new revision.
+ // This covers the case of "dupe deployments" where a client might push a
+ // node several times.
+ // TODO: Move this test to the uuid_services module.
+ $nodes = entity_uuid_load('node', array($node->uuid), array(), TRUE);
+ $node_test = reset($nodes);
+ // Store the current local revision ID to test with later.
+ $vid_old2 = $node_test->vid;
+ // Simulate this node coming from a remote environment by generating
+ // IDs that won't match.
+ $node_test->uuid_services = TRUE;
+ $node_test->nid = $nid_test;
+ $node_test->vid = $vid_test;
+ $node_test->vuuid = $vuuid_test;
+ $node_test->revision = TRUE;
+ entity_uuid_save('node', $node_test);
+ $node_test = node_load($node->nid, FALSE, TRUE);
+ $this->assertEqual($node_test->vid, $vid_old2, 'A new revision was not created, when trying to create new revision with existing revision UUID from remote site.');
+ $this->assertEqual($node_test->vuuid, $vuuid_test, 'The revison UUID was preserved after saving with UUID, when trying to create new revision with existing revision UUID from remote site.');
+
+ // Test the same this again, but now with an old revision.
+ $nodes = entity_uuid_load('node', array($uuid_old), array('vuuid' => $vuuid_old), TRUE);
+ $node_test = reset($nodes);
+ // Simulate this node coming from a remote environment by generating
+ // IDs that won't match.
+ $node_test->uuid_services = TRUE;
+ $node_test->nid = rand();
+ $node_test->vid = rand();
+ $node_test->revision = TRUE;
+ $node_test->title = 'newest title';
+ entity_uuid_save('node', $node_test);
+ $node_test = node_load($node->nid, $vid_old, TRUE);
+ $this->assertEqual($node_test->title, 'newest title', 'The revision was updated, when updating old revision with existing revision UUID from remote site.');
+ $this->assertEqual($node_test->vuuid, $vuuid_old, 'The revison UUID was preserved after saving with UUID, when updating old revision with existing revision UUID from remote site.');
+
+ // Setting the node options variable should also trigger a new revision.
+ $nodes = entity_uuid_load('node', array($node->uuid), array(), TRUE);
+ $node_test = reset($nodes);
+ variable_set('node_options_' . $node_test->type, array('revision'));
+ entity_uuid_save('node', $node_test);
+ $this->assertNotEqual($node_test->vuuid, $node->vuuid, 'A new node revison ID was generated after saving with UUID, when relying on the node options variable.');
+
// Test entity_uuid_delete() for nodes.
entity_uuid_delete('node', $node->uuid);
$node_test = node_load($node->nid);
$this->assertFalse($node_test, 'Deleting node with UUID worked.');
}
}
+
}
/**
@@ -264,6 +488,11 @@ class UUIDNodeTestCase extends UUIDTestCase {
*/
class UUIDCommentTestCase extends CommentHelperCase {
+ use UUIDTestHelper;
+
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'Comment implementation',
@@ -272,31 +501,21 @@ class UUIDCommentTestCase extends CommentHelperCase {
);
}
- /**
- * Helper function that asserts a UUID.
- *
- * We have duplicated this function from UUIDTestCase since we have to extend
- * CommentHelperCase instead.
- */
- function assertUUID($uuid, $message = NULL) {
- $this->assertTrue(uuid_is_valid($uuid), $message);
- }
-
/**
* Test CRUD on comments with UUID functions.
*/
- function testCommentCRUD() {
+ public function testCommentCrud() {
// This is sub optimal, but due to how CommentHelperCase::setUp() is
// constructed we are enforced to do this. So unfortunately this test
// depends on 'entity' module for now.
- module_enable(array('uuid', 'entity'), TRUE);
+ module_enable(array('uuid', 'entity'));
$user = $this->drupalCreateUser();
$this->drupalLogin($user);
$node = $this->drupalCreateNode();
$return = $this->postComment($node, 'Lorem ipsum');
$comment = comment_load($return->id);
- $this->assertUUID($comment->uuid, 'Comment UUID was generated.');
+ $this->assertUuid($comment->uuid, 'Comment UUID was generated.');
// Test updating comment.
$comment_test = clone $comment;
@@ -332,6 +551,7 @@ class UUIDCommentTestCase extends CommentHelperCase {
$this->assertFalse($comment_test, 'Deleting comment with UUID worked.');
}
}
+
}
/**
@@ -339,6 +559,11 @@ class UUIDCommentTestCase extends CommentHelperCase {
*/
class UUIDTaxonomyTestCase extends TaxonomyWebTestCase {
+ use UUIDTestHelper;
+
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'Taxonomy implementation',
@@ -348,40 +573,38 @@ class UUIDTaxonomyTestCase extends TaxonomyWebTestCase {
}
/**
+ * {@inheritdoc}
+ *
* A lot of code here is taken from TaxonomyTermTestCase::setUp().
*/
- function setUp() {
+ protected function setUp() {
+ $modules = array('taxonomy', 'uuid');
+
// Some tests depends on the optional Entity API module.
if (module_exists('entity')) {
- parent::setUp('taxonomy', 'uuid', 'entity');
+ $modules[] = 'entity';
}
- else {
- parent::setUp('taxonomy', 'uuid');
- }
- }
- /**
- * Helper function that asserts a UUID.
- *
- * We have duplicated this function from UUIDTestCase since we have to extend
- * TaxonomyWebTestCase instead.
- */
- function assertUUID($uuid, $message = NULL) {
- $this->assertTrue(uuid_is_valid($uuid), $message);
+ parent::setUp($modules);
}
/**
* Test CRUD on comments with UUID functions.
*/
- function testTaxonomyCRUD() {
- $user = $this->drupalCreateUser(array('administer taxonomy', 'administer nodes', 'bypass node access'));
+ public function testTaxonomyCrud() {
+ $perms = array(
+ 'administer taxonomy',
+ 'administer nodes',
+ 'bypass node access',
+ );
+ $user = $this->drupalCreateUser($perms);
$this->drupalLogin($user);
// Create a term by tagging a node. We'll use this node later too.
- $vocabulary = new stdClass;
+ $vocabulary = new stdClass();
$vocabulary->vid = 1;
$term = $this->createTerm($vocabulary);
- $this->assertUUID($term->uuid, 'Term UUID was generated.');
+ $this->assertUuid($term->uuid, 'Term UUID was generated.');
// Test updating term.
$term_test = clone $term;
@@ -413,6 +636,7 @@ class UUIDTaxonomyTestCase extends TaxonomyWebTestCase {
$this->assertFalse($term_test, 'Deleting term with UUID worked.');
}
}
+
}
/**
@@ -420,6 +644,9 @@ class UUIDTaxonomyTestCase extends TaxonomyWebTestCase {
*/
class UUIDSyncTestCase extends UUIDTestCase {
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'UUID sync',
@@ -434,19 +661,14 @@ class UUIDSyncTestCase extends UUIDTestCase {
* @todo
* There are something weird around this assertion.
*/
- function assertTableColumn($table, $column, $message) {
- $result = db_query("SHOW COLUMNS FROM {$table}");
- $exists = FALSE;
- foreach ($result as $record) {
- if ($record->field == $column) {
- $exists = TRUE;
- break;
- }
- }
- $this->assertTrue($exists, $message);
+ protected function assertTableColumn($table, $column, $message) {
+ $this->assertTrue(db_field_exists($table, $column), $message);
}
- function testSync() {
+ /**
+ * Tests creating UUIDs for entities that don't have them.
+ */
+ public function testSync() {
// These entities will not have UUID from the start, since the UUID module
// isn't installed yet.
$user = $this->drupalCreateUser();
@@ -473,218 +695,12 @@ class UUIDSyncTestCase extends UUIDTestCase {
// Test if UUID was generated for nodes.
$node_test = node_load($node->nid, FALSE, TRUE);
- $this->assertUUID($node_test->uuid, 'Node UUID was generated when clicking the sync button.');
- $this->assertUUID($node_test->vuuid, 'Node revision UUID was generated when clicking the sync button.');
+ $this->assertUuid($node_test->uuid, 'Node UUID was generated when clicking the sync button.');
+ $this->assertUuid($node_test->vuuid, 'Node revision UUID was generated when clicking the sync button.');
// Test if UUID was generated for users.
$user_test = user_load($user->uid, TRUE);
- $this->assertUUID($user_test->uuid, 'User UUID was generated when clicking the sync button.');
- }
-}
-
-class UUIDExportEntitiesWithDeploy extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Export UUID entities',
- 'description' => 'Test exporting UUID entities with Deploy and Features.',
- 'group' => 'UUID',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy', 'uuid', 'entity', 'features', 'deploy', 'deploy_example');
- }
-
- function testExport() {
- $test_user = $this->drupalCreateUser();
- $test_node = $this->drupalCreateNode(array(
- 'uid' => $test_user->uid,
- ));
- deploy_manager_add_to_plan('deploy_example_plan', 'node', $test_node);
- // TODO: Test the actual insert.
- $this->assertTrue(TRUE, 'Added a node with a user dependency to be exported as a Feature module.');
-
- // Login and recreate the example feature. The feature isn't installed. But
- // Features can still export the code, and we can test it.
- $web_user = $this->drupalCreateUser(array('administer features'));
- $this->drupalLogin($web_user);
- $code = $this->drupalPost('admin/structure/features/uuid_default_entities_example/recreate', array(), t('Download feature'));
- $this->assertTrue($code, 'Feature module was exported.');
-
- // Ensure that we find what we expect in the exported code.
- $node_test1 = preg_match('/' . $test_node->title . '/', $code);
- $node_test2 = preg_match("/'uri' => 'node\/" . $test_node->uuid . "'/", $code);
- $this->assertTrue($node_test1, 'Node title was found in the expoted code.');
- $this->assertTrue($node_test2, 'Node URI was found in the expoted code.');
- $user_test1 = preg_match('/' . $test_user->name . '/', $code);
- $user_test2 = preg_match("/'uri' => 'user\/" . $test_user->uuid . "'/", $code);
- $this->assertTrue($user_test1, 'User was found in the expoted code.');
- $this->assertTrue($user_test2, 'User URI was found in the expoted code.');
- }
-}
-
-/**
- * Tests for the UUID synchronization.
- */
-class UUIDImportEntitiesTestCase extends UUIDTestCase {
-
- /**
- * Representation of the UUIDs that is exported in our example feature, that
- * we use for testing.
- */
- public $term1_uuid = 'bcb92ce8-2236-e264-65c8-0c163ae716d1';
- public $term2_uuid = '4293a15c-531a-6164-7d1b-668ed019a6bd';
- public $term3_uuid = 'af738a46-f278-cf84-d94d-9e03879fd71e';
- public $node1_uuid = 'b0558664-c94b-3674-d9df-3e1696b2e471';
- public $node2_uuid = '5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837';
- public $user1_uuid = '7cf875e6-dc15-4404-f190-5a7c3e91d14c';
-
- /**
- * Helper method to assert the uuid_entities component in any features.
- */
- function assertFeatureState($feature, $state, $message = '') {
- if (empty($message)) {
- switch ($state) {
- case FEATURES_DEFAULT:
- $readable_state = 'default';
- break;
- case FEATURES_OVERRIDDEN:
- $readable_state = 'overridden';
- break;
- default:
- $readable_state = 'unknown';
- break;
- }
- $message = format_string('%component in %feature had state: %state', array('%component' => 'uuid_entities', '%feature' => $feature, '%state' => $readable_state));
- }
- // Ensure that the features we used is in default state.
- $states = features_get_component_states(array($feature), TRUE, TRUE);
- if (!$this->assertEqual($states[$feature]['uuid_entities'], $state, $message)) {
- debug(format_string('Enabling functionality to show diff output for debug purposes.'));
- $success = module_enable(array('diff'));
- if ($success) {
- // Make sure we run on cold caches.
- drupal_flush_all_caches();
- drupal_static_reset();
-
- $user = $this->drupalCreateUser(array('administer features'));
- $this->drupalLogin($user);
- $this->drupalGet('admin/structure/features/' . $feature . '/diff');
- }
- else {
- debug(format_string('Download !module to see diff output for debug purposes.', array('!module' => 'diff.module')));
- }
- }
- }
-
- function getEntityByUuid($entity_type, $uuid) {
- $ids = entity_get_id_by_uuid($entity_type, array($uuid));
- $entities = entity_load($entity_type, $ids, NULL, TRUE);
- return reset($entities);
- }
-
- function enableFeature($feature) {
- $success = module_enable(array($feature), TRUE);
- $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', array($feature)))));
- // Make sure we run on cold caches.
- drupal_flush_all_caches();
- drupal_static_reset();
- }
-
- function revertFeature($feature) {
- features_revert(array($feature => array('uuid_entities')));
- $this->assertTrue(TRUE, format_string('Reverted feature: %feature', array('%feature' => $feature)));
- }
-
- function testImport() {
- $term1 = $this->getEntityByUuid('taxonomy_term', $this->term1_uuid);
- $term2 = $this->getEntityByUuid('taxonomy_term', $this->term2_uuid);
- $term3 = $this->getEntityByUuid('taxonomy_term', $this->term3_uuid);
- $node1 = $this->getEntityByUuid('node', $this->node1_uuid);
- $node2 = $this->getEntityByUuid('node', $this->node2_uuid);
- $user1 = $this->getEntityByUuid('user', $this->user1_uuid);
-
- // Ensure that we don't have our entities yet.
- $this->assertTrue(empty($term1), 'Term 1 has not been created yet.');
- $this->assertTrue(empty($term2), 'Term 2 has not been created yet.');
- $this->assertTrue(empty($term3), 'Term 3 has not been created yet.');
- $this->assertTrue(empty($node1), 'Node 1 has not been created yet.');
- $this->assertTrue(empty($node2), 'Node 2 has not been created yet.');
- $this->assertTrue(empty($user1), 'User 1 has not been created yet.');
-
- $this->enableFeature('uuid_default_entities_example');
-
- $term1 = $this->getEntityByUuid('taxonomy_term', $this->term1_uuid);
- $term2 = $this->getEntityByUuid('taxonomy_term', $this->term2_uuid);
- $term3 = $this->getEntityByUuid('taxonomy_term', $this->term3_uuid);
- $node1 = $this->getEntityByUuid('node', $this->node1_uuid);
- $node2 = $this->getEntityByUuid('node', $this->node2_uuid);
- $user1 = $this->getEntityByUuid('user', $this->user1_uuid);
-
- // Ensure that our entities was created.
- $this->assertEqual($term1->uuid, $this->term1_uuid, 'Term 1 was created.');
- $this->assertEqual($term2->uuid, $this->term2_uuid, 'Term 2 was created.');
- $this->assertEqual($term3->uuid, $this->term3_uuid, 'Term 3 was created.');
- $this->assertEqual($node1->uuid, $this->node1_uuid, 'Node 1 was created.');
- $this->assertEqual($node2->uuid, $this->node2_uuid, 'Node 2 was created.');
- $this->assertEqual($user1->uuid, $this->user1_uuid, 'User 1 was created.');
-
- // Check the features state.
- $this->assertFeatureState('uuid_default_entities_example', FEATURES_DEFAULT);
-
- // New property.
- $new = 'foo bar';
- // Change a term.
- $term1->name = $new;
- $status = taxonomy_term_save($term1);
- $this->assertEqual($status, SAVED_UPDATED, 'Updated term 1.');
- // Change a node.
- $node1->title = $new;
- node_save($node1);
- $this->assertEqual($node1->title, $new, 'Updated node 1.');
- // Change a user.
- $user1->name = $new;
- $updated_user = user_save($user1);
- $this->assertEqual($user1->name, $updated_user->name, 'Updated user 1.');
-
- // Check the features state.
- $this->assertFeatureState('uuid_default_entities_example', FEATURES_OVERRIDDEN);
-
- // Revert the feature.
- $this->revertFeature('uuid_default_entities_example');
-
- // Check the features state.
- $this->assertFeatureState('uuid_default_entities_example', FEATURES_DEFAULT);
- }
-}
-
-class UUIDImportEntitiesWithDeploy extends UUIDImportEntitiesTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Import UUID entities, with Deploy',
- 'description' => 'Test importing UUID entities with Features and Deploy.',
- 'group' => 'UUID',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy', 'uuid', 'entity', 'features', 'deploy', 'deploy_example');
- }
-}
-
-class UUIDImportEntitiesWithoutDeploy extends UUIDImportEntitiesTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Import UUID entities, without Deploy',
- 'description' => 'Test importing UUID entities with Features only.',
- 'group' => 'UUID',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy', 'uuid', 'entity', 'features');
+ $this->assertUuid($user_test->uuid, 'User UUID was generated when clicking the sync button.');
}
+
}
diff --git a/sites/all/modules/uuid/uuid.tokens.inc b/sites/all/modules/uuid/uuid.tokens.inc
index 317ac00..5b7a9d4 100644
--- a/sites/all/modules/uuid/uuid.tokens.inc
+++ b/sites/all/modules/uuid/uuid.tokens.inc
@@ -28,6 +28,20 @@ function uuid_token_info() {
return $tokens;
}
+/**
+ * Implements hook_token_info_alter().
+ */
+function uuid_token_info_alter(&$data) {
+ foreach (entity_get_info() as $entity_type => $info) {
+ if (isset($info['uuid']) && $info['uuid'] == TRUE && !empty($info['entity keys']['uuid'])) {
+ $token_type = !empty($info['token type']) ? $info['token type'] : $entity_type;
+ if (empty($data['types'][$token_type])) {
+ unset($data['tokens'][$token_type]);
+ }
+ }
+ }
+}
+
/**
* Implements hook_tokens().
*/
diff --git a/sites/all/modules/uuid/uuid.views.inc b/sites/all/modules/uuid/uuid.views.inc
index f0255a9..b81a40e 100644
--- a/sites/all/modules/uuid/uuid.views.inc
+++ b/sites/all/modules/uuid/uuid.views.inc
@@ -1,7 +1,8 @@
array(
- 'type' => 'taxonomy_term',
- 'uri' => 'taxonomy_term/bcb92ce8-2236-e264-65c8-0c163ae716d1',
- 'cause' => 'node/b0558664-c94b-3674-d9df-3e1696b2e471',
- ),
- 'description' => NULL,
- 'format' => NULL,
- 'name' => 'Foo',
- 'path' => array(
- 'alias' => 'term/foo',
- ),
- 'rdf_mapping' => array(
- 'rdftype' => array(
- 0 => 'skos:Concept',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'rdfs:label',
- 1 => 'skos:prefLabel',
- ),
- ),
- 'description' => array(
- 'predicates' => array(
- 0 => 'skos:definition',
- ),
- ),
- 'vid' => array(
- 'predicates' => array(
- 0 => 'skos:inScheme',
- ),
- 'type' => 'rel',
- ),
- 'parent' => array(
- 'predicates' => array(
- 0 => 'skos:broader',
- ),
- 'type' => 'rel',
- ),
- ),
- 'uuid' => 'bcb92ce8-2236-e264-65c8-0c163ae716d1',
- 'vocabulary_machine_name' => 'tags',
- 'weight' => '0',
- );
- $entities['deploy_example_plan'][] = (object) array(
- '__metadata' => array(
- 'type' => 'taxonomy_term',
- 'uri' => 'taxonomy_term/4293a15c-531a-6164-7d1b-668ed019a6bd',
- 'cause' => 'node/b0558664-c94b-3674-d9df-3e1696b2e471',
- ),
- 'description' => NULL,
- 'format' => NULL,
- 'name' => 'Bar',
- 'rdf_mapping' => array(
- 'rdftype' => array(
- 0 => 'skos:Concept',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'rdfs:label',
- 1 => 'skos:prefLabel',
- ),
- ),
- 'description' => array(
- 'predicates' => array(
- 0 => 'skos:definition',
- ),
- ),
- 'vid' => array(
- 'predicates' => array(
- 0 => 'skos:inScheme',
- ),
- 'type' => 'rel',
- ),
- 'parent' => array(
- 'predicates' => array(
- 0 => 'skos:broader',
- ),
- 'type' => 'rel',
- ),
- ),
- 'uuid' => '4293a15c-531a-6164-7d1b-668ed019a6bd',
- 'vocabulary_machine_name' => 'tags',
- 'weight' => '0',
- );
- $entities['deploy_example_plan'][] = (object) array(
- '__metadata' => array(
- 'type' => 'node',
- 'uri' => 'node/b0558664-c94b-3674-d9df-3e1696b2e471',
- 'cause' => FALSE,
- ),
- 'body' => array(
- 'und' => array(
- 0 => array(
- 'format' => 'filtered_html',
- 'summary' => '',
- 'value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
- ),
- ),
- ),
- 'cid' => '0',
- 'comment' => '2',
- 'comment_count' => '0',
- 'field_image' => array(),
- 'field_tags' => array(
- 'und' => array(
- 0 => array(
- 'tid' => 'bcb92ce8-2236-e264-65c8-0c163ae716d1',
- ),
- 1 => array(
- 'tid' => '4293a15c-531a-6164-7d1b-668ed019a6bd',
- ),
- ),
- ),
- 'language' => 'und',
- 'last_comment_name' => NULL,
- 'last_comment_uid' => '1',
- 'log' => '',
- 'path' => array(
- 'alias' => 'lorem-ipsum',
- ),
- 'promote' => '1',
- 'rdf_mapping' => array(
- 'field_image' => array(
- 'predicates' => array(
- 0 => 'og:image',
- 1 => 'rdfs:seeAlso',
- ),
- 'type' => 'rel',
- ),
- 'field_tags' => array(
- 'predicates' => array(
- 0 => 'dc:subject',
- ),
- 'type' => 'rel',
- ),
- 'rdftype' => array(
- 0 => 'sioc:Item',
- 1 => 'foaf:Document',
- ),
- 'title' => array(
- 'predicates' => array(
- 0 => 'dc:title',
- ),
- ),
- 'created' => array(
- 'predicates' => array(
- 0 => 'dc:date',
- 1 => 'dc:created',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- 'changed' => array(
- 'predicates' => array(
- 0 => 'dc:modified',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- 'body' => array(
- 'predicates' => array(
- 0 => 'content:encoded',
- ),
- ),
- 'uid' => array(
- 'predicates' => array(
- 0 => 'sioc:has_creator',
- ),
- 'type' => 'rel',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'foaf:name',
- ),
- ),
- 'comment_count' => array(
- 'predicates' => array(
- 0 => 'sioc:num_replies',
- ),
- 'datatype' => 'xsd:integer',
- ),
- 'last_activity' => array(
- 'predicates' => array(
- 0 => 'sioc:last_activity_date',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- ),
- 'status' => '1',
- 'sticky' => '0',
- 'title' => 'Lorem ipsum',
- 'tnid' => '0',
- 'translate' => '0',
- 'type' => 'article',
- 'uid' => '1',
- 'uuid' => 'b0558664-c94b-3674-d9df-3e1696b2e471',
- );
- $entities['deploy_example_plan'][] = (object) array(
- '__metadata' => array(
- 'type' => 'taxonomy_term',
- 'uri' => 'taxonomy_term/af738a46-f278-cf84-d94d-9e03879fd71e',
- 'cause' => 'node/5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837',
- ),
- 'description' => NULL,
- 'format' => NULL,
- 'name' => 'Baz',
- 'rdf_mapping' => array(
- 'rdftype' => array(
- 0 => 'skos:Concept',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'rdfs:label',
- 1 => 'skos:prefLabel',
- ),
- ),
- 'description' => array(
- 'predicates' => array(
- 0 => 'skos:definition',
- ),
- ),
- 'vid' => array(
- 'predicates' => array(
- 0 => 'skos:inScheme',
- ),
- 'type' => 'rel',
- ),
- 'parent' => array(
- 'predicates' => array(
- 0 => 'skos:broader',
- ),
- 'type' => 'rel',
- ),
- ),
- 'uuid' => 'af738a46-f278-cf84-d94d-9e03879fd71e',
- 'vocabulary_machine_name' => 'tags',
- 'weight' => '0',
- );
- $entities['deploy_example_plan'][] = (object) array(
- '__metadata' => array(
- 'type' => 'user',
- 'uri' => 'user/7cf875e6-dc15-4404-f190-5a7c3e91d14c',
- 'cause' => 'node/5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837',
- ),
- 'init' => 'no@example.com',
- 'language' => '',
- 'mail' => 'no@example.com',
- 'name' => 'mohamed',
- 'pass' => '$S$DtyVr4YQkvCpofZdLT4.L23Xb6E8HUkmEgZikN919RTZXZSePwso',
- 'picture' => NULL,
- 'rdf_mapping' => array(
- 'rdftype' => array(
- 0 => 'sioc:UserAccount',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'foaf:name',
- ),
- ),
- 'homepage' => array(
- 'predicates' => array(
- 0 => 'foaf:page',
- ),
- 'type' => 'rel',
- ),
- ),
- 'roles' => array(
- 2 => 'authenticated user',
- 3 => 'administrator',
- ),
- 'signature' => '',
- 'signature_format' => 'filtered_html',
- 'status' => '1',
- 'theme' => '',
- 'timezone' => 'Asia/Riyadh',
- 'uuid' => '7cf875e6-dc15-4404-f190-5a7c3e91d14c',
- );
- $entities['deploy_example_plan'][] = (object) array(
- '__metadata' => array(
- 'type' => 'node',
- 'uri' => 'node/5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837',
- 'cause' => FALSE,
- ),
- 'body' => array(
- 'und' => array(
- 0 => array(
- 'format' => 'filtered_html',
- 'summary' => '',
- 'value' => 'Nunc sollicitudin justo ut augue egestas et varius quam consectetur.',
- ),
- ),
- ),
- 'cid' => '0',
- 'comment' => '2',
- 'comment_count' => '0',
- 'field_image' => array(),
- 'field_tags' => array(
- 'und' => array(
- 0 => array(
- 'tid' => 'af738a46-f278-cf84-d94d-9e03879fd71e',
- ),
- ),
- ),
- 'language' => 'und',
- 'last_comment_name' => NULL,
- 'last_comment_uid' => '7cf875e6-dc15-4404-f190-5a7c3e91d14c',
- 'log' => '',
- 'promote' => '1',
- 'rdf_mapping' => array(
- 'field_image' => array(
- 'predicates' => array(
- 0 => 'og:image',
- 1 => 'rdfs:seeAlso',
- ),
- 'type' => 'rel',
- ),
- 'field_tags' => array(
- 'predicates' => array(
- 0 => 'dc:subject',
- ),
- 'type' => 'rel',
- ),
- 'rdftype' => array(
- 0 => 'sioc:Item',
- 1 => 'foaf:Document',
- ),
- 'title' => array(
- 'predicates' => array(
- 0 => 'dc:title',
- ),
- ),
- 'created' => array(
- 'predicates' => array(
- 0 => 'dc:date',
- 1 => 'dc:created',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- 'changed' => array(
- 'predicates' => array(
- 0 => 'dc:modified',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- 'body' => array(
- 'predicates' => array(
- 0 => 'content:encoded',
- ),
- ),
- 'uid' => array(
- 'predicates' => array(
- 0 => 'sioc:has_creator',
- ),
- 'type' => 'rel',
- ),
- 'name' => array(
- 'predicates' => array(
- 0 => 'foaf:name',
- ),
- ),
- 'comment_count' => array(
- 'predicates' => array(
- 0 => 'sioc:num_replies',
- ),
- 'datatype' => 'xsd:integer',
- ),
- 'last_activity' => array(
- 'predicates' => array(
- 0 => 'sioc:last_activity_date',
- ),
- 'datatype' => 'xsd:dateTime',
- 'callback' => 'date_iso8601',
- ),
- ),
- 'status' => '1',
- 'sticky' => '0',
- 'title' => 'Nunc sollicitudin',
- 'tnid' => '0',
- 'translate' => '0',
- 'type' => 'article',
- 'uid' => '7cf875e6-dc15-4404-f190-5a7c3e91d14c',
- 'uuid' => '5e3d8bbe-a1f2-f2d4-fdc0-71e6c23aa837',
- );
-
- return $entities;
-}
diff --git a/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.info b/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.info
deleted file mode 100644
index b7abb3b..0000000
--- a/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.info
+++ /dev/null
@@ -1,15 +0,0 @@
-core = "7.x"
-dependencies[] = "entity"
-dependencies[] = "features"
-dependencies[] = "uuid"
-description = "Example feature mainly used for testing."
-features[uuid_entities][] = "deploy_example_plan"
-name = "UUID default entities example"
-package = "Features"
-
-; Information added by drupal.org packaging script on 2013-02-03
-version = "7.x-1.0-alpha3+52-dev"
-core = "7.x"
-project = "uuid"
-datestamp = "1359858369"
-
diff --git a/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.module b/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.module
deleted file mode 100644
index 8b958b0..0000000
--- a/sites/all/modules/uuid/uuid_default_entities_example/uuid_default_entities_example.module
+++ /dev/null
@@ -1,6 +0,0 @@
-pid);
unset($alias->source);
}
@@ -50,7 +50,7 @@ function _uuid_path_load_url_aliases(&$entities, $entity_type) {
function _uuid_path_save_url_aliases(&$entity, $entity_type) {
$info = entity_get_info($entity_type);
- // We only care when there is a url callback
+ // We only care when there is a url callback.
if (!isset($info['uri callback'])) {
return FALSE;
}
@@ -63,7 +63,7 @@ function _uuid_path_save_url_aliases(&$entity, $entity_type) {
path_delete(array('source' => $path));
// Continue if aliases are present.
- if(empty($entity->url_alias)) {
+ if (empty($entity->url_alias)) {
return FALSE;
}
@@ -77,10 +77,10 @@ function _uuid_path_save_url_aliases(&$entity, $entity_type) {
/**
* Loads all aliases associated with a path.
*
- * @param $path
+ * @param string $path
* The source path to look up.
*
- * @return
+ * @return array
* Array of paths or NULL if none found.
*/
function _uuid_path_url_alias_load($path) {
@@ -90,4 +90,3 @@ function _uuid_path_url_alias_load($path) {
->execute()
->fetchAll(PDO::FETCH_OBJ);
}
-
diff --git a/sites/all/modules/uuid/uuid_services/resources/field_collection.resource.inc b/sites/all/modules/uuid/uuid_services/resources/field_collection.resource.inc
deleted file mode 100644
index 74392c5..0000000
--- a/sites/all/modules/uuid/uuid_services/resources/field_collection.resource.inc
+++ /dev/null
@@ -1,12 +0,0 @@
- array());
- }
- else {
- return array();
- }
-}
diff --git a/sites/all/modules/uuid/uuid_services/uuid_services.admin.inc b/sites/all/modules/uuid/uuid_services/uuid_services.admin.inc
new file mode 100644
index 0000000..28e447c
--- /dev/null
+++ b/sites/all/modules/uuid/uuid_services/uuid_services.admin.inc
@@ -0,0 +1,30 @@
+ 'checkbox',
+ '#title' => t('Support all UUID entity types'),
+ '#description' => t('Check this box to automatically provide Services integration for all entity types with UUID support.'),
+ '#default_value' => variable_get('uuid_services_support_all_entity_types', FALSE),
+ );
+ $form['uuid_services_allowed_media_mimes'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Allowed Media Mime type'),
+ '#default_value' => variable_get('uuid_services_allowed_media_mimes', UUID_SERVICES_DEFAULT_ALLOWED_MEDIA_MIMES),
+ '#cols' => 40,
+ '#rows' => 5,
+ '#description' => t("Enter one mime type per line you wish to allow in the system without extension. Example mime type 'video/brightcove'."),
+ );
+ return system_settings_form($form);
+}
diff --git a/sites/all/modules/uuid/uuid_services/uuid_services.file_services.test b/sites/all/modules/uuid/uuid_services/uuid_services.file_services.test
new file mode 100644
index 0000000..23b2f75
--- /dev/null
+++ b/sites/all/modules/uuid/uuid_services/uuid_services.file_services.test
@@ -0,0 +1,150 @@
+ 'UUID File Services tests',
+ 'description' => 'Test the file services resource UUID methods and actions.',
+ 'group' => 'UUID',
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ public function setUp() {
+ parent::setUp(
+ 'ctools',
+ 'services',
+ 'rest_server',
+ 'uuid_services',
+ 'entity',
+ 'file',
+ 'field',
+ 'file_entity'
+ );
+ $this->endpoint = $this->saveNewEndpoint();
+
+ variable_set('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp mp3 mov mp4 m4a m4v mpeg avi ogg oga ogv weba webp webm');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function saveNewEndpoint() {
+ $edit = $this->populateEndpointFAPI();
+ $endpoint = new stdClass();
+ $endpoint->disabled = FALSE;
+ $endpoint->api_version = 3;
+ $endpoint->name = $edit['name'];
+ $endpoint->server = $edit['server'];
+ $endpoint->path = $edit['path'];
+ $endpoint->authentication = array(
+ 'services' => 'services',
+ );
+ $endpoint->server_settings = array(
+ 'formatters' => array(
+ 'json' => TRUE,
+ 'bencode' => TRUE,
+ 'rss' => TRUE,
+ 'plist' => TRUE,
+ 'xmlplist' => TRUE,
+ 'php' => TRUE,
+ 'yaml' => TRUE,
+ 'jsonp' => FALSE,
+ 'xml' => FALSE,
+ ),
+ 'parsers' => array(
+ 'application/x-yaml' => TRUE,
+ 'application/json' => TRUE,
+ 'application/vnd.php.serialized' => TRUE,
+ 'application/plist' => TRUE,
+ 'application/plist+xml' => TRUE,
+ 'application/x-www-form-urlencoded' => TRUE,
+ 'multipart/form-data' => TRUE,
+ ),
+ );
+ $endpoint->resources = array(
+ 'file' => array(
+ 'operations' => array(
+ 'retrieve' => array(
+ 'enabled' => '1',
+ ),
+ 'delete' => array(
+ 'enabled' => '1',
+ ),
+ 'index' => array(
+ 'enabled' => '1',
+ ),
+ 'update' => array(
+ 'enabled' => '1',
+ ),
+ ),
+ 'actions' => array(
+ 'create_raw' => array(
+ 'enabled' => '1',
+ ),
+ ),
+ ),
+ );
+ $endpoint->debug = 1;
+ $endpoint->export_type = FALSE;
+ services_endpoint_save($endpoint);
+ $endpoint = services_endpoint_load($endpoint->name);
+ $this->assertTrue($endpoint->name == $edit['name'], 'Endpoint successfully created');
+ return $endpoint;
+ }
+
+ /**
+ * Tests file creation.
+ */
+ public function testFileUpdate() {
+ $this->privilegedUser = $this->drupalCreateUser(array('create files'));
+ $this->drupalLogin($this->privilegedUser);
+
+ // Get a test file.
+ $testfiles = $this->drupalGetTestFiles('php');
+ $testfile = current($testfiles);
+
+ // Setup file to be created.
+ $filepath = file_default_scheme() . '://' . rand() . '/' . rand() . '/' . $testfile->filename;
+ $file_data = array(
+ 'uid' => '0',
+ 'filesize' => filesize($testfile->uri),
+ 'filename' => $testfile->filename,
+ 'filepath' => $filepath,
+ 'file' => base64_encode(file_get_contents($testfile->uri)),
+ 'uuid' => 'ee26fe5d-f781-4a38-bfe0-8bb350b90073',
+ 'type' => 'image',
+ 'filemime' => 'text/plain',
+ 'uri' => $testfile->uri,
+ );
+
+ $response = $this->servicesPut($this->endpoint->path . '/file/create', $file_data);
+
+ // Get the saved file's extension.
+ $file = file_load($response['body']->fid);
+ $name = explode('.', $file->filename);
+ $last = array_pop($name);
+ $extension = strtolower($last);
+
+ $this->assertNotEqual('php', $extension, 'File was not created with a "php" extension.', 'UUID: File Create');
+ }
+
+}
diff --git a/sites/all/modules/uuid/uuid_services/uuid_services.info b/sites/all/modules/uuid/uuid_services/uuid_services.info
index 700080b..dd1ae42 100644
--- a/sites/all/modules/uuid/uuid_services/uuid_services.info
+++ b/sites/all/modules/uuid/uuid_services/uuid_services.info
@@ -7,9 +7,14 @@ dependencies[] = services
dependencies[] = uuid
dependencies[] = entity
-; Information added by drupal.org packaging script on 2013-02-03
-version = "7.x-1.0-alpha3+52-dev"
+test_dependencies[] = services
+test_dependencies[] = entity
+test_dependencies[] = file
+test_dependencies[] = field
+test_dependencies[] = file_entity
+
+; Information added by Drupal.org packaging script on 2018-07-19
+version = "7.x-1.2"
core = "7.x"
project = "uuid"
-datestamp = "1359858369"
-
+datestamp = "1531990689"
diff --git a/sites/all/modules/uuid/uuid_services/uuid_services.install b/sites/all/modules/uuid/uuid_services/uuid_services.install
new file mode 100644
index 0000000..1dfeb6c
--- /dev/null
+++ b/sites/all/modules/uuid/uuid_services/uuid_services.install
@@ -0,0 +1,14 @@
+ 'UUID Services',
+ 'description' => 'Configure settings for UUID Services.',
+ 'access arguments' => array('administer services'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('uuid_services_settings'),
+ 'file' => 'uuid_services.admin.inc',
+ );
+ return $items;
+}
+
/**
* Implements hook_services_resources_alter().
*
@@ -14,7 +42,7 @@
*/
function uuid_services_services_resources_alter(&$resources, &$endpoint) {
foreach (entity_get_info() as $entity_type => $entity_info) {
- if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE && isset($resources[$entity_type])) {
+ if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE && (isset($resources[$entity_type]) || variable_get('uuid_services_support_all_entity_types', FALSE))) {
unset($resources[$entity_type]['operations']['create']);
// Alter 'retrieve' method to use UUID enabled functions and arguments.
@@ -126,6 +154,22 @@ function _uuid_services_entity_update($entity_type, $uuid, $entity) {
else {
$entity = (object) $entity;
}
+ $entity->uuid_services = TRUE;
+ // Check that the mime type is whitelisted.
+ $valid_media_mimes = variable_get('uuid_services_allowed_media_mimes', UUID_SERVICES_DEFAULT_ALLOWED_MEDIA_MIMES);
+
+ // Sanitize file user input.
+ if ($entity_type == 'file') {
+ // We have to make sure to whitelist mime types, to avoid the video files
+ // getting converted into text files, when deployed from one env to other.
+ if (!in_array($entity->filemime, preg_split('/\r?\n/', $valid_media_mimes))) {
+ $entity->filename = _services_file_check_name_extension($entity->filename);
+ $entity->uri = _services_file_check_destination_uri($entity->uri);
+ if (!empty($entity->filepath)) {
+ $entity->filepath = _services_file_check_destination($entity->filepath);
+ }
+ }
+ }
entity_uuid_save($entity_type, $entity);
return $entity;
}
@@ -142,7 +186,15 @@ function _uuid_services_entity_update($entity_type, $uuid, $entity) {
*/
function _uuid_services_entity_delete($entity_type, $uuid) {
try {
- $return = entity_uuid_delete($entity_type, array($uuid));
+ $uuid_exist = (bool) entity_get_id_by_uuid($entity_type, array($uuid));
+ if (!$uuid_exist) {
+ /* UUID not found. Don't try to delete something that doesn't exist. */
+ $args = array('@uuid' => $uuid, '@type' => $entity_type);
+ watchdog('uuid_services', 'UUID @uuid not found for entity type @type', $args, WATCHDOG_WARNING);
+ return TRUE;
+ }
+
+ $return = entity_uuid_delete($entity_type, array($uuid)) !== FALSE;
return $return;
}
catch (Exception $exception) {
@@ -154,14 +206,14 @@ function _uuid_services_entity_delete($entity_type, $uuid) {
/**
* Access callback.
*
- * @param $op
+ * @param string $op
* The operation we are trying to do on the entity. Can only be:
* - "view"
* - "update"
* - "delete"
* See 'uuid_services_services_resources_alter()' for an explanation why
* 'create' is missing.
- * @param $args
+ * @param array $args
* The arguments passed to the method. The keys are holding the following:
* 0.
' . t('Recommended value: %value.', array('%value' => t('1 day'))),
'#default_value' => variable_get('xmlsitemap_minimum_lifetime', 0),
);
@@ -288,16 +322,19 @@ function xmlsitemap_settings_form($form, &$form_state) {
'#collapsed' => !variable_get('xmlsitemap_developer_mode', 0),
'#weight' => 10,
);
- //$form['advanced']['xmlsitemap_gz'] = array(
- // '#type' => 'checkbox',
- // '#title' => t('Generate additional compressed sitemaps using gzip.'),
- // '#default_value' => xmlsitemap_var('gz'),
- // '#disabled' => !function_exists('gzencode'),
- //);
$form['advanced']['xmlsitemap_chunk_size'] = array(
'#type' => 'select',
'#title' => t('Number of links in each sitemap page'),
- '#options' => array('auto' => t('Automatic (recommended)')) + drupal_map_assoc(array(100, 500, 1000, 2500, 5000, 10000, 25000, XMLSITEMAP_MAX_SITEMAP_LINKS)),
+ '#options' => array('auto' => t('Automatic (recommended)')) + drupal_map_assoc(array(
+ 100,
+ 500,
+ 1000,
+ 2500,
+ 5000,
+ 10000,
+ 25000,
+ XMLSITEMAP_MAX_SITEMAP_LINKS,
+ )),
'#default_value' => xmlsitemap_var('chunk_size'),
// @todo This description is not clear.
'#description' => t('If there are problems with rebuilding the sitemap, you may want to manually set this value. If you have more than @max links, an index with multiple sitemap pages will be generated. There is a maximum of @max sitemap pages.', array('@max' => XMLSITEMAP_MAX_SITEMAP_LINKS)),
@@ -305,7 +342,18 @@ function xmlsitemap_settings_form($form, &$form_state) {
$form['advanced']['xmlsitemap_batch_limit'] = array(
'#type' => 'select',
'#title' => t('Maximum number of sitemap links to process at once'),
- '#options' => drupal_map_assoc(array(5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000)),
+ '#options' => drupal_map_assoc(array(
+ 5,
+ 10,
+ 25,
+ 50,
+ 100,
+ 250,
+ 500,
+ 1000,
+ 2500,
+ 5000,
+ )),
'#default_value' => xmlsitemap_var('batch_limit'),
'#description' => t('If you have problems running cron or rebuilding the sitemap, you may want to lower this value.'),
);
@@ -325,7 +373,7 @@ function xmlsitemap_settings_form($form, &$form_state) {
$form['advanced']['xmlsitemap_base_url'] = array(
'#type' => 'textfield',
'#title' => t('Default base URL'),
- '#default_value' => variable_get('xmlsitemap_base_url', $GLOBALS['base_url']),
+ '#default_value' => variable_get('xmlsitemap_base_url', $base_url),
'#size' => 30,
'#description' => t('This is the default base URL used for sitemaps and sitemap links.'),
'#required' => TRUE,
@@ -362,7 +410,11 @@ function xmlsitemap_settings_form($form, &$form_state) {
'changefreq' => t('Change frequency: @changfreq', array('@changfreq' => '
' . t('In order to verify site ownership with the search engines listed below, it is highly recommended to download and install the Site verification module.', array('@site-verify' => 'https://www.drupal.org/project/site_verify')) . '
'; } break; } @@ -41,12 +46,13 @@ function xmlsitemap_engines_menu() { 'type' => MENU_LOCAL_TASK, 'file' => 'xmlsitemap_engines.admin.inc', ); - //$items['admin/config/search/xmlsitemap/engines/submit'] = array( - // 'page callback' => 'xmlsitemap_engines_submit', - // 'access callback' => 'xmlsitemap_engines_submit_access', - // 'type' => MENU_CALLBACK, - //); - + // @code + // $items['admin/config/search/xmlsitemap/engines/submit'] = array( + // 'page callback' => 'xmlsitemap_engines_submit', + // 'access callback' => 'xmlsitemap_engines_submit_access', + // 'type' => MENU_CALLBACK, + // ); + // @endcode return $items; } @@ -59,6 +65,9 @@ function xmlsitemap_engines_cron() { } } +/** + * Check if can submit. + */ function xmlsitemap_engines_can_submit() { // Skip if the site is offline since search engines will not be able to // access the site's content. @@ -73,16 +82,21 @@ function xmlsitemap_engines_can_submit() { return TRUE; } +/** + * Submit access. + */ function xmlsitemap_engines_submit_access() { if (!xmlsitemap_engines_can_submit()) { return FALSE; } // Allow manual submissions to run. - //if ($_GET['q'] == 'admin/config/search/xmlsitemap/engines/submit' && user_access('administer xmlsitemap')) { - // return TRUE; - //} - + // @code + // @codingStandardsIgnoreLine + // if ($_GET['q'] == 'admin/config/search/xmlsitemap/engines/submit' && user_access('administer xmlsitemap')) { + // return TRUE; + // } + // @endcode $submit_updated = variable_get('xmlsitemap_engines_submit_updated', TRUE); $submitted_last = variable_get('xmlsitemap_engines_submit_last', 0); $minimum_lifetime = variable_get('xmlsitemap_engines_minimum_lifetime', 86400); @@ -103,7 +117,7 @@ function xmlsitemap_engines_submit_access() { /** * Submit the sitemaps to all the specified search engines. * - * @param $smids + * @param array $smids * An optional array of XML sitemap IDs. If not provided, it will load all * existing XML sitemaps. */ @@ -134,9 +148,9 @@ function xmlsitemap_engines_submit_engines(array $smids = array()) { /** * Submit the sitemaps to a specific URL. * - * @param $url + * @param string $url * The URL for sitemap submission. - * @param $sitemaps + * @param array $sitemaps * An array of URLs of the sitemaps to submit. */ function xmlsitemap_engines_submit_sitemaps($url, array $sitemaps) { @@ -151,9 +165,10 @@ function xmlsitemap_engines_submit_sitemaps($url, array $sitemaps) { /** * Replace valid tokens in the URL with their appropriate values. * - * @param $url + * @param string $url * An un-tokenized URL. - * @return + * + * @return string * A tokenized URL. */ function xmlsitemap_engines_prepare_url($url, $sitemap) { @@ -163,12 +178,9 @@ function xmlsitemap_engines_prepare_url($url, $sitemap) { /** * Returns information about supported search engines. * - * @param $engine + * @param string $engine * (optional) The engine to return information for. If omitted, information * for all engines is returned. - * @param $reset - * (optional) Boolean whether to reset the static cache and do nothing. Only - * used for tests. * * @see hook_xmlsitemap_engines_info() * @see hook_xmlsitemap_engines_info_alter() @@ -205,13 +217,13 @@ function xmlsitemap_engines_get_engine_info($engine = NULL) { function xmlsitemap_engines_xmlsitemap_engine_info() { $engines['google'] = array( 'name' => t('Google'), - 'url' => 'http://www.google.com/webmasters/tools/ping?sitemap=[sitemap]', - 'help url' => 'http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156184', + 'url' => 'https://www.google.com/webmasters/tools/ping?sitemap=[sitemap]', + 'help url' => 'https://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156184', ); $engines['bing'] = array( 'name' => t('Bing'), - 'url' => 'http://www.bing.com/webmaster/ping.aspx?siteMap=[sitemap]', - 'help url' => 'http://www.bing.com/webmaster', + 'url' => 'https://www.bing.com/webmaster/ping.aspx?siteMap=[sitemap]', + 'help url' => 'https://www.bing.com/webmaster', ); return $engines; } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.info b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.info index c3f79af..da3fe3f 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.info @@ -4,12 +4,10 @@ package = XML sitemap core = 7.x dependencies[] = xmlsitemap dependencies[] = i18n -files[] = xmlsitemap_i18n.module files[] = xmlsitemap_i18n.test -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.module b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.module index c02163f..3908ba3 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.module @@ -1,5 +1,10 @@ condition('x.language', array($current, LANGUAGE_NONE)); break; + case 'mixed': - // Mixed current language (if available) or default language (if not) and language neutral. + // Mixed current language (if available) or default language (if not) and + // language neutral. $query->condition('x.language', array($current, $default, LANGUAGE_NONE)); break; + case 'default': // Only default language and language neutral. $query->condition('x.language', array($default, LANGUAGE_NONE)); break; + case 'strict': // Only current language (for nodes), simple for all other types. $node_condition = db_and(); @@ -109,6 +118,7 @@ function xmlsitemap_i18n_query_xmlsitemap_generate_alter(QueryAlterableInterface $condition->condition($normal_condition); $query->condition($condition); break; + case 'off': // All content. No language conditions apply. break; diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.test b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.test index d34b388..9467d0f 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.test +++ b/sites/all/modules/xmlsitemap/xmlsitemap_i18n/xmlsitemap_i18n.test @@ -2,19 +2,29 @@ /** * @file - * Unit tests for the xmlsitemap_i18n module. + * Unit tests for the xmlsitemap_i18n project. */ /** * Common base test class for XML sitemap internationalization tests. */ class XMLSitemapI18nWebTestCase extends XMLSitemapTestHelper { + + /** + * Admin User. + * + * @var string + * + * @codingStandardsIgnoreStart + */ protected $admin_user; /** * Set up an administrative user account and testing keys. + * + * @codingStandardsIgnoreEnd */ - function setUp($modules = array()) { + public function setUp($modules = array()) { // Call parent::setUp() allowing test cases to pass further modules. $modules[] = 'locale'; $modules[] = 'translation'; @@ -29,7 +39,8 @@ class XMLSitemapI18nWebTestCase extends XMLSitemapTestHelper { variable_set('language_negotiation', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX); // Create the two different language-context sitemaps. - db_query("DELETE FROM {xmlsitemap_sitemap}"); + db_delete('xmlsitemap_sitemap')->execute(); + $sitemap = new stdClass(); $sitemap->context = array('language' => 'en'); xmlsitemap_sitemap_save($sitemap); @@ -37,9 +48,17 @@ class XMLSitemapI18nWebTestCase extends XMLSitemapTestHelper { $sitemap->context = array('language' => 'fr'); xmlsitemap_sitemap_save($sitemap); } + } +/** + * I18n Test. + */ class XMLSitemapI18nTest extends XMLSitemapI18nWebTestCase { + + /** + * Get Info. + */ public static function getInfo() { return array( 'name' => 'XML sitemap i18n tests', @@ -49,7 +68,10 @@ class XMLSitemapI18nTest extends XMLSitemapI18nWebTestCase { ); } - function testLanguageSelection() { + /** + * Language Selection. + */ + public function testLanguageSelection() { // Create our three different language nodes. $node = $this->addSitemapLink(array('type' => 'node', 'language' => LANGUAGE_NONE)); $node_en = $this->addSitemapLink(array('type' => 'node', 'language' => 'en')); @@ -104,9 +126,17 @@ class XMLSitemapI18nTest extends XMLSitemapI18nWebTestCase { $this->assertRawSitemapLinks($node_fr, $link, $link_fr); $this->assertNoRawSitemapLinks($node, $node_en, $link_en); } + } +/** + * Node Test. + */ class XMLSitemapI18nNodeTest extends XMLSitemapI18nWebTestCase { + + /** + * Get Info. + */ public static function getInfo() { return array( 'name' => 'XML sitemap i18n node tests', @@ -116,7 +146,10 @@ class XMLSitemapI18nNodeTest extends XMLSitemapI18nWebTestCase { ); } - function setUp($modules = array()) { + /** + * Setup. + */ + public function setUp($modules = array()) { $modules[] = 'xmlsitemap_node'; parent::setUp($modules); @@ -125,7 +158,10 @@ class XMLSitemapI18nNodeTest extends XMLSitemapI18nWebTestCase { $this->drupalLogin($this->admin_user); } - function testNodeLanguageData() { + /** + * Node Language Data. + */ + public function testNodeLanguageData() { $node = $this->drupalCreateNode(array()); $this->drupalPost('node/' . $node->nid . '/edit', array('language' => 'en'), t('Save')); @@ -136,4 +172,5 @@ class XMLSitemapI18nNodeTest extends XMLSitemapI18nWebTestCase { $link = $this->assertSitemapLink('node', $node->nid); $this->assertIdentical($link['language'], 'fr'); } + } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_menu/README.txt b/sites/all/modules/xmlsitemap/xmlsitemap_menu/README.txt new file mode 100644 index 0000000..cd61435 --- /dev/null +++ b/sites/all/modules/xmlsitemap/xmlsitemap_menu/README.txt @@ -0,0 +1,79 @@ +CONTENTS OF THIS FILE +--------------------- + +* Introduction +* Requirements +* Recommended modules +* Installation +* Configuration +* Maintainers + + +INTRODUCTION +------------ + +The XML sitemap menu module, part of the XML sitemap +(https://www.drupal.org/project/xmlsitemap) package, enables menu links to be on +the site map. The XML sitemap module creates a sitemap that conforms to the +sitemaps.org specification. This helps search engines to more intelligently +crawl a website and keep their results up to date. + +* For a full description of the module visit + https://www.drupal.org/documentation/modules/xmlsitemap + +* To submit bug reports and feature suggestions, or to track changes visit + https://www.drupal.org/project/issues/xmlsitemap + + +REQUIREMENTS +------------ + +This module requires the following module: + +* XML sitemap - https://www.drupal.org/project/xmlsitemap + + +RECOMMENDED MODULES +------------------- + +* Ctools - https://www.drupal.org/project/ctools +* RobotsTxt - https://www.drupal.org/project/robotstxt +* Site Verification - https://www.drupal.org/project/site_verify +* Browscap - https://www.drupal.org/project/browscap +* Vertical Tabs - https://www.drupal.org/project/vertical_tabs + + +INSTALLATION +------------ + +This is a submodule of the XML sitemap module. Install the XML sitemap module as +you would normally install a contributed Drupal module. Visit +https://www.drupal.org/node/895232 for further information. + + +CONFIGURATION +------------- + +1. Install the XML sitemap module. +2. Enable the XML sitemap module. +3. To include menu items in the sitemap, enable the XML sitemap menu submodule. +4. Navigate to Administration > Configuration > Search > XML Sitemap. +5. Select the Settings tab and there will be a Menu link field set. Open. +6. Choose the menu link to be edited. There will now be a XML sitemap horizontal + tab. Under "Inclusion" change "Excluded" to become "Included". Select Save. +7. Once that is all complete, go to Configuration > Search and Metadata > XML + Sitemap. +8. Select the Rebuild Links tab in the upper right. +9. Select on "Rebuild sitemap" even if the message says that you do not need to. +10. Now you're taken back to the configuration page which shows you the link to + your XML sitemap which you can select and confirm that pages have been + added. + + +MAINTAINERS +----------- + +* Andrei Mateescu (amateescu) - https://www.drupal.org/u/amateescu +* Dave Reid - https://www.drupal.org/u/dave-reid +* Juampy NR (juampynr) - https://www.drupal.org/u/juampynr +* Tasya Rukmana (tadityar) - https://www.drupal.org/u/tadityar diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.info b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.info index cdcfd8d..2286474 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.info @@ -4,13 +4,10 @@ package = XML sitemap core = 7.x dependencies[] = xmlsitemap dependencies[] = menu -files[] = xmlsitemap_menu.module -files[] = xmlsitemap_menu.install files[] = xmlsitemap_menu.test -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.module b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.module index 65e24f4..9864c5f 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.module @@ -1,5 +1,10 @@ 'xmlsitemap_menu_xmlsitemap_process_menu_links', ), ); + if (!isset($info['menu_link']['bundle label'])) { + $info['menu_link']['bundle label'] = t('Menu'); + } } } @@ -87,7 +95,7 @@ function xmlsitemap_menu_xmlsitemap_index_links($limit) { /** * Process menu sitemap links. * - * @param $mlids + * @param array $mlids * An array of menu link IDs. */ function xmlsitemap_menu_xmlsitemap_process_menu_links(array $mlids, array $xmlsitemap = array()) { @@ -122,19 +130,23 @@ function xmlsitemap_menu_form_menu_edit_menu_alter(&$form, $form_state) { xmlsitemap_add_link_bundle_settings($form, $form_state, 'menu_link', $menu); } -//function xmlsitemap_menu_form_menu_overview_form_alter(&$form, $form_state) { -// $form['#submit'][] = 'xmlsitemap_menu_menu_overview_form_submit'; -//} -// -//function xmlsitemap_menu_menu_overview_form_submit($form, $form_state) { -// $mlids = array(); -// foreach (element_children($form) as $mlid) { -// if (isset($form[$mlid]['#item'])) { -// $mlids[] = $form[$mlid]['#item']['mlid']; -// } -// } -// xmlsitemap_menu_xmlsitemap_process_menu_links($mlids); -//} +/** + * Example functions. + * + * Function xmlsitemap_menu_form_menu_overview_form_alter(&$form, $form_state) { + * $form['#submit'][] = 'xmlsitemap_menu_menu_overview_form_submit'; + * } + * + * Function xmlsitemap_menu_menu_overview_form_submit($form, $form_state) { + * $mlids = array(); + * foreach (element_children($form) as $mlid) { + * if (isset($form[$mlid]['#item'])) { + * $mlids[] = $form[$mlid]['#item']['mlid']; + * } + * } + * xmlsitemap_menu_xmlsitemap_process_menu_links($mlids); + * } + */ /** * Implements hook_form_FORM_ID_alter(). @@ -202,8 +214,9 @@ function xmlsitemap_menu_menu_link_insert(array $link) { * @see hook_menu_link_alter() */ function xmlsitemap_menu_menu_link_update(array $link) { - //$link += array('xmlsitemap' => array()); - //xmlsitemap_menu_xmlsitemap_process_menu_links(array($link['mlid']), $link['xmlsitemap']); + // $link += array('xmlsitemap' => array()); + // @codingStandardsIgnoreLine + // xmlsitemap_menu_xmlsitemap_process_menu_links(array($link['mlid']), $link['xmlsitemap']);. } /** @@ -213,7 +226,7 @@ function xmlsitemap_menu_menu_link_update(array $link) { * hook is not always called if the user does not edit the core menu item * fields. * - * @see http://drupal.org/node/1013856 + * @see https://www.drupal.org/node/1013856 */ function xmlsitemap_menu_menu_link_alter(array &$link) { if (!empty($link['mlid'])) { @@ -232,7 +245,7 @@ function xmlsitemap_menu_menu_link_delete(array $link) { /** * Create a sitemap link from a menu item. * - * @param $menu_item + * @param array $menu_item * A loaded menu item. */ function xmlsitemap_menu_create_link(array $menu_item) { @@ -262,6 +275,19 @@ function xmlsitemap_menu_create_link(array $menu_item) { $menu_item['xmlsitemap']['access'] = $menu_item['access'] && !$menu_item['external'] && !$menu_item['hidden']; $menu_item['xmlsitemap']['language'] = isset($menu_item['options']['langcode']) ? $menu_item['options']['langcode'] : LANGUAGE_NONE; + // Exclude menu items created for nodes that are added by xmlsitemap_node. + if ($menu_item['xmlsitemap']['access'] && $menu_item['router_path'] == 'node/%' && module_exists('xmlsitemap_node')) { + $node = node_load(substr($menu_item['link_path'], 5)); + if ($node) { + if (empty($node->xmlsitemap)) { + xmlsitemap_node_create_link($node); + } + if ($node->xmlsitemap['status'] && $node->xmlsitemap['access']) { + $menu_item['xmlsitemap']['status'] = FALSE; + } + } + } + return $menu_item['xmlsitemap']; } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.test b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.test index ac33351..2f8bd42 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.test +++ b/sites/all/modules/xmlsitemap/xmlsitemap_menu/xmlsitemap_menu.test @@ -2,13 +2,35 @@ /** * @file - * Unit tests for the xmlsitemap_menu module. + * Unit tests for the xmlsitemap_menu project.. */ +/** + * Menu Functional Test. + */ class XMLSitemapMenuFunctionalTest extends XMLSitemapTestHelper { + + /** + * Normal User. + * + * @var string + * + * @codingStandardsIgnoreStart + */ protected $normal_user; + + /** + * Menu Items. + * + * @var array + */ protected $menu_items = array(); + /** + * Get Info. + * + * @codingStandardsIgnoreEnd + */ public static function getInfo() { return array( 'name' => 'XML sitemap menu', @@ -17,7 +39,10 @@ class XMLSitemapMenuFunctionalTest extends XMLSitemapTestHelper { ); } - function setUp($modules = array()) { + /** + * Setup. + */ + public function setUp($modules = array()) { $modules[] = 'xmlsitemap_menu'; $modules[] = 'menu'; parent::setUp($modules); @@ -26,7 +51,10 @@ class XMLSitemapMenuFunctionalTest extends XMLSitemapTestHelper { $this->normal_user = $this->drupalCreateUser(array('access content')); } - function testMenuSettings() { + /** + * Menu Settings. + */ + public function testMenuSettings() { $this->drupalLogin($this->admin_user); $edit = array( @@ -36,7 +64,6 @@ class XMLSitemapMenuFunctionalTest extends XMLSitemapTestHelper { 'xmlsitemap[priority]' => '1.0', ); $this->drupalPost('admin/structure/menu/add', $edit, 'Save'); - $menu = menu_load($edit['menu_name']); $this->clickLink('Add link'); $edit = array( @@ -47,4 +74,5 @@ class XMLSitemapMenuFunctionalTest extends XMLSitemapTestHelper { ); $this->drupalPost(NULL, $edit, 'Save'); } + } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.info b/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.info index 5ef0d92..de615c9 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.info @@ -4,12 +4,10 @@ package = XML sitemap core = 7.x dependencies[] = xmlsitemap dependencies[] = ctools -files[] = xmlsitemap_modal.module hidden = TRUE -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.module b/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.module index bfc2bfd..02259dc 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_modal/xmlsitemap_modal.module @@ -1,11 +1,16 @@ $item) { - if (!empty($item['modal']) && strpos($path, '%ctools_js') === FALSE && $item['page callback'] ==='drupal_get_form') { + if (!empty($item['modal']) && strpos($path, '%ctools_js') === FALSE && $item['page callback'] === 'drupal_get_form') { $items["$path/%ctools_js"] = $item; $items["$path/%ctools_js"]['page callback'] = 'xmlsitemap_modal_get_form'; $items["$path/%ctools_js"]['page arguments'][] = substr_count($path, '/') + 1; @@ -73,7 +78,7 @@ function xmlsitemap_modal_xmlsitemap_operation_link_alter(array &$link) { $link['href'] = trim($link['href'], '/'); } - // @todo Remove when http://drupal.org/node/565808 is fixed. + // @todo Remove when https://www.drupal.org/node/565808 is fixed. if (substr($link['href'], -4) === 'nojs') { $link['href'] .= '/'; } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_node/README.txt b/sites/all/modules/xmlsitemap/xmlsitemap_node/README.txt new file mode 100644 index 0000000..a5bb9a1 --- /dev/null +++ b/sites/all/modules/xmlsitemap/xmlsitemap_node/README.txt @@ -0,0 +1,81 @@ +CONTENTS OF THIS FILE +--------------------- + +* Introduction +* Requirements +* Recommended modules +* Installation +* Configuration +* Maintainers + + +INTRODUCTION +------------ + +The XML sitemap node module, part of the XML sitemap +(https://www.drupal.org/project/xmlsitemap) package, enables content nodes to +be in the sitemap. The XML sitemap module creates a sitemap that conforms to +the sitemaps.org specification. This helps search engines to more intelligently +crawl a website and keep their results up to date. + +* For a full description of the module visit: + https://www.drupal.org/project/xmlsitemap + +* To submit bug reports and feature suggestions, or to track changes visit: + https://www.drupal.org/project/issues/xmlsitemap + + +REQUIREMENTS +------------ + +This module requires the following modules: + +* XML sitemap - (https://www.drupal.org/project/xmlsitemap) + + +RECOMMENDED MODULES +------------------- + +* Ctools - (https://www.drupal.org/project/ctools) +* RobotsTxt - (https://www.drupal.org/project/robotstxt) +* Site Verification - (https://www.drupal.org/project/site_verify) +* Browscap - (https://www.drupal.org/project/browscap) +* Vertical Tabs - (https://www.drupal.org/project/vertical_tabs) + + +INSTALLATION +------------ + +* This is a submodule of the XML sitemap module. Install the XML sitemap module +as you would normally install a contributed Drupal module. Visit +https://www.drupal.org/node/895232 for further information. + + +CONFIGURATION +------------- + +1. Install the XML sitemap module. +2. Enable the XML sitemap module. +3. To include nodes in the sitemap, enable the XML sitemap node submodule. +4. To add nodes to the sitemap, visit the Edit page of the Content Type which + you want to appear on the sitemap. +5. Select the XML sitemap horizontal tab. +6. Under "Inclusion" change "Excluded" to become "Included". Save. +7. If enabled, all content of the specific node type will be included. + Individual nodes can be excluded on their specific node edit page. +8. Once that is all complete, go to Configurations --> Search and Metadata --> + XML sitemap. +9. Select the Rebuild Links tab in the upper right. +10. Select on "Rebuild sitemap" even if the message says that you do not need + to. +11. Now you're taken back to the config page which shows you the link to your + XML sitemap which you can select and confirm that pages have been added. + + +MAINTAINERS +----------- + +* Andrei Mateescu (amateescu) - https://www.drupal.org/u/amateescu +* Dave Reid - https://www.drupal.org/u/dave-reid +* Juampy NR (juampynr) - https://www.drupal.org/u/juampynr +* Tasya Rukmana (tadityar) - https://www.drupal.org/u/tadityar diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.info b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.info index 7a3ac0f..7963361 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.info @@ -3,13 +3,10 @@ description = Adds content links to the sitemap. package = XML sitemap core = 7.x dependencies[] = xmlsitemap -files[] = xmlsitemap_node.module -files[] = xmlsitemap_node.install files[] = xmlsitemap_node.test -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.module b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.module index 20f5f05..c287f26 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.module @@ -1,5 +1,10 @@ 0 && $item = $queue->claimItem()) { + $limit--; + try { + $node = node_load($item->data); + // The node could have been deleted in the meantime, skip XML sitemap + // updates in this case. + if ($node) { + $link = xmlsitemap_node_create_link($node); + xmlsitemap_link_save($link, array($link['type'] => $node)); + } + $queue->deleteItem($item); + } + catch (Exception $e) { + // In case of exception log it and leave the item in the queue + // to be processed again later. + watchdog_exception('xmlsitemap_node', $e); + } + } + + // Add nodes that are missing from the {xmlsitemap} table. + // This catches nodes that were created prior to this module being enabled. + xmlsitemap_node_xmlsitemap_index_links($limit); } /** @@ -33,14 +63,23 @@ function xmlsitemap_node_xmlsitemap_index_links($limit) { /** * Process node sitemap links. * - * @param $nids + * @param array $nids * An array of node IDs. */ function xmlsitemap_node_xmlsitemap_process_node_links(array $nids) { - $nodes = node_load_multiple($nids); - foreach ($nodes as $node) { - $link = xmlsitemap_node_create_link($node); - xmlsitemap_link_save($link, array($link['type'] => $node)); + // Load no more than 15 nodes at a time. + if (count($nids) >= 1) { + $nids_chunks = array_chunk($nids, 15); + foreach ($nids_chunks as $chunk) { + $nodes = node_load_multiple($chunk); + foreach ($nodes as $node) { + $link = xmlsitemap_node_create_link($node); + xmlsitemap_link_save($link, array($link['type'] => $node)); + } + // Flush each entity from the load cache after processing, to avoid + // exceeding PHP memory limits if $nids is large. + entity_get_controller('node')->resetCache($chunk); + } } } @@ -55,8 +94,15 @@ function xmlsitemap_node_node_insert(stdClass $node) { * Implements hook_node_update(). */ function xmlsitemap_node_node_update(stdClass $node) { + // Save a sitemap link with revoked access until the node permissions are + // checked in the cron. $link = xmlsitemap_node_create_link($node); - xmlsitemap_link_save($link, array($link['type'] => $node)); + xmlsitemap_link_presave($link, array($link['type'] => $node)); + // Node access can not be accurately determined in hook_node_update() because + // node grants have not yet been written to the table, so we defer checking + // node access permissions and process the sitemap link during cron. + $queue = DrupalQueue::get('xmlsitemap_node'); + $queue->createItem($node->nid); } /** @@ -70,7 +116,7 @@ function xmlsitemap_node_node_delete(stdClass $node) { * Implements hook_comment_update(). */ function xmlsitemap_node_comment_update(stdClass $comment) { - if ($node = node_load($comment->nid, NULL, TRUE)) { + if ($node = entity_load_unchanged('node', $comment->nid)) { xmlsitemap_node_node_update($node); } } @@ -126,6 +172,8 @@ function xmlsitemap_node_form_node_type_form_alter(array &$form, array $form_sta /** * Implements hook_form_alter(). * + * @codingStandardsIgnoreLine + * * Add the XML sitemap individual link options for a node. * * @see xmlsitemap_add_form_link_options() @@ -140,9 +188,10 @@ function xmlsitemap_node_form_node_form_alter(array &$form, array &$form_state) /** * Fetch all the timestamps for when a node was changed. * - * @param $node + * @param object $node * A node object. - * @return + * + * @return array * An array of UNIX timestamp integers. */ function xmlsitemap_node_get_timestamps(stdClass $node) { @@ -164,7 +213,7 @@ function xmlsitemap_node_get_timestamps(stdClass $node) { * * The link will be saved as $node->xmlsitemap. * - * @param $node + * @param object $node * A node object. */ function xmlsitemap_node_create_link(stdClass $node) { @@ -195,11 +244,6 @@ function xmlsitemap_node_create_link(stdClass $node) { $node->xmlsitemap['changefreq'] = $node->nid ? xmlsitemap_calculate_changefreq($timestamps) : 0; $node->xmlsitemap['changecount'] = $node->nid ? count($timestamps) - 1 : 0; - // Node access must be reset since it a user may have changed published status, etc. - //$access = &drupal_static('node_access'); - //unset($access[0][$node->nid]); - //node_access_acquire_grants($node); - // The following values must always be checked because they are volatile. $node->xmlsitemap['loc'] = $uri['path']; $node->xmlsitemap['lastmod'] = count($timestamps) ? max($timestamps) : 0; @@ -212,16 +256,18 @@ function xmlsitemap_node_create_link(stdClass $node) { /** * Determine whether a user may view the specified node. * - * @param $node + * @param object $node * The node object on which the operation is to be performed, or node type * (e.g. 'forum') for "create" operation. - * @param $account + * @param object $account * Optional, a user object representing the user for whom the operation is to * be performed. Determines access for a user other than the current user. - * @return + * + * @return bool * TRUE if the operation may be performed, FALSE otherwise. * - * This is for all intesive purposes a copy of Drupal 7's node_access() function. + * This is for all intesive purposes a copy of Drupal 7's node_access() + * function. */ function xmlsitemap_node_view_access($node, $account = NULL) { global $user; @@ -241,8 +287,7 @@ function xmlsitemap_node_view_access($node, $account = NULL) { // $node may be either an object or a node type. Since node types cannot be // an integer, use either nid or type as the static cache id. - //$cid = is_object($node) ? $node->nid : $node; - + // $cid = is_object($node) ? $node->nid : $node; // If we've already checked access for this node, user and op, return from // cache. if (isset($rights[$account->uid][$node->nid])) { @@ -294,7 +339,8 @@ function xmlsitemap_node_view_access($node, $account = NULL) { $query->condition($nids); $query->range(0, 1); - // Fetch the node grants and allow other modules to alter them (D7 backport). + // Fetch the node grants and allow other modules to alter them + // (D7 backport). $grants = &drupal_static(__FUNCTION__ . ':grants', array()); if (!isset($grants[$account->uid][$op])) { // Indicate that this is our special function in the grants. diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.test b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.test index edb59fd..b74365f 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.test +++ b/sites/all/modules/xmlsitemap/xmlsitemap_node/xmlsitemap_node.test @@ -5,10 +5,30 @@ * Unit tests for the xmlsitemap_node module. */ +/** + * Node Functional Test. + */ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { + + /** + * Normal User. + * + * @var string + * + * @codingStandardsIgnoreStart + */ protected $normal_user; + + /** + * Nodes. + * + * @var array + */ protected $nodes = array(); + /** + * Get Info. + */ public static function getInfo() { return array( 'name' => 'XML sitemap node', @@ -17,21 +37,44 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { ); } - function setUp($modules = array()) { + /** + * Setup. + */ + public function setUp($modules = array()) { $modules[] = 'xmlsitemap_node'; $modules[] = 'comment'; parent::setUp($modules); - $this->admin_user = $this->drupalCreateUser(array('administer nodes', 'bypass node access', 'administer content types', 'administer xmlsitemap')); - $this->normal_user = $this->drupalCreateUser(array('create page content', 'edit any page content', 'access content', 'view own unpublished content')); + $this->admin_user = $this->drupalCreateUser(array( + 'administer nodes', + 'bypass node access', + 'administer content types', + 'administer xmlsitemap', + )); + $this->normal_user = $this->drupalCreateUser(array( + 'create page content', + 'edit any page content', + 'access content', + 'view own unpublished content', + )); xmlsitemap_link_bundle_settings_save('node', 'page', array('status' => 1, 'priority' => 0.5)); } - function testNodeSettings() { + /** + * Node Settings. + */ + public function testNodeSettings() { $body_field = 'body[' . LANGUAGE_NONE . '][0][value]'; $node = $this->drupalCreateNode(array('status' => FALSE, 'uid' => $this->normal_user->uid)); - $this->assertSitemapLinkValues('node', $node->nid, array('access' => 0, 'status' => 1, 'priority' => 0.5, 'status_override' => 0, 'priority_override' => 0)); + $this->cronRun(); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'access' => 0, + 'status' => 1, + 'priority' => 0.5, + 'status_override' => 0, + 'priority_override' => 0, + )); $this->drupalLogin($this->normal_user); $this->drupalGet('node/' . $node->nid . '/edit'); @@ -44,7 +87,14 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { ); $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); $this->assertText('Basic page Test node title has been updated.'); - $this->assertSitemapLinkValues('node', $node->nid, array('access' => 0, 'status' => 1, 'priority' => 0.5, 'status_override' => 0, 'priority_override' => 0)); + $this->cronRun(); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'access' => 0, + 'status' => 1, + 'priority' => 0.5, + 'status_override' => 0, + 'priority_override' => 0, + )); $this->drupalLogin($this->admin_user); $this->drupalGet('node/' . $node->nid . '/edit'); @@ -58,7 +108,14 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { ); $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); $this->assertText('Basic page Test node title has been updated.'); - $this->assertSitemapLinkValues('node', $node->nid, array('access' => 1, 'status' => 0, 'priority' => 0.9, 'status_override' => 1, 'priority_override' => 1)); + $this->cronRun(); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'access' => 1, + 'status' => 0, + 'priority' => 0.9, + 'status_override' => 1, + 'priority_override' => 1, + )); $edit = array( 'xmlsitemap[status]' => 'default', @@ -67,16 +124,24 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { ); $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); $this->assertText('Basic page Test node title has been updated.'); - $this->assertSitemapLinkValues('node', $node->nid, array('access' => 0, 'status' => 1, 'priority' => 0.5, 'status_override' => 0, 'priority_override' => 0)); + $this->cronRun(); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'access' => 0, + 'status' => 1, + 'priority' => 0.5, + 'status_override' => 0, + 'priority_override' => 0, + )); } /** * Test the content type settings. */ - function testTypeSettings() { + public function testTypeSettings() { $this->drupalLogin($this->admin_user); $node_old = $this->drupalCreateNode(); + $this->cronRun(); $this->assertSitemapLinkValues('node', $node_old->nid, array('status' => 1, 'priority' => 0.5)); $edit = array( @@ -87,6 +152,7 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { $this->assertText('The content type Basic page has been updated.'); $node = $this->drupalCreateNode(); + $this->cronRun(); $this->assertSitemapLinkValues('node', $node->nid, array('status' => 0, 'priority' => 0.0)); $this->assertSitemapLinkValues('node', $node_old->nid, array('status' => 0, 'priority' => 0.0)); @@ -98,9 +164,18 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertText('Changed the content type of 2 posts from page to page2.'); $this->assertText('The content type Basic page has been updated.'); + $this->cronRun(); - $this->assertSitemapLinkValues('node', $node->nid, array('subtype' => 'page2', 'status' => 1, 'priority' => 0.5)); - $this->assertSitemapLinkValues('node', $node_old->nid, array('subtype' => 'page2', 'status' => 1, 'priority' => 0.5)); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'subtype' => 'page2', + 'status' => 1, + 'priority' => 0.5, + )); + $this->assertSitemapLinkValues('node', $node_old->nid, array( + 'subtype' => 'page2', + 'status' => 1, + 'priority' => 0.5, + )); $this->assertEqual(count(xmlsitemap_link_load_multiple(array('type' => 'node', 'subtype' => 'page'))), 0); $this->assertEqual(count(xmlsitemap_link_load_multiple(array('type' => 'node', 'subtype' => 'page2'))), 2); @@ -112,7 +187,7 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { /** * Test the import of old nodes via cron. */ - function testCron() { + public function testCron() { $limit = 5; variable_set('xmlsitemap_batch_limit', $limit); @@ -127,17 +202,21 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { // Clear all the node link data so we can emulate 'old' nodes. db_delete('xmlsitemap') - ->condition('type', 'node') - ->execute(); + ->condition('type', 'node') + ->execute(); // Run cron to import old nodes. xmlsitemap_node_cron(); for ($i = 1; $i <= ($limit + 1); $i++) { - $node = array_pop($nodes); + $node = array_shift($nodes); if ($i <= $limit) { // The first $limit nodes should be inserted. - $this->assertSitemapLinkValues('node', $node->nid, array('access' => 1, 'status' => 1, 'lastmod' => $node->changed)); + $this->assertSitemapLinkValues('node', $node->nid, array( + 'access' => 1, + 'status' => 1, + 'lastmod' => $node->changed, + )); } else { // Any beyond $limit should not be in the sitemap. @@ -145,4 +224,5 @@ class XMLSitemapNodeFunctionalTest extends XMLSitemapTestHelper { } } } + } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/README.txt b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/README.txt new file mode 100644 index 0000000..f343aa5 --- /dev/null +++ b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/README.txt @@ -0,0 +1,83 @@ +CONTENTS OF THIS FILE +--------------------- + +* Introduction +* Requirements +* Recommended modules +* Installation +* Configuration +* Maintainers + + +INTRODUCTION +------------ + +The XML sitemap taxonomy module, part of the XML sitemap +(https://www.drupal.org/project/xmlsitemap) package, adds taxonomy term links +to the sitemap. The XML sitemap module creates a sitemap that conforms to the +sitemaps.org specification. This helps search engines to more intelligently +crawl a website and keep their results up to date. + +* For a full description of the module visit +https://www.drupal.org/documentation/modules/xmlsitemap + +* To submit bug reports and feature suggestions, or to track changes visit +https://www.drupal.org/project/issues/xmlsitemap + + +REQUIREMENTS +------------ + +This module requires the following modules: + +XML sitemap - (https://www.drupal.org/project/xmlsitemap) + + +RECOMMENDED MODULES +------------------- + +* Ctools - (https://www.drupal.org/project/ctools) +* RobotsTxt - (https://www.drupal.org/project/robotstxt) +* Site Verification - (https://www.drupal.org/project/site_verify) +* Browscap - (https://www.drupal.org/project/browscap) +* Vertical Tabs - (https://www.drupal.org/project/vertical_tabs) + + +INSTALLATION +------------ + +This is a submodule of the XML sitemap module. Install the XML sitemap module as +you would normally install a contributed Drupal module. Visit +https://www.drupal.org/node/895232 for more information. + + +CONFIGURATION +------------- + +1. Install the XML sitemap module. +2. Enable the XML sitemap module. +3. To include taxonomy terms in the sitemap, enable the XML sitemap taxonomy + submodule. +4. Navigate to Administration > Structure > Taxonomy. +5. To include a whole vocabulary in the sitemap, click "edit vocabulary". + Select the XML sitemap field set. Under "Inclusion" change "Excluded" to + become "Included". Save. +6. To include a single vocabulary term in the sitemap, select edit vocabulary. + Select the vocabulary term to be included. Select the XML sitemap field set. + Under "Inclusion" change "Excluded" to become "Included". Save. +7. Once that is all complete, go to Configurations > Search and Metadata > XML + Sitemap. +8. Select the Rebuild Links tab in the upper right. +9. Select "Rebuild sitemap" even if the message says that you do not need to. +10. Now you're taken back to the configuration page which shows you the link to + your XML sitemap which you can click and confirm that pages have been added. + + +MAINTAINERS +----------- + +* Andrei Mateescu (amateescu) - https://www.drupal.org/u/amateescu +* Renato Gonçalves (RenatoG) - https://www.drupal.org/u/RenatoG +* Dave Reid - https://www.drupal.org/u/dave-reid +* Juampy NR (juampynr) - https://www.drupal.org/u/juampynr +* Tasya Rukmana (tadityar) - https://www.drupal.org/u/tadityar diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.info b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.info index 214775f..a3a5245 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.info @@ -4,13 +4,10 @@ package = XML sitemap core = 7.x dependencies[] = xmlsitemap dependencies[] = taxonomy -files[] = xmlsitemap_taxonomy.module -files[] = xmlsitemap_taxonomy.install files[] = xmlsitemap_taxonomy.test -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.install b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.install index 78687c3..5c6ef5c 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.install +++ b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.install @@ -2,7 +2,7 @@ /** * @file - * Install and uninstall schema and functions for the xmlsitemap_taxonomy module. + * Install and uninstall schema and functions for the xmlsitemap_taxonomy. */ /** diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module index f0d335d..d97f9c3 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module @@ -1,5 +1,10 @@ tid); @@ -143,9 +148,10 @@ function xmlsitemap_taxonomy_field_extra_fields() { /** * Create a sitemap link from a taxonomy term. * - * @param $term + * @param object $term * A taxonomy term object. - * @return + * + * @return array * An array representing a sitemap link. */ function xmlsitemap_taxonomy_create_link(stdClass &$term) { @@ -182,20 +188,22 @@ function xmlsitemap_taxonomy_create_link(stdClass &$term) { /** * Calculate the priority of a taxonomy term based on depth and weight. + * + * Function xmlsitemap_taxonomy_calculate_term_priority(stdClass $term) { + * // Calculate priority. + * // Min weight = -128 + * // Max weight = 127 + * // Max depth = ? + * } */ -//function xmlsitemap_taxonomy_calculate_term_priority(stdClass $term) { -// // Calculate priority. -// // Min weight = -128 -// // Max weight = 127 -// // Max depth = ? -//} /** * Find the tree depth of a taxonomy term. * - * @param $term + * @param object $term * A taxonomy term object. - * @return + * + * @return array * The tree depth of the term. */ function xmlsitemap_taxonomy_get_term_depth(stdClass $term) { @@ -221,12 +229,16 @@ function xmlsitemap_taxonomy_get_term_depth(stdClass $term) { /** * Find the number of nodes that are associated with a taxonomy term. * - * @param $term + * @param obejct $term * A taxonomy term object. - * @return + * + * @return int * The number of nodes associated with the term. + * + * @codingStandardsIgnoreStart */ function xmlsitemap_taxonomy_get_node_count(stdClass $term) { + // @codingStandardsIgnoreEnd // @todo Use db_rewrite_sql() w/ switch user. return db_query_range("SELECT COUNT(ti.nid) FROM {taxonomy_index} ti LEFT JOIN {node n} USING (nid) WHERE ti.tid = :tid AND n.status = 1", 0, 1, array(':tid' => $term->tid))->fetchField(); } @@ -234,7 +246,7 @@ function xmlsitemap_taxonomy_get_node_count(stdClass $term) { /** * Implements hook_entity_query_alter(). * - * @todo Remove when http://drupal.org/node/1054162 is fixed. + * @todo Remove when https://www.drupal.org/node/1054162 is fixed. */ function xmlsitemap_taxonomy_entity_query_alter($query) { $conditions = &$query->entityConditions; @@ -243,7 +255,13 @@ function xmlsitemap_taxonomy_entity_query_alter($query) { if (isset($conditions['entity_type']) && $conditions['entity_type']['value'] == 'taxonomy_term' && isset($conditions['bundle'])) { // We can only support the operators that are explicit in values. - if (in_array($conditions['bundle']['operator'], array(NULL, '=', '!=', 'IN', 'NOT IN'))) { + if (in_array($conditions['bundle']['operator'], array( + NULL, + '=', + '!=', + 'IN', + 'NOT IN', + ))) { $vids = array(); // Convert vocabulary machine names to vocabulary IDs. diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.test b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.test index 9d1bf55..c84ccca 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.test +++ b/sites/all/modules/xmlsitemap/xmlsitemap_taxonomy/xmlsitemap_taxonomy.test @@ -5,10 +5,32 @@ * Unit tests for the xmlsitemap_taxonomy module. */ +/** + * Functional Test. + */ class XMLSitemapTaxonomyFunctionalTest extends XMLSitemapTestHelper { + + /** + * Normal User. + * + * @var string + * + * @codingStandardsIgnoreStart + */ protected $normal_user; + + /** + * Terms. + * + * @var array + */ protected $terms = array(); + /** + * Get Info. + * + * @codingStandardsIgnoreEnd + */ public static function getInfo() { return array( 'name' => 'XML sitemap taxonomy', @@ -17,7 +39,10 @@ class XMLSitemapTaxonomyFunctionalTest extends XMLSitemapTestHelper { ); } - function setUp($modules = array()) { + /** + * SetUp. + */ + public function setUp($modules = array()) { $modules[] = 'xmlsitemap_taxonomy'; $modules[] = 'taxonomy'; parent::setUp($modules); @@ -26,7 +51,10 @@ class XMLSitemapTaxonomyFunctionalTest extends XMLSitemapTestHelper { $this->normal_user = $this->drupalCreateUser(array('access content')); } - function testTaxonomySettings() { + /** + * TaxonomySettings. + */ + public function testTaxonomySettings() { $this->drupalLogin($this->admin_user); $edit = array( @@ -46,4 +74,5 @@ class XMLSitemapTaxonomyFunctionalTest extends XMLSitemapTestHelper { ); $this->drupalPost("admin/structure/taxonomy/{$vocabulary->machine_name}/add", $edit, 'Save'); } + } diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_user/README.txt b/sites/all/modules/xmlsitemap/xmlsitemap_user/README.txt new file mode 100644 index 0000000..6ca54ee --- /dev/null +++ b/sites/all/modules/xmlsitemap/xmlsitemap_user/README.txt @@ -0,0 +1,82 @@ +CONTENTS OF THIS FILE +--------------------- + +* Introduction +* Requirements +* Recommended modules +* Installation +* Configuration +* Maintainers + + +INTRODUCTION +------------ + +The XML sitemap user module, part of the XML sitemap +(https://www.drupal.org/project/xmlsitemap) package, adds user profiles to the +site map. The XML sitemap module creates a sitemap that conforms to the +sitemaps.org specification. This helps search engines to more intelligently +crawl a website and keep their results up to date. + +* For a full description of the module visit + https://www.drupal.org/documentation/modules/xmlsitemap + +* To submit bug reports and feature suggestions, or to track changes visit + https://www.drupal.org/project/issues/xmlsitemap + +REQUIREMENTS +------------ + +This module requires the following module: + +* XML sitemap - https://www.drupal.org/project/xmlsitemap + + +RECOMMENDED MODULES +------------------- + +* Ctools - https://www.drupal.org/project/ctools +* RobotsTxt - https://www.drupal.org/project/robotstxt +* Site Verification - https://www.drupal.org/project/site_verify +* Browscap - https://www.drupal.org/project/browscap +* Vertical Tabs - https://www.drupal.org/project/vertical_tabs + + +INSTALLATION +------------ + +This is a submodule of the XML sitemap module. Install the XML sitemap module as +you would normally install a contributed Drupal module. Visit +https://www.drupal.org/node/895232 for further information. + + +CONFIGURATION +------------- +1. Install the XML sitemap module. +2. Enable the XML sitemap module. +3. To include users in the sitemap, enable the XML sitemap user submodule. +4. To add individuals user to the site map navigate to Administration > People + and select edit on the user to be included in the sitemap. +5. Select the XML sitemap fieldset. +6. Under "Inclusion" change "Excluded" to become "Included". Save. +7. Once that is complete, navigate to Configurations > Search and Metadata > XML + Sitemap. +8. Select the Rebuild Links tab in the upper right. +9. Select "Rebuild sitemap" even if the message says that you do not need to. +10. Now you're taken back to the config page which shows you the link to your + XML sitemap which you can select and confirm that pages have been added. + + +TROUBLESHOOTING +--------------- + +In order to list user profiles in the site map, the anonymous user must have the +View user profiles permission. + + +MAINTAINERS +----------- +* Andrei Mateescu (amateescu) - https://www.drupal.org/u/amateescu +* Dave Reid - https://www.drupal.org/u/dave-reid +* Juampy NR (juampynr) - https://www.drupal.org/u/juampynr +* Tasya Rukmana (tadityar) - https://www.drupal.org/u/tadityar diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.info b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.info index 8361571..95a08b8 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.info +++ b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.info @@ -3,13 +3,10 @@ description = Adds user profile links to the sitemap. package = XML sitemap dependencies[] = xmlsitemap core = 7.x -files[] = xmlsitemap_user.module -files[] = xmlsitemap_user.install files[] = xmlsitemap_user.test -; Information added by Drupal.org packaging script on 2016-05-25 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-10-09 +version = "7.x-2.6" core = "7.x" project = "xmlsitemap" -datestamp = "1464191061" - +datestamp = "1539120486" diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.module b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.module index d441570..a68f6ec 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.module +++ b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.module @@ -1,5 +1,10 @@ xmlsitemap. * - * @param $account + * @param object $account * A user object. */ function xmlsitemap_user_create_link(stdClass &$account) { @@ -155,7 +160,7 @@ function xmlsitemap_user_create_link(stdClass &$account) { } /** - * Implementation of hook_variables(). + * Implements hook_variables(). */ function xmlsitemap_user_variables() { $defaults = array(); diff --git a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.test b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.test index 346038c..e84bc2b 100644 --- a/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.test +++ b/sites/all/modules/xmlsitemap/xmlsitemap_user/xmlsitemap_user.test @@ -5,10 +5,32 @@ * Unit tests for the xmlsitemap_user module. */ +/** + * Tests for User Functional. + */ class XMLSitemapUserFunctionalTest extends XMLSitemapTestHelper { + + /** + * Normal User. + * + * @var string + * + * @codingStandardsIgnoreStart + */ protected $normal_user; + + /** + * Accounts. + * + * @var array + */ protected $accounts = array(); + /** + * Get Info. + * + * @codingStandardsIgnoreEnd + */ public static function getInfo() { return array( 'name' => 'XML sitemap user', @@ -17,15 +39,23 @@ class XMLSitemapUserFunctionalTest extends XMLSitemapTestHelper { ); } - function setUp($modules = array()) { + /** + * Setup. + */ + public function setUp($modules = array()) { $modules[] = 'xmlsitemap_user'; parent::setUp($modules); // Save the user settings before creating the users. xmlsitemap_link_bundle_settings_save('user', 'user', array('status' => 1, 'priority' => 0.5)); - // Create the users - $this->admin_user = $this->drupalCreateUser(array('administer users', 'administer permissions', 'administer xmlsitemap')); + // Create the users. + $this->admin_user = $this->drupalCreateUser(array( + 'administer users', + 'administer permissions', + 'administer xmlsitemap', + )); + $this->normal_user = $this->drupalCreateUser(array('access content')); // Update the normal user to make its sitemap link visible. @@ -33,7 +63,10 @@ class XMLSitemapUserFunctionalTest extends XMLSitemapTestHelper { user_save($account, array('access' => 1, 'login' => 1)); } - function testBlockedUser() { + /** + * Blocked User(). + */ + public function testBlockedUser() { $this->drupalLogin($this->admin_user); $this->assertSitemapLinkVisible('user', $this->normal_user->uid); @@ -42,9 +75,10 @@ class XMLSitemapUserFunctionalTest extends XMLSitemapTestHelper { 'status' => 0, ); - // This will pass when http://drupal.org/node/360925 is fixed. + // This will pass when https://www.drupal.org/node/360925 is fixed. $this->drupalPost('user/' . $this->normal_user->uid . '/edit', $edit, t('Save')); $this->assertText('The changes have been saved.'); $this->assertSitemapLinkNotVisible('user', $this->normal_user->uid); } + } diff --git a/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.js b/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.js index ac28230..282665f 100644 --- a/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.js +++ b/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.js @@ -12,6 +12,8 @@ * */ /** + * + * @codingStandardsIgnoreFile Ignore because it's code from another project. * * @description Create a sortable table with multi-column sorting capabilitys * diff --git a/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.min.js b/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.min.js index 64c7007..d79fd0c 100644 --- a/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.min.js +++ b/sites/all/modules/xmlsitemap/xsl/jquery.tablesorter.min.js @@ -1,2 +1,2 @@ - +// @codingStandardsIgnoreFile Ignore because it's code from another project. (function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i