Skip to content
Snippets Groups Projects
Commit 9ffacb46 authored by Ivan Doroshenko's avatar Ivan Doroshenko
Browse files

#3099245: Add option to apply rabbit hole behaviors to all users including administrators.

parent 0958b3c8
No related branches found
No related tags found
2 merge requests!68Issue #3298741: Fix the issues reported by phpcs,!60#3099245: Add option to apply rabbit hole behaviors to all users including administrators.
...@@ -31,6 +31,9 @@ rabbit_hole.behavior_settings.*: ...@@ -31,6 +31,9 @@ rabbit_hole.behavior_settings.*:
action: action:
type: string type: string
label: 'Action' label: 'Action'
no_bypass:
type: boolean
label: 'No bypass'
configuration: configuration:
type: rabbit_hole.behavior.[%parent.action] type: rabbit_hole.behavior.[%parent.action]
......
...@@ -9,6 +9,7 @@ use Drupal\Core\Field\BaseFieldDefinition; ...@@ -9,6 +9,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldConfig;
use Drupal\rabbit_hole\BehaviorSettingsManager; use Drupal\rabbit_hole\BehaviorSettingsManager;
use Drupal\rabbit_hole\Entity\BehaviorSettings;
/** /**
* Install redirect_fallback_action field. * Install redirect_fallback_action field.
...@@ -344,3 +345,21 @@ function rabbit_hole_update_8109() { ...@@ -344,3 +345,21 @@ function rabbit_hole_update_8109() {
->getEditable('rabbit_hole.behavior_settings.default') ->getEditable('rabbit_hole.behavior_settings.default')
->delete(); ->delete();
} }
/**
* Add "no_bypass" settings to existing configuration.
*/
function rabbit_hole_update_8110() {
$config_factory = \Drupal::configFactory();
$configs = $config_factory->listAll('rabbit_hole.behavior_settings');
foreach ($configs as $config) {
$config = $config_factory->getEditable($config);
// Skip configs that already have "no_bypass" values.
if ($config->get('no_bypass') !== NULL) {
continue;
}
$config->set('no_bypass', FALSE);
$config->save(TRUE);
}
}
...@@ -154,8 +154,12 @@ class BehaviorInvoker implements BehaviorInvokerInterface { ...@@ -154,8 +154,12 @@ class BehaviorInvoker implements BehaviorInvokerInterface {
// Adding a note that prefixed values are deprecated. // Adding a note that prefixed values are deprecated.
$values['deprecation_note'] = 'Prefixed values (rh_action, rh_redirect, etc.) are deprecated and will be removed in next versions. Use properties without "rh_" prefix.'; $values['deprecation_note'] = 'Prefixed values (rh_action, rh_redirect, etc.) are deprecated and will be removed in next versions. Use properties without "rh_" prefix.';
$permission = 'rabbit hole bypass ' . $entity->getEntityTypeId(); // Perform the access check if bypass is not disabled.
$values['bypass_access'] = $this->currentUser->hasPermission($permission); $values['bypass_access'] = FALSE;
if (empty($values['no_bypass'])) {
$permission = 'rabbit hole bypass ' . $entity->getEntityTypeId();
$values['bypass_access'] = $this->currentUser->hasPermission($permission);
}
// Allow altering Rabbit Hole values. // Allow altering Rabbit Hole values.
$this->moduleHandler->alter('rabbit_hole_values', $values, $entity); $this->moduleHandler->alter('rabbit_hole_values', $values, $entity);
......
...@@ -25,4 +25,20 @@ interface BehaviorSettingsInterface extends ConfigEntityInterface { ...@@ -25,4 +25,20 @@ interface BehaviorSettingsInterface extends ConfigEntityInterface {
*/ */
public function getAction(); public function getAction();
/**
* Set whether to ignore bypass permissions.
*
* @param bool $no_bypass
* TRUE - ignore, FALSE - do not ignore.
*/
public function setNoBypass(bool $no_bypass);
/**
* Get whether to ignore bypass permissions.
*
* @return bool
* TRUE - ignore, FALSE - do not ignore.
*/
public function getNoBypass(): bool;
} }
...@@ -122,6 +122,7 @@ class BehaviorSettingsManager implements BehaviorSettingsManagerInterface { ...@@ -122,6 +122,7 @@ class BehaviorSettingsManager implements BehaviorSettingsManagerInterface {
$default = $this->configFactory->get('rabbit_hole.behavior_settings.default'); $default = $this->configFactory->get('rabbit_hole.behavior_settings.default');
return !$default->isNew() ? $default->get() : [ return !$default->isNew() ? $default->get() : [
'action' => 'display_page', 'action' => 'display_page',
'no_bypass' => FALSE,
'configuration' => [], 'configuration' => [],
]; ];
} }
...@@ -130,8 +131,10 @@ class BehaviorSettingsManager implements BehaviorSettingsManagerInterface { ...@@ -130,8 +131,10 @@ class BehaviorSettingsManager implements BehaviorSettingsManagerInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getEntityBehaviorSettings(ContentEntityInterface $entity): array { public function getEntityBehaviorSettings(ContentEntityInterface $entity): array {
$values = [];
$config_data = $this->getBehaviorSettings($entity->getEntityTypeId(), $entity->bundle()); $config_data = $this->getBehaviorSettings($entity->getEntityTypeId(), $entity->bundle());
$values = [
'no_bypass' => $config_data['no_bypass'],
];
// We trigger the default bundle action under the following circumstances: // We trigger the default bundle action under the following circumstances:
$trigger_default_bundle_action = $trigger_default_bundle_action =
......
...@@ -25,6 +25,7 @@ use Drupal\rabbit_hole\BehaviorSettingsInterface; ...@@ -25,6 +25,7 @@ use Drupal\rabbit_hole\BehaviorSettingsInterface;
* "entity_id", * "entity_id",
* "uuid", * "uuid",
* "action", * "action",
* "no_bypass",
* "configuration" * "configuration"
* }, * },
* links = {} * links = {}
...@@ -60,6 +61,13 @@ class BehaviorSettings extends ConfigEntityBase implements BehaviorSettingsInter ...@@ -60,6 +61,13 @@ class BehaviorSettings extends ConfigEntityBase implements BehaviorSettingsInter
*/ */
protected $entity_id; protected $entity_id;
/**
* The bypass action.
*
* @var bool
*/
protected $no_bypass;
/** /**
* The action-specific configuration. * The action-specific configuration.
* *
...@@ -81,6 +89,20 @@ class BehaviorSettings extends ConfigEntityBase implements BehaviorSettingsInter ...@@ -81,6 +89,20 @@ class BehaviorSettings extends ConfigEntityBase implements BehaviorSettingsInter
return $this->action; return $this->action;
} }
/**
* {@inheritdoc}
*/
public function setNoBypass(bool $no_bypass) {
$this->no_bypass = $no_bypass;
}
/**
* {@inheritdoc}
*/
public function getNoBypass(): bool {
return $this->no_bypass;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -124,10 +124,17 @@ class FormManglerService { ...@@ -124,10 +124,17 @@ class FormManglerService {
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $this->t('Allow these settings to be overridden for individual entities'), '#title' => $this->t('Allow these settings to be overridden for individual entities'),
'#default_value' => $this->entityHelper->hasRabbitHoleField($entity_type->id(), $bundle_name), '#default_value' => $this->entityHelper->hasRabbitHoleField($entity_type->id(), $bundle_name),
'#description' => $this->t('If this is checked, users with the %permission permission will be able to override these settings for individual entities.', [ '#description' => $this->t('If checked, users with the %permission permission will be able to override these settings for individual entities.', [
'%permission' => $this->t('Administer Rabbit Hole settings for @entity_type', ['@entity_type' => $entity_type->getLabel()]), '%permission' => $this->t('Administer Rabbit Hole settings for @entity_type', ['@entity_type' => $entity_type->getLabel()]),
]), ]),
]; ];
$form['no_bypass'] = [
'#type' => 'checkbox',
'#title' => $this->t('Disable permissions-based bypassing'),
'#default_value' => $settings['no_bypass'],
'#description' => $this->t("If checked, users won't be able to bypass configured Rabbit Hole behavior. It will be applied to Administrators and other users with bypass permissions."),
];
} }
/** /**
...@@ -162,6 +169,7 @@ class FormManglerService { ...@@ -162,6 +169,7 @@ class FormManglerService {
$settings = [ $settings = [
'action' => $action, 'action' => $action,
'no_bypass' => $form_values['no_bypass'],
]; ];
// Get action settings if it exists in the form. // Get action settings if it exists in the form.
......
<?php
namespace Drupal\Tests\rabbit_hole\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPlugin\PageNotFound;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
/**
* Test cases for BehaviorInvoker.
*
* @coversDefaultClass \Drupal\rabbit_hole\BehaviorInvoker
* @group rabbit_hole
*/
class BehaviorInvokerTest extends KernelTestBase {
use ContentTypeCreationTrait;
use UserCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'filter',
'text',
'field',
'user',
'node',
'rabbit_hole',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installConfig(['filter', 'node', 'system', 'rabbit_hole']);
\Drupal::service('rabbit_hole.behavior_settings_manager')->enableEntityType('node');
$this->createContentType(['type' => 'article']);
$this->createContentType(['type' => 'page']);
\Drupal::service('rabbit_hole.behavior_settings_manager')->saveBehaviorSettings([
'action' => 'page_not_found',
'no_bypass' => FALSE,
], 'node_type', 'article');
\Drupal::service('rabbit_hole.behavior_settings_manager')->saveBehaviorSettings([
'action' => 'page_not_found',
'no_bypass' => TRUE,
], 'node_type', 'page');
}
/**
* @covers ::getBehaviorPlugin()
*/
public function testGetBehaviorPlugin() {
$node1 = Node::create(['title' => '#freeAzov', 'type' => 'article']);
$node1->save();
$node2 = Node::create(['title' => 'Support Ukraine', 'type' => 'page']);
$node2->save();
$behavior_invoker = \Drupal::service('rabbit_hole.behavior_invoker');
$this->setUpCurrentUser([], [], TRUE);
// "No bypass" for articles is disabled, so admin should see the page.
// In other words, the plugin should be not available.
$this->assertNull($behavior_invoker->getBehaviorPlugin($node1));
// For pages, "no bypass" is enabled, so action plugin is expected.
$this->assertInstanceOf(PageNotFound::class, $behavior_invoker->getBehaviorPlugin($node2));
// Verify that regular user cannot access article page.
$this->setUpCurrentUser();
$this->assertInstanceOf(PageNotFound::class, $behavior_invoker->getBehaviorPlugin($node1));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment