diff --git a/core/includes/entity.inc b/core/includes/entity.inc index a686ec6..d81d49c 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -742,3 +742,22 @@ function entity_query($entity_type, $conjunction = 'AND') { function entity_page_access(EntityInterface $entity, $operation = 'view') { return $entity->access($operation); } + +/** + * Generic access callback for create entity pages. + * + * Some entity types might have create access per bundle or something else. + * In that case you have to create a custom access callback. + * + * @param string $entity_type + * The entity type. + * + * @return bool + * TRUE if the access is granted. FALSE if access is denied. + */ +function entity_page_create_access($entity_type) { + $entity = drupal_container()->get('plugin.manager.entity') + ->getStorageController($entity_type) + ->create(array()); + return $entity->access('create'); +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php index d1a9314..132fc2c 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php @@ -22,6 +22,7 @@ * module = "taxonomy", * controller_class = "Drupal\taxonomy\TermStorageController", * render_controller_class = "Drupal\taxonomy\TermRenderController", + * access_controller_class = "Drupal\taxonomy\TermAccessController", * form_controller_class = { * "default" = "Drupal\taxonomy\TermFormController" * }, diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php index ec2607c..79fa073 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php @@ -19,6 +19,7 @@ * label = @Translation("Taxonomy vocabulary"), * module = "taxonomy", * controller_class = "Drupal\taxonomy\VocabularyStorageController", + * access_controller_class = "Drupal\taxonomy\VocabularyAccessController", * form_controller_class = { * "default" = "Drupal\taxonomy\VocabularyFormController" * }, diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/field/LinkEdit.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/field/LinkEdit.php index 1d990d1..346e0b4 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/field/LinkEdit.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/field/LinkEdit.php @@ -65,7 +65,7 @@ function render($values) { $term = entity_create('taxonomy_term', array( 'vid' => $values->{$this->aliases['vid']}, )); - if (taxonomy_term_access('edit', $term)) { + if ($term->access('update')) { $text = !empty($this->options['text']) ? $this->options['text'] : t('edit'); return l($text, 'taxonomy/term/'. $tid . '/edit', array('query' => drupal_get_destination())); } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php new file mode 100644 index 0000000..c45aa02 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php @@ -0,0 +1,49 @@ +bundle()}", $account) || user_access('administer taxonomy', $account); + } + + /** + * Implements \Drupal\Core\Entity\EntityAccessControllerInterface::deleteAccess(). + */ + public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) { + return user_access("delete terms in {$entity->bundle()}", $account) || user_access('administer taxonomy', $account); + } + +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php index 59226fd..ab36a79 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermTranslationController.php @@ -16,20 +16,6 @@ class TermTranslationController extends EntityTranslationController { /** - * Overrides EntityTranslationController::getAccess(). - */ - public function getAccess(EntityInterface $entity, $op) { - switch ($op) { - case 'create': - case 'update': - return taxonomy_term_access('edit', $entity); - case 'delete': - return taxonomy_term_access('delete', $entity); - } - return parent::getAccess($entity, $op); - } - - /** * Overrides EntityTranslationController::entityFormAlter(). */ public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) { @@ -53,4 +39,5 @@ function entityFormSave(array $form, array &$form_state) { $form_state['redirect'] = $this->getEditPath($entity); } } + } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php new file mode 100644 index 0000000..b1ec119 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php @@ -0,0 +1,49 @@ +id()]['#vocabulary'] = $vocabulary; $form[$vocabulary->id()]['name'] = array('#markup' => check_plain($vocabulary->name)); - $form[$vocabulary->id()]['weight'] = array( - '#type' => 'weight', - '#title' => t('Weight for @title', array('@title' => $vocabulary->name)), - '#title_display' => 'invisible', - '#delta' => 10, - '#default_value' => $vocabulary->weight, - ); + if ($admin_access) { + $form[$vocabulary->id()]['weight'] = array( + '#type' => 'weight', + '#title' => t('Weight for @title', array('@title' => $vocabulary->name)), + '#title_display' => 'invisible', + '#delta' => 10, + '#default_value' => $vocabulary->weight, + '#access' => $vocabulary->access('update'), + ); + } $links = array(); - $links['edit'] = array( - 'title' => t('edit vocabulary'), - 'href' => "admin/structure/taxonomy/{$vocabulary->id()}/edit", - ); + if ($vocabulary->access('update')) { + $links['edit'] = array( + 'title' => t('edit vocabulary'), + 'href' => "admin/structure/taxonomy/{$vocabulary->id()}/edit", + ); + } $links['list'] = array( 'title' => t('list terms'), 'href' => "admin/structure/taxonomy/{$vocabulary->id()}", ); - $links['add'] = array( - 'title' => t('add terms'), - 'href' => "admin/structure/taxonomy/{$vocabulary->id()}/add", - ); + if ($vocabulary->access('create')) { + $links['add'] = array( + 'title' => t('add terms'), + 'href' => "admin/structure/taxonomy/{$vocabulary->id()}/add", + ); + } $form[$vocabulary->id()]['operations'] = array( '#type' => 'operations', '#links' => $links, @@ -50,11 +58,15 @@ function taxonomy_overview_vocabularies($form) { // Only make this form include a submit button and weight if more than one // vocabulary exists. - if (count($vocabularies) > 1) { + if (count($vocabularies) > 1 && $admin_access) { $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#button_type' => 'primary'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + '#button_type' => 'primary', + ); } - elseif (isset($vocabulary)) { + elseif (isset($vocabulary) && $admin_access) { unset($form[$vocabulary->id()]['weight']); } return $form; @@ -87,7 +99,7 @@ function taxonomy_overview_vocabularies_submit($form, &$form_state) { */ function theme_taxonomy_overview_vocabularies($variables) { $form = $variables['form']; - + $draggable = FALSE; $rows = array(); foreach (element_children($form) as $key) { @@ -111,7 +123,12 @@ function theme_taxonomy_overview_vocabularies($variables) { drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight'); } $header[] = t('Operations'); - return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No vocabularies available. Add vocabulary.', array('@link' => url('admin/structure/taxonomy/add'))), 'attributes' => array('id' => 'taxonomy'))) . drupal_render_children($form); + $empty_text = t('No vocabularies available.'); + // Create a vocabulary object to check create access. + if (entity_create('taxonomy_vocabulary', array())->access('create')) { + $empty_text .= ' ' . l(t('Add vocabulary'), 'admin/structure/taxonomy/add'); + } + return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => $empty_text, 'attributes' => array('id' => 'taxonomy'))) . drupal_render_children($form); } /** @@ -151,6 +168,7 @@ function taxonomy_overview_terms($form, &$form_state, Vocabulary $vocabulary) { $form['#tree'] = TRUE; $form['#parent_fields'] = FALSE; + $admin_access = user_access('administer taxonomy'); $page = isset($_GET['page']) ? $_GET['page'] : 0; $page_increment = config('taxonomy.settings')->get('terms_per_page_admin'); // Number of terms per page. $page_entries = 0; // Elements shown on this page. @@ -261,7 +279,7 @@ function taxonomy_overview_terms($form, &$form_state, Vocabulary $vocabulary) { } $form[$key]['view'] = array('#type' => 'link', '#title' => $term->label(), '#href' => "taxonomy/term/$term->tid"); - if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) { + if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1 && $admin_access) { $form['#parent_fields'] = TRUE; $form[$key]['tid'] = array( '#type' => 'hidden', @@ -285,10 +303,14 @@ function taxonomy_overview_terms($form, &$form_state, Vocabulary $vocabulary) { '#default_value' => $term->weight, ); } - $operations = array( - 'edit' => array('title' => t('edit'), 'href' => 'taxonomy/term/' . $term->tid . '/edit', 'query' => $destination), - 'delete' => array('title' => t('delete'), 'href' => 'taxonomy/term/' . $term->tid . '/delete', 'query' => $destination), - ); + $operations = array(); + if ($term->access('update')) { + $operations['edit'] = array('title' => t('edit'), 'href' => 'taxonomy/term/' . $term->tid . '/edit', 'query' => $destination); + } + if ($term->access('delete')) { + $operations['delete'] = array('title' => t('delete'), 'href' => 'taxonomy/term/' . $term->tid . '/delete', 'query' => $destination); + } + if (module_invoke('translation_entity', 'translate_access', $term)) { $operations['translate'] = array( 'title' => t('translate'), @@ -307,9 +329,14 @@ function taxonomy_overview_terms($form, &$form_state, Vocabulary $vocabulary) { $form['#page_entries'] = $page_entries; $form['#back_step'] = $back_step; $form['#forward_step'] = $forward_step; - $form['#empty_text'] = t('No terms available. Add term.', array('@link' => url('admin/structure/taxonomy/' . $vocabulary->id() . '/add'))); + $form['#empty_text'] = t('No terms available.'); + // Create a test term object that belongs to this vocabulary + // to check create access against. + if (entity_create('taxonomy_term', array('vid' => $vocabulary->id()))->access('create')) { + $form['#empty_text'] .= ' ' . l(t('Add term'), 'admin/structure/taxonomy/' . $vocabulary->id() . '/add'); + } - if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) { + if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1 && $admin_access) { $form['actions'] = array('#type' => 'actions', '#tree' => FALSE); $form['actions']['submit'] = array( '#type' => 'submit', @@ -457,19 +484,22 @@ function taxonomy_overview_terms_submit($form, &$form_state) { function theme_taxonomy_overview_terms($variables) { $form = $variables['form']; + $admin_access = user_access('administer taxonomy'); $page_increment = $form['#page_increment']; $page_entries = $form['#page_entries']; $back_step = $form['#back_step']; $forward_step = $form['#forward_step']; - // Add drag and drop if parent fields are present in the form. - if ($form['#parent_fields']) { - drupal_add_tabledrag('taxonomy', 'match', 'parent', 'term-parent', 'term-parent', 'term-id', FALSE); - drupal_add_tabledrag('taxonomy', 'depth', 'group', 'term-depth', NULL, NULL, FALSE); - drupal_add_library('taxonomy', 'drupal.taxonomy'); - drupal_add_js(array('taxonomy' => array('backStep' => $back_step, 'forwardStep' => $forward_step)), 'setting'); + if ($admin_access) { + // Add drag and drop if parent fields are present in the form. + if ($form['#parent_fields']) { + drupal_add_tabledrag('taxonomy', 'match', 'parent', 'term-parent', 'term-parent', 'term-id', FALSE); + drupal_add_tabledrag('taxonomy', 'depth', 'group', 'term-depth', NULL, NULL, FALSE); + drupal_add_library('taxonomy', 'drupal.taxonomy'); + drupal_add_js(array('taxonomy' => array('backStep' => $back_step, 'forwardStep' => $forward_step)), 'setting'); + } + drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'term-weight'); } - drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'term-weight'); $errors = form_get_errors() != FALSE ? form_get_errors() : array(); $rows = array(); diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 16d1019..648527a 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -89,9 +89,20 @@ function taxonomy_permission() { 'administer taxonomy' => array( 'title' => t('Administer vocabularies and terms'), ), + 'access taxonomy overview' => array( + 'title' => t('Access the taxonomy overview page'), + 'description' => t('Access the taxonomy overview page at admin/structure/taxonomy.', array( + '@url' => url('admin/structure/taxonomy'), + )), + ), ); foreach (taxonomy_vocabulary_load_multiple() as $vocabulary) { $permissions += array( + 'create terms in ' . $vocabulary->id() => array( + 'title' => t('Add terms in %vocabulary', array('%vocabulary' => $vocabulary->name)), + ), + ); + $permissions += array( 'edit terms in ' . $vocabulary->id() => array( 'title' => t('Edit terms in %vocabulary', array('%vocabulary' => $vocabulary->name)), ), @@ -260,7 +271,7 @@ function taxonomy_menu() { 'description' => 'Manage tagging, categorization, and classification of your content.', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_overview_vocabularies'), - 'access arguments' => array('administer taxonomy'), + 'access arguments' => array('access taxonomy overview'), 'file' => 'taxonomy.admin.inc', ); $items['admin/structure/taxonomy/list'] = array( @@ -271,7 +282,8 @@ function taxonomy_menu() { $items['admin/structure/taxonomy/add'] = array( 'title' => 'Add vocabulary', 'page callback' => 'taxonomy_vocabulary_add', - 'access arguments' => array('administer taxonomy'), + 'access callback' => 'entity_page_create_access', + 'access arguments' => array('taxonomy_vocabulary'), 'type' => MENU_LOCAL_ACTION, 'file' => 'taxonomy.admin.inc', ); @@ -282,7 +294,8 @@ function taxonomy_menu() { 'title arguments' => array(2), 'page callback' => 'taxonomy_term_page', 'page arguments' => array(2), - 'access arguments' => array('access content'), + 'access callback' => 'entity_page_access', + 'access arguments' => array(2, 'view'), 'file' => 'taxonomy.pages.inc', ); $items['taxonomy/term/%taxonomy_term/view'] = array( @@ -295,8 +308,8 @@ function taxonomy_menu() { // Pass a NULL argument to ensure that additional path components are not // passed to taxonomy_term_form() as the vocabulary machine name argument. 'page arguments' => array(2), - 'access callback' => 'taxonomy_term_access', - 'access arguments' => array('edit', 2), + 'access callback' => 'entity_page_access', + 'access arguments' => array(2, 'update'), 'type' => MENU_LOCAL_TASK, 'weight' => 10, 'file' => 'taxonomy.admin.inc', @@ -305,8 +318,8 @@ function taxonomy_menu() { 'title' => 'Delete', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_term_confirm_delete', 2), - 'access callback' => 'taxonomy_term_access', - 'access arguments' => array('delete', 2), + 'access callback' => 'entity_page_access', + 'access arguments' => array(2, 'delete'), 'type' => MENU_LOCAL_TASK, 'weight' => 11, 'file' => 'taxonomy.admin.inc', @@ -317,7 +330,8 @@ function taxonomy_menu() { 'title arguments' => array(2), 'page callback' => 'taxonomy_term_feed', 'page arguments' => array(2), - 'access arguments' => array('access content'), + 'access callback' => 'entity_page_access', + 'access arguments' => array(2, 'view'), 'type' => MENU_CALLBACK, 'file' => 'taxonomy.pages.inc', ); @@ -335,7 +349,7 @@ function taxonomy_menu() { 'title arguments' => array(3), 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_overview_terms', 3), - 'access arguments' => array('administer taxonomy'), + 'access arguments' => array('access taxonomy overview'), 'file' => 'taxonomy.admin.inc', ); $items['admin/structure/taxonomy/%taxonomy_vocabulary/list'] = array( @@ -347,7 +361,8 @@ function taxonomy_menu() { 'title' => 'Edit', 'page callback' => 'entity_get_form', 'page arguments' => array(3), - 'access arguments' => array('administer taxonomy'), + 'access callback' => 'entity_page_access', + 'access arguments' => array(3, 'update'), 'type' => MENU_LOCAL_TASK, 'weight' => -10, 'file' => 'taxonomy.admin.inc', @@ -357,7 +372,8 @@ function taxonomy_menu() { 'title' => 'Add term', 'page callback' => 'taxonomy_term_add', 'page arguments' => array(3), - 'access arguments' => array('administer taxonomy'), + 'access callback' => 'entity_page_create_access', + 'access arguments' => array('taxonomy_term'), 'type' => MENU_LOCAL_ACTION, 'file' => 'taxonomy.admin.inc', ); @@ -379,32 +395,6 @@ function taxonomy_admin_paths() { } /** - * Access callback: Checks a user's permission for performing a taxonomy term - * operation. - * - * @param $op - * The operation to be performed on the taxonomy term. Possible values are: - * - "edit" - * - "delete" - * @param $term - * The $term object on which the operation is to be performed. - * - * @return - * TRUE if the operation may be performed, FALSE otherwise. - * - * @see taxonomy_menu() - */ -function taxonomy_term_access($op, $term) { - if (!$term || !in_array($op, array('edit', 'delete'), TRUE)) { - // If there was no term to check against, or the $op was not one of the - // supported ones, we return access denied. - return FALSE; - } - - return user_access("$op terms in {$term->bundle()}") || user_access('administer taxonomy'); -} - -/** * Saves a vocabulary. * * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary