From 8a94cd2e4d52adb67799b65c046dc24ed6abb564 Mon Sep 17 00:00:00 2001 From: Chris Skene Date: Tue, 25 Mar 2014 15:34:55 +1100 Subject: [PATCH] Issue #2225181 by xtfer: Validate multisites by URL. --- apachesolr_multisitesearch.admin.inc | 170 ++++++++++++++++++++++++++++------- apachesolr_multisitesearch.install | 9 +- apachesolr_multisitesearch.module | 75 ++++++++++++++-- 3 files changed, 210 insertions(+), 44 deletions(-) diff --git a/apachesolr_multisitesearch.admin.inc b/apachesolr_multisitesearch.admin.inc index b2c23ed..4afd876 100644 --- a/apachesolr_multisitesearch.admin.inc +++ b/apachesolr_multisitesearch.admin.inc @@ -13,12 +13,18 @@ * this also reduces the clutter on the blocks admin page. */ function apachesolr_multisitesearch_settings() { + + apachesolr_multisitesearch_version_warning(); + module_load_include('inc', 'apachesolr_multisitesearch', 'apachesolr_multisitesearch.index'); $form = array(); $form['#tree'] = TRUE; $form['submit_message'] = array( '#type' => 'value', - '#value' => t('The Apache Solr Multisite Search filter settings were changed. To arrange the blocks for your enabled filters, visit the blocks administration page.', array('@url' => url('admin/structure/block'))), + '#value' => t('The Apache Solr Multisite Search filter settings were changed. + To arrange the blocks for your enabled filters, visit the + blocks administration page.', + array('@url' => url('admin/structure/block'))), ); $form['admin'] = array( '#type' => 'fieldset', @@ -27,7 +33,6 @@ function apachesolr_multisitesearch_settings() { $form['admin']['refresh'] = array( '#type' => 'submit', '#value' => t('Refresh metadata now'), - '#prefix' => '

' . t('Multisite metadata is used to communicate between all of the sites in a multisite setup. If site names are not showing properly in the search results and facet blocks try refreshing the metadata. Metadata is also refreshed periodically on cron runs.') . '

', '#submit' => array('apachesolr_multisitesearch_refresh_metadata_now'), ); @@ -39,35 +44,116 @@ function apachesolr_multisitesearch_settings() { $metadata = apachesolr_multisitesearch_get_cached_metadata(); $hashes = apachesolr_multisitesearch_get_site_hashes(); $options = array(); + + $current_hash = apachesolr_site_hash(); + $current_m_hash = apachesolr_multisitesearch_generate_site_hash(); + + if ($current_hash != $current_m_hash) { + drupal_set_message(t("The ApacheSolr index hash (%index_hash) used by + ApacheSolr Multisite Search does not match this site's base URL hash + (%actual_hash). This may mean that your multisite is referencing an incorrect + index hash. If you have set this has manually, are using a development + site with a different URL to your production index, you can ignore this + message.", array( + '%index_hash' => $current_hash, + '%actual_hash' => $current_m_hash, + )), + 'warning', + FALSE + ); + } + foreach ($hashes as $site_hash => $count) { - if ($site_hash == apachesolr_site_hash()) { - $options[$site_hash] = t('This site (!site, !count documents)', array( - '!site' => variable_get('site_name', 'Drupal'), - '!count' => $count, - )); - } - elseif (!empty($metadata[$site_hash])) { - $options[$site_hash] = $metadata[$site_hash]['site'] . ' ' . t('(!count documents)', array('!count' => $count)); + + if (!empty($metadata[$site_hash])) { + $options[$site_hash]['url'] = $metadata[$site_hash]['site']; + $options[$site_hash]['documents'] = t('!count documents', array('!count' => $count)); + $options[$site_hash]['label'] = $metadata[$site_hash]['ss_multisite_meta_sitename']; + $options[$site_hash]['m_hash'] = apachesolr_multisitesearch_generate_site_hash(rtrim($metadata[$site_hash]['site'], '/')); } else { - $options[$site_hash] = $site_hash . ' ' . t('(!count documents)', array('!count' => $count)); + $options[$site_hash]['url'] = $site_hash; + $options[$site_hash]['documents'] = t('!count documents', array('!count' => $count)); + $options[$site_hash]['label'] = t('Unknown site (Hash: %hash)', array('%hash' => $site_hash)); + $options[$site_hash]['m_hash'] = t('Not calculable.'); + } + + if ($site_hash == $current_hash) { + $options[$site_hash]['label'] .= ' ' . t('(this site)'); } } - if (count($options) > 0) { - $form['admin']['delete']['hashes'] = array( - '#type' => 'checkboxes', - '#title' => t('Delete data from sites using this index'), - '#options' => $options, - '#description' => t('If you end up in a situation where the index has hashes that no longer map to real active sites, use this option to delete the outdated data. If you delete another site\'s index from this site, that site will have to first trigger a re-index, and then run cron until the index is rebuilt.'), + $form['sites'] = array( + '#type' => 'fieldset', + '#title' => t('Sites using this index'), + '#description' => t('If you have Unknown Sites in your site list, you may + need to refresh site metadata.'), + ); + $form['sites']['set'] = array( + '#type' => 'vertical_tabs', + ); + + foreach ($hashes as $site_hash => $count) { + + $form['sites']['set'][$site_hash] = array( + '#type' => 'fieldset', + '#title' => $options[$site_hash]['label'], ); - $form['admin']['delete']['submit'] = array( - '#type' => 'submit', - '#value' => t('Delete selected indexes'), - '#submit' => array('apachesolr_multisitesearch_delete_indexes'), + + if ($site_hash == $current_hash && $current_hash != $current_m_hash) { + $form['sites']['set'][$site_hash][$site_hash . '_warning'] = array( + '#markup' => t('
The site hash for + this site does not match the multisite URL hash. You may wish + to regenerate it.
'), + ); + } + + $form['sites']['set'][$site_hash][$site_hash . '_info'] = array( + '#theme' => 'item_list', + '#items' => array( + t('URL: %url', array('%url' => $options[$site_hash]['url'])), + t('Documents: %docs', array('%docs' => $options[$site_hash]['documents'])), + t('Saved hash: %hash', array('%hash' => $site_hash)), + t('Multisite hash: %m_hash', array('%m_hash' => $options[$site_hash]['m_hash'])), + ), ); + $form['sites']['set'][$site_hash]['delete'] = array( + '#type' => 'checkbox', + '#title' => t("Delete this index and its' content"), + '#description' => t("If you end up in a situation where the index has + hashes that no longer map to real active sites, use this option to delete + the outdated data. If you delete another site's index from this site, + that site will have to first trigger a re-index, and then run cron until + the index is rebuilt."), + ); + if ($site_hash == $current_hash) { + $form['sites']['set'][$site_hash]['regen_hash'] = array( + '#type' => 'checkbox', + '#title' => t('Regenerate site hash.'), + '#description' => t('In some cases (such as where one site is copied to + make another) the Apache Solr site hash can be duplicated. This is indicated + by two sites both identifying with the same hash. This will regenerate the + local site hash to dedupe the index. You will need to queue all content for + re-indexing to complete this process.'), + ); + } + else { + $form['sites']['set'][$site_hash]['regen_message'] = array( + '#type' => 'checkbox', + '#disabled' => TRUE, + '#title' => t('Regenerate site hash'), + '#description' => t('Site hashes can only be regenerated from the + originating site.'), + ); + } } + $form['sites']['sites_submit'] = array( + '#type' => 'submit', + '#value' => t('Update sites'), + '#submit' => array('apachesolr_multisitesearch_update_indexes'), + ); + // Check variables for the metadata which contains the bundles and bundle // names. $multsite_entity_info = apachesolr_multisitesearch_entity_data(); @@ -166,24 +252,46 @@ function apachesolr_multisitesearch_exclude_indexes($form, &$form_state) { /** * Submit handler for the "Delete selected indexes" button. */ -function apachesolr_multisitesearch_delete_indexes($form, &$form_state) { +function apachesolr_multisitesearch_update_indexes($form, &$form_state) { + module_load_include('inc', 'apachesolr_multisitesearch', 'apachesolr_multisitesearch.index'); - $fv = $form_state['values']; + // Instantiate a new Solr object. $solr = apachesolr_get_solr(); $env_id = apachesolr_default_environment(); - foreach ($fv['admin']['delete']['hashes'] as $hash) { - if ($hash) { - $query = "hash:$hash"; - $solr->deleteByQuery($query); - drupal_set_message(t('The index for !hash has been deleted.', array('!hash' => $hash))); - if (apachesolr_site_hash() == $hash) { - //Todo : we might want to execute apachesolr_node_check_index_table(); - apachesolr_set_last_index_updated($env_id, time()); + + if (isset($form_state['values']['sites']['set']) && !empty($form_state['values']['sites']['set'])) { + foreach ($form_state['values']['sites']['set'] as $site_hash => $ops) { + + // Delete the index. + if ($ops['delete'] == 1) { + + $query = "hash:$site_hash"; + $solr->deleteByQuery($query); + drupal_set_message(t('The index for !hash has been deleted.', array('!hash' => $site_hash))); + + if (apachesolr_site_hash() == $site_hash) { + // @todo : we might want to execute + // apachesolr_node_check_index_table(); + apachesolr_set_last_index_updated($env_id, time()); + } + } + + // Regenerate the site hash. + if (isset($ops['regen_hash']) && $ops['regen_hash'] == 1) { + + apachesolr_multisitesearch_regenerate_site_hash(); + drupal_set_message(t('The site hash for this site has been regenerated. You should reindex now.')); } } } + $solr->commit(); + + // Force the metadata to update. This ensure our hash is set. + apachesolr_multisitesearch_update_metadata(); + + // Fetch the metadata again, so we are up to date. apachesolr_multisitesearch_retrieve_metadata(); } diff --git a/apachesolr_multisitesearch.install b/apachesolr_multisitesearch.install index c6e4eb5..b804fc6 100644 --- a/apachesolr_multisitesearch.install +++ b/apachesolr_multisitesearch.install @@ -17,14 +17,7 @@ function apachesolr_multisitesearch_install() { */ function apachesolr_multisitesearch_update_7001() { - if (variable_get('apachesolr_multisitesearch_api', NULL) < 2) { - $exclusions = apachesolr_multisitesearch_get_cached_bundle_exclusions(); - if (!empty($exclusions)) { - drupal_set_message(t('ApacheSolr Multisite excluded bundle settings have changed. !link', array( - '!link' => l(t('You must update your settings for exclusions to function correctly.'), 'admin/config/search/apachesolr/multisite-filters'), - )), 'warning'); - } - } + apachesolr_multisitesearch_version_warning(); } /** diff --git a/apachesolr_multisitesearch.module b/apachesolr_multisitesearch.module index 50ba131..fd44bb7 100644 --- a/apachesolr_multisitesearch.module +++ b/apachesolr_multisitesearch.module @@ -38,6 +38,26 @@ function apachesolr_multisitesearch_menu() { } /** + * Implements hook_help(). + */ +function apachesolr_multisitesearch_help($path, $arg) { + + switch ($path) { + case 'admin/config/search/apachesolr/multisite-filters': + return '

' . t('Multisite metadata is used to communicate between all + of the sites in a multisite setup. If site names are not showing properly + in the search results and facet blocks try refreshing the metadata. + Metadata is also refreshed periodically on cron runs.') . '

' + . t('ApacheSolr uses the concept of site hashes to + track which content to a site. These hashes are normally generated + randomly. For ApacheSolr Multisite to correctly validate these hashes, + Multisite can generate URL-specific hashes which you can set on a per-site + basis. Multisite will still work without them, but you will not get + validation for duplicate indexes.') . '

'; + } +} + +/** * Implements hook_facetapi_facet_info(). * * Maps the hash label in Apache Solr to a facet @@ -162,11 +182,11 @@ function apachesolr_multisitesearch_entity_data() { if (!empty($site_metadata)) { // Iterates for each site available in the multi-site search. - foreach ($site_metadata as $site_hash => $entity_settings) { + foreach ($site_metadata as $site_hash => $site_settings) { // Grabs all of the bundle names and save them. - if (!empty($entity_settings['sm_multisite_meta_bundles'])) { - foreach ($entity_settings['sm_multisite_meta_bundles'] as $entity_type => $entity_bundles) { + if (!empty($site_settings['sm_multisite_meta_bundles'])) { + foreach ($site_settings['sm_multisite_meta_bundles'] as $entity_type => $entity_bundles) { $bundles = array(); // Add all site bundles to the global entity/bundle array. @@ -178,8 +198,8 @@ function apachesolr_multisitesearch_entity_data() { $multsite_entity_info[$entity_type]['bundles'] = $bundles; // Ensure a label is set for the entity bundle array. - if (!empty($entity_settings['sm_multisite_meta_entities'][$entity_type])) { - $multsite_entity_info[$entity_type]['label'] = $entity_settings['sm_multisite_meta_entities'][$entity_type]; + if (!empty($site_settings['sm_multisite_meta_entities'][$entity_type])) { + $multsite_entity_info[$entity_type]['label'] = $site_settings['sm_multisite_meta_entities'][$entity_type]; } else { $multsite_entity_info[$entity_type]['label'] = $entity_type; @@ -350,3 +370,48 @@ function apachesolr_multisitesearch_sort_by_key(&$array, $key) { return $a[$key] - $b[$key]; }); } + +/** + * Helper to warn when versions are incorrect. + */ +function apachesolr_multisitesearch_version_warning() { + + if (variable_get('apachesolr_multisitesearch_api', NULL) < 2) { + $exclusions = apachesolr_multisitesearch_get_cached_bundle_exclusions(); + if (!empty($exclusions)) { + drupal_set_message(t('ApacheSolr Multisite excluded bundle settings have changed. !link', array( + '!link' => l(t('You must update your settings for exclusions to function correctly.'), 'admin/config/search/apachesolr/multisite-filters'), + )), 'warning'); + } + } +} + +/** + * Regenerate the ApacheSolr site hash. + */ +function apachesolr_multisitesearch_regenerate_site_hash() { + + $hash = apachesolr_multisitesearch_generate_site_hash(); + variable_set('apachesolr_site_hash', $hash); +} + +/** + * Generate a hash compatible with the ApacheSolr module, but unique per URL. + * + * @param string|null $url + * (Optional) The URL to generate a hash for. If not provided, the base url + * will be used. + * + * @return string + * A 6 digit hash based on the site URL. + */ +function apachesolr_multisitesearch_generate_site_hash($url = NULL) { + + if (empty($url)) { + global $base_url; + $url = $base_url; + } + + // Set a random 6 digit base-36 number as the hash. + return substr(base_convert(sha1($url), 16, 36), 0, 6); +} -- 1.8.4.2