diff --git a/core/core.services.yml b/core/core.services.yml index 9bfc560..1b0a347 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -592,6 +592,8 @@ services: site_status_negotiator: class: Drupal\Core\Site\StatusNegotiator arguments: ['@state', '@current_user'] + tags: + - { name: service_collector, tag: maintenance_mode_exemption, call: addExemption } maintenance_mode_subscriber: class: Drupal\Core\EventSubscriber\MaintenanceModeSubscriber arguments: ['@site_status_negotiator', '@config.factory', '@string_translation', '@url_generator', '@current_user'] diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php index d9b5f1f..2ae47c8 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php @@ -89,29 +89,31 @@ public function __construct(StatusNegotiatorInterface $status_negotiator, Config */ public function onKernelRequestMaintenance(GetResponseEvent $event) { $request = $event->getRequest(); - if ($this->statusNegotiator->getStatus($this->account) != StatusNegotiatorInterface::SITE_ONLINE) { - // Deliver the 503 page if the site is in maintenance mode and the logged - // in user is not allowed to bypass it. - drupal_maintenance_theme(); - $content = Xss::filterAdmin(String::format($this->config->get('system.maintenance')->get('message'), array( - '@site' => $this->config->get('system.site')->get('name'), - ))); - $content = DefaultHtmlPageRenderer::renderPage($content, t('Site under maintenance')); - $response = new Response('Service unavailable', 503); - $response->setContent($content); - $event->setResponse($response); - } - elseif ($this->statusNegotiator->getStatus() != StatusNegotiatorInterface::SITE_ONLINE) { - // Display a message if the logged in user has access to the site in - // maintenance mode. However, suppress it on the maintenance mode setting - // spage. - $is_maintenance_route = $request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'system.site_maintenance_mode'; - if (!$is_maintenance_route) { - if ($this->account->hasPermission('administer site configuration')) { - $this->drupalSetMessage($this->t('Operating in maintenance mode. Go online.', array('@url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE); - } - else { - $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE); + if ($this->statusNegotiator->getStatus() != StatusNegotiatorInterface::SITE_ONLINE) { + if (!$this->statusNegotiator->exempt($request, $this->account)) { + // Deliver the 503 page if the site is in maintenance mode and the + // logged in user is not allowed to bypass it. + drupal_maintenance_theme(); + $content = Xss::filterAdmin(String::format($this->config->get('system.maintenance')->get('message'), array( + '@site' => $this->config->get('system.site')->get('name'), + ))); + $content = DefaultHtmlPageRenderer::renderPage($content, t('Site under maintenance')); + $response = new Response('Service unavailable', 503); + $response->setContent($content); + $event->setResponse($response); + } + else { + // Display a message if the logged in user has access to the site in + // maintenance mode. However, suppress it on the maintenance mode + // setting spage. + $is_maintenance_route = $request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'system.site_maintenance_mode'; + if (!$is_maintenance_route) { + if ($this->account->hasPermission('administer site configuration')) { + $this->drupalSetMessage($this->t('Operating in maintenance mode. Go online.', array('@url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE); + } + else { + $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE); + } } } } diff --git a/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php b/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php new file mode 100644 index 0000000..506985f --- /dev/null +++ b/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php @@ -0,0 +1,33 @@ +state = $state; + $this->exemptionHandlers = array(); } /** * {@inheritdoc} */ - public function getStatus(AccountInterface $account = NULL) { - if (!isset($this->status)) { - $this->status = $this->state->get('system.maintenance_mode') ? StatusNegotiatorInterface::SITE_OFFLINE : StatusNegotiatorInterface::SITE_ONLINE; - } + public function getStatus() { + return $this->state->get('system.maintenance_mode') ? StatusNegotiatorInterface::SITE_OFFLINE : StatusNegotiatorInterface::SITE_ONLINE; + } - if (isset($account) && $account->hasPermission('access site in maintenance mode')) { - return StatusNegotiatorInterface::SITE_ONLINE; + /** + * {@inheritdoc} + */ + public function exempt(Request $request, AccountInterface $account) { + foreach ($this->exemptionHandlers as $handler) { + if ($handler->exempt($request, $account)) { + return TRUE; + } } - return $this->status; + return FALSE; } /** - * {@inheritdoc} + * Add an exemption handler. + * + * @param \Drupal\Core\Site\MaintenanceExemptionInterface $handler + * A maintenance exemption handler. */ - public function overrideStatus($status = NULL) { - $this->status = $status; + public function addExemption(MaintenanceExemptionInterface $handler) { + $this->exemptionHandlers[] = $handler; } } diff --git a/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php index 153380f..0eabb49 100644 --- a/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php +++ b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php @@ -8,12 +8,11 @@ namespace Drupal\Core\Site; use Drupal\Core\State\StateInterface; -use Drupal\Core\Session\AccountInterface; /** * Provides the default implementation of the site status negotiator. */ -interface StatusNegotiatorInterface { +interface StatusNegotiatorInterface extends MaintenanceExemptionInterface { /** * @defgroup menu_status_codes Menu status codes @@ -38,22 +37,9 @@ /** * Returns whether the site is in maintenance mode. * - * @param \Drupal\Core\Session\AccountInterface $account - * (optional) An account to use when checking whether the site should be - * displayed in maintenance mode. If omitted, the site status is returned. - * * @return int * Either static::SITE_OFFLINE or static::SITE_ONLINE. */ - public function getStatus(AccountInterface $account = NULL); - - /** - * Overrides the site status for the current request. - * - * @param int $status - * (optional) Either static::SITE_OFFLINE or static::SITE_ONLINE. If - * omitted, the overridden status is cleared. - */ - public function overrideStatus($status = NULL); + public function getStatus(); } diff --git a/core/modules/system/src/Site/MaintenanceExemption.php b/core/modules/system/src/Site/MaintenanceExemption.php new file mode 100644 index 0000000..24a8b37 --- /dev/null +++ b/core/modules/system/src/Site/MaintenanceExemption.php @@ -0,0 +1,28 @@ +hasPermission('access site in maintenance mode')) { + return TRUE; + } + } + +} diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml index 8d09004..4caf4d8 100644 --- a/core/modules/system/system.services.yml +++ b/core/modules/system/system.services.yml @@ -33,3 +33,7 @@ services: arguments: ['@cron', '@config.factory', '@state'] tags: - { name: event_subscriber } + system.maintenance_mode_exemption: + class: Drupal\system\Site\MaintenanceExemption + tags: + - { name: maintenance_mode_exemption } diff --git a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php index 2bcc631..ce4db76 100644 --- a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php +++ b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php @@ -58,31 +58,17 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) { $path = $request->attributes->get('_system_path'); if ($site_status == StatusNegotiatorInterface::SITE_OFFLINE) { // If the site is offline, log out unprivileged users. - if ($this->account->isAuthenticated() && !$this->account->hasPermission('access site in maintenance mode')) { + if ($this->account->isAuthenticated() && !$this->statusNegotiator->exempt($request, $this->account)) { user_logout(); // Redirect to homepage. $event->setResponse(new RedirectResponse(url('', array('absolute' => TRUE)))); return; } - if ($this->account->isAnonymous()) { - switch ($path) { - case 'user': - // Forward anonymous user to login page. - $event->setResponse(new RedirectResponse(url('user/login', array('absolute' => TRUE)))); - return; - case 'user/login': - case 'user/password': - // Disable offline mode. - $this->statusNegotiator->overrideStatus(StatusNegotiatorInterface::SITE_ONLINE); - break; - default: - if (strpos($path, 'user/reset/') === 0) { - // Disable offline mode. - $this->statusNegotiator->overrideStatus(StatusNegotiatorInterface::SITE_ONLINE); - } - break; - } + if ($this->account->isAnonymous() && $path == 'user') { + // Forward anonymous user to login page. + $event->setResponse(new RedirectResponse(url('user/login', array('absolute' => TRUE)))); + return; } } if ($this->account->isAuthenticated()) { diff --git a/core/modules/user/src/Site/MaintenanceExemption.php b/core/modules/user/src/Site/MaintenanceExemption.php new file mode 100644 index 0000000..05a3052 --- /dev/null +++ b/core/modules/user/src/Site/MaintenanceExemption.php @@ -0,0 +1,29 @@ +attributes->get('_system_path'); + if ($path == 'user/login' || $path == 'user/password' || strpos($path, 'user/reset/') === 0) { + return TRUE; + } + } + +} diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index 3a3e3a8..74b68df 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -55,3 +55,7 @@ services: user.tempstore: class: Drupal\user\TempStoreFactory arguments: ['@serialization.phpserialize', '@database', '@lock'] + user.maintenance_mode_exemption: + class: Drupal\user\Site\MaintenanceExemption + tags: + - { name: maintenance_mode_exemption }