diff --git a/composer.json b/composer.json index d564500360..9b70915a77 100644 --- a/composer.json +++ b/composer.json @@ -225,7 +225,10 @@ "3417771 : Some styling no longer applies due to form-actions -> field-actions html change (https://git.drupalcode.org/project/paragraphs/-/merge_requests/93.diff)": "patches/drupal/paragraphs/3417771.diff" }, "drupal/purge": { - "3094343 : Garbled purge tag IDs": "https://www.drupal.org/files/issues/2023-09-07/purge-3094343-15.patch" + "3094343 : Garbled purge tag IDs": "https://www.drupal.org/files/issues/2023-09-07/purge-3094343-15.patch", + "3460094 : Running drush p:queue-add fails (https://www.drupal.org/files/issues/2024-07-25/3460094-5-there-is-no-purger-supporting-array.patch)": "patches/drupal/purge/3460094.diff", + "3460094 : Purge defines drush commands twice (https://www.drupal.org/files/issues/2024-10-18/3460094-remove_drush_services_yml.patch)": "patches/drupal/purge/3460094-2.diff" + }, "drupal/responsive_favicons": { "3376766 : Incorrect path if Drupal is installed in subfolder": "https://git.drupalcode.org/project/responsive_favicons/-/merge_requests/6.patch", diff --git a/composer.lock b/composer.lock index e0c66ad674..b99d82202b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "12b69e2ce70d858b8fd7d185a771116b", + "content-hash": "4a625e91f0bc8534a90074ce044dd03d", "packages": [ { "name": "acquia/blt", diff --git a/docroot/profiles/custom/cgov_site/modules/custom/cgov_caching_cdn/cgov_caching_cdn.install b/docroot/profiles/custom/cgov_site/modules/custom/cgov_caching_cdn/cgov_caching_cdn.install index b5a4350432..3357796bc1 100644 --- a/docroot/profiles/custom/cgov_site/modules/custom/cgov_caching_cdn/cgov_caching_cdn.install +++ b/docroot/profiles/custom/cgov_site/modules/custom/cgov_caching_cdn/cgov_caching_cdn.install @@ -27,7 +27,7 @@ function cgov_caching_cdn_install() { // Set config. $config_factory = \Drupal::service('config.factory'); $config_installer = new CgovPurgeConfigInstaller($config_factory); - $config_installer->installPurgeConfiguration(['acquia_purge', 'akamai_tag']); + $config_installer->installPurgeConfiguration(['acquia_purge', 'akamai_tag', 'akamai']); } /** @@ -42,3 +42,13 @@ function cgov_caching_cdn_update_8001() { $config_installer = new CgovPurgeConfigInstaller($config_factory); $config_installer->installPurgeConfiguration(['acquia_purge', 'akamai_tag']); } + +/** + * Updates purge config to include Akamai purger for URLs. + */ +function cgov_caching_cdn_update_10001() { + // Set config. + $config_factory = \Drupal::service('config.factory'); + $config_installer = new CgovPurgeConfigInstaller($config_factory); + $config_installer->installPurgeConfiguration(['acquia_purge', 'akamai_tag', 'akamai']); +} diff --git a/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/cgov_core.module b/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/cgov_core.module index 5ef3358161..e9c291a020 100644 --- a/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/cgov_core.module +++ b/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/cgov_core.module @@ -22,6 +22,9 @@ use Drupal\views\Plugin\views\query\QueryPluginBase; use Drupal\Core\Cache\Cache; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\Site\Settings; +use Drupal\redirect\Entity\Redirect; +use Drupal\Core\Language\Language; /** * Implements hook_block_build_alter(). @@ -848,3 +851,71 @@ function cgov_core_taxonomy_term_delete(EntityInterface $entity) { } } } + +/** + * Method to clear source paths for redirects when inserted or updated. + */ +function clearRedirectSourceCache(Redirect $entity) { + // On local development without purge, make sure we don't fail. + $moduleHandler = \Drupal::service('module_handler'); + if (!$moduleHandler->moduleExists('purge')) { + \Drupal::logger('cgov_core')->notice("Attempted to purge redirect without the purge module installed."); + return; + } + + // Set up our needed variables for calculating the URL. + // The value for cgdp.cache_url_host is computed in cgov_caching.settings.php. + $host = Settings::get('cgdp.cache_url_host'); + $host = rtrim($host, '/'); + $sourcePath = '/' . $entity->redirect_source->path; + + // The purge invalidation factory helps us construct an invalidation object + // that can be understood by the queuer and purgers. + $purgeInvalidationFactory = \Drupal::service('purge.invalidation.factory'); + + // If no language is specified for the redirect, + // purge the url for all languages. + $language = [$entity->language->value]; + if ($entity->language->value === Language::LANGCODE_NOT_SPECIFIED) { + $langcodes = \Drupal::languageManager()->getLanguages(); + $language = array_keys($langcodes); + } + + // Create an absolute url for all languages based on $language, + // then create an invalidation object using it. + $invalidations = []; + foreach ($language as $value) { + $language_prefix = \Drupal::config('language.negotiation')->get("url.prefixes.$value"); + if (!empty($language_prefix)) { + $sourcePath = Url::fromUri("internal:/{$language_prefix}{$sourcePath}")->toString(); + } + $invalidateUrl = $host . $sourcePath; + $invalidations[] = $purgeInvalidationFactory->get('url', $invalidateUrl); + } + + // Actually add the invalidations to the purge queue. + $purgeQueuers = \Drupal::service('purge.queuers'); + $queuer = $purgeQueuers->get('drush_purge_queue_add'); + if (empty($queuer)) { + \Drupal::logger('cgov_core')->notice("Attempted to purge redirect without the drush purgue queuer installed."); + return; + } + $purgeQueue = \Drupal::service('purge.queue'); + $purgeQueue->add($queuer, $invalidations); +} + +/** + * Implements hook_ENTITY_TYPE_insert(). + */ +function cgov_core_redirect_insert(Redirect $entity) { + clearRedirectSourceCache($entity); +} + +/** + * Implements hook_ENTITY_TYPE_update(). + */ +function cgov_core_redirect_update(Redirect $entity) { + clearRedirectSourceCache($entity); + // We do not need to clear the $entity->original because the redirect module + // already clears that on updates and deletes via cache tag. +} diff --git a/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/src/CgovPurgeConfigInstaller.php b/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/src/CgovPurgeConfigInstaller.php index 0932247486..522310759b 100644 --- a/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/src/CgovPurgeConfigInstaller.php +++ b/docroot/profiles/custom/cgov_site/modules/custom/cgov_core/src/CgovPurgeConfigInstaller.php @@ -28,6 +28,7 @@ class CgovPurgeConfigInstaller { private const PURGERS = [ 'acquia_purge' => '8813de186f', 'akamai_tag' => 'bf950143a3', + 'akamai' => '08153881ce', ]; /** diff --git a/docroot/sites/settings/cgov_caching.settings.php b/docroot/sites/settings/cgov_caching.settings.php index aa21cde106..140db5f7fd 100644 --- a/docroot/sites/settings/cgov_caching.settings.php +++ b/docroot/sites/settings/cgov_caching.settings.php @@ -7,14 +7,16 @@ * @see https://docs.acquia.com/site-factory/tiers/paas/workflow/hooks */ +require_once 'cgov_settings_utilities.inc'; + +$env = CGovSettingsUtil::getEnvironmentName(); +$domain = CGovSettingsUtil::getDomain(); + +// Set the domain for use when purging the cache. +$settings['cgdp.cache_url_host'] = 'https://' . $domain; + // Verify we're on an Acquia-hosted environment. -if (file_exists('/var/www/site-php') && isset($_ENV['AH_SITE_ENVIRONMENT'])) { - // Alter '01dev,' '01test', and '01live' to match - // your website's environment names. - $env = $_ENV['AH_SITE_ENVIRONMENT']; - if (preg_match('/^ode\d*$/', $env)) { - $env = 'ode'; - } +if (CGovSettingsUtil::isAcquia()) { $config['system.performance']['css']['preprocess'] = TRUE; $config['system.performance']['css']['gzip'] = TRUE; @@ -34,8 +36,11 @@ break; } - // Setup proper .edgerc path for Akamai module - $ah_group = isset($_ENV['AH_SITE_GROUP']) ? $_ENV['AH_SITE_GROUP'] : NULL; - $config['akamai.settings']['edgerc_path'] = "/mnt/gfs/home/$ah_group/common/.edgerc"; - + // ODEs are not behind Akamai, but everything else conceivably could be. + if ($env != 'ode') { + // Setup proper .edgerc path for Akamai module + $ah_group = isset($_ENV['AH_SITE_GROUP']) ? $_ENV['AH_SITE_GROUP'] : NULL; + $config['akamai.settings']['edgerc_path'] = "/mnt/gfs/home/$ah_group/common/.edgerc"; + $config['akamai.settings']['basepath'] = 'https://' . $domain; + } } diff --git a/docroot/sites/settings/cgov_core.settings.php b/docroot/sites/settings/cgov_core.settings.php index e70369c240..688d7c212a 100644 --- a/docroot/sites/settings/cgov_core.settings.php +++ b/docroot/sites/settings/cgov_core.settings.php @@ -7,6 +7,11 @@ * @see https://docs.acquia.com/site-factory/tiers/paas/workflow/hooks */ +require_once 'cgov_settings_utilities.inc'; + +$env = CGovSettingsUtil::getEnvironmentName(); +$domain = CGovSettingsUtil::getDomain(); + /* * Set the translation path to allow for easy management of third-party * translation files. The installer ignores the path for the initial install, @@ -20,40 +25,12 @@ $config['locale.settings']['translation']['use_source'] = 'local'; $config['locale.settings']['translation']['path'] = DRUPAL_ROOT . '/translations'; -// Pass in the correct ACSF site name to build the sitemap.xml. -// The base_url is picked up from, well, who knows what actually. It should be -// what is passed in for the --uri flag to drush for the cron, but then again -// it should appear as the site factory name? In any case we want to find the -// preferred domain, which should always be the public facing one. This is -// the name that shows on the card for the site. Anyway, you should always -// add that one as the first domain when creating a site, and then we will -// make sure that shows up in the sitemap.xml with the following code. -if ($is_acsf_env && $acsf_db_name) { - $domains = gardens_data_get_sites_from_file($GLOBALS['gardens_site_settings']['conf']['acsf_db_name']); - // Full disclosure, I don't know if the preferred_domain is always set. - $domain = array_keys($domains)[0]; - foreach ($domains as $site_name => $site_info) { - if (!empty($site_info['flags']['preferred_domain'])) { - $domain = $site_name; - } - } - $config['simple_sitemap.settings']['base_url'] = 'https://' . $domain; -} else { - // NOTE: you can override this in your local.settings.php. - $config['simple_sitemap.settings']['base_url'] = 'https://www.cancer.gov'; -} +// Pass in the correct domain name to build the sitemap.xml. +// NOTE: you can override this in your local.settings.php. +$config['simple_sitemap.settings']['base_url'] = 'https://' . $domain; -// Get our current environment -if (file_exists('/var/www/site-php') && isset($_ENV['AH_SITE_ENVIRONMENT'])) { - $env = $_ENV['AH_SITE_ENVIRONMENT']; - if (preg_match('/^ode\d*$/', $env)) { - $env = 'ode'; - } -} else { - $env = 'local'; -} // Settings for metatag attribute cgdp.domain. -if($is_acsf_env && $acsf_db_name) { +if(CGovSettingsUtil::isACSF()) { // For ACSF env. $acsf_domains = array_keys(gardens_data_get_sites_from_file($GLOBALS['gardens_site_settings'])); foreach ($acsf_domains as $domain_value) { @@ -73,10 +50,13 @@ $settings['cgdp_domain'] = $env; } -// on non-prod environments, route emails to logger +// On non-prod environments, override email settings. if ($env !== "01live") { - // route e-mails to the logger. + // Route e-mails to the logger. $config['system.mail']['interface']['default'] = 'cgov_mail_logger'; + // Change the contact form address. + $config['cgov_mail.settings']['contact_form_recipient'] = 'CancerGovTEST@nih.gov'; + $config['cgov_mail.settings']['es_contact_form_recipient'] = 'CancerGovTEST@nih.gov'; } // Outlook doesn't adhere to standards, so accommodating and using @@ -92,7 +72,7 @@ // Get the license dir from our current environment $licenseDir = '/var/licenses'; -if (file_exists('/var/www/site-php') && isset($_ENV['AH_SITE_ENVIRONMENT'])) { +if (CGovSettingsUtil::isAcquia()) { $licenseDir = "/mnt/files/{$_ENV['AH_SITE_GROUP']}.{$_ENV['AH_SITE_ENVIRONMENT']}/licenses"; } diff --git a/docroot/sites/settings/cgov_saml_auth_config.settings.php b/docroot/sites/settings/cgov_saml_auth_config.settings.php index efe7f5d379..1bad444415 100644 --- a/docroot/sites/settings/cgov_saml_auth_config.settings.php +++ b/docroot/sites/settings/cgov_saml_auth_config.settings.php @@ -5,10 +5,12 @@ * Set up SAML settings for Single Sign-On */ + require_once 'cgov_settings_utilities.inc'; + $samlDir = ""; // Get our current environment -if (file_exists('/var/www/site-php') && isset($_ENV['AH_SITE_ENVIRONMENT'])) { +if (CGovSettingsUtil::isAcquia()) { $samlDir = "/mnt/files/{$_ENV['AH_SITE_GROUP']}.{$_ENV['AH_SITE_ENVIRONMENT']}/saml"; } elseif (file_exists('/var/saml')) { $samlDir = "/var/saml"; diff --git a/docroot/sites/settings/cgov_settings_utilities.inc b/docroot/sites/settings/cgov_settings_utilities.inc new file mode 100644 index 0000000000..b239eca941 --- /dev/null +++ b/docroot/sites/settings/cgov_settings_utilities.inc @@ -0,0 +1,97 @@ + $site_info) { + if (!empty($site_info['flags']['preferred_domain'])) { + $domain = $site_name; + } + } + // For non-ACSF sites, the domain depends on the environment name. + } else { + $env = self::getEnvironmentName(); + switch ($env) { + case 'local': + $domain = 'www.devbox'; + break; + case 'ode': + $domain = 'ncigovcd' . $_ENV['AH_SITE_ENVIRONMENT'] . '.prod.acquia-sites.com'; + break; + // Other AC environments have a standard domain format. + default: + $domain = 'www-' . $env . '-ac.cancer.gov'; + break; + } + } + return $domain; + } +} + + diff --git a/patches/drupal/purge/3460094-2.diff b/patches/drupal/purge/3460094-2.diff new file mode 100644 index 0000000000..4bcdaecd14 --- /dev/null +++ b/patches/drupal/purge/3460094-2.diff @@ -0,0 +1,57 @@ +diff --git a/src/Drush/Commands/QueueCommands.php b/src/Drush/Commands/QueueCommands.php +index 38e64bc..604bb6b 100644 +--- a/src/Drush/Commands/QueueCommands.php ++++ b/src/Drush/Commands/QueueCommands.php +@@ -123,6 +123,12 @@ class QueueCommands extends DrushCommands implements SiteAliasManagerAwareInterf + * @hook init p:queue-add + */ + public function queueAddParseExpressions(InputInterface $input, AnnotationData $annotationData) { ++ // This hook is run twice for some reason, so skip if we have already run. ++ $hasinitHookRunAlready = static::initHookStaticVariable(); ++ if ($hasinitHookRunAlready) { ++ // Already run. ++ return; ++ } + $raw = trim(implode(" ", $input->getArguments()['expressions'])); + $expressions = []; + if ($raw) { +@@ -147,6 +153,15 @@ class QueueCommands extends DrushCommands implements SiteAliasManagerAwareInterf + $input->setArgument('expressions', $expressions); + } + ++ /** ++ * Reset static varaible so command can be called again in same request. ++ * ++ * @hook post-init p:queue-add ++ */ ++ public function queueAddParseExpressionsPostRun(InputInterface $input, AnnotationData $annotationData) { ++ static::initHookStaticVariable(TRUE); ++ } ++ + /** + * Add one or more items to the queue for later processing. + * +@@ -635,4 +650,23 @@ class QueueCommands extends DrushCommands implements SiteAliasManagerAwareInterf + return $result; + } + ++ /** ++ * Provide a init hook static variable tracker. Default return is FALSE. ++ * ++ * @param bool $reset ++ * Reset the staic varibale back to TRUE. Return is unaffected. ++ * ++ * @return bool ++ * The previous static, regardless if reset. ++ */ ++ protected static function initHookStaticVariable($reset = FALSE) { ++ static $hasInitHookRun = FALSE; ++ $old_state = $hasInitHookRun; ++ $hasInitHookRun = TRUE; ++ if ($reset) { ++ $hasInitHookRun = FALSE; ++ } ++ return $old_state; ++ } ++ + } diff --git a/patches/drupal/purge/3460094.diff b/patches/drupal/purge/3460094.diff new file mode 100644 index 0000000000..34d70d37a1 --- /dev/null +++ b/patches/drupal/purge/3460094.diff @@ -0,0 +1,63 @@ +diff --git a/composer.json b/composer.json +index 08b04a8..3d2a947 100644 +--- a/composer.json ++++ b/composer.json +@@ -12,11 +12,6 @@ + "extra": { + "branch-alias": { + "dev-8.x-3.x": "3.x-dev" +- }, +- "drush": { +- "services": { +- "drush.services.yml": ">=10" +- } + } + } + } +diff --git a/drush.services.yml b/drush.services.yml +deleted file mode 100644 +index f026873..0000000 +--- a/drush.services.yml ++++ /dev/null +@@ -1,41 +0,0 @@ +-services: +- purge_drush.debug_commands: +- class: Drupal\purge\Drush\Commands\DebugCommands +- arguments: ['@purge.logger'] +- tags: +- - { name: drush.command } +- purge_drush.diagnostics_command: +- class: Drupal\purge\Drush\Commands\DiagnosticsCommand +- arguments: ['@purge.diagnostics'] +- tags: +- - { name: drush.command } +- purge_drush.invalidate_command: +- class: Drupal\purge\Drush\Commands\InvalidateCommand +- arguments: ['@purge.invalidation.factory', '@purge.processors', '@purge.purgers'] +- tags: +- - { name: drush.command } +- purge_drush.processor_commands: +- class: Drupal\purge\Drush\Commands\ProcessorCommands +- arguments: ['@purge.processors'] +- tags: +- - { name: drush.command } +- purge_drush.purger_commands: +- class: Drupal\purge\Drush\Commands\PurgerCommands +- arguments: ['@purge.purgers'] +- tags: +- - { name: drush.command } +- purge_drush.queue_commands: +- class: Drupal\purge\Drush\Commands\QueueCommands +- arguments: ['@purge.processors', '@purge.purgers', '@purge.invalidation.factory', '@purge.queue', '@purge.queue.stats', '@purge.queuers'] +- tags: +- - { name: drush.command } +- purge_drush.queuer_commands: +- class: Drupal\purge\Drush\Commands\QueuerCommands +- arguments: ['@purge.queuers'] +- tags: +- - { name: drush.command } +- purge_drush.types_command: +- class: Drupal\purge\Drush\Commands\TypesCommand +- arguments: ['@purge.invalidation.factory', '@purge.purgers'] +- tags: +- - { name: drush.command }