Commit bbcf0470 authored by catch's avatar catch

Issue #611294 by swentel, tsphethean: Refine permissions for Field UI.

parent 5ff1cee3
......@@ -118,7 +118,6 @@ function comment_entity_info(&$info) {
'path' => 'admin/structure/types/manage/%comment_node_type/comment',
'bundle argument' => 4,
'real path' => 'admin/structure/types/manage/' . $type . '/comment',
'access arguments' => array('administer content types'),
),
);
}
......
......@@ -20,7 +20,7 @@ abstract class CommentTestBase extends WebTestBase {
*
* @var array
*/
public static $modules = array('comment', 'node', 'history');
public static $modules = array('comment', 'node', 'history', 'field_ui');
/**
* An administrative user with permission to configure comment settings.
......@@ -57,6 +57,7 @@ function setUp() {
$this->admin_user = $this->drupalCreateUser(array(
'administer content types',
'administer comments',
'administer comment fields',
'skip comment approval',
'post comments',
'access comments',
......
<?php
/**
* @file
* Install, update, and uninstall functions for the Field UI module.
*/
/**
* Upgrade Field UI permissions.
*/
function field_ui_update_8001() {
$permissions = array(
'administer comments' => array(
'administer comment fields',
'administer comment display',
),
'administer content types' => array(
'administer node fields',
'administer node display',
),
'administer users' => array(
'administer user fields',
'administer user display',
),
'administer taxonomy' => array(
'administer taxonomy_term fields',
'administer taxonomy_term display',
),
);
// We can not call user_permission_get_modules() as that will start
// invoking hooks which we can't during update hooks. Directly query
// for the permissions and insert them into the database.
foreach ($permissions as $old_permission => $new_permissions) {
$results = db_query("SELECT rid FROM {role_permission} WHERE permission = :permission", array(':permission' => $old_permission));
foreach ($results as $record) {
$query = db_insert('role_permission')->fields(array('rid', 'permission', 'module'));
foreach ($new_permissions as $new_permission) {
$query->values(array($record->rid, $new_permission, 'field_ui'));
}
$query->execute();
}
// Remove old permission.
db_delete('role_permission')
->condition('permission', $old_permission)
->execute();
}
}
......@@ -94,11 +94,15 @@ function field_ui_menu() {
// items below.
$field_position = count(explode('/', $path)) + 1;
// Extract access information, providing defaults.
$access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
$access += array(
// User access check to be done against the permission to edit
// fields or the display per entity type.
$access_fields = array(
'access callback' => 'user_access',
'access arguments' => array('administer site configuration'),
'access arguments' => array('administer ' . $entity_type . ' fields'),
);
$access_display = array(
'access callback' => 'user_access',
'access arguments' => array('administer ' . $entity_type . ' display'),
);
$items["$path/fields"] = array(
......@@ -108,7 +112,7 @@ function field_ui_menu() {
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
$items["$path/fields/%field_ui_instance"] = array(
'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
'title callback' => 'field_ui_instance_title',
......@@ -116,7 +120,7 @@ function field_ui_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('field_ui_field_edit_form', $field_position),
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
$items["$path/fields/%field_ui_instance/edit"] = array(
'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
'title' => 'Edit',
......@@ -124,7 +128,7 @@ function field_ui_menu() {
'page arguments' => array('field_ui_field_edit_form', $field_position),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
$items["$path/fields/%field_ui_instance/field-settings"] = array(
'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
'title' => 'Field settings',
......@@ -132,7 +136,7 @@ function field_ui_menu() {
'page arguments' => array('field_ui_field_settings_form', $field_position),
'type' => MENU_LOCAL_TASK,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
$items["$path/fields/%field_ui_instance/widget-type"] = array(
'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
'title' => 'Widget type',
......@@ -140,7 +144,7 @@ function field_ui_menu() {
'page arguments' => array('field_ui_widget_type_form', $field_position),
'type' => MENU_LOCAL_TASK,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
$items["$path/fields/%field_ui_instance/delete"] = array(
'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
'title' => 'Delete',
......@@ -149,7 +153,7 @@ function field_ui_menu() {
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'weight' => 10,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_fields;
// 'Manage display' tab.
$items["$path/display"] = array(
......@@ -159,7 +163,7 @@ function field_ui_menu() {
'type' => MENU_LOCAL_TASK,
'weight' => 2,
'file' => 'field_ui.admin.inc',
) + $access;
) + $access_display;
// View modes secondary tabs.
// The same base $path for the menu item (with a placeholder) can be
......@@ -179,7 +183,7 @@ function field_ui_menu() {
// display' setting for the view mode, and the overall access
// rules for the bundle admin pages.
'access callback' => '_field_ui_view_mode_menu_access',
'access arguments' => array_merge(array($entity_type, $bundle_arg, $view_mode, $access['access callback']), $access['access arguments']),
'access arguments' => array($entity_type, $bundle_arg, $view_mode, $access_display['access arguments'][0]),
'type' => ($view_mode == 'default' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK),
'weight' => ($view_mode == 'default' ? -10 : $weight++),
'file' => 'field_ui.admin.inc',
......@@ -192,6 +196,29 @@ function field_ui_menu() {
return $items;
}
/**
* Implements hook_permission().
*/
function field_ui_permission() {
$permissions = array();
foreach (entity_get_info() as $entity_type => $entity_info) {
if ($entity_info['fieldable']) {
// Create a permission for each fieldable entity to manage
// the fields and the display.
$permissions['administer ' . $entity_type . ' fields'] = array(
'title' => t('%entity_label: Administer fields', array('%entity_label' => $entity_info['label'])),
'restrict access' => TRUE,
);
$permissions['administer ' . $entity_type . ' display'] = array(
'title' => t('%entity_label: Administer display', array('%entity_label' => $entity_info['label']))
);
}
}
return $permissions;
}
/**
* Menu loader callback: Loads a field instance based on field and bundle name.
*
......@@ -251,32 +278,16 @@ function field_ui_instance_title($instance) {
*
* @see field_ui_menu()
*/
function _field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $access_callback) {
function _field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $permission) {
// First, determine visibility according to the 'use custom display'
// setting for the view mode.
$bundle = field_extract_bundle($entity_type, $bundle);
$view_mode_settings = field_view_mode_settings($entity_type, $bundle);
$visibility = ($view_mode == 'default') || !empty($view_mode_settings[$view_mode]['custom_settings']);
// Then, determine access according to the $access parameter. This duplicates
// part of _menu_check_access().
// Then, determine access according to the $permission parameter.
if ($visibility) {
// Grab the variable 'access arguments' part.
$args = array_slice(func_get_args(), 4);
$callback = empty($access_callback) ? 0 : trim($access_callback);
if (is_numeric($callback)) {
return (bool) $callback;
}
else {
// As call_user_func_array() is quite slow and user_access is a very
// common callback, it is worth making a special case for it.
if ($access_callback == 'user_access') {
return (count($args) == 1) ? user_access($args[0]) : user_access($args[0], $args[1]);
}
else {
return call_user_func_array($access_callback, $args);
}
}
return user_access($permission);
}
}
......
......@@ -37,7 +37,7 @@ function setUp() {
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
// Create test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer users'));
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer users', 'administer user fields'));
$this->drupalLogin($admin_user);
}
......
......@@ -25,7 +25,7 @@ function setUp() {
parent::setUp();
// Create test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy', 'administer users', 'bypass node access'));
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node display', 'administer taxonomy', 'administer taxonomy_term fields', 'administer taxonomy_term display', 'administer users', 'administer user display'));
$this->drupalLogin($admin_user);
// Create content type, with underscores.
......
......@@ -116,7 +116,7 @@ function createField() {
// should also appear in the 'taxonomy term' entity.
$vocabulary = taxonomy_vocabulary_load('tags');
$this->drupalGet('admin/structure/taxonomy/' . $vocabulary->id() . '/fields');
$this->assertTrue($this->xpath('//select[@name="fields[_add_existing_field][field_name]"]//option[@value="' . $this->field_name . '"]'), 'Existing field was found in account settings.');
$this->assertTrue($this->xpath('//select[@name="fields[_add_existing_field][field_name]"]//option[@value="' . $this->field_name . '"]'), 'Existing field was found in taxonomy term fields.');
}
/**
......
......@@ -19,7 +19,7 @@ abstract class FileFieldTestBase extends WebTestBase {
*
* @var array
*/
public static $modules = array('file', 'file_module_test');
public static $modules = array('file', 'file_module_test', 'field_ui');
protected $profile = 'standard';
......@@ -27,7 +27,7 @@ abstract class FileFieldTestBase extends WebTestBase {
function setUp() {
parent::setUp();
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access'));
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer node fields', 'administer node display', 'administer comment fields', 'administer nodes', 'bypass node access'));
$this->drupalLogin($this->admin_user);
}
......
......@@ -36,7 +36,7 @@ abstract class ImageFieldTestBase extends WebTestBase {
*
* @var array
*/
public static $modules = array('node', 'image');
public static $modules = array('node', 'image', 'field_ui');
protected $admin_user;
......@@ -49,7 +49,7 @@ function setUp() {
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
}
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles'));
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer node fields', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles'));
$this->drupalLogin($this->admin_user);
}
......
......@@ -32,7 +32,7 @@ public static function getInfo() {
function setUp() {
parent::setUp();
$this->web_user = $this->drupalCreateUser(array('administer content types'));
$this->web_user = $this->drupalCreateUser(array('administer content types', 'administer node fields', 'administer node display'));
$this->drupalLogin($this->web_user);
}
......
......@@ -30,12 +30,14 @@ function node_overview_types() {
'weight' => 0,
);
if ($field_ui) {
if ($field_ui && user_access('administer node fields')) {
$links['fields'] = array(
'title' => t('manage fields'),
'href' => 'admin/structure/types/manage/' . $type->type . '/fields',
'weight' => 5,
);
}
if ($field_ui && user_access('administer node display')) {
$links['display'] = array(
'title' => t('manage display'),
'href' => 'admin/structure/types/manage/' . $type->type . '/display',
......
......@@ -34,7 +34,7 @@ public function setUp() {
// Create some users.
$this->admin_user = $this->drupalCreateUser(array('access content', 'bypass node access'));
$this->content_admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
$this->content_admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields'));
// Add a custom field to the page content type.
$this->field_name = drupal_strtolower($this->randomName() . '_field_name');
......
......@@ -80,7 +80,7 @@ function testTranslateLinkContentAdminPage() {
* Tests field translation form.
*/
function testFieldTranslationForm() {
$admin_user = $this->drupalCreateUser(array('translate any entity', 'access administration pages', 'bypass node access'));
$admin_user = $this->drupalCreateUser(array('translate any entity', 'access administration pages', 'bypass node access', 'administer node fields'));
$this->drupalLogin($admin_user);
$article = $this->drupalCreateNode(array('type' => 'article', 'langcode' => 'en'));
......
......@@ -30,7 +30,7 @@ public static function getInfo() {
function setUp() {
parent::setUp();
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types', 'administer languages'));
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types', 'administer node fields', 'administer node display', 'administer languages'));
$this->drupalLogin($web_user);
}
......
......@@ -80,7 +80,7 @@ function testNodeTypeCreation() {
* Tests editing a node type using the UI.
*/
function testNodeTypeEditing() {
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types'));
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types', 'administer node fields'));
$this->drupalLogin($web_user);
$instance = field_info_instance('node', 'body', 'page');
......
......@@ -206,7 +206,6 @@ function node_entity_info(&$info) {
'path' => 'admin/structure/types/manage/%node_type',
'real path' => 'admin/structure/types/manage/' . $type,
'bundle argument' => 4,
'access arguments' => array('administer content types'),
),
);
}
......
......@@ -36,7 +36,7 @@ public static function getInfo() {
function setUp() {
parent::setUp();
$this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types'));
$this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types', 'administer node fields','administer node display'));
$this->drupalLogin($this->web_user);
}
......
......@@ -33,7 +33,7 @@ function setUp() {
parent::setUp();
// Create test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer taxonomy'));
$this->drupalLogin($admin_user);
// Create content type, with underscores.
......
......@@ -477,7 +477,7 @@ function testOnOffCheckbox() {
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
// Create admin user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer taxonomy'));
$this->drupalLogin($admin_user);
// Create a test field instance.
......
......@@ -46,6 +46,7 @@ public function setUp() {
'access administration pages',
'administer site configuration',
'administer content types',
'administer node display',
'administer nodes',
'create article content',
'edit any article content',
......
<?php
/**
* @file
* Contains Drupal\system\Tests\Upgrade\FieldUIUpgradePathTest.
*/
namespace Drupal\system\Tests\Upgrade;
/**
* Test upgrade of Field UI.
*/
class FieldUIUpgradePathTest extends UpgradePathTestBase {
protected $normal_role_id = 4;
protected $normal_role_name = 'Normal role';
protected $admin_role_id = 5;
protected $admin_role_name = 'Admin role';
public static function getInfo() {
return array(
'name' => 'Field UI upgrade test',
'description' => 'Upgrade tests for Field UI.',
'group' => 'Upgrade path',
);
}
public function setUp() {
$this->databaseDumpFiles = array(
drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.filled.standard_all.database.php.gz',
drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.field_ui.database.php',
);
parent::setUp();
}
/**
* Tests Field UI permissions upgrade path.
*
* Test that after upgrade users who have the 'administer comments',
* 'administer content types', 'administer users', and 'administer taxonomy'
* permission still have access to the manage field and display screens of
* those entities.
*/
function testFieldUIPermissions() {
$this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
$permissions = array(
'administer comments' => array(
'administer comment fields',
'administer comment display',
),
'administer content types' => array(
'administer node fields',
'administer node display',
),
'administer users' => array(
'administer user fields',
'administer user display',
),
'administer taxonomy' => array(
'administer taxonomy_term fields',
'administer taxonomy_term display',
),
);
$role_permissions = user_role_permissions(array($this->normal_role_id => $this->normal_role_name, $this->admin_role_id => $this->admin_role_name));
foreach ($permissions as $old_permission => $new_permissions) {
$this->assertFalse(isset($role_permissions[$this->normal_role_id][$old_permission]), format_string('%role_name does not have the old %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $old_permission)));
$this->assertFalse(isset($role_permissions[$this->admin_role_id][$old_permission]), format_string('%role_name does not have the old %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $old_permission)));
foreach ($new_permissions as $new_permission) {
$this->assertFalse(isset($role_permissions[$this->normal_role_id][$new_permission]), format_string('%role_name does not have the new %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $new_permission)));
$this->assertTrue(isset($role_permissions[$this->admin_role_id][$new_permission]), format_string('%role_name has the new %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $new_permission)));
}
}
}
}
<?php
/**
* @file
* Database additions for Field UI tests tests. Used in
* \Drupal\system\Tests\Upgrade\FieldUIUpgradePathTest.
*
* This dump only contains data and schema components relevant for Field UI
* upgrade tests. The drupal-7.filled.database.php.gz file is imported before
* this dump, so the two form the database structure expected in tests
* altogether.
*/
db_insert('role')->fields(array(
'rid',
'name',
'weight',
))
->values(array(
'rid' => '4',
'name' => 'Normal role',
'weight' => '3',
))
->values(array(
'rid' => '5',
'name' => 'Admin role',
'weight' => '4',
))
->execute();
// Add the 'Administer comments', 'Administer content types',
// 'Administer users' and 'Administer vocabularies and terms' permissions
// to the Admin role.
db_insert('role_permission')->fields(array(
'rid',
'permission',
'module',
))
->values(array(
'rid' => '5',
'permission' => 'administer comments',
'module' => 'comment',
))
->values(array(
'rid' => '5',
'permission' => 'administer content types',
'module' => 'node',
))
->values(array(
'rid' => '5',
'permission' => 'administer users',
'module' => 'user',
))
->values(array(
'rid' => '5',
'permission' => 'administer taxonomy',
'module' => 'taxonomy',
))
->execute();
......@@ -30,7 +30,7 @@ public static function getInfo() {
function setUp() {
parent::setUp();
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types'));
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types', 'administer node display'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
......
......@@ -117,7 +117,6 @@ function taxonomy_entity_info(&$info) {
'path' => 'admin/structure/taxonomy/%taxonomy_vocabulary',
'real path' => 'admin/structure/taxonomy/' . $id,
'bundle argument' => 3,
'access arguments' => array('administer taxonomy'),
),
);
}
......
......@@ -39,6 +39,7 @@ function setUp() {
$this->admin = $this->drupalCreateUser(array(
'administer languages',
'administer content types',
'administer node fields',
'access administration pages',
'bypass node access',
filter_permission_name($full_html_format),
......
......@@ -20,7 +20,7 @@ function translation_entity_overview(EntityInterface $entity) {
$languages = language_list();
$original = $entity->language()->langcode;
$translations = $entity->getTranslationLanguages();
$field_ui = module_exists('field_ui');
$field_ui = module_exists('field_ui') && user_access('administer ' . $entity->entityType() . ' fields');
$path = $controller->getViewPath($entity);
$base_path = $controller->getBasePath($entity);
......
......@@ -38,7 +38,6 @@
* "label" = "User",
* "admin" = {
* "path" = "admin/config/people/accounts",
* "access arguments" = {"administer users"}
* }
* }
* },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment