/**
   * Edit the field value of the existing flagging.
   */
  public function doEditFlagField() {
    $flag_id = $this->flag->id();

    $this->drupalGet('node/' . $this->nodeId);

    // Get the details form.
    $this->clickLink($this->flag->getUnflagShortText());
    $this->assertUrl('flag/details/edit/' . $flag_id . '/' . $this->nodeId, [
      'query' => [
        'destination' => 'node/' . $this->nodeId,
      ],
    ]);

    // See if the details message is displayed.
    $this->assertText($this->flagDetailsMessage);

    // See if the field value was preserved.
    $this->assertFieldByName('field_' . $this->flagFieldId . '[0][value]', $this->flagFieldValue);

    // Update the field value.
    $this->flagFieldValue = $this->randomString();
    $edit = [
      'field_' . $this->flagFieldId . '[0][value]' => $this->flagFieldValue,
    ];
    $this->drupalPostForm(NULL, $edit, t('Update Flagging'));

    // Get the details form.
    $this->drupalGet('flag/details/edit/' . $flag_id . '/' . $this->nodeId);

    // See if the field value was preserved.
    $this->assertFieldByName('field_' . $this->flagFieldId . '[0][value]', $this->flagFieldValue);
  }
  /**
   * Test an AJAX flag link.
   */
  public function doUseAjaxFlag() {
    // Create and login as an authenticated user.
    $auth_user = $this->drupalCreateUser();
    $this->drupalLogin($auth_user);

    $node_url = $this->node->toUrl();

    // Navigate to the node page.
    $this->drupalGet($node_url);

    // Confirm the flag link exists.
    $this->assertLink($this->flag->getFlagShortText());

    // Click the flag link. This ensures that the non-JS fallback works we are
    // redirected to back to the page and the node is flagged.
    $this->clickLink($this->flag->getFlagShortText());
    $this->assertUrl($node_url);
    $this->assertLink($this->flag->getUnflagShortText());

    // Click the unflag link, repeat the check.
    $this->clickLink($this->flag->getUnflagShortText());
    $this->assertUrl($node_url);
    $this->assertLink($this->flag->getFlagShortText());

    // Now also test with an ajax request and that the correct response is
    // returned. Use the same logic as clickLink() to find the link.
    $urls = $this->xpath('//a[normalize-space()=:label]', array(':label' => $this->flag->getFlagShortText()));
    $url_target = $this->getAbsoluteUrl($urls[0]['href']);
    $ajax_response = $this->drupalGetAjax($url_target);

    // Assert that the replace selector is correct.
    $this->assertEqual($ajax_response[0]['selector'], '#' .$urls[0]['id']);

    // Request the returned URL to ensure that link is valid and has a valid
    // CSRF token.
    $xml_data = new \SimpleXMLElement($ajax_response[0]['data']);
    $this->assertEqual($this->flag->getUnflagShortText(), (string) $xml_data);

    $ajax_response = $this->drupalGetAjax($this->getAbsoluteUrl($xml_data['href']));
    // Assert that the replace selector is correct.
    $this->assertEqual($ajax_response[0]['selector'], '#' . $xml_data['id']);

    $xml_data_unflag = new \SimpleXMLElement($ajax_response[0]['data']);
    $this->assertEqual($this->flag->getFlagShortText(), (string) $xml_data_unflag);

  }
  /**
   * Create a node, flag it and unflag it.
   */
  public function doFlagUnflagNode() {
    $node = $this->drupalCreateNode(['type' => $this->nodeType]);
    $node_id = $node->id();
    $flag_id = $this->flag->id();

    // Grant the flag permissions to the authenticated role, so that both
    // users have the same roles and share the render cache.
    $this->grantFlagPermissions($this->flag);

    // Create and login a new user.
    $user_1 = $this->drupalCreateUser();
    $this->drupalLogin($user_1);

    // Get the flag count before the flagging, querying the database directly.
    $flag_count_pre = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();

    // Click the flag link.
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getFlagShortText());

    // Check if we have the confirm form message displayed.
    $this->assertText($this->flagConfirmMessage);

    // Submit the confirm form.
    $this->drupalPostForm('flag/confirm/flag/' . $flag_id . '/' . $node_id, [], t('Flag'));
    $this->assertResponse(200);

    // Check that the node is flagged.
    $this->drupalGet('node/' . $node_id);
    $this->assertLink($this->flag->getUnflagShortText());

    // Check the flag count was incremented.
    $flag_count_flagged = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();
    $this->assertEqual($flag_count_flagged, $flag_count_pre + 1, "The flag count was incremented.");

    // Unflag the node.
    $this->clickLink($this->flag->getUnflagShortText());

    // Check if we have the confirm form message displayed.
    $this->assertText($this->unflagConfirmMessage);

    // Submit the confirm form.
    $this->drupalPostForm(NULL, [], t('Unflag'));
    $this->assertResponse(200);

    // Check that the node is no longer flagged.
    $this->drupalGet('node/' . $node_id);
    $this->assertLink($this->flag->getFlagShortText());

    // Check the flag count was decremented.
    $flag_count_unflagged = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();
    $this->assertEqual($flag_count_unflagged, $flag_count_flagged - 1, "The flag count was decremented.");
  }
  /**
   * Flags a node using different user accounts and checks flag counts.
   */
  public function doTestFlagCounts() {
    /** \Drupal\Core\Database\Connection $connection */
    $connection = \Drupal::database();

    $node = $this->drupalCreateNode(['type' => $this->nodeType]);
    $node_id = $node->id();

    // Grant the flag permissions to the authenticated role, so that both
    // users have the same roles and share the render cache.
    $this->grantFlagPermissions($this->flag);

    // Create and login user 1.
    $user_1 = $this->drupalCreateUser();
    $this->drupalLogin($user_1);

    // Flag node (first count).
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getFlagShortText());
    $this->assertResponse(200);
    $this->assertLink($this->flag->getUnflagShortText());

    // Check for 1 flag count.
    $count_flags_before = $connection->select('flag_counts')
      ->condition('flag_id', $this->flag->id())
      ->condition('entity_type', $node->getEntityTypeId())
      ->condition('entity_id', $node_id)
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertTrue(1, $count_flags_before);

    // Logout user 1, create and login user 2.
    $user_2 = $this->drupalCreateUser();
    $this->drupalLogin($user_2);

    // Flag node (second count).
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getFlagShortText());
    $this->assertResponse(200);
    $this->assertLink($this->flag->getUnflagShortText());

    // Check for 2 flag counts.
    $count_flags_after = $connection->select('flag_counts')
      ->condition('flag_id', $this->flag->id())
      ->condition('entity_type', $node->getEntityTypeId())
      ->condition('entity_id', $node_id)
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertTrue(2, $count_flags_after);

    // Unflag the node again.
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getUnflagShortText());
    $this->assertResponse(200);
    $this->assertLink($this->flag->getFlagShortText());

    // Check for 1 flag count.
    $count_flags_before = $connection->select('flag_counts')
      ->condition('flag_id', $this->flag->id())
      ->condition('entity_type', $node->getEntityTypeId())
      ->condition('entity_id', $node_id)
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertEqual(1, $count_flags_before);

    // Delete  user 1.
    $user_1->delete();

    // Check for 0 flag counts, user deletion should lead to count decrement
    // or row deletion.
    $count_flags_before = $connection->select('flag_counts')
      ->condition('flag_id', $this->flag->id())
      ->condition('entity_type', $node->getEntityTypeId())
      ->condition('entity_id', $node_id)
      ->countQuery()
      ->execute()
      ->fetchField();

    $this->assertEqual(0, $count_flags_before);
  }
  /**
   * Flag a node.
   */
  public function doFlagNode() {
    $node = $this->drupalCreateNode(['type' => $this->nodeType]);
    $node_id = $node->id();
    $flag_id = $this->flag->id();

    // Grant the flag permissions to the authenticated role, so that both
    // users have the same roles and share the render cache. ???? TODO
    $this->grantFlagPermissions($this->flag);

    // Create and login a new user.
    $user_1 = $this->drupalCreateUser();
    $this->drupalLogin($user_1);

    // Get the flag count before the flagging, querying the database directly.
    $flag_count_pre = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();

    // Attempt to load the reload link URL without the token.
    // We (probably) can't obtain the URL from the route rather than hardcoding
    // it, as that would probably give us the token too.
    $this->drupalGet("flag/flag/$flag_id/$node_id");
    $this->assertResponse(403, "Access to the flag reload link is denied when no token is supplied.");

    // Click the flag link.
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getFlagShortText());

    // Check that the node is flagged.
    $this->drupalGet('node/' . $node_id);
    $this->assertLink($this->flag->getUnflagShortText());

    // Check the flag count was incremented.
    $flag_count_flagged = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();
    $this->assertEqual($flag_count_flagged, $flag_count_pre + 1, "The flag count was incremented.");

    // Attempt to load the reload link URL without the token.
    $this->drupalGet("flag/unflag/$flag_id/$node_id");
    $this->assertResponse(403, "Access to the unflag reload link is denied when no token is supplied.");

    // Unflag the node.
    $this->drupalGet('node/' . $node_id);
    $this->clickLink($this->flag->getUnflagShortText());

    // Check that the node is no longer flagged.
    $this->drupalGet('node/' . $node_id);
    $this->assertLink($this->flag->getFlagShortText());

    // Check the flag count was decremented.
    $flag_count_unflagged = db_query('SELECT count FROM {flag_counts}
      WHERE flag_id = :flag_id AND entity_type = :entity_type AND entity_id = :entity_id', [
      ':flag_id' => $flag_id,
      ':entity_type' => 'node',
      ':entity_id' => $node_id,
    ])->fetchField();
    $this->assertEqual($flag_count_unflagged, $flag_count_flagged - 1, "The flag count was decremented.");
  }