diff --git a/core/core.services.yml b/core/core.services.yml index f73d453..95c56a8 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -304,6 +304,10 @@ services: class: Drupal\Core\Access\DefaultAccessCheck tags: - { name: access_check } + access_check.entity: + class: Drupal\Core\Entity\EntityAccessCheck + tags: + - { name: access_check } maintenance_mode_subscriber: class: Drupal\Core\EventSubscriber\MaintenanceModeSubscriber tags: diff --git a/core/lib/Drupal/Core/Entity/EntityAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php new file mode 100644 index 0000000..f55567e --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php @@ -0,0 +1,56 @@ +getRequirements()); + } + + /** + * Implements \Drupal\Core\Access\AccessCheckInterface::access(). + * + * The value of the '_entity_access' key must be in the pattern + * 'entity_type.operation.' The entity type must match the {entity_type} + * parameter in the route pattern. This will check a node for 'update' access: + * @code + * pattern: '/foo/{node}/bar' + * requirements: + * _entity_access: 'node.update' + * @endcode + * Available operations are 'view', 'update', 'create', and 'delete'. + */ + public function access(Route $route, Request $request) { + // Split the entity type and the operation. + $requirement = $route->getRequirement('_entity_access'); + list($entity_type, $operation) = explode('.', $requirement); + // If there is valid entity of the given entity type, check its access. + if ($request->attributes->has($entity_type)) { + $entity = $request->attributes->get($entity_type); + if ($entity instanceof EntityInterface) { + return $entity->access($operation); + } + } + // No opinion, so other access checks should decide if access should be + // allowed or not. + return NULL; + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php b/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php new file mode 100644 index 0000000..d6b454a --- /dev/null +++ b/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php @@ -0,0 +1,37 @@ +getRequirements()); + } + + /** + * {@inheritdoc} + */ + public function access(Route $route, Request $request) { + $menu_link = $request->attributes->get('menu_link'); + $set_name = str_replace('shortcut-', '', $menu_link['menu_name']); + if ($shortcut_set = shortcut_set_load($set_name)) { + return shortcut_set_edit_access($shortcut_set); + } + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/LinkDelete.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/LinkDelete.php new file mode 100644 index 0000000..e61713b --- /dev/null +++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/LinkDelete.php @@ -0,0 +1,72 @@ + $this->menuLink->link_title)); + } + + /** + * {@inheritdoc} + */ + protected function getCancelPath() { + return 'admin/config/user-interface/shortcut/manage/' . $this->menuLink->menu_name; + } + + /** + * {@inheritdoc} + */ + protected function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, MenuLink $menu_link = NULL) { + $this->menuLink = $menu_link; + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + menu_link_delete($this->menuLink->mlid); + $set_name = str_replace('shortcut-', '' , $this->menuLink->menu_name); + $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set_name; + drupal_set_message(t('The shortcut %title has been deleted.', array('%title' => $this->menuLink->link_title))); + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/SetDelete.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetDelete.php new file mode 100644 index 0000000..70e4e24 --- /dev/null +++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetDelete.php @@ -0,0 +1,128 @@ +database = $database; + $this->moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('database'), + $container->get('module_handler') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'shortcut_set_delete_form'; + } + + /** + * {@inheritdoc} + */ + protected function getQuestion() { + return t('Are you sure you want to delete the shortcut set %title?', array('%title' => $this->shortcut->label())); + } + + /** + * {@inheritdoc} + */ + protected function getCancelPath() { + return 'admin/config/user-interface/shortcut/manage/' . $this->shortcut->id(); + } + + /** + * {@inheritdoc} + */ + protected function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, Shortcut $shortcut = NULL) { + $this->shortcut = $shortcut; + + // Find out how many users are directly assigned to this shortcut set, and + // make a message. + $number = $this->database->query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $this->shortcut->id()))->fetchField(); + $info = ''; + if ($number) { + $info .= '

' . format_plural($number, + '1 user has chosen or been assigned to this shortcut set.', + '@count users have chosen or been assigned to this shortcut set.') . '

'; + } + + // Also, if a module implements hook_shortcut_default_set(), it's possible + // that this set is being used as a default set. Add a message about that too. + if ($this->moduleHandler->getImplementations('shortcut_default_set')) { + $info .= '

' . t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '

'; + } + + $form['info'] = array( + '#markup' => $info, + ); + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $this->shortcut->delete(); + $form_state['redirect'] = 'admin/config/user-interface/shortcut'; + drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $this->shortcut->label()))); + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php index 57b75df..dd44422 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php @@ -20,6 +20,7 @@ * module = "shortcut", * controllers = { * "storage" = "Drupal\shortcut\ShortcutStorageController", + * "access" = "Drupal\shortcut\ShortcutAccessController", * "list" = "Drupal\shortcut\ShortcutListController", * "form" = { * "default" = "Drupal\shortcut\ShortcutFormController" diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php new file mode 100644 index 0000000..a95a0e0 --- /dev/null +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php @@ -0,0 +1,30 @@ +id() != 'default'; + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php index 059de38..db600fd 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php @@ -53,7 +53,7 @@ public function form(array $form, array &$form_state, EntityInterface $entity) { protected function actions(array $form, array &$form_state) { // Disable delete of default shortcut set. $actions = parent::actions($form, $form_state); - $actions['delete']['#access'] = shortcut_set_delete_access($this->getEntity($form_state)); + $actions['delete']['#access'] = $this->getEntity($form_state)->access('delete'); return $actions; } diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php index 6cf8f9d8..f1aaa60 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php @@ -38,7 +38,7 @@ public function getOperations(EntityInterface $entity) { 'options' => $uri['options'], 'weight' => 10, ); - if (shortcut_set_delete_access($entity)) { + if ($entity->access('delete')) { $operations['delete'] = array( 'title' => t('Delete set'), 'href' => $uri['path'] . '/delete', diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc index 0e43052..dec4dbd 100644 --- a/core/modules/shortcut/shortcut.admin.inc +++ b/core/modules/shortcut/shortcut.admin.inc @@ -472,113 +472,6 @@ function shortcut_admin_add_link($shortcut_link, &$shortcut_set) { } /** - * Form callback: builds the confirmation form for deleting a shortcut set. - * - * @param $form - * An associative array containing the structure of the form. - * @param $form_state - * An associative array containing the current state of the form. - * @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut - * An object representing the shortcut set, as returned from - * shortcut_set_load(). - * - * @return - * An array representing the form definition. - * - * @ingroup forms - * @see shortcut_set_delete_form_submit() - */ -function shortcut_set_delete_form($form, &$form_state, $shortcut_set) { - $form['shortcut_set'] = array( - '#type' => 'value', - '#value' => $shortcut_set->id(), - ); - - // Find out how many users are directly assigned to this shortcut set, and - // make a message. - $number = db_query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $shortcut_set->id()))->fetchField(); - $info = ''; - if ($number) { - $info .= '

' . format_plural($number, - '1 user has chosen or been assigned to this shortcut set.', - '@count users have chosen or been assigned to this shortcut set.') . '

'; - } - - // Also, if a module implements hook_shortcut_default_set(), it's possible - // that this set is being used as a default set. Add a message about that too. - if (count(module_implements('shortcut_default_set')) > 0) { - $info .= '

' . t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '

'; - } - - $form['info'] = array( - '#markup' => $info, - ); - - return confirm_form( - $form, - t('Are you sure you want to delete the shortcut set %title?', array('%title' => $shortcut_set->label())), - 'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id(), - t('This action cannot be undone.'), - t('Delete'), - t('Cancel') - ); -} - -/** - * Submit handler for shortcut_set_delete_form(). - */ -function shortcut_set_delete_form_submit($form, &$form_state) { - $shortcut_set = shortcut_set_load($form_state['values']['shortcut_set']); - $label = $shortcut_set->label(); - $shortcut_set->delete(); - $form_state['redirect'] = 'admin/config/user-interface/shortcut'; - drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $label))); -} - -/** - * Form callback: builds the confirmation form for deleting a shortcut link. - * - * @param $form - * An associative array containing the structure of the form. - * @param $form_state - * An associative array containing the current state of the form. - * @param $shortcut_link - * An array representing the link that will be deleted. - * - * @return - * An array representing the form definition. - * - * @ingroup forms - * @see shortcut_link_delete_submit() - */ -function shortcut_link_delete($form, &$form_state, $shortcut_link) { - $form['shortcut_link'] = array( - '#type' => 'value', - '#value' => $shortcut_link, - ); - - return confirm_form( - $form, - t('Are you sure you want to delete the shortcut %title?', array('%title' => $shortcut_link['link_title'])), - 'admin/config/user-interface/shortcut/manage/' . $shortcut_link['menu_name'], - t('This action cannot be undone.'), - t('Delete'), - t('Cancel') - ); -} - -/** - * Submit handler for shortcut_link_delete_submit(). - */ -function shortcut_link_delete_submit($form, &$form_state) { - $shortcut_link = $form_state['values']['shortcut_link']; - menu_link_delete($shortcut_link['mlid']); - $set_name = str_replace('shortcut-', '' , $shortcut_link['menu_name']); - $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set_name; - drupal_set_message(t('The shortcut %title has been deleted.', array('%title' => $shortcut_link['link_title']))); -} - -/** * Menu page callback: creates a new link in the provided shortcut set. * * After completion, redirects the user back to where they came from. diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index 25a04c7..db3373b 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -101,11 +101,7 @@ function shortcut_menu() { ); $items['admin/config/user-interface/shortcut/manage/%shortcut_set/delete'] = array( 'title' => 'Delete shortcut set', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('shortcut_set_delete_form', 5), - 'access callback' => 'shortcut_set_delete_access', - 'access arguments' => array(5), - 'file' => 'shortcut.admin.inc', + 'route_name' => 'shortcut_set_delete', ); $items['admin/config/user-interface/shortcut/manage/%shortcut_set/add-link'] = array( 'title' => 'Add shortcut', @@ -135,11 +131,7 @@ function shortcut_menu() { ); $items['admin/config/user-interface/shortcut/link/%menu_link/delete'] = array( 'title' => 'Delete shortcut', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('shortcut_link_delete', 5), - 'access callback' => 'shortcut_link_access', - 'access arguments' => array(5), - 'file' => 'shortcut.admin.inc', + 'route_name' => 'shortcut_link_delete', ); $items['user/%user/shortcuts'] = array( 'title' => 'Shortcuts', @@ -200,30 +192,6 @@ function shortcut_set_edit_access($shortcut_set = NULL) { } /** - * Access callback for deleting a shortcut set. - * - * @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut - * The shortcut set to be deleted. - * - * @return - * TRUE if the current user has access to delete shortcut sets and this is - * not the site-wide default set; FALSE otherwise. - */ -function shortcut_set_delete_access($shortcut_set) { - // Only admins can delete sets. - if (!user_access('administer shortcuts')) { - return FALSE; - } - - // Never let the default shortcut set be deleted. - if ($shortcut_set->id() == 'default') { - return FALSE; - } - - return TRUE; -} - -/** * Access callback for switching the shortcut set assigned to a user account. * * @param object $account diff --git a/core/modules/shortcut/shortcut.routing.yml b/core/modules/shortcut/shortcut.routing.yml new file mode 100644 index 0000000..277853f --- /dev/null +++ b/core/modules/shortcut/shortcut.routing.yml @@ -0,0 +1,13 @@ +shortcut_link_delete: + pattern: '/admin/config/user-interface/shortcut/link/{menu_link}/delete' + defaults: + _form: 'Drupal\shortcut\Form\LinkDelete' + requirements: + _access_shortcut_link_delete: 'TRUE' + +shortcut_set_delete: + pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}/delete' + defaults: + _form: 'Drupal\shortcut\Form\SetDelete' + requirements: + _entity_access: 'shortcut.delete' diff --git a/core/modules/shortcut/shortcut.services.yml b/core/modules/shortcut/shortcut.services.yml new file mode 100644 index 0000000..bb95f49 --- /dev/null +++ b/core/modules/shortcut/shortcut.services.yml @@ -0,0 +1,5 @@ +services: + access_check.shortcut.link: + class: Drupal\shortcut\Access\LinkDeleteAccessCheck + tags: + - { name: access_check } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php new file mode 100644 index 0000000..a1604aa --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php @@ -0,0 +1,81 @@ + 'Entity access check test', + 'description' => 'Unit test of entity access checking system.', + 'group' => 'Entity' + ); + } + + /** + * Tests the method for checking if the access check applies to a route. + */ + public function testApplies() { + $applies_check = new EntityAccessCheck(); + + $route = $this->getMockBuilder('Symfony\Component\Routing\Route') + ->disableOriginalConstructor() + ->getMock(); + $route->expects($this->any()) + ->method('getRequirements') + ->will($this->returnValue(array('_entity_access' => ''))); + $res = $applies_check->applies($route); + $this->assertEquals(TRUE, $res); + + $route = $this->getMockBuilder('Symfony\Component\Routing\Route') + ->disableOriginalConstructor() + ->getMock(); + $route->expects($this->any()) + ->method('getRequirements') + ->will($this->returnValue(array())); + $res = $applies_check->applies($route); + $this->assertEquals(FALSE, $res); + } + + /** + * Tests the method for checking access to routes. + */ + public function testAccess() { + $route = new Route('/foo', array(), array('_entity_access' => 'node.update')); + $request = new Request(); + $node = $this->getMockBuilder('Drupal\node\Plugin\Core\Entity\Node') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('access') + ->will($this->returnValue(TRUE)); + $access_check = new EntityAccessCheck(); + $request->attributes->set('node', $node); + $access = $access_check->access($route, $request); + $this->assertEquals(TRUE, $access); + } + +}