diff --git a/PATCHES/user-expire-reset-activation-period.patch b/PATCHES/user-expire-reset-activation-period.patch new file mode 100644 index 000000000..199075b36 --- /dev/null +++ b/PATCHES/user-expire-reset-activation-period.patch @@ -0,0 +1,120 @@ +diff --git a/user_expire.module b/user_expire.module +index 4d01061f69b447cdefcd7d6b3e5bdaec09eed438..332ab12a88793eff57e233e298330721627aeb9c 100644 +--- a/user_expire.module ++++ b/user_expire.module +@@ -164,7 +164,7 @@ function user_expire_user_update(&$edit, $account, $category) { + function _user_expire_save($account) { + if (isset($account->user_expiration) && $account->user_expiration) { + if (is_array($account->user_expiration_date) && isset($account->user_expiration_date['month'])) { +- $time_for_datetime = $account->user_expiration_date['year'] . '-' . $account->user_expiration_date['month'] . '-' . $account->user_expiration_date['day']; ++ $time_for_datetime = $account->user_expiration_date['year'] . '-' . $account->user_expiration_date['month'] . '-' . $account->user_expiration_date['day']; + } + else { + $time_for_datetime = $account->user_expiration_date; +@@ -254,7 +254,6 @@ function user_expire_set_expiration($account, $expiration = NULL) { + if (!isset($account->is_new) || !$account->is_new) { + // New accounts can't have a record to delete. + // Existing records (!is_new) might. +- + // Remove user expiration times for this user. + $deleted = db_delete('user_expire') + ->condition('uid', $account->uid) +@@ -483,7 +482,7 @@ function user_expire_mail($key, &$message, $params) { + $message['body'][] = ''; + $message['body'][] = t('Thanks, @site_name', array('@site_name' => variable_get('site_name', 'Drupal.org'))); + } +- else if ($key == 'account_expired') { ++ elseif ($key == 'account_expired') { + // The subject. + $message['subject'] = t('@site_name: Account expired', array('@site_name' => variable_get('site_name', 'Drupal.org'))); + // The body. +@@ -499,3 +498,15 @@ function user_expire_mail($key, &$message, $params) { + $message['body'][] = t('Thanks, @site_name', array('@site_name' => variable_get('site_name', 'Drupal.org'))); + } + } ++ ++/** ++ * Implements hook_user_presave(). ++ * ++ * If the account was blocked but is now active, update the expiry so it is ++ * not re-blocked by the next cron run. ++ */ ++function user_expire_user_presave(&$edit, $account, $category) { ++ if (!empty($account->original) && $account->original->status == 0 && $edit['status'] == 1) { ++ $edit['access'] = REQUEST_TIME; ++ } ++} +diff --git a/user_expire.test b/user_expire.test +index cb9e3bdafc3ef27711b8d1b1c58ad4437257c97b..3d955a99e0c329b64fd837c7f28de875eb926eea 100644 +--- a/user_expire.test ++++ b/user_expire.test +@@ -4,6 +4,9 @@ + * Tests for User expire module. + */ + ++/** ++ * {@inheritdoc} ++ */ + class UserExpireTestCase extends DrupalWebTestCase { + /** + * Implements getInfo(). +@@ -17,6 +20,9 @@ class UserExpireTestCase extends DrupalWebTestCase { + ); + } + ++ /** ++ * {@inheritdoc} ++ */ + public function setUp() { + // Enable User Expire module. + parent::setUp('user_expire'); +@@ -30,11 +36,14 @@ class UserExpireTestCase extends DrupalWebTestCase { + 'administer users', + 'set user expiration', + 'view expiring users report', +- 'administer user expire settings' ++ 'administer user expire settings', + )); + } + +- function testUserExpire() { ++ /** ++ * Run all user_expire tests. ++ */ ++ public function testUserExpire() { + $this->assertTrue($this->basic_account->status, t('User account is currently enabled.')); + user_expire_set_expiration($this->basic_account, REQUEST_TIME - 1); + user_expire_expire_users(array($this->basic_account)); +@@ -142,7 +151,7 @@ class UserExpireTestCase extends DrupalWebTestCase { + user_expire_expire_by_role(); + + // Ensure they are still enabled. +- $this->drupalGet("user/$new_basic_account->uid/edit"); ++ $this->drupalGet("user/{$new_basic_account->uid}/edit"); + $this->assertRaw('type="radio" id="edit-status-1" name="status" value="1" checked="checked" class="form-radio"', t('New user account stays active.')); + + // Age the new user's created by 90+ days. +@@ -151,9 +160,21 @@ class UserExpireTestCase extends DrupalWebTestCase { + // Process it. + user_expire_expire_by_role(); + +- // Ensure they are disabled +- $this->drupalGet("user/$new_basic_account->uid/edit"); ++ // Ensure they are disabled. ++ $this->drupalGet("user/{$new_basic_account->uid}/edit"); + $this->assertRaw('type="radio" id="edit-status-0" name="status" value="0" checked="checked" class="form-radio"', t('User account is currently disabled.')); + ++ // Manually unblock the user. ++ $edit = array(); ++ $edit['status'] = 1; ++ $this->drupalPost("user/{$new_basic_account->uid}/edit", $edit, t('Save')); ++ ++ // Process it. ++ user_expire_expire_by_role(); ++ ++ // Ensure they are still active. ++ $this->drupalGet("user/{$new_basic_account->uid}/edit"); ++ $this->assertRaw('type="radio" id="edit-status-1" name="status" value="1" checked="checked" class="form-radio"', $this->t('User account is currently active.')); + } ++ + } diff --git a/composer.lock b/composer.lock index 0d4dd0dc1..ed51fae2c 100644 --- a/composer.lock +++ b/composer.lock @@ -1508,17 +1508,17 @@ }, { "name": "drupal/context", - "version": "3.11.0", + "version": "3.12.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/context.git", - "reference": "7.x-3.11" + "reference": "7.x-3.12" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/context-7.x-3.11.zip", - "reference": "7.x-3.11", - "shasum": "7b577980af28d264eeb071b5fab97ec8603296dd" + "url": "https://ftp.drupal.org/files/projects/context-7.x-3.12.zip", + "reference": "7.x-3.12", + "shasum": "c69d450179fbbb0241be29a37b19e09102d408eb" }, "require": { "drupal/ctools": "*", @@ -1527,8 +1527,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "7.x-3.11", - "datestamp": "1658944702", + "version": "7.x-3.12", + "datestamp": "1675905573", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -1766,24 +1766,23 @@ }, { "name": "drupal/ctools", - "version": "1.20.0", + "version": "1.21.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/ctools.git", - "reference": "7.x-1.20" + "reference": "7.x-1.21" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/ctools-7.x-1.20.zip", - "reference": "7.x-1.20", - "shasum": "695e3ac7705d4de343bfd0b7183706fa3203fa52" + "url": "https://ftp.drupal.org/files/projects/ctools-7.x-1.21.zip", + "reference": "7.x-1.21", + "shasum": "005d39917737407efd1a730ef2e2e082227e13c7" }, "require": { "drupal/drupal": "~7.0" }, "require-dev": { "drupal/advanced_help": "*", - "drupal/color-color": "*", "drupal/page_manager": "*", "drupal/panels": "*", "drupal/views": "*" @@ -1791,8 +1790,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "7.x-1.20", - "datestamp": "1642577344", + "version": "7.x-1.21", + "datestamp": "1675152415", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -2394,10 +2393,6 @@ "reference": "7.94", "shasum": "4d732bbf9b50a5076e8c353cd77d1a4e879d94a4" }, - "require-dev": { - "drupal/color-color": "*", - "drupal/rdf": "*" - }, "type": "drupal-core", "extra": { "drupal": { @@ -5270,17 +5265,17 @@ }, { "name": "drupal/jquery_update", - "version": "4.0.0", + "version": "4.1.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/jquery_update.git", - "reference": "7.x-4.0" + "reference": "7.x-4.1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/jquery_update-7.x-4.0.zip", - "reference": "7.x-4.0", - "shasum": "3ff1a393c244f506052a26d9cc59020e3661449e" + "url": "https://ftp.drupal.org/files/projects/jquery_update-7.x-4.1.zip", + "reference": "7.x-4.1", + "shasum": "c555b66fc3b353f7045c4004db858c3a75e4fab5" }, "require": { "drupal/drupal": "~7.0" @@ -5288,8 +5283,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "7.x-4.0", - "datestamp": "1669044747", + "version": "7.x-4.1", + "datestamp": "1675437622", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5646,26 +5641,29 @@ }, { "name": "drupal/linkchecker", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/linkchecker.git", - "reference": "7.x-1.4" + "reference": "7.x-1.5" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/linkchecker-7.x-1.4.zip", - "reference": "7.x-1.4", - "shasum": "aa0f20ccb135d4585433289b70dd2dd5dafa1979" + "url": "https://ftp.drupal.org/files/projects/linkchecker-7.x-1.5.zip", + "reference": "7.x-1.5", + "shasum": "4f63f46b9a55e8dad14923805beceacde8735067" }, "require": { "drupal/drupal": "~7.0" }, + "require-dev": { + "drupal/bean": "*" + }, "type": "drupal-module", "extra": { "drupal": { - "version": "7.x-1.4", - "datestamp": "1534714680", + "version": "7.x-1.5", + "datestamp": "1674441216", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5688,6 +5686,10 @@ { "name": "hass", "homepage": "https://www.drupal.org/user/85918" + }, + { + "name": "VladimirAus", + "homepage": "https://www.drupal.org/user/673120" } ], "description": "Periodically checks for broken links in node types, blocks and fields and reports the results.", @@ -7161,7 +7163,7 @@ }, { "name": "drupal/page_manager", - "version": "1.20.0", + "version": "1.21.0", "require": { "drupal/ctools": "*", "drupal/drupal": "~7.0" @@ -7169,8 +7171,8 @@ "type": "metapackage", "extra": { "drupal": { - "version": "7.x-1.20", - "datestamp": "1642577344", + "version": "7.x-1.21", + "datestamp": "1675152415", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -10480,13 +10482,13 @@ "GPL-2.0-or-later" ], "authors": [ - { - "name": "RickJ", - "homepage": "https://www.drupal.org/user/3371606" - }, { "name": "killua99", "homepage": "https://www.drupal.org/user/699418" + }, + { + "name": "RickJ", + "homepage": "https://www.drupal.org/user/3371606" } ], "description": "Views plugin to export a view as a PDF file.", diff --git a/composer.patches.json b/composer.patches.json index 8351d5fa4..1d5ff665b 100644 --- a/composer.patches.json +++ b/composer.patches.json @@ -104,7 +104,7 @@ "Disable entity loading 2": "PATCHES/shs_lazyload_2.patch" }, "drupal/user_expire": { - "If a user is activated, deactivated by the module, and reactivated by an admin, reset their expiration period": "https://git.drupalcode.org/project/user_expire/-/merge_requests/8.diff", + "If a user is activated, deactivated by the module, and reactivated by an admin, reset their expiration period": "PATCHES/user-expire-reset-activation-period.patch", "OPS-8147: Customise the expiry email text": "PATCHES/user-expire-2836514-mails-hack.patch" } } diff --git a/docker/Dockerfile b/docker/Dockerfile index c34dac2e7..45d6c38b7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /srv/www RUN composer self-update && \ composer install --quiet --no-dev --prefer-dist -FROM public.ecr.aws/unocha/php-k8s:${TAG:-7.4-NR-stable} +FROM public.ecr.aws/unocha/php-k8s:7.4-stable ARG VCS_REF ARG VCS_URL @@ -33,6 +33,7 @@ COPY --from=builder /srv/www/vendor /srv/www/vendor COPY --from=builder /srv/www/composer.json /srv/www/composer.json COPY --from=builder /srv/www/composer.lock /srv/www/composer.lock COPY --from=builder /srv/www/composer.patches.json /srv/www/composer.patches.json +COPY --from=builder /srv/www/docker/fastcgi_drupal.conf /etc/nginx/apps/drupal/fastcgi_drupal.conf COPY --from=builder /srv/www/docker/custom /etc/nginx/custom RUN cd /srv/www/html/sites && \ diff --git a/docker/fastcgi_drupal.conf b/docker/fastcgi_drupal.conf new file mode 100644 index 000000000..be59f8516 --- /dev/null +++ b/docker/fastcgi_drupal.conf @@ -0,0 +1,43 @@ +#-*- mode: nginx; mode: flyspell-prog; ispell-local-dictionary: "american" -*- +### fastcgi configuration for serving private files. +## 1. Parameters. +fastcgi_param QUERY_STRING q=$uri&$args; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_NAME /index.php; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; +## PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; +fastcgi_param SCRIPT_FILENAME $document_root/index.php; +## HTTPS 'on' parameter. This requires Nginx version 1.1.11 or +## later. The if_not_empty flag was introduced in 1.1.11. See: +## http://nginx.org/en/CHANGES. If using a version that doesn't +## support this comment out the line below. +fastcgi_param HTTPS $fastcgi_https if_not_empty; +## For Nginx versions below 1.1.11 uncomment the line below after commenting out the above. +#fastcgi_param HTTPS $fastcgi_https; + +## 2. Nginx FCGI specific directives. +fastcgi_buffers 256 4k; +fastcgi_intercept_errors on; +## Allow 4 hrs - pass timeout responsibility to upstream. +fastcgi_read_timeout 14400; +fastcgi_index index.php; +## Hide the X-Drupal-Cache header provided by Pressflow. +fastcgi_hide_header 'X-Drupal-Cache'; +## Hide the Drupal 7 header X-Generator. +fastcgi_hide_header 'X-Generator'; diff --git a/html/sites/all/modules/contrib/context/context.info b/html/sites/all/modules/contrib/context/context.info index 9280e938a..4b1801954 100644 --- a/html/sites/all/modules/contrib/context/context.info +++ b/html/sites/all/modules/contrib/context/context.info @@ -8,8 +8,8 @@ files[] = tests/context.test files[] = tests/context.conditions.test files[] = tests/context.reactions.test -; Information added by Drupal.org packaging script on 2022-07-26 -version = "7.x-3.11" +; Information added by Drupal.org packaging script on 2023-02-09 +version = "7.x-3.12" core = "7.x" project = "context" -datestamp = "1658874334" +datestamp = "1675905575" diff --git a/html/sites/all/modules/contrib/context/context.module b/html/sites/all/modules/contrib/context/context.module index c83b15ef2..93e95ba9e 100644 --- a/html/sites/all/modules/contrib/context/context.module +++ b/html/sites/all/modules/contrib/context/context.module @@ -527,7 +527,7 @@ function context_empty($element) { /** * Get a plugin handler. */ -function context_get_plugin($type = 'condition', $key, $reset = FALSE) { +function context_get_plugin($type, $key, $reset = FALSE) { static $cache = array(); if (!isset($cache[$type][$key]) || $reset) { switch ($type) { diff --git a/html/sites/all/modules/contrib/context/context_layouts/context_layouts.info b/html/sites/all/modules/contrib/context/context_layouts/context_layouts.info index a3e18bffc..d047ec4c6 100644 --- a/html/sites/all/modules/contrib/context/context_layouts/context_layouts.info +++ b/html/sites/all/modules/contrib/context/context_layouts/context_layouts.info @@ -6,8 +6,8 @@ core = 7.x files[] = plugins/context_layouts_reaction_block.inc -; Information added by Drupal.org packaging script on 2022-07-26 -version = "7.x-3.11" +; Information added by Drupal.org packaging script on 2023-02-09 +version = "7.x-3.12" core = "7.x" project = "context" -datestamp = "1658874334" +datestamp = "1675905575" diff --git a/html/sites/all/modules/contrib/context/context_ui/context_ui.info b/html/sites/all/modules/contrib/context/context_ui/context_ui.info index 8f282f3e3..83fd05708 100644 --- a/html/sites/all/modules/contrib/context/context_ui/context_ui.info +++ b/html/sites/all/modules/contrib/context/context_ui/context_ui.info @@ -8,8 +8,8 @@ configure = admin/structure/context files[] = context.module files[] = tests/context_ui.test -; Information added by Drupal.org packaging script on 2022-07-26 -version = "7.x-3.11" +; Information added by Drupal.org packaging script on 2023-02-09 +version = "7.x-3.12" core = "7.x" project = "context" -datestamp = "1658874334" +datestamp = "1675905575" diff --git a/html/sites/all/modules/contrib/context/plugins/context_condition_context_all.inc b/html/sites/all/modules/contrib/context/plugins/context_condition_context_all.inc index faecbb346..ad4c0fc1a 100644 --- a/html/sites/all/modules/contrib/context/plugins/context_condition_context_all.inc +++ b/html/sites/all/modules/contrib/context/plugins/context_condition_context_all.inc @@ -13,8 +13,18 @@ class context_condition_context_all extends context_condition_path { // and have values set. if (!in_array($context->name, $active_contexts, TRUE) && $values = $this->fetch_from_context($context, 'values')) { + $contexts_matched = 0; + + // Count the matched contexts + foreach($values as $value) { + // Always check against the active contexts. + if ($this->match(array_keys(context_active_contexts()), array($value))) { + $contexts_matched++; + } + } + // The condition is met if all contexts are active. - if (count(array_intersect($values, $active_contexts)) == count($values)) { + if ($contexts_matched == count($values)) { $this->condition_met($context); } } @@ -26,4 +36,46 @@ class context_condition_context_all extends context_condition_path { } } } + + /** + * Retrieve all context conditions. + * + * This method is slightly adapted to context_condition::get_contexts() in + * order to ensure that a context that is used as condition in another context + * gets handled before. + */ + function get_contexts($value = NULL) { + $map = context_condition_map(); + $map = isset($map[$this->plugin]) ? $map[$this->plugin] : array(); + + $contexts = array(); + + // Add the contexts that are needed for conditions in the other contexts + // first. Start with the negated ones first, as we can not unset a met + // condition afterwards. + krsort($map); + foreach ($map as $key => $submap) { + // Negated context conditions start with a "~". + if (substr($key, 0, 1) == "~") { + $key = substr($key, 1); + } + if (!isset($contexts[$key])) { + $context = context_load($key); + // Check if context exists. This will fail for wildcards. + if ($context) { + $contexts[$context->name] = $context; + } + } + } + foreach ($map as $key => $submap) { + foreach ($submap as $name) { + if (!isset($contexts[$name])) { + $context = context_load($name); + $contexts[$context->name] = $context; + } + } + } + + return $contexts; + } } diff --git a/html/sites/all/modules/contrib/context/plugins/context_condition_user.inc b/html/sites/all/modules/contrib/context/plugins/context_condition_user.inc index f7184f007..a6d62ccca 100644 --- a/html/sites/all/modules/contrib/context/plugins/context_condition_user.inc +++ b/html/sites/all/modules/contrib/context/plugins/context_condition_user.inc @@ -20,12 +20,45 @@ class context_condition_user extends context_condition { return $values; } + function options_form($context) { + $defaults = $this->fetch_from_context($context, 'options'); + return array( + 'negate_role' => array( + '#title' => t('Make role a negative condition'), + '#type' => 'checkbox', + '#description' => t("Checking this box will make this condition fire if the user's role is NOT one of the role's checked"), + '#default_value' => isset($defaults['negate_role']) ? $defaults['negate_role'] : 0, + ), + ); + } + function execute($account) { - $roles = $account->roles; - foreach ($roles as $rid => $role) { + $all_roles = user_roles(); + $users_roles = $account->roles; + foreach ($all_roles as $rid => $role) { foreach ($this->get_contexts($role) as $context) { - $this->condition_met($context, $role); + $options = $this->fetch_from_context($context, 'options'); + if (empty($options['negate_role'])) { + if (in_array($role, $users_roles)){ + $this->condition_met($context, $role); + } + } + else { + $negate_flag = TRUE; + foreach ($this->fetch_from_context($context, 'values') as $nid => $negated_role) { + if (!in_array($negated_role, $users_roles)) { + $negate_flag &= TRUE; + } + else { + $negate_flag &= FALSE; + } + } + if ($negate_flag) { + $this->condition_met($context, $role); + } + } } } } + } diff --git a/html/sites/all/modules/contrib/context/plugins/context_reaction_block.js b/html/sites/all/modules/contrib/context/plugins/context_reaction_block.js index 42bcdfa5f..8d1042c1d 100644 --- a/html/sites/all/modules/contrib/context/plugins/context_reaction_block.js +++ b/html/sites/all/modules/contrib/context/plugins/context_reaction_block.js @@ -425,7 +425,7 @@ DrupalContextBlockEditor.prototype = { $('a.context_ui_dialog-stop').hide(); $('.editing-context-label').remove(); - var label = $('#context-editable-trigger-'+context+' .label').text(); + var label = $('#context-editable-trigger-'+context+' .label.top').text(); label = Drupal.t('Now editing: @label', {'@label': label}); editor.parent().parent().prepend('