/**
  * Tests Quick Edit autocomplete term behavior.
  */
 public function testAutocompleteQuickEdit()
 {
     $this->drupalLogin($this->editor_user);
     $quickedit_uri = 'quickedit/form/node/' . $this->node->id() . '/' . $this->field_name . '/' . $this->node->language()->getId() . '/full';
     $post = array('nocssjs' => 'true') + $this->getAjaxPageStatePostData();
     $response = $this->drupalPost($quickedit_uri, 'application/vnd.drupal-ajax', $post);
     $ajax_commands = Json::decode($response);
     // Prepare form values for submission. drupalPostAJAX() is not suitable for
     // handling pages with JSON responses, so we need our own solution here.
     $form_tokens_found = preg_match('/\\sname="form_token" value="([^"]+)"/', $ajax_commands[0]['data'], $token_match) && preg_match('/\\sname="form_build_id" value="([^"]+)"/', $ajax_commands[0]['data'], $build_id_match);
     $this->assertTrue($form_tokens_found, 'Form tokens found in output.');
     if ($form_tokens_found) {
         $post = array('form_id' => 'quickedit_field_form', 'form_token' => $token_match[1], 'form_build_id' => $build_id_match[1], $this->field_name => implode(', ', array($this->term1->getName(), 'new term', $this->term2->getName())), 'op' => t('Save'));
         // Submit field form and check response. Should render back all the terms.
         $response = $this->drupalPost($quickedit_uri, 'application/vnd.drupal-ajax', $post);
         $this->assertResponse(200);
         $ajax_commands = Json::decode($response);
         $this->drupalSetContent($ajax_commands[0]['data']);
         $this->assertLink($this->term1->getName());
         $this->assertLink($this->term2->getName());
         $this->assertText('new term');
         $this->assertNoLink('new term');
         // Load the form again, which should now get it back from TempStore.
         $quickedit_uri = 'quickedit/form/node/' . $this->node->id() . '/' . $this->field_name . '/' . $this->node->language()->getId() . '/full';
         $post = array('nocssjs' => 'true') + $this->getAjaxPageStatePostData();
         $response = $this->drupalPost($quickedit_uri, 'application/vnd.drupal-ajax', $post);
         $ajax_commands = Json::decode($response);
         // The AjaxResponse's first command is an InsertCommand which contains
         // the form to edit the taxonomy term field, it should contain all three
         // taxonomy terms, including the one that has just been newly created and
         // which is not yet stored.
         $this->drupalSetContent($ajax_commands[0]['data']);
         $this->assertFieldByName($this->field_name, implode(', ', array($this->term1->getName(), 'new term', $this->term2->label())));
         // Save the entity.
         $post = array('nocssjs' => 'true');
         $response = $this->drupalPost('quickedit/entity/node/' . $this->node->id(), 'application/json', $post);
         $this->assertResponse(200);
         // The full node display should now link to all entities, with the new
         // one created in the database as well.
         $this->drupalGet('node/' . $this->node->id());
         $this->assertLink($this->term1->getName());
         $this->assertLink($this->term2->getName());
         $this->assertLink('new term');
     }
 }
Esempio n. 2
0
 /**
  * {@inheritdoc}
  */
 public function write(NodeInterface $node, array $grants, $realm = NULL, $delete = TRUE)
 {
     if ($delete) {
         $query = $this->database->delete('node_access')->condition('nid', $node->id());
         if ($realm) {
             $query->condition('realm', array($realm, 'all'), 'IN');
         }
         $query->execute();
     }
     // Only perform work when node_access modules are active.
     if (!empty($grants) && count($this->moduleHandler->getImplementations('node_grants'))) {
         $query = $this->database->insert('node_access')->fields(array('nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete'));
         // If we have defined a granted langcode, use it. But if not, add a grant
         // for every language this node is translated to.
         foreach ($grants as $grant) {
             if ($realm && $realm != $grant['realm']) {
                 continue;
             }
             if (isset($grant['langcode'])) {
                 $grant_languages = array($grant['langcode'] => $this->languageManager->getLanguage($grant['langcode']));
             } else {
                 $grant_languages = $node->getTranslationLanguages(TRUE);
             }
             foreach ($grant_languages as $grant_langcode => $grant_language) {
                 // Only write grants; denies are implicit.
                 if ($grant['grant_view'] || $grant['grant_update'] || $grant['grant_delete']) {
                     $grant['nid'] = $node->id();
                     $grant['langcode'] = $grant_langcode;
                     // The record with the original langcode is used as the fallback.
                     if ($grant['langcode'] == $node->language()->getId()) {
                         $grant['fallback'] = 1;
                     } else {
                         $grant['fallback'] = 0;
                     }
                     $query->values($grant);
                 }
             }
         }
         $query->execute();
     }
 }
 /**
  * Build the default links (Read more) for a node.
  *
  * @param \Drupal\node\NodeInterface $entity
  *   The node object.
  * @param string $view_mode
  *   A view mode identifier.
  *
  * @return array
  *   An array that can be processed by drupal_pre_render_links().
  */
 protected static function buildLinks(NodeInterface $entity, $view_mode)
 {
     $links = array();
     // Always display a read more link on teasers because we have no way
     // to know when a teaser view is different than a full view.
     if ($view_mode == 'teaser') {
         $node_title_stripped = strip_tags($entity->label());
         $links['node-readmore'] = array('title' => t('Read more<span class="visually-hidden"> about @title</span>', array('@title' => $node_title_stripped)), 'url' => $entity->urlInfo(), 'language' => $entity->language(), 'html' => TRUE, 'attributes' => array('rel' => 'tag', 'title' => $node_title_stripped));
     }
     return array('#theme' => 'links__node__node', '#links' => $links, '#attributes' => array('class' => array('links', 'inline')));
 }
 /**
  * Checks node revision access.
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node to check.
  * @param \Drupal\Core\Session\AccountInterface $account
  *   A user object representing the user for whom the operation is to be
  *   performed.
  * @param string $op
  *   (optional) The specific operation being checked. Defaults to 'view.'
  *
  * @return bool
  *   TRUE if the operation may be performed, FALSE otherwise.
  */
 public function checkAccess(NodeInterface $node, AccountInterface $account, $op = 'view')
 {
     $map = array('view' => 'view all revisions', 'update' => 'revert all revisions', 'delete' => 'delete all revisions');
     $bundle = $node->bundle();
     $type_map = array('view' => "view {$bundle} revisions", 'update' => "revert {$bundle} revisions", 'delete' => "delete {$bundle} revisions");
     if (!$node || !isset($map[$op]) || !isset($type_map[$op])) {
         // If there was no node to check against, or the $op was not one of the
         // supported ones, we return access denied.
         return FALSE;
     }
     // Statically cache access by revision ID, language code, user account ID,
     // and operation.
     $langcode = $node->language()->getId();
     $cid = $node->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $op;
     if (!isset($this->access[$cid])) {
         // Perform basic permission checks first.
         if (!$account->hasPermission($map[$op]) && !$account->hasPermission($type_map[$op]) && !$account->hasPermission('administer nodes')) {
             $this->access[$cid] = FALSE;
             return FALSE;
         }
         // There should be at least two revisions. If the vid of the given node
         // and the vid of the default revision differ, then we already have two
         // different revisions so there is no need for a separate database check.
         // Also, if you try to revert to or delete the default revision, that's
         // not good.
         if ($node->isDefaultRevision() && ($this->nodeStorage->countDefaultLanguageRevisions($node) == 1 || $op == 'update' || $op == 'delete')) {
             $this->access[$cid] = FALSE;
         } elseif ($account->hasPermission('administer nodes')) {
             $this->access[$cid] = TRUE;
         } else {
             // First check the access to the default revision and finally, if the
             // node passed in is not the default revision then access to that, too.
             $this->access[$cid] = $this->nodeAccess->access($this->nodeStorage->load($node->id()), $op, $account) && ($node->isDefaultRevision() || $this->nodeAccess->access($node, $op, $account));
         }
     }
     return $this->access[$cid];
 }
Esempio n. 5
0
 /**
  * Generates an overview table of older revisions of a node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   A node object.
  *
  * @return array
  *   An array as expected by drupal_render().
  */
 public function revisionOverview(NodeInterface $node)
 {
     $account = $this->currentUser();
     $langcode = $node->language()->getId();
     $langname = $node->language()->getName();
     $languages = $node->getTranslationLanguages();
     $has_translations = count($languages) > 1;
     $node_storage = $this->entityManager()->getStorage('node');
     $type = $node->getType();
     $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', ['@langname' => $langname, '%title' => $node->label()]) : $this->t('Revisions for %title', ['%title' => $node->label()]);
     $header = array($this->t('Revision'), $this->t('Operations'));
     $revert_permission = ($account->hasPermission("revert {$type} revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes')) && $node->access('update');
     $delete_permission = ($account->hasPermission("delete {$type} revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete');
     $rows = array();
     $vids = $node_storage->revisionIds($node);
     $latest_revision = TRUE;
     foreach (array_reverse($vids) as $vid) {
         /** @var \Drupal\node\NodeInterface $revision */
         $revision = $node_storage->loadRevision($vid);
         // Only show revisions that are affected by the language that is being
         // displayed.
         if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
             $username = ['#theme' => 'username', '#account' => $revision->getRevisionAuthor()];
             // Use revision link to link to revisions that are not active.
             $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short');
             if ($vid != $node->getRevisionId()) {
                 $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
             } else {
                 $link = $node->link($date);
             }
             $row = [];
             $column = ['data' => ['#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', '#context' => ['date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()]]]];
             // @todo Simplify once https://www.drupal.org/node/2334319 lands.
             $this->renderer->addCacheableDependency($column['data'], $username);
             $row[] = $column;
             if ($latest_revision) {
                 $row[] = ['data' => ['#prefix' => '<em>', '#markup' => $this->t('Current revision'), '#suffix' => '</em>']];
                 foreach ($row as &$current) {
                     $current['class'] = ['revision-current'];
                 }
                 $latest_revision = FALSE;
             } else {
                 $links = [];
                 if ($revert_permission) {
                     $links['revert'] = ['title' => $this->t('Revert'), 'url' => $has_translations ? Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) : Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
                 }
                 if ($delete_permission) {
                     $links['delete'] = ['title' => $this->t('Delete'), 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid])];
                 }
                 $row[] = ['data' => ['#type' => 'operations', '#links' => $links]];
             }
             $rows[] = $row;
         }
     }
     $build['node_revisions_table'] = array('#theme' => 'table', '#rows' => $rows, '#header' => $header, '#attached' => array('library' => array('node/drupal.node.admin')));
     return $build;
 }