/** * AJAX handler for by_user_state. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @return array */ public function toggleByUserMode($form, FormStateInterface $form_state) { $by_user_mode = $form_state->getUserInput(); $by_user_mode = !empty($by_user_mode['by_user_mode']); \Drupal::configFactory()->getEditable('devel_node_access.settings')->set('by_user_mode', $by_user_mode)->save(TRUE); $form['user_content'][0] = $by_user_mode ? DnaBlock::buildByUserInfo() : []; return $form['user_content']; }
/** * Helper function that mimics node.module's node_access() function. * * Unfortunately, this needs to be updated manually whenever node.module * changes! * * @param string $op * Operation to check. * @param NodeInterface $node * Node to check. * @param AccountInterface $account * (optional) The user object for the user whose access is being checked. If * omitted, the current user is used. Defaults to NULL. * @param string $langcode * (optional) The language code for which access is being checked. If * omitted, the default language is used. Defaults to NULL. * * @return array * An array suitable for theming with theme_dna_permission(). */ public static function explainAccess($op, NodeInterface $node, AccountInterface $account = NULL, $langcode = NULL) { $user = Drupal::currentUser(); if (!$node) { return array(FALSE, '???', t('No node passed to node_access(); this should never happen!')); } if (!in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) { return array(FALSE, t('!NO: invalid $op', array('!NO' => t('NO'))), t("'@op' is an invalid operation!", array('@op' => $op))); } if ($op == 'create' && is_object($node)) { $node = $node->bundle(); } if (!empty($account)) { // To try to get the most authentic result we impersonate the given user! // This may reveal bugs in other modules, leading to contradictory // results. /* @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */ $account_switcher = Drupal::service('account_switcher'); $account_switcher->switchTo($account); $result = DnaBlock::explainAccess($op, $node, NULL, $langcode); $account_switcher->switchBack(); $access_handler = Drupal::entityTypeManager()->getAccessControlHandler('node'); $second_opinion = $access_handler->access($node, $op, $account); if ($second_opinion != $result[0]) { $result[1] .= '<span class="' . ($second_opinion ? 'ok' : 'error') . '" title="Core seems to disagree on this item. This is a bug in either DNA or Core and should be fixed! Try to look at this node as this user and check whether there is still disagreement.">*</span>'; } return $result; } if (empty($langcode)) { $langcode = is_object($node) && $node->id() ? $node->language()->getId() : ''; } $variables = array('!NO' => t('NO'), '!YES' => t('YES'), '!bypass_node_access' => t('bypass node access'), '!access_content' => t('access content')); if (Drupal::currentUser()->hasPermission('bypass node access')) { return array(TRUE, t('!YES: bypass node access', $variables), t("!YES: This user has the '!bypass_node_access' permission and may do everything with nodes.", $variables)); } if (!Drupal::currentUser()->hasPermission('access content')) { return array(FALSE, t('!NO: access content', $variables), t("!NO: This user does not have the '!access_content' permission and is denied doing anything with content.", $variables)); } foreach (Drupal::moduleHandler()->getImplementations('node_access') as $module) { $function = $module . '_node_access'; if (function_exists($function)) { $result = $function($node, $op, $user, $langcode); if ($module == 'node') { $module = 'node (permissions)'; } if (isset($result)) { /* TODO if ($result === NODE_ACCESS_DENY) { $denied_by[] = $module; } elseif ($result === NODE_ACCESS_ALLOW) { $allowed_by[] = $module; } */ $access[] = $result; } } } $variables += array('@deniers' => empty($denied_by) ? NULL : implode(', ', $denied_by), '@allowers' => empty($allowed_by) ? NULL : implode(', ', $allowed_by)); if (!empty($denied_by)) { $variables += array('%module' => $denied_by[0] . (count($denied_by) > 1 ? '+' : '')); return [FALSE, t('!NO: by %module', $variables), empty($allowed_by) ? t("!NO: hook_node_access() of the following module(s) denies this: @deniers.", $variables) : t("!NO: hook_node_access() of the following module(s) denies this: @deniers – even though the following module(s) would allow it: @allowers.", $variables)]; } if (!empty($allowed_by)) { $variables += array('%module' => $allowed_by[0] . (count($allowed_by) > 1 ? '+' : ''), '!view_own_unpublished_content' => t('view own unpublished content')); return array(TRUE, t('!YES: by %module', $variables), t("!YES: hook_node_access() of the following module(s) allows this: @allowers.", $variables)); } // TODO if ($op == 'view' && !$node->get('status', $langcode) && \Drupal::currentUser()->hasPermission('view own unpublished content') && $user->uid == $node->get('uid', $langcode) && $user->uid != 0) { if ($op == 'view' && !$node->isPublished() && Drupal::currentUser()->hasPermission('view own unpublished content') && $user->id() == $node->getRevisionAuthor()->id() && $user->id() != 0) { return array(TRUE, t('!YES: view own unpublished content', $variables), t("!YES: The node is unpublished, but the user has the '!view_own_unpublished_content' permission.", $variables)); } if ($op != 'create' && $node->id()) { $access_handler = Drupal::entityTypeManager()->getAccessControlHandler('node'); // TODO if (node_access($op, $node, $user, $langcode)) { // delegate this part if ($access_handler->access($node, $op, $user)) { // Delegate this part. $variables['@node_access_table'] = '{node_access}'; return array(TRUE, t('!YES: @node_access_table', $variables), t('!YES: Node access allows this based on one or more records in the @node_access_table table (see the other DNA block!).', $variables)); } } return array(FALSE, t('!NO: no reason', $variables), t("!NO: None of the checks resulted in allowing this, so it's denied.", $variables) . ($op == 'create' ? ' ' . t('This is most likely due to a withheld permission.') : '')); }