Skip to content
Snippets Groups Projects
Unverified Commit 7df81ba3 authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #3310756 by heddn, Charlie ChX Negyesi: Add menu item crud permission

parent 1519f257
Branches
Tags
No related merge requests found
......@@ -6,6 +6,8 @@
*/
use Drupal\Core\Site\Settings;
use Drupal\group\Entity\GroupRole;
use Drupal\group\Entity\GroupRoleInterface;
use Drupal\group_content_menu\GroupContentMenuInterface;
use Drupal\menu_link_content\Entity\MenuLinkContent;
......@@ -46,3 +48,30 @@ function group_content_menu_post_update_menu_prefix_rewrite(&$sandbox) {
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
return t("Updated: @progress out of @max menu links.", ['@progress' => $sandbox['progress'], '@max' => $sandbox['max']]);
}
/**
* Add additional group role permission to manage menu links.
*/
function group_content_menu_post_update_group_role_permissions(&$sandbox) {
// If 'progress' is not set, this will be the first run of the batch.
if (!isset($sandbox['progress'])) {
$sandbox['ids'] = \Drupal::entityTypeManager()->getStorage('group_role')
->getQuery()
->condition('permissions.*', 'manage group_content_menu')
->accessCheck(FALSE)
->sort('id', 'ASC')
->execute();
$sandbox['max'] = count($sandbox['ids']);
$sandbox['progress'] = 0;
}
$ids = array_slice($sandbox['ids'], $sandbox['progress'], Settings::get('entity_update_batch_size', 50));
foreach (GroupRole::loadMultiple($ids) as $group_role) {
assert($group_role instanceof GroupRoleInterface);
$group_role->grantPermission('manage group_content_menu menu items')
->save();
$sandbox['progress']++;
}
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
return t("Updated: @progress out of @max group roles.", ['@progress' => $sandbox['progress'], '@max' => $sandbox['max']]);
}
......@@ -32,6 +32,10 @@ class GroupContentMenuPermissionProvider extends GroupContentPermissionProvider
'Manage menus',
'Create, update and delete menus'
);
$permissions['manage group_content_menu menu items'] = $this->buildPermission(
'Manage menu items',
'Create, update and delete menu items within group menus'
);
return $permissions;
}
......
......@@ -76,7 +76,7 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
'_title' => 'Edit menu link',
'_controller' => sprintf('%s::editLink', GroupContentMenuController::class),
])
->setRequirement('_group_permission', 'manage group_content_menu')
->setRequirement('_group_permission', 'manage group_content_menu menu items')
->setRequirement('_group_installed_content', implode('+', $this->getPluginIds()))
->setOption('parameters', [
'group' => ['type' => 'entity:group'],
......@@ -105,7 +105,7 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
'_title' => 'Delete menu link',
'_controller' => sprintf('%s::deleteLink', GroupContentMenuController::class),
])
->setRequirement('_group_permission', 'manage group_content_menu')
->setRequirement('_group_permission', 'manage group_content_menu menu items')
->setRequirement('_group_installed_content', implode('+', $this->getPluginIds()))
->setOption('parameters', [
'group' => ['type' => 'entity:group'],
......@@ -121,6 +121,11 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
*/
protected function getAddPageRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getAddPageRoute($entity_type)) {
$requirements = $route->getRequirements();
// Remove entity access requirement since we only want group permissions,
// not some global user permission.
unset($requirements['_entity_create_any_access']);
$route->setRequirements($requirements);
return $route
->setDefaults([
'_title' => 'Add new menu',
......@@ -138,6 +143,8 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
protected function getAddFormRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getAddFormRoute($entity_type)) {
$requirements = $route->getRequirements();
// Remove entity access requirement since we only want group permissions,
// not some global user permission.
unset($requirements['_entity_create_access']);
$route->setRequirements($requirements);
return $route
......@@ -184,10 +191,13 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
protected function getCanonicalRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getCanonicalRoute($entity_type)) {
$requirements = $route->getRequirements();
// Remove entity access requirement since we only want group permissions,
// not some global user permission.
unset($requirements['_entity_access']);
$route->setRequirements($requirements);
return $route
->setRequirement('_group_menu_owns_content', 'TRUE')
->setRequirement('_group_permission', 'manage group_content_menu')
->setOption('_group_operation_route', TRUE)
->setOption('parameters', [
'group' => ['type' => 'entity:group'],
......@@ -202,11 +212,13 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
protected function getEditFormRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getEditFormRoute($entity_type)) {
$requirements = $route->getRequirements();
// Remove entity access requirement since we only want group permissions,
// not some global user permission.
unset($requirements['_entity_access']);
$route->setRequirements($requirements);
return $route
->setRequirement('_group_menu_owns_content', 'TRUE')
->setRequirement('_group_permission', 'manage group_content_menu')
->setRequirement('_group_permission', 'manage group_content_menu menu items')
->setOption('_group_operation_route', TRUE)
->setOption('parameters', [
'group' => ['type' => 'entity:group'],
......@@ -221,6 +233,8 @@ class GroupContentMenuRouteProvider extends DefaultHtmlRouteProvider {
protected function getDeleteFormRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getDeleteFormRoute($entity_type)) {
$requirements = $route->getRequirements();
// Remove entity access requirement since we only want group permissions,
// not some global user permission.
unset($requirements['_entity_access']);
$route->setRequirements($requirements);
return $route
......
......@@ -5,6 +5,8 @@ namespace Drupal\Tests\group_content_menu\Functional;
use Drupal\Core\Url;
use Drupal\group\Entity\GroupType;
use Drupal\Tests\group\Functional\GroupBrowserTestBase;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;
/**
* Test description.
......@@ -24,18 +26,26 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
'node',
];
/**
* @var string
*/
protected $menuId;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->menuId = strtolower($this->randomMachineName());
// Add group permissions.
$role = GroupType::load('default')->getMemberRole();
$role->grantPermissions([
'access group content menu overview',
'create group_content_menu:group_menu content',
sprintf('create group_content_menu:%s content', $this->menuId),
'manage group_content_menu',
'manage group_content_menu menu items'
]);
$role->save();
......@@ -60,19 +70,24 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
/**
* Test creation of a group content menu with group nodes.
*/
public function testNodeGroupContentMenu() {
/** @var \Drupal\Tests\WebAssert $assert */
public function testNodeGroupContentMenu(): void {
// To see the menu option on the node edit form, add menu access.
$group_creator = $this->drupalCreateUser(array_merge($this->getGlobalPermissions(), [
'administer menu',
]));
$this->drupalLogin($group_creator);
$assert = $this->assertSession();
/** @var \Behat\Mink\Element\DocumentElement $page */
$page = $this->getSession()->getPage();
// Create a group.
$this->drupalGet('/group/add/default');
$page->fillField('label[0][value]', 'Group page');
$group_name = $this->randomString();
$page->fillField('label[0][value]', $group_name);
$page->pressButton('Create Default label and complete your membership');
$page->pressButton('Save group and membership');
$assert->statusCodeEquals(200);
$assert->pageTextContains('Default label Group page has been created.');
$assert->pageTextContains(sprintf('Default label %s has been created.', $group_name));
// Visit the group menu page.
$this->drupalGet('/group/1/menus');
......@@ -83,11 +98,12 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
$this->drupalGet('admin/structure/group_content_menu_types');
$page->clickLink('Add group menu type');
$assert->statusCodeEquals(200);
$page->fillField('label', 'Group Menu');
$page->fillField('id', 'group_menu');
$page->pressButton('Save');
$menu_label = $this->randomString();
$page->fillField('label', $menu_label);
$page->fillField('id', $this->menuId);
$page->pressButton('Save group menu type');
$assert->statusCodeEquals(200);
$assert->pageTextContains('The group menu type Group Menu has been added.');
$assert->pageTextContains(sprintf('The group menu type %s has been added.', $menu_label));
// Enable the gnode content plugin for basic page.
$this->drupalGet('/admin/group/content/install/default/group_node:page');
......@@ -100,7 +116,7 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
$assert->pageTextContains('The content plugin was installed on the group type.');
// Enable the group content plugin.
$this->drupalGet('/admin/group/content/install/default/group_content_menu:group_menu');
$this->drupalGet(sprintf('/admin/group/content/install/default/group_content_menu:%s', $this->menuId));
$page->pressButton('Install plugin');
$assert->pageTextContains('The content plugin was installed on the group type.');
......@@ -148,21 +164,20 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
/**
* Test creation of a group content menu.
*/
public function testCreateGroupContentMenu() {
/** @var \Drupal\Tests\WebAssert $assert */
public function testCreateGroupContentMenu(): void {
$assert = $this->assertSession();
/** @var \Behat\Mink\Element\DocumentElement $page */
$page = $this->getSession()->getPage();
// Generate a group content menu type.
$this->drupalGet('admin/structure/group_content_menu_types');
$page->clickLink('Add group menu type');
$assert->statusCodeEquals(200);
$page->fillField('label', 'Group Menu');
$page->fillField('id', 'group_menu');
$menu_label = $this->randomString();
$page->fillField('label', $menu_label);
$page->fillField('id', $this->menuId);
$page->pressButton('Save');
$assert->statusCodeEquals(200);
$assert->pageTextContains('The group menu type Group Menu has been added.');
$assert->pageTextContains(sprintf('The group menu type %s has been added.', $menu_label));
// Place a group content menu block.
$default_theme = $this->config('system.theme')->get('default');
......@@ -173,7 +188,7 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
],
];
$this->drupalGet(Url::fromRoute('block.admin_library', ['theme' => $default_theme], $options));
$block_name = 'group_content_menu:group_menu';
$block_name = sprintf('group_content_menu:%s', $this->menuId);
$add_url = Url::fromRoute('block.admin_add', [
'plugin_id' => $block_name,
'theme' => $default_theme,
......@@ -187,7 +202,7 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
$assert->statusCodeEquals(200);
// Enable the group content plugin.
$this->drupalGet('/admin/group/content/install/default/group_content_menu:group_menu');
$this->drupalGet(sprintf('/admin/group/content/install/default/group_content_menu:%s', $this->menuId));
$page->checkField('auto_create_group_menu');
$page->checkField('auto_create_home_link');
$page->fillField('auto_create_home_link_title', 'Group home page');
......@@ -236,10 +251,10 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
// Delete menu.
$this->drupalGet('/group/1/menu/1/delete');
$page->pressButton('Delete');
$assert->pageTextContains('The group content menu Group Menu has been deleted.');
$assert->pageTextContains(sprintf('The group content menu %s has been deleted.', $menu_label));
// Re-add menu.
$this->drupalGet('/group/1/content/create/group_content_menu:group_menu');
$this->drupalGet(sprintf('/group/1/content/create/group_content_menu:%s', $this->menuId));
$menu_title = $this->randomString();
$page->fillField('label[0][value]', $menu_title);
$page->pressButton('Save');
......@@ -249,24 +264,23 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
/**
* Test adding the group content menu item manually.
*/
public function testAddMenuManually() {
/** @var \Drupal\Tests\WebAssert $assert */
public function testAddMenuManually(): void {
$assert = $this->assertSession();
/** @var \Behat\Mink\Element\DocumentElement $page */
$page = $this->getSession()->getPage();
// Generate a group content menu type.
$this->drupalGet('admin/structure/group_content_menu_types');
$page->clickLink('Add group menu type');
$assert->statusCodeEquals(200);
$page->fillField('label', 'Group Menu');
$page->fillField('id', 'group_menu');
$menu_label = $this->randomString();
$page->fillField('label', $menu_label);
$page->fillField('id', $this->menuId);
$page->pressButton('Save');
$assert->statusCodeEquals(200);
$assert->pageTextContains('The group menu type Group Menu has been added.');
$assert->pageTextContains(sprintf('The group menu type %s has been added.', $menu_label));
// Enable the group content plugin.
$this->drupalGet('/admin/group/content/install/default/group_content_menu:group_menu');
$this->drupalGet(sprintf('/admin/group/content/install/default/group_content_menu:%s', $this->menuId));
$page->pressButton('Install plugin');
$assert->pageTextContains('The content plugin was installed on the group type. ');
......@@ -291,12 +305,18 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
/**
* Test creation of a group content menu with multiple menu types available.
*/
public function testMultipleMenus() {
/** @var \Drupal\Tests\WebAssert $assert */
public function testMultipleMenus(): void {
$assert = $this->assertSession();
/** @var \Behat\Mink\Element\DocumentElement $page */
$page = $this->getSession()->getPage();
// Add group permissions.
$role = GroupType::load('default')->getMemberRole();
$role->grantPermissions([
'create group_content_menu:group_menu_one content',
'create group_content_menu:group_menu_two content',
]);
$role->save();
// Generate Group Menu One content menu type.
$this->drupalGet('admin/structure/group_content_menu_types/add');
$page->fillField('label', 'Group Menu One');
......@@ -342,25 +362,24 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
/**
* Test Expand All Menu Items option.
*/
public function testExpandAllItems() {
/** @var \Drupal\Tests\WebAssert $assert */
public function testExpandAllItems(): void {
$assert = $this->assertSession();
/** @var \Behat\Mink\Element\DocumentElement $page */
$page = $this->getSession()->getPage();
// Generate a group content menu type.
$this->drupalGet('admin/structure/group_content_menu_types');
$page->clickLink('Add group menu type');
$assert->statusCodeEquals(200);
$page->fillField('label', 'Group Menu');
$page->fillField('id', 'group_menu');
$menu_label = $this->randomString();
$page->fillField('label', $menu_label);
$page->fillField('id', $this->menuId);
$page->pressButton('Save');
$assert->statusCodeEquals(200);
$assert->pageTextContains('The group menu type Group Menu has been added.');
$assert->pageTextContains(sprintf('The group menu type %s has been added.', $menu_label));
// Place group content menu block.
$default_theme = $this->config('system.theme')->get('default');
$group_menu_block = $this->drupalPlaceBlock('group_content_menu:group_menu', [
$group_menu_block = $this->drupalPlaceBlock(sprintf('group_content_menu:%s', $this->menuId), [
'id' => $default_theme . '_groupmenu',
'context_mapping' => [
'group' => '@group.group_route_context:group',
......@@ -370,7 +389,7 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
$group_menu_block_id = $group_menu_block->id();
// Enable the group content plugin.
$this->drupalGet('/admin/group/content/install/default/group_content_menu:group_menu');
$this->drupalGet(sprintf('/admin/group/content/install/default/group_content_menu:%s', $this->menuId));
$page->checkField('auto_create_group_menu');
$page->checkField('auto_create_home_link');
$page->fillField('auto_create_home_link_title', 'Group home page');
......@@ -420,15 +439,193 @@ class GroupContentMenuTest extends GroupBrowserTestBase {
$assert->linkExists($link_sub_level);
}
/**
* Test the group permissions of this module.
*/
public function testGroupPermissions(): void {
// Enable group content menu plugin.
$group_content_menu_type = $this->entityTypeManager->getStorage('group_content_menu_type')->create([
'id' => $this->menuId,
'label' => $this->randomString(),
]);
$group_content_menu_type->save();
$plugin_id = 'group_content_menu:' . $group_content_menu_type->id();
$group_type = GroupType::load('default');
$this->container->get('plugin.manager.group_content_enabler')->clearCachedDefinitions();
$group_content_menu = $this->entityTypeManager->getStorage('group_content_type')->createFromPlugin(
$group_type,
$plugin_id,
[
'auto_create_group_menu' => TRUE,
'auto_create_home_link' => TRUE,
]
);
$group_content_menu->save();
$group = $this->createGroup();
// Grant permissions and create group admin, menu admin, member and
// outsider, and anonymous roles.
// Admin role.
$admin_role = $this->entityTypeManager->getStorage('group_role')->create([
'id' => 'admin',
'label' => 'Admin',
'weight' => 0,
'group_type' => $group_type->id(),
]);
$admin_role->changePermissions([
sprintf('create group_content_menu:%s content', $this->menuId) => FALSE,
'access group content menu overview' => TRUE,
'manage group_content_menu' => TRUE,
'manage group_content_menu menu items' => FALSE,
'view group' => TRUE,
])->save();
// Menu admin.
$menu_admin_role = $this->entityTypeManager->getStorage('group_role')->create([
'id' => 'menu_admin',
'label' => 'Menu admin',
'weight' => 0,
'group_type' => $group_type->id(),
]);
$menu_admin_role->changePermissions([
sprintf('create group_content_menu:%s content', $this->menuId) => TRUE,
'access group content menu overview' => FALSE,
'manage group_content_menu' => FALSE,
'manage group_content_menu menu items' => TRUE,
'view group' => TRUE,
])->save();
// Member role.
$role = $group_type->getMemberRole();
$role->changePermissions([
sprintf('create group_content_menu:%s content', $this->menuId) => FALSE,
'access group content menu overview' => FALSE,
'manage group_content_menu' => FALSE,
'manage group_content_menu menu items' => FALSE,
'view group' => TRUE,
])->save();
// Outsider role.
$role = $group_type->getOutsiderRole();
$role->grantPermissions([
'view group',
])->save();
// Anonymous role.
$role = $group_type->getAnonymousRole();
$role->grantPermissions([
'view group',
])->save();
// Create various user types.
$group_admin = $this->drupalCreateUser([
'access content',
]);
$menu_admin = $this->drupalCreateUser([
'access content',
]);
$member = $this->drupalCreateUser([
'access content'
]);
$outsider = $this->drupalCreateUser([
'access content'
]);
$anonymous = User::load(0);
// Assign various users membership types.
$group->addMember($group_admin, [
'group_roles' => [$admin_role->id()],
]);
$group->addMember($menu_admin, [
'group_roles' => [$menu_admin_role->id()],
]);
$group->addMember($member, [
'group_roles' => [$group_type->getMemberRoleId()],
]);
$this->drupalLogin($group_admin);
$this->assertMenuManagePermissions(200);
$this->assertMenuItemCrudPermissions(403);
$this->drupalLogin($menu_admin);
$this->assertMenuManagePermissions(403);
$this->assertMenuItemCrudPermissions(200);
$this->assertMenuPermissions($member, 403);
$this->assertMenuPermissions($outsider, 403);
$this->assertMenuPermissions($anonymous, 403);
}
/**
* Assert menu permissions.
*/
private function assertMenuPermissions(UserInterface $user, int $status_code): void {
$assert = $this->assertSession();
if ($user->isAuthenticated()) {
$this->drupalLogin($user);
}
$this->drupalGet(Url::fromRoute('entity.group.canonical', [
'group' => 1,
]));
$assert->statusCodeEquals(200);
$this->assertMenuManagePermissions($status_code);
$this->assertMenuManagePermissions($status_code);
}
/**
* Assert menu manage permissions.
*/
private function assertMenuManagePermissions(int $status_code): void {
$assert = $this->assertSession();
$this->drupalGet(Url::fromRoute('entity.group_content_menu.collection', [
'group' => 1,
]));
$assert->statusCodeEquals($status_code);
$this->drupalGet(Url::fromRoute('entity.group_content_menu.add_page', [
'group' => 1,
]));
$assert->statusCodeEquals($status_code);
$this->drupalGet(Url::fromRoute('entity.group_content_menu.delete_form', [
'group' => 1,
'group_content_menu' => 1,
]));
$assert->statusCodeEquals($status_code);
}
/**
* Assert menu item CRUD permissions.
*/
private function assertMenuItemCrudPermissions(int $status_code): void {
$assert = $this->assertSession();
$this->drupalGet(Url::fromRoute('entity.group_content_menu.edit_form', [
'group' => 1,
'group_content_menu' => 1,
]));
$assert->statusCodeEquals($status_code);
$this->drupalGet(Url::fromRoute('entity.group_content_menu.add_link', [
'group' => 1,
'group_content_menu' => 1,
]));
$assert->statusCodeEquals($status_code);
$this->drupalGet(Url::fromRoute('entity.group_content_menu.edit_link', [
'group' => 1,
'group_content_menu' => 1,
'menu_link_content' => 1,
]));
$assert->statusCodeEquals($status_code);
$this->drupalGet(Url::fromRoute('entity.group_content_menu.delete_link', [
'group' => 1,
'group_content_menu' => 1,
'menu_link_content' => 1,
]));
$assert->statusCodeEquals($status_code);
}
/**
* {@inheritdoc}
*/
protected function getGlobalPermissions() {
protected function getGlobalPermissions(): array {
return [
'administer blocks',
'administer group content menu types',
'administer group',
'administer menu',
'bypass group access',
] + parent::getGlobalPermissions();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment