From e42d7a7dc2a88cc191c04dfd2d8825af116cf746 Mon Sep 17 00:00:00 2001 From: christian medders Date: Wed, 18 Dec 2024 10:51:05 -0500 Subject: [PATCH 01/17] DIGITAL-239: init work for custom logout --- .../config/install/dg_autologout.settings.yml | 21 + .../config/schema/dg_autologout.schema.yml | 92 +++ .../dg_autologout/dg_autologout.api.php | 59 ++ .../dg_autologout.config_translation.yml | 5 + .../dg_autologout/dg_autologout.info.yml | 12 + .../dg_autologout/dg_autologout.install | 64 +++ .../dg_autologout/dg_autologout.libraries.yml | 10 + .../dg_autologout.links.menu.yml | 6 + .../dg_autologout.links.task.yml | 4 + .../custom/dg_autologout/dg_autologout.module | 355 ++++++++++++ .../dg_autologout.permissions.yml | 4 + .../dg_autologout/dg_autologout.routing.yml | 41 ++ .../dg_autologout/dg_autologout.services.yml | 12 + .../custom/dg_autologout/js/dg_autologout.js | 372 ++++++++++++ .../Controller/dg_AutologoutController.php | 150 +++++ .../dg_AutologoutSubscriber.php | 206 +++++++ .../src/Form/dg_AutologoutBlockForm.php | 77 +++ .../src/Form/dg_AutologoutSettingsForm.php | 529 ++++++++++++++++++ .../Block/dg_AutologoutWarningBlock.php | 144 +++++ .../destination/dg_ConfigAutologoutRoles.php | 38 ++ .../migrate/source/d6/dg_AutologoutRoles.php | 15 + .../migrate/source/d7/dg_AutologoutRoles.php | 15 + .../migrate/source/dg_AutologoutRoles.php | 77 +++ .../src/dg_AutologoutManager.php | 374 +++++++++++++ .../src/dg_AutologoutManagerInterface.php | 110 ++++ 25 files changed, 2792 insertions(+) create mode 100644 web/modules/custom/dg_autologout/config/install/dg_autologout.settings.yml create mode 100644 web/modules/custom/dg_autologout/config/schema/dg_autologout.schema.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.api.php create mode 100644 web/modules/custom/dg_autologout/dg_autologout.config_translation.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.info.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.install create mode 100644 web/modules/custom/dg_autologout/dg_autologout.libraries.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.links.menu.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.links.task.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.module create mode 100644 web/modules/custom/dg_autologout/dg_autologout.permissions.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.routing.yml create mode 100644 web/modules/custom/dg_autologout/dg_autologout.services.yml create mode 100644 web/modules/custom/dg_autologout/js/dg_autologout.js create mode 100644 web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php create mode 100644 web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php create mode 100644 web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php create mode 100644 web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php create mode 100644 web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php create mode 100644 web/modules/custom/dg_autologout/src/Plugin/migrate/destination/dg_ConfigAutologoutRoles.php create mode 100644 web/modules/custom/dg_autologout/src/Plugin/migrate/source/d6/dg_AutologoutRoles.php create mode 100644 web/modules/custom/dg_autologout/src/Plugin/migrate/source/d7/dg_AutologoutRoles.php create mode 100644 web/modules/custom/dg_autologout/src/Plugin/migrate/source/dg_AutologoutRoles.php create mode 100644 web/modules/custom/dg_autologout/src/dg_AutologoutManager.php create mode 100644 web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php diff --git a/web/modules/custom/dg_autologout/config/install/dg_autologout.settings.yml b/web/modules/custom/dg_autologout/config/install/dg_autologout.settings.yml new file mode 100644 index 00000000..d3d77086 --- /dev/null +++ b/web/modules/custom/dg_autologout/config/install/dg_autologout.settings.yml @@ -0,0 +1,21 @@ +enabled: true +timeout: 1800 +max_timeout: 172800 +padding: 20 +logout_regardless_of_activity: false +no_individual_logout_threshold: false +role_logout: false +role_logout_max: false +redirect_url: /user/login +include_destination: true +no_dialog: false +message: 'We are about to log you out for inactivity. If we do, you will lose any unsaved work. Do you need more time?' +inactivity_message: 'You have been logged out due to inactivity.' +inactivity_message_type: status +modal_width: 450 +enforce_admin: false +jstimer_format: '%hours%:%mins%:%secs%' +jstimer_js_load_option: false +use_alt_logout_method: false +use_watchdog: true +whitelisted_ip_addresses: '' diff --git a/web/modules/custom/dg_autologout/config/schema/dg_autologout.schema.yml b/web/modules/custom/dg_autologout/config/schema/dg_autologout.schema.yml new file mode 100644 index 00000000..9eede2ab --- /dev/null +++ b/web/modules/custom/dg_autologout/config/schema/dg_autologout.schema.yml @@ -0,0 +1,92 @@ +dg_autologout.settings: + type: config_object + mapping: + enabled: + type: boolean + label: 'Enable autologout' + timeout: + type: integer + label: 'Timeout value' + max_timeout: + type: integer + label: 'Max timeout value' + padding: + type: integer + label: 'Seconds to give a user to respond' + logout_regardless_of_activity: + type: boolean + label: 'Logout user regardless of activity' + no_individual_logout_threshold: + type: boolean + label: 'Disable user-specific logout thresholds' + role_logout: + type: boolean + label: 'Enable role timeout' + role_logout_max: + type: boolean + label: 'Use highest role timeout value' + redirect_url: + type: string + label: 'Redirect url' + include_destination: + type: boolean + label: 'Include destination' + no_dialog: + type: boolean + label: 'Integer label' + message: + type: text + label: 'Message to display' + inactivity_message: + type: text + label: 'Message displayed after logging out' + inactivity_message_type: + type: string + label: 'Type of the message displayed' + modal_width: + type: integer + label: 'Modal width' + enforce_admin: + type: boolean + label: 'Enable admin logout' + jstimer_format: + type: string + label: 'JS timer format' + jstimer_js_load_option: + type: boolean + label: 'JS timer load' + use_alt_logout_method: + type: boolean + label: 'Use alternate logout methode' + use_watchdog: + type: boolean + label: 'Use watchdog' + dialog_title: + type: label + label: 'Title' + disable_buttons: + type: boolean + label: 'Disable buttons' + yes_button: + type: label + label: 'Yes button text' + no_button: + type: label + label: 'No button text' + whitelisted_ip_addresses: + type: string + label: 'Whitelisted IP addresses' + +dg_autologout.role.*: + type: config_object + label: 'Role Settings' + mapping: + enabled: + type: boolean + label: 'Enabled' + timeout: + type: integer + label: 'Timeout' + url: + type: string + label: 'redirect_url' diff --git a/web/modules/custom/dg_autologout/dg_autologout.api.php b/web/modules/custom/dg_autologout/dg_autologout.api.php new file mode 100644 index 00000000..5027bf0c --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.api.php @@ -0,0 +1,59 @@ +isAdminRoute(routeMatch()->getRouteObject()) && !\Drupal::config('dg_autologout.settings')->get('enforce_admin')) { + return TRUE; + } +} + +/** + * React right after user has been logged out via dg_autologout. + * + * This hook fires only when user is logged out via dg_autologout, not when the + * user logs themselves out. This is fired after the session has been destroyed + * and the active user has been set to anonymous. + */ +function hook_dg_autologout_user_logout() { +} diff --git a/web/modules/custom/dg_autologout/dg_autologout.config_translation.yml b/web/modules/custom/dg_autologout/dg_autologout.config_translation.yml new file mode 100644 index 00000000..da55b1ea --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.config_translation.yml @@ -0,0 +1,5 @@ +dg_autologout.config: + title: 'Digital.gov Autologout' + base_route_name: dg_autologout.set_admin + names: + - dg_autologout.settings diff --git a/web/modules/custom/dg_autologout/dg_autologout.info.yml b/web/modules/custom/dg_autologout/dg_autologout.info.yml new file mode 100644 index 00000000..d003a0e8 --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.info.yml @@ -0,0 +1,12 @@ +name: Digital.gov Automated Logout +type: module +description: 'Adds automated timed logout.' +core_version_requirement: ^9.2 || ^10 || ^11 +configure: dg_autologout.set_admin +dependencies: + - js_cookie:js_cookie + +# Information added by Drupal.org packaging script on 2024-11-22 +version: '2.0.1' +project: 'dg_autologout' +datestamp: 1732235108 diff --git a/web/modules/custom/dg_autologout/dg_autologout.install b/web/modules/custom/dg_autologout/dg_autologout.install new file mode 100644 index 00000000..e9b9c1e4 --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.install @@ -0,0 +1,64 @@ +select('config', 'c') + ->fields('c', ['name', 'data']) + ->condition('name', 'dg_autologout.user.%', 'LIKE') + ->execute()->fetchAll(); + if (!isset($sandbox['current'])) { + $sandbox['current'] = 0; + $sandbox['max'] = count($result); + } + $limit = 5; + $result = array_slice($result, $sandbox['current'], $limit); + foreach ($result as $row) { + $key = $row->name; + // User uid is a part of the key after. E.g. dg_autologout.user.1 for user 1. + $user_id = (substr($key, 16)); + $data = unserialize($row->data); + \Drupal::service('user.data')->set('dg_autologout', $user_id, 'timeout', $data['timeout']); + \Drupal::service('user.data')->set('dg_autologout', $user_id, 'enabled', $data['enabled']); + $sandbox['current']++; + } + $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']); + if ($sandbox['#finished'] >= 1) { + return t('Autologout settings are successfully updated. Updated @users', ["@users" => $sandbox['max']]); + } +} + +/** + * Configure default value for dialog title. + */ +function dg_autologout_update_8002(&$sandbox) { + $dg_autologout_settings = \Drupal::service('config.factory')->getEditable('dg_autologout.settings'); + $default_dialog_title = \Drupal::config('system.site')->get('name') . ' Alert'; + $dg_autologout_settings->set('dialog_title', $default_dialog_title)->save(); +} + +/** + * Store default value for setting 'Disable user-specific logout thresholds'. + */ +function dg_autologout_update_8003(&$sandbox) { + $config_factory = \Drupal::configFactory(); + $config = $config_factory->getEditable('dg_autologout.settings'); + $config->set('no_individual_logout_threshold', FALSE); + $config->save(TRUE); +} + +/** + * Make sure the js_cookie dependency is enabled. + */ +function dg_autologout_update_9201(&$sandbox): void { + \Drupal::service('module_installer')->install(['js_cookie']); +} diff --git a/web/modules/custom/dg_autologout/dg_autologout.libraries.yml b/web/modules/custom/dg_autologout/dg_autologout.libraries.yml new file mode 100644 index 00000000..d977410c --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.libraries.yml @@ -0,0 +1,10 @@ +drupal.dg_autologout: + version: VERSION + js: + js/dg_autologout.js: {} + + dependencies: + - core/drupal.dialog + - core/drupal.ajax + - core/drupalSettings + - js_cookie/js-cookie diff --git a/web/modules/custom/dg_autologout/dg_autologout.links.menu.yml b/web/modules/custom/dg_autologout/dg_autologout.links.menu.yml new file mode 100644 index 00000000..0b454033 --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.links.menu.yml @@ -0,0 +1,6 @@ +dg_autologout.set_admin: + title: 'Digital.gov Automated logout settings' + parent: user.admin_index + description: 'Configure default automated logout settings.' + weight: -10 + route_name: dg_autologout.set_admin diff --git a/web/modules/custom/dg_autologout/dg_autologout.links.task.yml b/web/modules/custom/dg_autologout/dg_autologout.links.task.yml new file mode 100644 index 00000000..3965e77f --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.links.task.yml @@ -0,0 +1,4 @@ +dg_autologout.set_admin: + title: 'Digital.gov Automated logout settings' + route_name: dg_autologout.set_admin + base_route: dg_autologout.set_admin diff --git a/web/modules/custom/dg_autologout/dg_autologout.module b/web/modules/custom/dg_autologout/dg_autologout.module new file mode 100644 index 00000000..b844ecce --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.module @@ -0,0 +1,355 @@ +getUserTimeout(); + $output = ''; + $output .= '

' . t('About') . '

'; + $output .= '

' . t("This module allows you to force site users to be logged out after a given amount of time due to inactivity after first being presented with a confirmation dialog. Your current logout threshold is %seconds seconds.", ['%seconds' => $seconds]) . '

'; + return $output; + } +} + +/** + * Implements hook_form_FORM_ID_alter(). + * + * Adds a field to user/edit to change that users logout. + */ +function dg_autologout_form_user_form_alter(&$form, FormStateInterface $form_state) { + $user = \Drupal::currentUser(); + $account = $form_state->getFormObject()->getEntity(); + $user_id = $account->id(); + $access = FALSE; + + // If user-specific thresholds are enabled (the default), and user has access + // to change and they are changing their own and only + // their own timeout, or they are an admin. + if (!\Drupal::config('dg_autologout.settings')->get('no_individual_logout_threshold') && !\Drupal::currentUser()->isAnonymous() && (($user->hasPermission('change own logout threshold') && $user->id() == $user_id) || $user->hasPermission('administer dg_autologout'))) { + $access = TRUE; + + if ($user_id !== NULL) { + $dg_autologout_data = \Drupal::service('user.data')->get('dg_autologout', $user_id, 'timeout'); + } + } + + if ($access) { + $max_timeout = \Drupal::config('dg_autologout.settings')->get('max_timeout'); + $form['user_' . $user_id] = [ + '#type' => 'textfield', + '#title' => t('Your current logout threshold'), + '#default_value' => $dg_autologout_data ?? '', + '#size' => 8, + '#description' => t('The length of inactivity time, in seconds, before automated log out. Must be between 60 and @max_timeout seconds.', ['@max_timeout' => $max_timeout]), + '#element_validate' => ['_dg_autologout_user_uid_timeout_validate'], + ]; + + $form['actions']['submit']['#submit'][] = 'dg_autologout_user_profile_submit'; + } +} + +/** + * Form validation. + */ +function _dg_autologout_user_uid_timeout_validate($element, FormStateInterface $form_state) { + $max_timeout = \Drupal::config('dg_autologout.settings')->get('max_timeout'); + $timeout = $element['#value']; + + // Set error if timeout isn't strictly a number between 60 and max. + if ($timeout != "" && ($timeout < 10 || ($timeout > 0 && $timeout < 60) || $timeout > $max_timeout || !is_numeric($timeout))) { + $form_state->setError($element, t('The timeout must be an integer greater than 60, and less then %max.', ['%max' => $max_timeout])); + } +} + +/** + * Handle submission of timeout threshold in user/edit. + */ +function dg_autologout_user_profile_submit(&$form, FormStateInterface $form_state) { + $user = \Drupal::currentUser(); + $user_id = $form_state->getFormObject()->getEntity()->id(); + $access = FALSE; + + // If user-specific thresholds are enabled (the default), and user has access + // to change and they are changing their own and only + // their own timeout, or they are an admin. + if (!\Drupal::currentUser()->isAnonymous() && (($user->hasPermission('change own logout threshold') && $user->id() == $user_id) || $user->hasPermission('administer dg_autologout'))) { + $access = TRUE; + } + + // Access is reused here as a security measure. Not only will the element not + // display but wont submit without access. + // Do not store config if setting to not store config for every user is TRUE. + if ($access && !\Drupal::config('dg_autologout.settings')->get('no_individual_logout_threshold')) { + $timeout = $form_state->getValue('user_' . $user_id); + \Drupal::service('user.data')->set('dg_autologout', $user_id, 'timeout', $timeout); + } + else { + $timeout = \Drupal::config('dg_autologout.settings')->get('timeout'); + \Drupal::service('user.data')->set('dg_autologout', $user_id, 'timeout', $timeout); + } +} + +/** + * Implements hook_dg_autologout_prevent(). + */ +function dg_autologout_dg_autologout_prevent() { + $user = \Drupal::currentUser(); + $user_ip = \Drupal::request()->getClientIp(); + + // Don't include dg_autologout JS checks on ajax callbacks. + $paths = [ + 'system', + 'dg_autologout_ajax_get_time_left', + 'dg_autologout_ajax_logout', + 'dg_autologout_ajax_set_last', + ]; + // getPath is used because Url::fromRoute('')->toString() doesn't + // give correct path for XHR request. + $url = \Drupal::service('path.current')->getPath(); + $path_args = explode('/', $url); + + // Check if user IP address is in the whitelist. + $ip_address_whitelist = array_map('trim', + explode("\n", trim(\Drupal::config('dg_autologout.settings')->get('whitelisted_ip_addresses') ?: '')) + ); + + if (in_array($path_args[1], $paths)) { + return TRUE; + } + + // If user is anonymous. + if ($user->id() == 0) { + return TRUE; + } + + // If user has no timeout set. + if (\Drupal::service('dg_autologout.manager')->getUserTimeout() === 0) { + dg_autologout_check_session_variable(); + return TRUE; + } + + // If the user has checked remember_me via the remember_me module. + $remember_me = \Drupal::service('user.data')->get('remember_me', $user->id(), 'remember_me'); + if (!empty($remember_me)) { + return TRUE; + } + // If the user has checked Remember me on the login page via + // the persistent_login module. + if (\Drupal::hasService('persistent_login.token_manager')) { + $request = \Drupal::request(); + // Get cookie from request. + $cookie = \Drupal::service('persistent_login.cookie_helper')->getCookieValue($request); + if (isset($cookie)) { + // Get all user's tokens. + $rememberPersistentTokens = \Drupal::service('persistent_login.token_manager')->getTokensForUser(User::load($user->id())); + $count = count($rememberPersistentTokens); + if ($count > 0) { + // Get current token. + $currentToken = \Drupal::service('persistent_login.token_handler')->getTokenFromCookie($request); + foreach ($rememberPersistentTokens as $value) { + if (1 == $value->getStatus() && $value->getSeries() == $currentToken->getSeries()) { + return TRUE; + } + } + } + } + } + if (in_array($user_ip, $ip_address_whitelist)) { + dg_autologout_check_session_variable(); + return TRUE; + } + + return FALSE; +} + +/** + * Helper function to unset the dg_autologout session variable if present. + */ +function dg_autologout_check_session_variable() { + $currentRequest = \Drupal::service('request_stack')->getCurrentRequest(); + $session = $currentRequest->getSession()->get('dg_autologout_last'); + if (isset($session)) { + $currentRequest->getSession()->remove('dg_autologout_last'); + } +} + +/** + * Implements hook_dg_autologout_refresh_only(). + */ +function dg_autologout_dg_autologout_refresh_only() { + if (!\Drupal::config('dg_autologout.settings')->get('enforce_admin') && \Drupal::service('router.admin_context')->isAdminRoute(\Drupal::routeMatch()->getRouteObject())) { + return TRUE; + } +} + +/** + * Implements hook_page_attachments(). + * + * Add a form element to every page which is used to detect if the page was + * loaded from browser cache. This happens when the browser's back button is + * pressed for example. The JS will set the value of the hidden input element + * to 1 after initial load. If this is 1 on subsequent loads, the page was + * loaded from cache and an dg_autologout timeout refresh needs to be triggered. + */ +function dg_autologout_page_attachments_alter(array &$attachments) { + $dg_autologout_manager = \Drupal::service('dg_autologout.manager'); + + // Check if JS should be included on this request. + if ($dg_autologout_manager->preventJs()) { + return; + } + + // Check if anything wants to be refresh only. This URL would include the + // javascript but will keep the login alive whilst that page is opened. + $refresh_only = $dg_autologout_manager->refreshOnly(); + + $settings = \Drupal::config('dg_autologout.settings'); + + // Get all settings JS will need for dialog. + $timeout = $dg_autologout_manager->getUserTimeout(); + $timeout_padding = $settings->get('padding'); + $redirect_url = $dg_autologout_manager->getUserRedirectUrl(); + $redirect_query = []; + if ($settings->get('include_destination')) { + $redirect_query[] = \Drupal::service('redirect.destination')->getAsArray(); + } + $redirect_query += ['dg_autologout_timeout' => 1]; + $no_dialog = $settings->get('no_dialog'); + $disable_buttons = $settings->get('disable_buttons'); + $yes_button = $settings->get('yes_button'); + if (empty($yes_button)) { + $yes_button = t('Yes'); + } + $no_button = $settings->get('no_button'); + if (empty($no_button)) { + $no_button = t('No'); + } + $use_alt_logout_method = $settings->get('use_alt_logout_method'); + $title = $settings->get('dialog_title'); + if (!$title) { + $title = \Drupal::config('system.site')->get('name') . ' Alert'; + } + // phpcs:ignore + $msg = t(Xss::filter($settings->get('message'))); + $logout_regardless_of_activity = $settings->get('logout_regardless_of_activity'); + + $settings = [ + 'timeout' => $refresh_only ? ($timeout * 500) : ($timeout * 1000), + 'timeout_padding' => $timeout_padding * 1000, + 'message' => $msg, + 'redirect_url' => Url::fromUserInput($redirect_url, ['query' => $redirect_query])->toString(), + // phpcs:ignore + 'title' => t($title), + 'refresh_only' => $refresh_only, + 'no_dialog' => $no_dialog, + 'disable_buttons' => $disable_buttons, + 'yes_button' => $yes_button, + 'no_button' => $no_button, + 'use_alt_logout_method' => $use_alt_logout_method, + 'logout_regardless_of_activity' => $logout_regardless_of_activity, + 'modal_width' => $settings->get('modal_width') ? (int) $settings->get('modal_width') : 'auto', + ]; + // If this is an AJAX request, then the logout redirect url should still be + // referring to the page that generated this request. + $current_request = \Drupal::request(); + if ($current_request->isXmlHttpRequest()) { + $base_url = Url::fromRoute('', [], ['absolute' => TRUE])->toString(); + $referer = $current_request->headers->get('referer'); + if ($referer) { + $destination = str_replace($base_url . '/', '', $referer); + } + else { + $destination = $base_url; + } + $settings['redirect_url'] = Url::fromUserInput($redirect_url, [ + 'query' => ['destination' => urlencode($destination)], + 'dg_autologout_timeout' => 1, + ]); + } + + dg_autologout_attach_js($attachments, $settings); +} + +/** + * Implements hook_page_bottom(). + */ +function dg_autologout_page_bottom(array &$page_bottom) { + if (!\Drupal::service('dg_autologout.manager')->preventJs()) { + $page_bottom['dg_autologout'] = [ + '#markup' => '
', + ]; + } +} + +/** + * Adds the necessary js and libraries. + * + * @param array $element + * The renderable array element to #attach the js to. + * @param array $settings + * The JS Settings. + */ +function dg_autologout_attach_js(array &$element, array $settings) { + $element['#attached']['drupalSettings']['dg_autologout'] = $settings; + $element['#attached']['library'][] = 'dg_autologout/drupal.dg_autologout'; + $element['#cache']['tags'][] = 'config:dg_autologout.settings'; +} + +/** + * Implements hook_user_login(). + * + * Delete stale sessions for the user on login. This stops + * session_limit module thinking the user has reached their + * session limit. + */ +function dg_autologout_user_login($account): void { + // Cleanup old sessions. + $dg_autologout_manager = \Drupal::service('dg_autologout.manager'); + $timeout = \Drupal::service('dg_autologout.manager')->getUserTimeout($account->id()); + + // Do not clear sessions if dg_autologout prevent is triggered. + if ($dg_autologout_manager->preventJs()) { + return; + } + // Now Sessions table is no longer defined in system_schema(). + // Do not clear session if there is no sessions table. + // @see https://www.drupal.org/node/3431286 + if (\Drupal::database()->schema()->tableExists('sessions')) { + $timeout_padding = \Drupal::config('dg_autologout.settings')->get('padding'); + $timestamp = \Drupal::time()->getRequestTime() - ($timeout + $timeout_padding); + + // Find all stale sessions. + $database = \Drupal::database(); + $sids = $database->select('sessions', 's') + ->fields('s', ['sid']) + ->condition('uid', $account->id()) + ->condition('timestamp', $timestamp, '<') + ->orderBy('timestamp', 'DESC') + ->execute() + ->fetchCol(); + + if (!empty($sids)) { + // Delete stale sessions at login. + $database->delete('sessions') + ->condition('sid', $sids, 'IN') + ->execute(); + } + } + + // Add login time cookie. + user_cookie_save(['dg_autologout_login' => \Drupal::time()->getCurrentTime()]); +} diff --git a/web/modules/custom/dg_autologout/dg_autologout.permissions.yml b/web/modules/custom/dg_autologout/dg_autologout.permissions.yml new file mode 100644 index 00000000..e66ce1ec --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.permissions.yml @@ -0,0 +1,4 @@ +change own logout threshold: + title: 'Change own logout threshold' +administer dg_autologout: + title: 'Administer Autologout' diff --git a/web/modules/custom/dg_autologout/dg_autologout.routing.yml b/web/modules/custom/dg_autologout/dg_autologout.routing.yml new file mode 100644 index 00000000..187ef6a5 --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.routing.yml @@ -0,0 +1,41 @@ +dg_autologout.set_admin: + path: '/admin/config/people/dg_autologout' + defaults: + _form: '\Drupal\dg_autologout\Form\AutologoutSettingsForm' + _title: 'Automated logout settings' + requirements: + _permission: 'administer dg_autologout' + +dg_autologout.alt_logout: + path: '/dg_autologout_alt_logout' + defaults: + _controller: '\Drupal\dg_autologout\Controller\AutologoutController::altLogout' + requirements: + _user_is_logged_in: 'TRUE' + +dg_autologout.ajax_logout: + path: '/dg_autologout_ajax_logout' + defaults: + _controller: '\Drupal\dg_autologout\Controller\AutologoutController::ajaxLogout' + options: + _theme: ajax_base_page + requirements: + _user_is_logged_in: 'TRUE' + +dg_autologout.ajax_set_last: + path: '/dg_autologout_ajax_set_last' + defaults: + _controller: '\Drupal\dg_autologout\Controller\AutologoutController::ajaxSetLast' + options: + _theme: ajax_base_page + requirements: + _user_is_logged_in: 'TRUE' + +dg_autologout.ajax_get_time_left: + path: '/dg_autologout_ajax_get_time_left' + defaults: + _controller: '\Drupal\dg_autologout\Controller\AutologoutController::ajaxGetRemainingTime' + options: + _theme: ajax_base_page + requirements: + _user_is_logged_in: 'TRUE' diff --git a/web/modules/custom/dg_autologout/dg_autologout.services.yml b/web/modules/custom/dg_autologout/dg_autologout.services.yml new file mode 100644 index 00000000..3e88eba2 --- /dev/null +++ b/web/modules/custom/dg_autologout/dg_autologout.services.yml @@ -0,0 +1,12 @@ +services: + dg_autologout_event_subscriber: + class: Drupal\dg_autologout\EventSubscriber\AutologoutSubscriber + tags: + - {name: event_subscriber} + arguments: ['@dg_autologout.manager', '@current_user', '@config.factory','@theme.manager','@datetime.time', '@request_stack', '@language_manager'] + + dg_autologout.manager: + class: Drupal\dg_autologout\AutologoutManager + tags: + - {name: dg_autologout_manager} + arguments: ['@module_handler', '@config.factory', '@messenger', '@current_user', '@logger.factory', '@session_manager', '@user.data', '@datetime.time', '@entity_type.manager', '@request_stack'] diff --git a/web/modules/custom/dg_autologout/js/dg_autologout.js b/web/modules/custom/dg_autologout/js/dg_autologout.js new file mode 100644 index 00000000..9a6dbe4b --- /dev/null +++ b/web/modules/custom/dg_autologout/js/dg_autologout.js @@ -0,0 +1,372 @@ +/** + * @file + * JavaScript for dg_autologout. + */ + +(function ($, Drupal, cookies) { + + 'use strict'; + + /** + * Used to lower the cpu burden for activity tracking on browser events. + * + * @param {function} f + * The function to debounce. + */ + function debounce(f) { + let timeout; + return function () { + let savedContext = this; + let savedArguments = arguments; + let finalRun = function () { + timeout = null; + f.apply(savedContext, savedArguments); + }; + if (!timeout) { + f.apply(savedContext, savedArguments); + } + clearTimeout(timeout); + timeout = setTimeout(finalRun, 500); + }; + } + + /** + * Attaches the batch behavior for dg_autologout. + * + * @type {Drupal~behavior} + */ + Drupal.behaviors.dg_autologout = { + attach: function (context, settings) { + if (context !== document) { + return; + } + + let paddingTimer; + let theDialog; + let t; + let localSettings; + + // Timer to keep track of activity resets. + let activityResetTimer; + + // Prevent settings being overridden by ajax callbacks by cloning it. + localSettings = jQuery.extend(true, {}, settings.dg_autologout); + + // Add timer element to prevent detach of all behaviours. + let timerMarkup = $('
').hide(); + $('body').append(timerMarkup); + + if (localSettings.refresh_only) { + // On pages where user shouldn't be logged out, don't set the timer. + t = setTimeout(keepAlive, localSettings.timeout); + } + else { + settings.activity = false; + if (localSettings.logout_regardless_of_activity) { + // Ignore users activity and set timeout. + let timestamp = Math.round((new Date()).getTime() / 1000); + let login_time = cookies.get("Drupal.visitor.dg_autologout_login"); + let difference = (timestamp - login_time) * 1000; + + t = setTimeout(init, localSettings.timeout - difference); + } + else { + // Bind formUpdated events to preventAutoLogout event. + $('body').bind('formUpdated', debounce(function (event) { + $(event.target).trigger('preventAutologout'); + })); + + // Bind formUpdated events to preventAutoLogout event. + $('body').bind('mousemove', debounce(function (event) { + $(event.target).trigger('preventAutologout'); + })); + + // Replaces the CKEditor5 check because keyup should always prevent autologout. + document.addEventListener('keyup', debounce(function (event) { + document.dispatchEvent(new Event('preventAutologout')); + })); + + $('body').bind('preventAutologout', function (event) { + // When the preventAutologout event fires, we set activity to true. + settings.activity = true; + + // Clear timer if one exists. + clearTimeout(activityResetTimer); + + // Set a timer that goes off and resets this activity indicator after + // half a minute, otherwise sessions never timeouts. + activityResetTimer = setTimeout(function () { + settings.activity = false; + }, 30000); + }); + + // On pages where the user should be logged out, set the timer to popup + // and log them out. + setTimeout(function () { + init(); + }, localSettings.timeout); + } + } + + function init() { + let noDialog = settings.dg_autologout.no_dialog; + if (settings.activity) { + refresh(); + } + else { + // The user has not been active, ask them if they want to stay logged + // in and start the logout timer. + paddingTimer = setTimeout(confirmLogout, localSettings.timeout_padding); + // While the countdown timer is going, lookup the remaining time. If + // there is more time remaining (i.e. a user is navigating in another + // tab), then reset the timer for opening the dialog. + Drupal.Ajax['dg_autologout.getTimeLeft'].dg_autologoutGetTimeLeft(function (time) { + if (time > 0) { + clearTimeout(paddingTimer); + t = setTimeout(init, time); + } + else { + // Logout user right away without displaying a confirmation dialog. + if (noDialog) { + logout(); + return; + } + theDialog = dialog(); + } + }); + } + } + + function dialog() { + let disableButtons = settings.dg_autologout.disable_buttons; + + let buttons = {}; + if (!disableButtons) { + let yesButton = settings.dg_autologout.yes_button; + buttons[Drupal.t(yesButton)] = function () { + cookies.set("Drupal.visitor.dg_autologout_login", Math.round((new Date()).getTime() / 1000)); + $(this).dialog("destroy"); + clearTimeout(paddingTimer); + refresh(); + }; + + let noButton = settings.dg_autologout.no_button; + buttons[Drupal.t(noButton)] = function () { + $(this).dialog("destroy"); + logout(); + }; + } + + return $('
' + localSettings.message + '
').dialog({ + modal: true, + closeOnEscape: false, + width: localSettings.modal_width, + dialogClass: 'autologout-dialog', + title: localSettings.title, + buttons: buttons, + close: function (event, ui) { + logout(); + } + }); + } + + // A user could have used the reset button on the tab/window they're + // actively using, so we need to double check before actually logging out. + function confirmLogout() { + $(theDialog).dialog('destroy'); + + Drupal.Ajax['dg_autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) { + if (time > 0) { + t = setTimeout(init, time); + } + else { + logout(); + } + }); + } + + function triggerLogoutEvent(logoutMethod, logoutUrl) { + const logoutEvent = new CustomEvent('dg_autologout', { + detail: { + logoutMethod: logoutMethod, + logoutUrl: logoutUrl, + }, + }); + document.dispatchEvent(logoutEvent); + } + + function logout() { + if (localSettings.use_alt_logout_method) { + let logoutUrl = drupalSettings.path.baseUrl + "dg_autologout_alt_logout"; + triggerLogoutEvent('alternative', logoutUrl); + + window.location = logoutUrl; + } + else { + $.ajax({ + url: drupalSettings.path.baseUrl + "dg_autologout_ajax_logout", + type: "POST", + beforeSend: function (xhr) { + xhr.setRequestHeader('X-Requested-With', { + toString: function () { + return ''; + } + }); + }, + success: function () { + let logoutUrl = localSettings.redirect_url; + triggerLogoutEvent('normal', logoutUrl); + + window.location = logoutUrl; + }, + error: function (XMLHttpRequest, textStatus) { + if (XMLHttpRequest.status === 403 || XMLHttpRequest.status === 404) { + window.location = localSettings.redirect_url; + } + } + }); + } + } + + /** + * Get the remaining time. + * + * Use the Drupal ajax library to handle get time remaining events + * because if using the JS Timer, the return will update it. + * + * @param function callback(time) + * The function to run when ajax is successful. The time parameter + * is the time remaining for the current user in ms. + */ + Drupal.Ajax.prototype.dg_autologoutGetTimeLeft = function (callback) { + let ajax = this; + + // Store the original success temporary to be called later. + const originalSuccess = ajax.options.success; + ajax.options.submit = { + uactive: settings.activity + }; + ajax.options.success = function (response, status, xmlhttprequest) { + if (typeof response == 'string') { + response = $.parseJSON(response); + } + if (typeof response[0].command === 'string' && response[0].command === 'alert') { + // In the event of an error, we can assume user has been logged out. + window.location = localSettings.redirect_url; + } + + // Loop through response to get correct keys. + for (let key in response) { + if (response[key].command === "settings" && typeof response[key].settings.time !== 'undefined') { + callback(response[key].settings.time); + } + if (response[key].command === "insert" && response[key].selector === '#timer' && typeof response[key].data !== 'undefined') { + response[key].data = ''; + } + } + + // Let Drupal.ajax handle the JSON response. + return originalSuccess.call(ajax, response, status, xmlhttprequest); + }; + + try { + $.ajax(ajax.options); + } + catch (e) { + ajax.ajaxing = false; + } + }; + + Drupal.Ajax['dg_autologout.getTimeLeft'] = Drupal.ajax({ + base: null, + element: document.body, + url: drupalSettings.path.baseUrl + 'dg_autologout_ajax_get_time_left', + submit: { + uactive: settings.activity + }, + event: 'dg_autologout.getTimeLeft', + error: function (XMLHttpRequest, textStatus) { + // Disable error reporting to the screen. + }, + }); + + /** + * Handle refresh event. + * + * Use the Drupal ajax library to handle refresh events because if using + * the JS Timer, the return will update it. + * + * @param function timerFunction + * The function to tell the timer to run after its been restarted. + */ + Drupal.Ajax.prototype.dg_autologoutRefresh = function (timerfunction) { + let ajax = this; + + if (ajax.ajaxing) { + return false; + } + + // Store the original success temporary to be called later. + const originalSuccess = ajax.options.success; + ajax.options.success = function (response, status, xmlhttprequest) { + if (typeof response === 'string') { + response = $.parseJSON(response); + } + if (typeof response[0].command === 'string' && response[0].command === 'alert') { + // In the event of an error, we can assume the user has been logged out. + window.location = localSettings.redirect_url; + } + + t = setTimeout(timerfunction, localSettings.timeout); + + // Wrap response data in timer markup to prevent detach of all behaviors. + response[0].data = ''; + + // Let Drupal.ajax handle the JSON response. + return originalSuccess.call(ajax, response, status, xmlhttprequest); + }; + + try { + $.ajax(ajax.options); + } + catch (e) { + ajax.ajaxing = false; + } + }; + + Drupal.Ajax['dg_autologout.refresh'] = Drupal.ajax({ + base: null, + element: document.body, + url: drupalSettings.path.baseUrl + 'dg_autologout_ajax_set_last', + event: 'dg_autologout.refresh', + error: function (XMLHttpRequest, textStatus) { + // Disable error reporting to the screen. + } + }); + + function keepAlive() { + if (!document.hidden) { + Drupal.Ajax['dg_autologout.refresh'].autologoutRefresh(keepAlive); + } else { + t = setTimeout(keepAlive, localSettings.timeout); + } + } + + function refresh() { + Drupal.Ajax['dg_autologout.refresh'].autologoutRefresh(init); + } + + // Check if the page was loaded via a back button click. + let $dirty_bit = $('#autologout-cache-check-bit'); + if ($dirty_bit.length !== 0) { + if ($dirty_bit.val() === '1') { + // Page was loaded via back button click, we should refresh the timer. + refresh(); + } + + $dirty_bit.val('1'); + } + } + }; + +})(jQuery, Drupal, window.Cookies); diff --git a/web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php b/web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php new file mode 100644 index 00000000..a4c0c0d3 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php @@ -0,0 +1,150 @@ +dg_autoLogoutManager = $dg_autologout; + $this->time = $time; + $this->requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('dg_autologout.manager'), + $container->get('datetime.time'), + $container->get('request_stack') + ); + } + + /** + * Alternative logout. + */ + public function altLogout() { + $redirect_url = $this->dg_autoLogoutManager->getUserRedirectUrl(); + $this->dg_autoLogoutManager->logout(); + $url = Url::fromUserInput( + $redirect_url, + [ + 'absolute' => TRUE, + 'query' => [ + 'dg_autologout_timeout' => 1, + ], + ] + ); + + return new RedirectResponse($url->toString()); + } + + /** + * AJAX logout. + */ + public function ajaxLogout() { + $this->dg_autoLogoutManager->logout(); + $response = new AjaxResponse(); + $response->setStatusCode(200); + + return $response; + } + + /** + * Ajax callback to reset the last access session variable. + */ + public function ajaxSetLast() { + $this->requestStack->getCurrentRequest()->getSession()->set('dg_autologout_last', $this->time->getRequestTime()); + + // Reset the timer. + $response = new AjaxResponse(); + $markup = $this->autoLogoutManager->createTimer(); + $response->addCommand(new ReplaceCommand('#timer', $markup)); + $response->addCommand(new SettingsCommand(['activity' => TRUE])); + + return $response; + } + + /** + * AJAX callback that returns the time remaining for this user is logged out. + */ + public function ajaxGetRemainingTime() { + $req = $this->requestStack->getCurrentRequest(); + $active = $req->get('uactive'); + $response = new AjaxResponse(); + + if (isset($active) && $active === "false") { + $response->addCommand(new ReplaceCommand('#timer', 0)); + $response->addCommand(new SettingsCommand([ + 'time' => 0, + 'activity' => FALSE, + ])); + + return $response; + } + + $time_remaining_ms = $this->autoLogoutManager->getRemainingTime() * 1000; + + // Reset the timer. + $markup = $this->dg_autoLogoutManager->createTimer(); + + $response->addCommand(new ReplaceCommand('#timer', $markup)); + $response->addCommand(new SettingsCommand([ + 'time' => $time_remaining_ms, + 'activity' => TRUE, + ])); + + return $response; + } + +} diff --git a/web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php b/web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php new file mode 100644 index 00000000..67c6cbf1 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php @@ -0,0 +1,206 @@ +dg_autoLogoutManager = $dg_autologout; + $this->currentUser = $account; + $this->config = $config; + $this->theme = $theme; + $this->time = $time; + $this->requestStack = $requestStack; + $this->languageManager = $language_manager; + } + + /** + * Check for dg_autologout JS. + * + * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event + * The request event. + */ + public function onRequest(RequestEvent $event) { + $dg_autologout_manager = $this->dg_autoLogoutManager; + + $uid = $this->currentUser->id(); + + if ($uid == 0) { + $dg_autologout_timeout = $this->requestStack->getCurrentRequest()->query->get('dg_autologout_timeout'); + $post = $this->requestStack->getCurrentRequest()->request->all(); + if (!empty($dg_autologout_timeout) && $dg_autologout_timeout == 1 && empty($post)) { + $dg_autologout_manager->inactivityMessage(); + } + return; + } + + // If user is not anonymous. + $session = $this->requestStack->getCurrentRequest()->hasSession() + ? $this->requestStack->getCurrentRequest()->getSession() + : NULL; + $auto_redirect = $session ? $session->get('auto_redirect') : NULL; + + // If http referer url has 'destination' and session is not set, + // then only redirect to user page if uid doesn't match. + if (empty($auto_redirect) && ($destination = $this->getDestination())) { + $match = preg_match('#^destination=(/[a-z]+)?/user/([0-9]+)$#', $destination, $matches); + + if ($match && $matches[2] != $uid) { + $session->set('auto_redirect', 1); + $login_url = Url::fromRoute('user.page', [], ['absolute' => TRUE])->toString(); + + // Redirect user to user page. + $response = new RedirectResponse($login_url); + $event->setResponse($response); + } + } + + if ($this->dg_autoLogoutManager->preventJs()) { + return; + } + + $now = $this->time->getRequestTime(); + // Check if anything wants to be refresh only. This URL would include the + // javascript but will keep the login alive whilst that page is opened. + $refresh_only = $dg_autologout_manager->refreshOnly(); + $timeout = $dg_autologout_manager->getUserTimeout(); + $timeout_padding = $this->config->get('dg_autologout.settings')->get('padding'); + $is_altlogout = strpos($event->getRequest()->getRequestUri(), '/dg_autologout_alt_logout') !== FALSE; + + // We need a backup plan if JS is disabled. + $session = $this->requestStack->getCurrentRequest()->getSession()->get('dg_autologout_last'); + if (!$is_altlogout && !$refresh_only && isset($session)) { + // If time since last access is > timeout + padding, log them out. + $diff = $now - $session; + if ($diff >= ($timeout + (int) $timeout_padding)) { + $dg_autologout_manager->logout(); + // User has changed so force Drupal to remake decisions based on user. + global $theme, $theme_key; + drupal_static_reset(); + $theme = NULL; + $theme_key = NULL; + $this->theme->getActiveTheme(); + $dg_autologout_manager->inactivityMessage(); + } + else { + $this->requestStack->getCurrentRequest()->getSession()->set('dg_autologout_last', $now); + } + } + else { + $this->requestStack->getCurrentRequest()->getSession()->set('dg_autologout_last', $now); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + $events[KernelEvents::REQUEST][] = ['onRequest', 100]; + + return $events; + } + + /** + * Get destination from referer. + * + * @return string|null + * The destination query string or null. + */ + private function getDestination(): ?string { + $request = $this->requestStack->getCurrentRequest(); + if (!$referer = $request->server->get('HTTP_REFERER')) { + return NULL; + } + // Get query string from http referer url. + $referer_parts = parse_url($referer, PHP_URL_QUERY); + if (!empty($referer_parts) && str_contains($referer_parts, 'destination')) { + return $referer_parts; + } + return FALSE; + } + +} diff --git a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php b/web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php new file mode 100644 index 00000000..d6d14012 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php @@ -0,0 +1,77 @@ +dg_autoLogoutManager = $dg_autologout; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('dg_autologout.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $form['reset'] = [ + '#type' => 'button', + '#value' => $this->t('Reset Timeout'), + '#weight' => 1, + '#limit_validation_errors' => FALSE, + '#executes_submit_callback' => FALSE, + '#ajax' => [ + 'callback' => 'dg_autologout_ajax_set_last', + ], + ]; + + $form['timer'] = [ + '#markup' => $this->dg_autoLogoutManager->createTimer(), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Submits on block form. + } + +} diff --git a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php b/web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php new file mode 100644 index 00000000..566c91dd --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php @@ -0,0 +1,529 @@ +moduleHandler = $module_handler; + $this->userData = $user_data; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory'), + $container->get('config.typed'), + $container->get('module_handler'), + $container->get('user.data'), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getEditableConfigNames() { + return ['dg_autologout.settings']; + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'dg_autologout_settings'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $config = $this->config('dg_autologout.settings'); + $default_dialog_title = $config->get('dialog_title'); + if (!$default_dialog_title) { + $default_dialog_title = $this->config('system.site')->get('name') . ' Alert'; + } + + $form['enabled'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enable autologout'), + '#default_value' => $config->get('enabled'), + '#weight' => -20, + '#description' => $this->t("Enable autologout on this site."), + ]; + + $form['timeout'] = [ + '#type' => 'textfield', + '#title' => $this->t('Timeout value in seconds'), + '#default_value' => $config->get('timeout'), + '#size' => 8, + '#weight' => -10, + '#description' => $this->t('The length of inactivity time, in seconds, before automated log out. Must be 60 seconds or greater. Will not be used if role timeout is activated.'), + ]; + + $form['max_timeout'] = [ + '#type' => 'textfield', + '#title' => $this->t('Max timeout setting'), + '#default_value' => $config->get('max_timeout'), + '#size' => 10, + '#maxlength' => 12, + '#weight' => -8, + '#description' => $this->t('The maximum logout threshold time that can be set by users who have the permission to set user level timeouts.'), + ]; + + $form['padding'] = [ + '#type' => 'textfield', + '#title' => $this->t('Timeout padding'), + '#default_value' => $config->get('padding'), + '#size' => 8, + '#weight' => -6, + '#description' => $this->t('How many seconds to give a user to respond to the logout dialog before ending their session.'), + ]; + + $form['logout_regardless_of_activity'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Logout user regardless of activity'), + '#default_value' => $config->get('logout_regardless_of_activity'), + '#weight' => -5, + '#description' => $this->t("Enable this to autologout user regardless of their activity."), + ]; + + $form['no_individual_logout_threshold'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Disable user-specific logout thresholds'), + '#default_value' => $config->get('no_individual_logout_threshold'), + '#weight' => -5, + '#description' => $this->t("Enable this to only allow autologout thresholds to be set globally on this form and don't allow users to set their own logout threshold."), + ]; + + $form['role_logout'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Role Timeout'), + '#default_value' => $config->get('role_logout'), + '#weight' => -4, + '#description' => $this->t('Enable each role to have its own timeout threshold and redirect URL, a refresh may be required for changes to take effect. Any role not ticked will use the default timeout value and default redirect URL. Any role can have a timeout value of 0 which means that they will never be logged out. Roles without specified redirect URL will use the default redirect URL.'), + ]; + + $form['role_logout_max'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Use highest role timeout value'), + '#default_value' => $config->get('role_logout_max'), + '#description' => $this->t('Check this to use the highest timeout value instead of the lowest for users that have more than one role.'), + '#states' => [ + 'visible' => [ + // Only show this field when the 'role_logout' checkbox is enabled. + ':input[name="role_logout"]' => ['checked' => TRUE], + ], + ], + ]; + + $form['redirect_url'] = [ + '#type' => 'textfield', + '#title' => $this->t('Redirect URL at logout'), + '#default_value' => $config->get('redirect_url'), + '#size' => 40, + '#description' => $this->t('Send users to this internal page when they are logged out.'), + ]; + + $form['include_destination'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Include destination'), + '#default_value' => $config->get('include_destination'), + '#description' => $this->t('Enable this if you want to set the redirect destination.'), + ]; + + $form['no_dialog'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Do not display the logout dialog'), + '#default_value' => $config->get('no_dialog'), + '#description' => $this->t('Enable this if you want users to logout right away and skip displaying the logout dialog.'), + ]; + + $form['use_alt_logout_method'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Use alternate logout method'), + '#default_value' => $config->get('use_alt_logout_method'), + '#description' => $this->t('Normally when auto logout is triggered, it is done via an AJAX service call. Sites that use an SSO provider, such as CAS, are likely to see this request fail with the error "Origin is not allowed by Access-Control-Allow-Origin". The alternate approach is to have the auto logout trigger a page redirect to initiate the logout process instead.'), + ]; + + $form['dialog_title'] = [ + '#type' => 'textfield', + '#title' => $this->t('Dialog title'), + '#default_value' => $default_dialog_title, + '#size' => 40, + '#description' => $this->t('This text will be dialog box title.'), + ]; + + $form['message'] = [ + '#type' => 'textarea', + '#title' => $this->t('Message to display in the logout dialog'), + '#default_value' => $config->get('message'), + '#size' => 40, + '#description' => $this->t('This message must be plain text as it might appear in a JavaScript confirm dialog.'), + ]; + + $form['inactivity_message'] = [ + '#type' => 'textarea', + '#title' => $this->t('Message to display to the user after they are logged out'), + '#default_value' => $config->get('inactivity_message'), + '#size' => 40, + '#description' => $this->t('This message is displayed after the user was logged out due to inactivity. You can leave this blank to show no message to the user.'), + ]; + + $form['inactivity_message_type'] = [ + '#type' => 'select', + '#title' => $this->t('Type of the message to display'), + '#default_value' => $config->get('inactivity_message_type'), + '#description' => $this->t('Specifies whether to display the message as status or warning.'), + '#options' => [ + MessengerInterface::TYPE_STATUS => $this->t('Status'), + MessengerInterface::TYPE_WARNING => $this->t('Warning'), + ], + ]; + + $form['modal_width'] = [ + '#type' => 'textfield', + '#title' => $this->t('Modal width'), + '#default_value' => $config->get('modal_width'), + '#size' => 40, + '#description' => $this->t('This modal dialog width in pixels.'), + ]; + + $form['disable_buttons'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Disable buttons'), + '#default_value' => $config->get('disable_buttons'), + '#description' => $this->t('Disable Yes/No buttons for automatic logout popout.'), + ]; + + $form['yes_button'] = [ + '#type' => 'textfield', + '#title' => $this->t('Custom confirm button text'), + '#default_value' => $config->get('yes_button'), + '#size' => 40, + '#description' => $this->t('Add custom text to confirmation button.'), + ]; + + $form['no_button'] = [ + '#type' => 'textfield', + '#title' => $this->t('Custom decline button text'), + '#default_value' => $config->get('no_button'), + '#size' => 40, + '#description' => $this->t('Add custom text to decline button.'), + ]; + + $form['use_watchdog'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enable watchdog Automated Logout logging'), + '#default_value' => $config->get('use_watchdog'), + '#description' => $this->t('Enable logging of automatically logged out users'), + ]; + + $form['enforce_admin'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enforce auto logout on admin pages'), + '#default_value' => $config->get('enforce_admin'), + '#description' => $this->t('If checked, then users will be automatically logged out when administering the site.'), + ]; + $form['whitelisted_ip_addresses'] = [ + '#type' => 'textarea', + '#title' => $this->t('Whitelisted ip addresses'), + '#default_value' => $config->get('whitelisted_ip_addresses'), + '#size' => 40, + '#description' => $this->t('Users from these IP addresses will not be logged out.'), + ]; + if ($this->moduleHandler->moduleExists('jstimer') && $this->moduleHandler->moduleExists('jst_timer')) { + $form['jstimer_format'] = [ + '#type' => 'textfield', + '#title' => $this->t('Autologout block time format'), + '#default_value' => $config->get('jstimer_format'), + '#description' => $this->t('Change the display of the dynamic timer. Available replacement values are: %day%, %month%, %year%, %dow%, %moy%, %years%, %ydays%, %days%, %hours%, %mins%, and %secs%.'), + ]; + } + + $form['role_container'] = [ + '#type' => 'container', + '#weight' => -2, + '#states' => [ + 'visible' => [ + // Only show this field when the 'role_logout' checkbox is enabled. + ':input[name="role_logout"]' => ['checked' => TRUE], + ], + ], + ]; + + $form['role_container']['table'] = [ + '#type' => 'table', + '#header' => [ + 'enable' => $this->t('Customize'), + 'name' => $this->t('Role Name'), + 'timeout' => $this->t('Timeout (seconds)'), + 'url' => $this->t('Redirect URL at logout'), + ], + ]; + + foreach ($this->entityTypeManager->getStorage('user_role')->loadMultiple() as $key => $role) { + if ($key !== AccountInterface::ANONYMOUS_ROLE) { + $form['role_container']['table'][$key] = [ + 'enabled' => [ + '#type' => 'checkbox', + '#default_value' => $this->config('autologout.role.' . $key)->get('enabled'), + ], + 'role' => [ + '#type' => 'item', + '#value' => $key, + '#markup' => $key, + ], + 'timeout' => [ + '#type' => 'textfield', + '#default_value' => $this->config('autologout.role.' . $key)->get('timeout'), + '#size' => 8, + ], + 'url' => [ + '#type' => 'textfield', + '#default_value' => $this->config('autologout.role.' . $key)->get('url'), + '#size' => 40, + ], + ]; + } + } + + return parent::buildForm($form, $form_state); + } + + /** + * Validate timeout range. + * + * Checks to see if timeout threshold is outside max/min values. Done here + * to centralize and stop repeated code. Hard coded min, configurable max. + * + * @param int $timeout + * The timeout value in seconds to validate. + * @param int $max_timeout + * (optional) Maximum value of timeout. If not set, system default is used. + * + * @return bool + * Return TRUE or FALSE + */ + public function timeoutValidate($timeout, $max_timeout = NULL) { + $validate = TRUE; + if (is_null($max_timeout)) { + $max_timeout = $this->config('autologout.settings')->get('max_timeout'); + } + + if (!is_numeric($timeout) || $timeout < 0 || ($timeout > 0 && $timeout < 60) || $timeout > $max_timeout) { + // Less than 60, greater than max_timeout and is numeric. + // 0 is allowed now as this means no timeout. + $validate = FALSE; + } + return $validate; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + $new_stack = []; + if (!empty($values['table'])) { + foreach ($values['table'] as $key => $pair) { + if (is_array($pair)) { + foreach ($pair as $pairkey => $pairvalue) { + $new_stack[$key][$pairkey] = $pairvalue; + } + } + } + } + + $max_timeout = $values['max_timeout']; + + if ($values['role_logout']) { + // Validate timeouts for each role. + foreach (array_keys($this->entityTypeManager->getStorage('user_role')->loadMultiple()) as $role) { + if (empty($new_stack[$role]) || $new_stack[$role]['enabled'] == 0) { + // Don't validate role timeouts for non enabled roles. + continue; + } + + $timeout = $new_stack[$role]['timeout']; + $validate = $this->timeoutValidate($timeout, $max_timeout); + if (!$validate) { + // phpcs:ignore + $form_state->setErrorByName('table][' . $role . '][timeout', $this->t('%role role timeout must be an integer greater than 60, less then %max or 0 to disable autologout for that role.', ['%role' => $role, '%max' => $max_timeout])); + } + $role_redirect_url = $new_stack[$role]['url']; + if (!empty($role_redirect_url) && strpos($role_redirect_url, '/') !== 0) { + // phpcs:ignore + $form_state->setErrorByName('table][' . $role . '][url', $this->t("%role role redirect URL at logout :redirect_url must begin with a '/'", ['%role' => $role, ':redirect_url' => $role_redirect_url])); + } + } + } + + $timeout = $values['timeout']; + // Validate timeout. + if ($timeout < 60) { + $form_state->setErrorByName('timeout', $this->t('The timeout value must be an integer 60 seconds or greater.')); + } + elseif ($max_timeout <= 60) { + $form_state->setErrorByName('max_timeout', $this->t('The max timeout must be an integer greater than 60.')); + } + elseif ($max_timeout > $this->maxAllowedTimeout) { + $form_state->setErrorByName('max_timeout', $this->t('The max timeout must be an integer lower than or equal to %limit.', ['%limit' => $this->maxAllowedTimeout])); + } + elseif (!is_numeric($timeout) || ((int) $timeout != $timeout) || $timeout < 60 || $timeout > $max_timeout) { + $form_state->setErrorByName('timeout', $this->t('The timeout must be an integer greater than or equal to 60 and less then or equal to %max.', ['%max' => $max_timeout])); + } + + $redirect_url = $values['redirect_url']; + + // Validate redirect url. + if (strpos($redirect_url, '/') !== 0) { + $form_state->setErrorByName('redirect_url', $this->t("Redirect URL at logout :redirect_url must begin with a '/'", [':redirect_url' => $redirect_url])); + } + // Validate ip address list. + $whitelisted_ip_addresses_list = explode("\n", trim($values['whitelisted_ip_addresses'])); + + foreach ($whitelisted_ip_addresses_list as $ip_address) { + if (!empty($ip_address) && !filter_var(trim($ip_address), FILTER_VALIDATE_IP)) { + $form_state->setErrorByName( + 'whitelisted_ip_addresses', + $this->t('Whitlelisted IP address list should contain only valid IP addresses, one per row') + ); + } + } + parent::validateForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + $dg_autologout_settings = $this->config('dg_autologout.settings'); + + $old_no_individual_logout_threshold = $dg_autologout_settings->get('no_individual_logout_threshold'); + $new_no_individual_logout_threshold = (bool) $values['no_individual_logout_threshold']; + + $dg_autologout_settings + ->set('enabled', $values['enabled']) + ->set('timeout', $values['timeout']) + ->set('max_timeout', $values['max_timeout']) + ->set('padding', $values['padding']) + ->set('no_individual_logout_threshold', $values['no_individual_logout_threshold']) + ->set('logout_regardless_of_activity', $values['logout_regardless_of_activity']) + ->set('role_logout', $values['role_logout']) + ->set('role_logout_max', $values['role_logout_max']) + ->set('redirect_url', $values['redirect_url']) + ->set('include_destination', $values['include_destination']) + ->set('no_dialog', $values['no_dialog']) + ->set('dialog_title', $values['dialog_title']) + ->set('message', $values['message']) + ->set('inactivity_message', $values['inactivity_message']) + ->set('inactivity_message_type', $values['inactivity_message_type']) + ->set('modal_width', $values['modal_width']) + ->set('disable_buttons', $values['disable_buttons']) + ->set('yes_button', $values['yes_button']) + ->set('no_button', $values['no_button']) + ->set('enforce_admin', $values['enforce_admin']) + ->set('whitelisted_ip_addresses', $values['whitelisted_ip_addresses']) + ->set('use_alt_logout_method', $values['use_alt_logout_method']) + ->set('use_watchdog', $values['use_watchdog']) + ->save(); + + if (!empty($values['table'])) { + foreach ($values['table'] as $user) { + $this->configFactory()->getEditable('dg_autologout.role.' . $user['role']) + ->set('enabled', $user['enabled']) + ->set('timeout', $user['timeout']) + ->set('url', $user['url']) + ->save(); + } + } + + if (isset($values['jstimer_format'])) { + $dg_autologout_settings->set('jstimer_format', $values['jstimer_format'])->save(); + } + + // If individual logout threshold setting is no longer enabled, + // clear existing individual timeouts from users. + if ($old_no_individual_logout_threshold === FALSE && $new_no_individual_logout_threshold === TRUE) { + $users_timeout = $this->userData->get('dg_autologout', NULL, 'timeout'); + foreach ($users_timeout as $uid => $current_timeout_value) { + if ($current_timeout_value !== NULL) { + $this->userData->set('dg_autologout', $uid, 'timeout', NULL); + } + } + } + + parent::submitForm($form, $form_state); + } + +} diff --git a/web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php b/web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php new file mode 100644 index 00000000..ac50db3e --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php @@ -0,0 +1,144 @@ +moduleHandler = $module_handler; + $this->dateFormatter = $date_formatter; + $this->autoLogoutSettings = $dg_autologout_settings; + $this->manager = $manager; + $this->builder = $builder; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('module_handler'), + $container->get('date.formatter'), + $container->get('config.factory')->get('dg_autologout.settings'), + $container->get('dg_autologout.manager'), + $container->get('form_builder'), + ); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + // @todo This is not the place where we should be doing this. + $return = []; + return $return; + } + + /** + * {@inheritdoc} + */ + public function build() { + $dg_autologout_manager = $this->manager; + if ($dg_autologout_manager->preventJs()) { + + // Don't display the block if the user is not going + // to be logged out on this page. + return []; + } + + if ($dg_autologout_manager->refreshOnly()) { + $markup = $this->t('Autologout does not apply on the current page, + you will be kept logged in whilst this page remains open.'); + } + elseif ($this->moduleHandler->moduleExists('jstimer') && $this->moduleHandler->moduleExists('jst_timer')) { + return $this->builder->getForm('Drupal\dg_autologout\Form\AutologoutBlockForm'); + } + else { + $timeout = (int) $dg_autologout_manager->getUserTimeout(); + $markup = $this->t('You will be logged out in @time if this page is not refreshed before then.', ['@time' => $this->dateFormatter->formatInterval($timeout)]); + } + + return [ + '#type' => 'markup', + '#markup' => $markup, + ]; + } + +} diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/dg_ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/dg_ConfigAutologoutRoles.php new file mode 100644 index 00000000..68421e63 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/dg_ConfigAutologoutRoles.php @@ -0,0 +1,38 @@ +getStorage('user_role')->loadMultiple(); + foreach ($roles as $role) { + if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { + $dg_autologout_role = 'dg_autologout.role.' . $role->id(); + $this->config->setName($dg_autologout_role); + $this->config->save(); + break; + } + } + + $entity_ids = parent::import($row, $old_destination_id_values); + $entity_ids[0] = $dg_autologout_role; + + return $entity_ids; + } + +} diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/source/d6/dg_AutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/source/d6/dg_AutologoutRoles.php new file mode 100644 index 00000000..91fb6109 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/source/d6/dg_AutologoutRoles.php @@ -0,0 +1,15 @@ +select('variable', 'v') + ->fields('v') + ->condition('name', 'dg_autologout_role_%_timeout', 'LIKE'); + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'enabled' => $this->t('Autologout user role is enabled.'), + 'timeout' => $this->t('Autologout user role timeout.'), + 'role' => $this->t('Autologout user role.'), + ]; + return $fields; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + $row_name = str_replace('_timeout', '', $row->getSourceProperty('name')); + $timeout = unserialize($row->getSourceProperty('value'), ['allowed_classes' => FALSE]); + $query = $this->select('variable', 'v') + ->fields('v', ['value']) + ->condition('name', $row_name) + ->execute() + ->fetchAssoc(); + $enabled = unserialize($query['value'], ['allowed_classes' => FALSE]); + + $row_name = str_replace('_timeout', '', $row->getSourceProperty('name')); + $rid = explode('_', $row_name)[2]; + $query_roles = $this->select('role', 'r') + ->fields('r', ['name']) + ->condition('rid', $rid) + ->execute() + ->fetchAssoc(); + $role = $query_roles['name']; + + $row->setSourceProperty('enabled', (bool) $enabled); + $row->setSourceProperty('timeout', (int) $timeout); + $row->setSourceProperty('role', $role); + + return parent::prepareRow($row); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['name']['type'] = 'string'; + $ids['value']['type'] = 'string'; + return $ids; + } + +} diff --git a/web/modules/custom/dg_autologout/src/dg_AutologoutManager.php b/web/modules/custom/dg_autologout/src/dg_AutologoutManager.php new file mode 100644 index 00000000..3a06af21 --- /dev/null +++ b/web/modules/custom/dg_autologout/src/dg_AutologoutManager.php @@ -0,0 +1,374 @@ +moduleHandler = $module_handler; + $this->autoLogoutSettings = $config_factory->get('dg_autologout.settings'); + $this->configFactory = $config_factory; + $this->messenger = $messenger; + $this->currentUser = $current_user; + $this->logger = $logger->get('dg_autologout'); + $this->session = $sessionManager; + $this->userData = $userData; + $this->time = $time; + $this->entityTypeManager = $entityTypeManager; + $this->requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public function preventJs() { + if ($this->autoLogoutSettings->get('enabled') === FALSE) { + // Autologout is disabled globally. + return TRUE; + } + + foreach ($this->moduleHandler->invokeAll('dg_autologout_prevent') as $prevent) { + if (!empty($prevent)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function refreshOnly() { + foreach ($this->moduleHandler->invokeAll('dg_autologout_refresh_only') as $module_refresh_only) { + if (!empty($module_refresh_only)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function inactivityMessage() { + $message = Xss::filter($this->autoLogoutSettings->get('inactivity_message')); + $type = $this->autoLogoutSettings->get('inactivity_message_type') ?? 'status'; + if (!empty($message)) { + $this->messenger->addMessage($this->t('@message', ['@message' => $message]), $type); + } + } + + /** + * {@inheritdoc} + */ + public function logout() { + $user = $this->currentUser; + if ($this->autoLogoutSettings->get('use_watchdog')) { + $this->logger->info( + 'Session automatically closed for %name by dg_autologout.', + ['%name' => $user->getAccountName()] + ); + } + + // Destroy the current session. + $this->moduleHandler->invokeAll('user_logout', [$user]); + $this->session->clear(); + $user->setAccount(new AnonymousUserSession()); + + $this->moduleHandler->invokeAll('dg_autologout_user_logout', []); + } + + /** + * {@inheritdoc} + */ + public function getRoleTimeout() { + $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); + $role_timeout = []; + + // Go through roles, get timeouts for each and return as array. + foreach ($roles as $name => $role) { + $role_settings = $this->configFactory->get('dg_autologout.role.' . $name); + if ($role_settings->get('enabled')) { + $timeout_role = $role_settings->get('timeout'); + $role_timeout[$name] = $timeout_role; + } + } + + return $role_timeout; + } + + /** + * {@inheritdoc} + */ + public function getRoleUrl() { + $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); + $role_url = []; + + // Go through roles, get timeouts for each and return as array. + foreach ($roles as $name => $role) { + $role_settings = $this->configFactory->get('dg_autologout.role.' . $name); + if ($role_settings->get('enabled')) { + $url_role = $role_settings->get('url'); + $role_url[$name] = $url_role; + } + } + return $role_url; + } + + /** + * {@inheritdoc} + */ + public function getRemainingTime() { + if ($this->autoLogoutSettings->get('logout_regardless_of_activity')) { + $time_passed = $this->time->getRequestTime() - $this->requestStack->getCurrentRequest()->cookies->get('Drupal_visitor_dg_autologout_login'); + } + else { + $session = $this->requestStack->getCurrentRequest()->getSession()->get('dg_autologout_last'); + $time_passed = isset($session) + ? $this->time->getRequestTime() - $session + : 0; + } + $timeout = $this->getUserTimeout(); + return $timeout - $time_passed; + } + + /** + * {@inheritdoc} + */ + public function createTimer() { + return $this->getRemainingTime(); + } + + /** + * {@inheritdoc} + */ + public function getUserTimeout($uid = NULL) { + if (is_null($uid)) { + // If $uid is not provided, use the logged in user. + $user = $this->currentUser; + } + else { + $user = $this->entityTypeManager->getStorage('user') + ->load($uid); + } + + if ($user->id() == 0) { + // Anonymous doesn't get logged out. + return 0; + } + $user_timeout = $this->userData->get('dg_autologout', $user->id(), 'timeout'); + + if (is_numeric($user_timeout)) { + // User timeout takes precedence. + return $user_timeout; + } + + // Get role timeouts for user. + if ($this->autoLogoutSettings->get('role_logout')) { + $user_roles = $user->getRoles(); + $output = []; + $timeouts = $this->getRoleTimeout(); + foreach ($user_roles as $rid => $role) { + if (isset($timeouts[$role])) { + $output[$rid] = $timeouts[$role]; + } + } + + // Assign the lowest/highest timeout value to be session timeout value. + if (!empty($output)) { + // If one of the user's roles has a unique timeout, use this. + if ($this->autoLogoutSettings->get('role_logout_max')) { + return max($output); + } + else { + return min($output); + } + } + } + + // If no user or role override exists, return the default timeout. + return $this->autoLogoutSettings->get('timeout'); + } + + /** + * {@inheritdoc} + */ + public function getUserRedirectUrl($uid = NULL) { + if (is_null($uid)) { + // If $uid is not provided, use the logged in user. + $user = $this->entityTypeManager->getStorage('user') + ->load($this->currentUser->id()); + } + else { + $user = $this->entityTypeManager->getStorage('user') + ->load($uid); + } + + if ($user->id() == 0) { + // Anonymous doesn't get logged out. + return; + } + + // Get role timeouts for user. + if ($this->autoLogoutSettings->get('role_logout')) { + $user_roles = $user->getRoles(); + $output = []; + $urls = $this->getRoleUrl(); + foreach ($user_roles as $rid => $role) { + if (isset($urls[$role])) { + $output[$rid] = $urls[$role]; + } + } + + // Assign the first matching Role. + if (!empty($output) && !empty(reset($output))) { + // If one of the user's roles has a unique URL, use this. + return reset($output); + } + } + + // If the redirect URL set in configuration is empty, use user login URL. + return $this->autoLogoutSettings->get('redirect_url') ?? "/user/login"; + } + + /** + * {@inheritdoc} + */ + public function logoutRole(UserInterface $user) { + if ($this->autoLogoutSettings->get('role_logout')) { + foreach ($user->roles as $name => $role) { + if ($this->configFactory->get('dg_autologout.role.' . $name . '.enabled')) { + return TRUE; + } + } + } + + return FALSE; + } + +} diff --git a/web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php b/web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php new file mode 100644 index 00000000..d562956f --- /dev/null +++ b/web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php @@ -0,0 +1,110 @@ + Date: Wed, 18 Dec 2024 14:38:27 -0500 Subject: [PATCH 02/17] DIGITAL-239: update files to copy autologout module --- .../dg_autologout/dg_autologout.libraries.yml | 2 +- .../dg_autologout/dg_autologout.services.yml | 4 ++-- .../js/{dg_autologout.js => autologout.js} | 0 ...ogoutManager.php => AutologoutManager.php} | 3 ++- ...ontroller.php => AutologoutController.php} | 24 +++++++++---------- ...e.php => DgAutologoutManagerInterface.php} | 4 ++-- ...ubscriber.php => AutologoutSubscriber.php} | 16 ++++++------- ...tBlockForm.php => AutologoutBlockForm.php} | 14 +++++------ ...ngsForm.php => AutologoutSettingsForm.php} | 2 +- ...ngBlock.php => AutologoutWarningBlock.php} | 2 +- 10 files changed, 35 insertions(+), 36 deletions(-) rename web/modules/custom/dg_autologout/js/{dg_autologout.js => autologout.js} (100%) rename web/modules/custom/dg_autologout/src/{dg_AutologoutManager.php => AutologoutManager.php} (98%) rename web/modules/custom/dg_autologout/src/Controller/{dg_AutologoutController.php => AutologoutController.php} (81%) rename web/modules/custom/dg_autologout/src/{dg_AutologoutManagerInterface.php => DgAutologoutManagerInterface.php} (96%) rename web/modules/custom/dg_autologout/src/EventSubscriber/{dg_AutologoutSubscriber.php => AutologoutSubscriber.php} (90%) rename web/modules/custom/dg_autologout/src/Form/{dg_AutologoutBlockForm.php => AutologoutBlockForm.php} (75%) rename web/modules/custom/dg_autologout/src/Form/{dg_AutologoutSettingsForm.php => AutologoutSettingsForm.php} (99%) rename web/modules/custom/dg_autologout/src/Plugin/Block/{dg_AutologoutWarningBlock.php => AutologoutWarningBlock.php} (98%) diff --git a/web/modules/custom/dg_autologout/dg_autologout.libraries.yml b/web/modules/custom/dg_autologout/dg_autologout.libraries.yml index d977410c..3532c7c3 100644 --- a/web/modules/custom/dg_autologout/dg_autologout.libraries.yml +++ b/web/modules/custom/dg_autologout/dg_autologout.libraries.yml @@ -1,7 +1,7 @@ drupal.dg_autologout: version: VERSION js: - js/dg_autologout.js: {} + js/autologout.js: {} dependencies: - core/drupal.dialog diff --git a/web/modules/custom/dg_autologout/dg_autologout.services.yml b/web/modules/custom/dg_autologout/dg_autologout.services.yml index 3e88eba2..bba6289f 100644 --- a/web/modules/custom/dg_autologout/dg_autologout.services.yml +++ b/web/modules/custom/dg_autologout/dg_autologout.services.yml @@ -7,6 +7,6 @@ services: dg_autologout.manager: class: Drupal\dg_autologout\AutologoutManager - tags: - - {name: dg_autologout_manager} + # tags: + # - {name: autologout_manager} arguments: ['@module_handler', '@config.factory', '@messenger', '@current_user', '@logger.factory', '@session_manager', '@user.data', '@datetime.time', '@entity_type.manager', '@request_stack'] diff --git a/web/modules/custom/dg_autologout/js/dg_autologout.js b/web/modules/custom/dg_autologout/js/autologout.js similarity index 100% rename from web/modules/custom/dg_autologout/js/dg_autologout.js rename to web/modules/custom/dg_autologout/js/autologout.js diff --git a/web/modules/custom/dg_autologout/src/dg_AutologoutManager.php b/web/modules/custom/dg_autologout/src/AutologoutManager.php similarity index 98% rename from web/modules/custom/dg_autologout/src/dg_AutologoutManager.php rename to web/modules/custom/dg_autologout/src/AutologoutManager.php index 3a06af21..d3921ab6 100644 --- a/web/modules/custom/dg_autologout/src/dg_AutologoutManager.php +++ b/web/modules/custom/dg_autologout/src/AutologoutManager.php @@ -2,6 +2,7 @@ namespace Drupal\dg_autologout; +// use Drupal\dg_autologout\DgAutologoutManagerInterface as test; use Drupal\Component\Datetime\TimeInterface; use Drupal\Component\Utility\Xss; use Drupal\Core\Config\Config; @@ -23,7 +24,7 @@ /** * Defines an AutologoutManager service. */ -class AutologoutManager implements AutologoutManagerInterface { +class AutologoutManager implements DgAutologoutManagerInterface { use StringTranslationTrait; diff --git a/web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php similarity index 81% rename from web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php rename to web/modules/custom/dg_autologout/src/Controller/AutologoutController.php index a4c0c0d3..38b86c0c 100644 --- a/web/modules/custom/dg_autologout/src/Controller/dg_AutologoutController.php +++ b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php @@ -1,6 +1,5 @@ dg_autoLogoutManager = $dg_autologout; + public function __construct(DgAutologoutManagerInterface $autologout, TimeInterface $time, RequestStack $requestStack) { + $this->autoLogoutManager = $autologout; $this->time = $time; $this->requestStack = $requestStack; } @@ -74,8 +72,8 @@ public static function create(ContainerInterface $container) { * Alternative logout. */ public function altLogout() { - $redirect_url = $this->dg_autoLogoutManager->getUserRedirectUrl(); - $this->dg_autoLogoutManager->logout(); + $redirect_url = $this->autoLogoutManager->getUserRedirectUrl(); + $this->autoLogoutManager->logout(); $url = Url::fromUserInput( $redirect_url, [ @@ -93,7 +91,7 @@ public function altLogout() { * AJAX logout. */ public function ajaxLogout() { - $this->dg_autoLogoutManager->logout(); + $this->autoLogoutManager->logout(); $response = new AjaxResponse(); $response->setStatusCode(200); @@ -136,7 +134,7 @@ public function ajaxGetRemainingTime() { $time_remaining_ms = $this->autoLogoutManager->getRemainingTime() * 1000; // Reset the timer. - $markup = $this->dg_autoLogoutManager->createTimer(); + $markup = $this->autoLogoutManager->createTimer(); $response->addCommand(new ReplaceCommand('#timer', $markup)); $response->addCommand(new SettingsCommand([ diff --git a/web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php b/web/modules/custom/dg_autologout/src/DgAutologoutManagerInterface.php similarity index 96% rename from web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php rename to web/modules/custom/dg_autologout/src/DgAutologoutManagerInterface.php index d562956f..83619f5e 100644 --- a/web/modules/custom/dg_autologout/src/dg_AutologoutManagerInterface.php +++ b/web/modules/custom/dg_autologout/src/DgAutologoutManagerInterface.php @@ -5,9 +5,9 @@ use Drupal\user\UserInterface; /** - * Interface for dg_AutologoutManager. + * Interface for AutologoutManager. */ -interface dg_AutologoutManagerInterface { +interface DgAutologoutManagerInterface { /** * Get the timer HTML markup. diff --git a/web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php b/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php similarity index 90% rename from web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php rename to web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php index 67c6cbf1..b2d4d11d 100644 --- a/web/modules/custom/dg_autologout/src/EventSubscriber/dg_AutologoutSubscriber.php +++ b/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php @@ -9,7 +9,7 @@ use Drupal\Core\Session\AccountInterface; use Drupal\Core\Theme\ThemeManager; use Drupal\Core\Url; -use Drupal\dg_autologout\dg_AutologoutManagerInterface; +use Drupal\dg_autologout\DgAutologoutManagerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RequestStack; @@ -24,9 +24,9 @@ class AutologoutSubscriber implements EventSubscriberInterface { /** * The autologout manager service. * - * @var \Drupal\dg_autologout\dg_AutologoutManagerInterface + * @var \Drupal\dg_autologout\DgAutologoutManagerInterface */ - protected dg_AutologoutManagerInterface $dg_autoLogoutManager; + protected DgAutologoutManagerInterface $AutologoutManager; /** * The user account service. @@ -73,7 +73,7 @@ class AutologoutSubscriber implements EventSubscriberInterface { /** * Constructs an AutologoutSubscriber object. * - * @param \Drupal\dg_autologout\dg_AutologoutManagerInterface $dg_autologout + * @param \Drupal\dg_autologout\DgAutologoutManagerInterface $dg_autologout * The autologout manager service. * @param \Drupal\Core\Session\AccountInterface $account * The user account service. @@ -88,8 +88,8 @@ class AutologoutSubscriber implements EventSubscriberInterface { * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. */ - public function __construct(dg_AutologoutManagerInterface $dg_autologout, AccountInterface $account, ConfigFactory $config, ThemeManager $theme, TimeInterface $time, RequestStack $requestStack, LanguageManagerInterface $language_manager) { - $this->dg_autoLogoutManager = $dg_autologout; + public function __construct(DgAutologoutManagerInterface $dg_autologout, AccountInterface $account, ConfigFactory $config, ThemeManager $theme, TimeInterface $time, RequestStack $requestStack, LanguageManagerInterface $language_manager) { + $this->AutologoutManager = $dg_autologout; $this->currentUser = $account; $this->config = $config; $this->theme = $theme; @@ -105,7 +105,7 @@ public function __construct(dg_AutologoutManagerInterface $dg_autologout, Accoun * The request event. */ public function onRequest(RequestEvent $event) { - $dg_autologout_manager = $this->dg_autoLogoutManager; + $dg_autologout_manager = $this->AutologoutManager; $uid = $this->currentUser->id(); @@ -139,7 +139,7 @@ public function onRequest(RequestEvent $event) { } } - if ($this->dg_autoLogoutManager->preventJs()) { + if ($this->AutologoutManager->preventJs()) { return; } diff --git a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php similarity index 75% rename from web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php rename to web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php index d6d14012..2f42ff53 100644 --- a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutBlockForm.php +++ b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php @@ -4,7 +4,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\dg_autologout\dg_AutologoutManagerInterface; +use Drupal\dg_autologout\DgAutologoutManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -15,9 +15,9 @@ class dg_AutologoutBlockForm extends FormBase { /** * The autologout manager service. * - * @var \Drupal\dg_autologout\dg_AutologoutManagerInterface + * @var \Drupal\dg_autologout\DgAutologoutManagerInterface */ - protected $dg_autoLogoutManager; + protected $AutologoutManager; /** * {@inheritdoc} @@ -29,11 +29,11 @@ public function getFormId() { /** * Constructs an AutologoutBlockForm object. * - * @param \Drupal\dg_autologout\dg_AutologoutManagerInterface $dg_autologout + * @param \Drupal\dg_autologout\DgAutologoutManagerInterface $dg_autologout * The autologout manager service. */ - public function __construct(dg_AutologoutManagerInterface $dg_autologout) { - $this->dg_autoLogoutManager = $dg_autologout; + public function __construct(DgAutologoutManagerInterface $dg_autologout) { + $this->AutologoutManager = $dg_autologout; } /** @@ -61,7 +61,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; $form['timer'] = [ - '#markup' => $this->dg_autoLogoutManager->createTimer(), + '#markup' => $this->AutologoutManager->createTimer(), ]; return $form; diff --git a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php b/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php similarity index 99% rename from web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php rename to web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php index 566c91dd..db5de510 100644 --- a/web/modules/custom/dg_autologout/src/Form/dg_AutologoutSettingsForm.php +++ b/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php @@ -16,7 +16,7 @@ /** * Provides settings for autologout module. */ -class dg_AutologoutSettingsForm extends ConfigFormBase { +class AutologoutSettingsForm extends ConfigFormBase { /** * Defines the timeout limit. diff --git a/web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php b/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php similarity index 98% rename from web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php rename to web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php index ac50db3e..428034af 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/Block/dg_AutologoutWarningBlock.php +++ b/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php @@ -1,6 +1,6 @@ Date: Wed, 18 Dec 2024 14:40:58 -0500 Subject: [PATCH 03/17] DIGITAL-239: Udpate to config --- config/sync/core.extension.yml | 1 + config/sync/dg_autologout.settings.yml | 27 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 config/sync/dg_autologout.settings.yml diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index aef11b06..cf6d49c9 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -17,6 +17,7 @@ module: dblog: 0 default_content: 0 default_content_config: 0 + dg_autologout: 0 dg_breadcrumb: 0 dg_fields: 0 dg_token: 0 diff --git a/config/sync/dg_autologout.settings.yml b/config/sync/dg_autologout.settings.yml new file mode 100644 index 00000000..c91dc49f --- /dev/null +++ b/config/sync/dg_autologout.settings.yml @@ -0,0 +1,27 @@ +_core: + default_config_hash: ou29sK1fi0MGjbVgsIAp1n-2_yofUuGcszRhDDPwpYo +enabled: true +timeout: 43200 +max_timeout: 43200 +padding: null +logout_regardless_of_activity: true +no_individual_logout_threshold: false +role_logout: false +role_logout_max: false +redirect_url: /user/login +include_destination: true +no_dialog: true +message: 'We are about to log you out for inactivity. If we do, you will lose any unsaved work. Do you need more time?' +inactivity_message: 'You have been logged out due to inactivity.' +inactivity_message_type: status +modal_width: 450 +enforce_admin: true +jstimer_format: '%hours%:%mins%:%secs%' +jstimer_js_load_option: false +use_alt_logout_method: false +use_watchdog: true +dialog_title: 'Digital.gov Alert' +disable_buttons: false +yes_button: '' +no_button: '' +whitelisted_ip_addresses: '' From 6462d0967388c2df6269fb5cfec074def9b14fba Mon Sep 17 00:00:00 2001 From: christian medders Date: Wed, 18 Dec 2024 15:27:22 -0500 Subject: [PATCH 04/17] DIGITAL-239: Code Standard fixes --- web/modules/custom/dg_autologout/dg_autologout.api.php | 3 ++- web/modules/custom/dg_autologout/dg_autologout.install | 3 ++- web/modules/custom/dg_autologout/src/AutologoutManager.php | 1 - .../dg_autologout/src/Controller/AutologoutController.php | 1 - .../src/EventSubscriber/AutologoutSubscriber.php | 3 +-- .../custom/dg_autologout/src/Form/AutologoutBlockForm.php | 4 ++-- ...dg_ConfigAutologoutRoles.php => ConfigAutologoutRoles.php} | 0 .../source/{dg_AutologoutRoles.php => AutologoutRoles.php} | 0 .../source/d6/{dg_AutologoutRoles.php => AutologoutRoles.php} | 0 .../source/d7/{dg_AutologoutRoles.php => AutologoutRoles.php} | 0 10 files changed, 7 insertions(+), 8 deletions(-) rename web/modules/custom/dg_autologout/src/Plugin/migrate/destination/{dg_ConfigAutologoutRoles.php => ConfigAutologoutRoles.php} (100%) rename web/modules/custom/dg_autologout/src/Plugin/migrate/source/{dg_AutologoutRoles.php => AutologoutRoles.php} (100%) rename web/modules/custom/dg_autologout/src/Plugin/migrate/source/d6/{dg_AutologoutRoles.php => AutologoutRoles.php} (100%) rename web/modules/custom/dg_autologout/src/Plugin/migrate/source/d7/{dg_AutologoutRoles.php => AutologoutRoles.php} (100%) diff --git a/web/modules/custom/dg_autologout/dg_autologout.api.php b/web/modules/custom/dg_autologout/dg_autologout.api.php index 5027bf0c..e2c78f92 100644 --- a/web/modules/custom/dg_autologout/dg_autologout.api.php +++ b/web/modules/custom/dg_autologout/dg_autologout.api.php @@ -10,7 +10,8 @@ * * This allows other modules to indicate that a page should not be included * in the dg_autologout checks. This works in the same way as not ticking the - * enforce on admin pages option for dg_autologout which stops a user being logged + * enforce on admin pages option for + * dg_autologout which stops a user being logged * out of admin pages. * * @return bool diff --git a/web/modules/custom/dg_autologout/dg_autologout.install b/web/modules/custom/dg_autologout/dg_autologout.install index e9b9c1e4..447aae54 100644 --- a/web/modules/custom/dg_autologout/dg_autologout.install +++ b/web/modules/custom/dg_autologout/dg_autologout.install @@ -24,7 +24,8 @@ function dg_autologout_update_8001(&$sandbox) { $result = array_slice($result, $sandbox['current'], $limit); foreach ($result as $row) { $key = $row->name; - // User uid is a part of the key after. E.g. dg_autologout.user.1 for user 1. + // User uid is a part of the key after. + // E.g. dg_autologout.user.1 for user 1. $user_id = (substr($key, 16)); $data = unserialize($row->data); \Drupal::service('user.data')->set('dg_autologout', $user_id, 'timeout', $data['timeout']); diff --git a/web/modules/custom/dg_autologout/src/AutologoutManager.php b/web/modules/custom/dg_autologout/src/AutologoutManager.php index d3921ab6..446b841c 100644 --- a/web/modules/custom/dg_autologout/src/AutologoutManager.php +++ b/web/modules/custom/dg_autologout/src/AutologoutManager.php @@ -2,7 +2,6 @@ namespace Drupal\dg_autologout; -// use Drupal\dg_autologout\DgAutologoutManagerInterface as test; use Drupal\Component\Datetime\TimeInterface; use Drupal\Component\Utility\Xss; use Drupal\Core\Config\Config; diff --git a/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php index 38b86c0c..2d0eaae2 100644 --- a/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php +++ b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php @@ -1,6 +1,5 @@ Date: Fri, 20 Dec 2024 16:27:31 -0500 Subject: [PATCH 05/17] DIGITAL-239: Don't let users set a logout period for DG autologout as well. --- config/sync/dg_autologout.role.admin.yml | 3 +++ config/sync/dg_autologout.role.authenticated.yml | 3 +++ config/sync/dg_autologout.role.author.yml | 3 +++ config/sync/dg_autologout.role.content_admin.yml | 3 +++ config/sync/dg_autologout.role.data_analyst.yml | 3 +++ config/sync/dg_autologout.role.editor.yml | 3 +++ config/sync/dg_autologout.role.identifier_admin.yml | 3 +++ config/sync/dg_autologout.role.publisher.yml | 3 +++ config/sync/dg_autologout.role.user_admin.yml | 3 +++ config/sync/dg_autologout.settings.yml | 2 +- 10 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 config/sync/dg_autologout.role.admin.yml create mode 100644 config/sync/dg_autologout.role.authenticated.yml create mode 100644 config/sync/dg_autologout.role.author.yml create mode 100644 config/sync/dg_autologout.role.content_admin.yml create mode 100644 config/sync/dg_autologout.role.data_analyst.yml create mode 100644 config/sync/dg_autologout.role.editor.yml create mode 100644 config/sync/dg_autologout.role.identifier_admin.yml create mode 100644 config/sync/dg_autologout.role.publisher.yml create mode 100644 config/sync/dg_autologout.role.user_admin.yml diff --git a/config/sync/dg_autologout.role.admin.yml b/config/sync/dg_autologout.role.admin.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.admin.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.authenticated.yml b/config/sync/dg_autologout.role.authenticated.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.authenticated.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.author.yml b/config/sync/dg_autologout.role.author.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.author.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.content_admin.yml b/config/sync/dg_autologout.role.content_admin.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.content_admin.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.data_analyst.yml b/config/sync/dg_autologout.role.data_analyst.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.data_analyst.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.editor.yml b/config/sync/dg_autologout.role.editor.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.editor.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.identifier_admin.yml b/config/sync/dg_autologout.role.identifier_admin.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.identifier_admin.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.publisher.yml b/config/sync/dg_autologout.role.publisher.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.publisher.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.role.user_admin.yml b/config/sync/dg_autologout.role.user_admin.yml new file mode 100644 index 00000000..bd22cf4d --- /dev/null +++ b/config/sync/dg_autologout.role.user_admin.yml @@ -0,0 +1,3 @@ +enabled: false +timeout: null +url: '' diff --git a/config/sync/dg_autologout.settings.yml b/config/sync/dg_autologout.settings.yml index c91dc49f..8b91616e 100644 --- a/config/sync/dg_autologout.settings.yml +++ b/config/sync/dg_autologout.settings.yml @@ -5,7 +5,7 @@ timeout: 43200 max_timeout: 43200 padding: null logout_regardless_of_activity: true -no_individual_logout_threshold: false +no_individual_logout_threshold: true role_logout: false role_logout_max: false redirect_url: /user/login From 48f852e906969257ad2ceae4940dd36c329a9dcc Mon Sep 17 00:00:00 2001 From: Matt Poole Date: Fri, 20 Dec 2024 16:27:46 -0500 Subject: [PATCH 06/17] DIGITAL-239: Fixed property name reference. --- .../src/EventSubscriber/AutologoutSubscriber.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php b/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php index e160546e..d1aeeb9c 100644 --- a/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php +++ b/web/modules/custom/dg_autologout/src/EventSubscriber/AutologoutSubscriber.php @@ -88,7 +88,7 @@ class AutologoutSubscriber implements EventSubscriberInterface { * The language manager. */ public function __construct(DgAutologoutManagerInterface $dg_autologout, AccountInterface $account, ConfigFactory $config, ThemeManager $theme, TimeInterface $time, RequestStack $requestStack, LanguageManagerInterface $language_manager) { - $this->AutologoutManager = $dg_autologout; + $this->autologoutManager = $dg_autologout; $this->currentUser = $account; $this->config = $config; $this->theme = $theme; @@ -104,7 +104,7 @@ public function __construct(DgAutologoutManagerInterface $dg_autologout, Account * The request event. */ public function onRequest(RequestEvent $event) { - $dg_autologout_manager = $this->AutologoutManager; + $dg_autologout_manager = $this->autologoutManager; $uid = $this->currentUser->id(); @@ -138,7 +138,7 @@ public function onRequest(RequestEvent $event) { } } - if ($this->AutologoutManager->preventJs()) { + if ($this->autologoutManager->preventJs()) { return; } From 3d0c4c0ec450f17edcace59d9aa9becb383f7c77 Mon Sep 17 00:00:00 2001 From: Matt Poole Date: Mon, 23 Dec 2024 10:46:34 -0500 Subject: [PATCH 07/17] DIGITAL-239: Made the DG autologout.js more unique with regards to re-using the same names. --- .../custom/dg_autologout/js/autologout.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web/modules/custom/dg_autologout/js/autologout.js b/web/modules/custom/dg_autologout/js/autologout.js index 9a6dbe4b..6d855856 100644 --- a/web/modules/custom/dg_autologout/js/autologout.js +++ b/web/modules/custom/dg_autologout/js/autologout.js @@ -53,7 +53,7 @@ localSettings = jQuery.extend(true, {}, settings.dg_autologout); // Add timer element to prevent detach of all behaviours. - let timerMarkup = $('
').hide(); + let timerMarkup = $('
').hide(); $('body').append(timerMarkup); if (localSettings.refresh_only) { @@ -120,7 +120,7 @@ // While the countdown timer is going, lookup the remaining time. If // there is more time remaining (i.e. a user is navigating in another // tab), then reset the timer for opening the dialog. - Drupal.Ajax['dg_autologout.getTimeLeft'].dg_autologoutGetTimeLeft(function (time) { + Drupal.Ajax['dg_autologout.getTimeLeft'].dgAutologoutGetTimeLeft(function (time) { if (time > 0) { clearTimeout(paddingTimer); t = setTimeout(init, time); @@ -157,7 +157,7 @@ }; } - return $('
' + localSettings.message + '
').dialog({ + return $('
' + localSettings.message + '
').dialog({ modal: true, closeOnEscape: false, width: localSettings.modal_width, @@ -175,7 +175,7 @@ function confirmLogout() { $(theDialog).dialog('destroy'); - Drupal.Ajax['dg_autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) { + Drupal.Ajax['dg_autologout.getTimeLeft'].dgAutologoutGetTimeLeft(function (time) { if (time > 0) { t = setTimeout(init, time); } @@ -238,7 +238,7 @@ * The function to run when ajax is successful. The time parameter * is the time remaining for the current user in ms. */ - Drupal.Ajax.prototype.dg_autologoutGetTimeLeft = function (callback) { + Drupal.Ajax.prototype.dgAutologoutGetTimeLeft = function (callback) { let ajax = this; // Store the original success temporary to be called later. @@ -261,7 +261,7 @@ callback(response[key].settings.time); } if (response[key].command === "insert" && response[key].selector === '#timer' && typeof response[key].data !== 'undefined') { - response[key].data = ''; + response[key].data = ''; } } @@ -299,7 +299,7 @@ * @param function timerFunction * The function to tell the timer to run after its been restarted. */ - Drupal.Ajax.prototype.dg_autologoutRefresh = function (timerfunction) { + Drupal.Ajax.prototype.dgAutologoutRefresh = function (timerfunction) { let ajax = this; if (ajax.ajaxing) { @@ -320,7 +320,7 @@ t = setTimeout(timerfunction, localSettings.timeout); // Wrap response data in timer markup to prevent detach of all behaviors. - response[0].data = ''; + response[0].data = ''; // Let Drupal.ajax handle the JSON response. return originalSuccess.call(ajax, response, status, xmlhttprequest); @@ -346,14 +346,14 @@ function keepAlive() { if (!document.hidden) { - Drupal.Ajax['dg_autologout.refresh'].autologoutRefresh(keepAlive); + Drupal.Ajax['dg_autologout.refresh'].dgAutologoutRefresh(keepAlive); } else { t = setTimeout(keepAlive, localSettings.timeout); } } function refresh() { - Drupal.Ajax['dg_autologout.refresh'].autologoutRefresh(init); + Drupal.Ajax['dg_autologout.refresh'].dgAutologoutRefresh(init); } // Check if the page was loaded via a back button click. From 07e34534d65e6c15f9a8b53e22c04679947a3846 Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:21:58 -0500 Subject: [PATCH 08/17] DIGITAL-239: update to coding standards --- .../dg_autologout/src/Controller/AutologoutController.php | 2 +- .../custom/dg_autologout/src/Form/AutologoutBlockForm.php | 4 ++-- .../custom/dg_autologout/src/Form/AutologoutSettingsForm.php | 2 +- .../dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php index 2d0eaae2..03147411 100644 --- a/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php +++ b/web/modules/custom/dg_autologout/src/Controller/AutologoutController.php @@ -60,7 +60,7 @@ public function __construct(DgAutologoutManagerInterface $autologout, TimeInterf * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( + return new self( $container->get('dg_autologout.manager'), $container->get('datetime.time'), $container->get('request_stack') diff --git a/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php index 29aaaa88..8a70e72d 100644 --- a/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php +++ b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php @@ -33,14 +33,14 @@ public function getFormId() { * The autologout manager service. */ public function __construct(DgAutologoutManagerInterface $dg_autologout) { - $this->AutologoutManager = $dg_autologout; + $this->autologoutManager = $dg_autologout; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( + return new self( $container->get('dg_autologout.manager') ); } diff --git a/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php b/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php index db5de510..2d61ed74 100644 --- a/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php +++ b/web/modules/custom/dg_autologout/src/Form/AutologoutSettingsForm.php @@ -79,7 +79,7 @@ public function __construct(ConfigFactoryInterface $config_factory, TypedConfigM * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static( + return new self( $container->get('config.factory'), $container->get('config.typed'), $container->get('module_handler'), diff --git a/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php b/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php index 428034af..ae6b02c7 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php +++ b/web/modules/custom/dg_autologout/src/Plugin/Block/AutologoutWarningBlock.php @@ -90,7 +90,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( + return new self( $configuration, $plugin_id, $plugin_definition, From 94b763957c90fd06c6cb0f80f4306145631a539b Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:29:23 -0500 Subject: [PATCH 09/17] DIGITAL-239: Standard update --- .../custom/dg_autologout/src/Form/AutologoutBlockForm.php | 2 +- .../src/Plugin/migrate/destination/ConfigAutologoutRoles.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php index 8a70e72d..bbe1f078 100644 --- a/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php +++ b/web/modules/custom/dg_autologout/src/Form/AutologoutBlockForm.php @@ -61,7 +61,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; $form['timer'] = [ - '#markup' => $this->AutologoutManager->createTimer(), + '#markup' => $this->autologoutManager->createTimer(), ]; return $form; diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 68421e63..4d3bb204 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -4,6 +4,7 @@ use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; +use Drupal\Core\Entity\EntityTypeManagerInterface; /** * Autologout Configuration Migration. From 24d18d8123857f90207a5e9ca544451373f1740c Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:32:11 -0500 Subject: [PATCH 10/17] DIGITAL-239: coding standard fix --- .../destination/ConfigAutologoutRoles.php | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 4d3bb204..6e1e517b 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -5,6 +5,7 @@ use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Autologout Configuration Migration. @@ -15,12 +16,38 @@ */ class ConfigAutologoutRoles extends Config { + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Constructs a ConfigAutologoutRoles object. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager service. + */ + public function __construct(EntityTypeManagerInterface $entity_type_manager) { + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $container->get('entity_type.manager') + ); + } + /** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = []) { $dg_autologout_role = 'dg_autologout.role.'; - $roles = \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(); + $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); foreach ($roles as $role) { if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { $dg_autologout_role = 'dg_autologout.role.' . $role->id(); @@ -35,5 +62,4 @@ public function import(Row $row, array $old_destination_id_values = []) { return $entity_ids; } - } From 406f1bcfb7204fe24cda41400999313c960ff929 Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:34:36 -0500 Subject: [PATCH 11/17] DIGITAL-239: reverting change --- .../destination/ConfigAutologoutRoles.php | 30 ++----------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 6e1e517b..4d3bb204 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -5,7 +5,6 @@ use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * Autologout Configuration Migration. @@ -16,38 +15,12 @@ */ class ConfigAutologoutRoles extends Config { - /** - * The entity type manager service. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - protected $entityTypeManager; - - /** - * Constructs a ConfigAutologoutRoles object. - * - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager service. - */ - public function __construct(EntityTypeManagerInterface $entity_type_manager) { - $this->entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $container->get('entity_type.manager') - ); - } - /** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = []) { $dg_autologout_role = 'dg_autologout.role.'; - $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); + $roles = \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(); foreach ($roles as $role) { if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { $dg_autologout_role = 'dg_autologout.role.' . $role->id(); @@ -62,4 +35,5 @@ public function import(Row $row, array $old_destination_id_values = []) { return $entity_ids; } + } From 21da65641475be6e46323af2269e5b2cab74a36e Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:37:39 -0500 Subject: [PATCH 12/17] DIGITAL-239: code standard fix --- .../src/Plugin/migrate/destination/ConfigAutologoutRoles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 4d3bb204..b26d2985 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -20,7 +20,7 @@ class ConfigAutologoutRoles extends Config { */ public function import(Row $row, array $old_destination_id_values = []) { $dg_autologout_role = 'dg_autologout.role.'; - $roles = \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(); + $roles = entityTypeManager()->getStorage('user_role')->loadMultiple(); foreach ($roles as $role) { if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { $dg_autologout_role = 'dg_autologout.role.' . $role->id(); From daf7ce8a2a618d99f9384b41fb9f5879aa7034fc Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:41:38 -0500 Subject: [PATCH 13/17] DIGITAL-239: Another update to code standard --- .../destination/ConfigAutologoutRoles.php | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index b26d2985..22f9993c 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -2,9 +2,10 @@ namespace Drupal\dg_autologout\Plugin\migrate\destination; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; -use Drupal\Core\Entity\EntityTypeManagerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Autologout Configuration Migration. @@ -15,15 +16,51 @@ */ class ConfigAutologoutRoles extends Config { + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Constructs a new ConfigAutologoutRoles object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_type.manager') + ); + } + /** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = []) { $dg_autologout_role = 'dg_autologout.role.'; - $roles = entityTypeManager()->getStorage('user_role')->loadMultiple(); + $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); foreach ($roles as $role) { if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { - $dg_autologout_role = 'dg_autologout.role.' . $role->id(); + $dg_autologout_role = 'dg_autologout.role.'. $role->id(); $this->config->setName($dg_autologout_role); $this->config->save(); break; From cf8297a31208e02a69e9313166407313e930cc61 Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:50:29 -0500 Subject: [PATCH 14/17] DIGITAL-239: trying something else --- .../destination/ConfigAutologoutRoles.php | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 22f9993c..d21c244e 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -2,9 +2,9 @@ namespace Drupal\dg_autologout\Plugin\migrate\destination; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -17,7 +17,7 @@ class ConfigAutologoutRoles extends Config { /** - * The entity type manager. + * The entity type manager service. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ @@ -26,17 +26,10 @@ class ConfigAutologoutRoles extends Config { /** * Constructs a new ConfigAutologoutRoles object. * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. + * The entity type manager service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition); + public function __construct(EntityTypeManagerInterface $entity_type_manager) { $this->entityTypeManager = $entity_type_manager; } @@ -45,9 +38,6 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( - $configuration, - $plugin_id, - $plugin_definition, $container->get('entity_type.manager') ); } @@ -58,9 +48,10 @@ public static function create(ContainerInterface $container, array $configuratio public function import(Row $row, array $old_destination_id_values = []) { $dg_autologout_role = 'dg_autologout.role.'; $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); + foreach ($roles as $role) { if (strtolower($row->getSourceProperty('role')) === strtolower($role->label())) { - $dg_autologout_role = 'dg_autologout.role.'. $role->id(); + $dg_autologout_role = 'dg_autologout.role.' . $role->id(); $this->config->setName($dg_autologout_role); $this->config->save(); break; @@ -72,5 +63,5 @@ public function import(Row $row, array $old_destination_id_values = []) { return $entity_ids; } - } + From e8254aac6d327b6803f381dc212cbb105c370d4c Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:52:55 -0500 Subject: [PATCH 15/17] DIGITAL-239: Fix new dep --- .../src/Plugin/migrate/destination/ConfigAutologoutRoles.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index d21c244e..8f6d8c6d 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -36,8 +36,8 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) { /** * {@inheritdoc} */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, $migration) { + return new self( $container->get('entity_type.manager') ); } From 7085105c3e5ec2c4f4837dadfcfda08aabd0b3a0 Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 13:59:04 -0500 Subject: [PATCH 16/17] DIGITAL-239: making migration optional --- .../src/Plugin/migrate/destination/ConfigAutologoutRoles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 8f6d8c6d..17e2d92a 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -36,7 +36,7 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) { /** * {@inheritdoc} */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, $migration) { + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, $migration = NULL) { return new self( $container->get('entity_type.manager') ); From beffa8c2396c079d409f1411ec8739ba661629e8 Mon Sep 17 00:00:00 2001 From: christian medders Date: Mon, 23 Dec 2024 14:08:28 -0500 Subject: [PATCH 17/17] DIGITAL-239: Update to more code --- web/modules/custom/dg_autologout/dg_autologout.install | 2 +- .../src/Plugin/migrate/destination/ConfigAutologoutRoles.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web/modules/custom/dg_autologout/dg_autologout.install b/web/modules/custom/dg_autologout/dg_autologout.install index 447aae54..f532cb47 100644 --- a/web/modules/custom/dg_autologout/dg_autologout.install +++ b/web/modules/custom/dg_autologout/dg_autologout.install @@ -27,7 +27,7 @@ function dg_autologout_update_8001(&$sandbox) { // User uid is a part of the key after. // E.g. dg_autologout.user.1 for user 1. $user_id = (substr($key, 16)); - $data = unserialize($row->data); + $data = serialize($row->data); \Drupal::service('user.data')->set('dg_autologout', $user_id, 'timeout', $data['timeout']); \Drupal::service('user.data')->set('dg_autologout', $user_id, 'enabled', $data['enabled']); $sandbox['current']++; diff --git a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php index 17e2d92a..54d03ebc 100644 --- a/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php +++ b/web/modules/custom/dg_autologout/src/Plugin/migrate/destination/ConfigAutologoutRoles.php @@ -2,9 +2,9 @@ namespace Drupal\dg_autologout\Plugin\migrate\destination; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\migrate\Plugin\migrate\destination\Config; use Drupal\migrate\Row; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -62,6 +62,7 @@ public function import(Row $row, array $old_destination_id_values = []) { $entity_ids[0] = $dg_autologout_role; return $entity_ids; + } -} +}