/** * 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); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $this->flaggingService->reset($this->flag); drupal_set_message($this->t('Flag %label was reset.', [ '%label' => $this->flag->label(), ])); $form_state->setRedirectUrl($this->getCancelUrl()); }
/** * {@inheritdoc} */ public function reset(FlagInterface $flag, EntityInterface $entity = NULL) { $query = $this->entityQueryManager->get('flagging') ->condition('flag_id', $flag->id()); if (!empty($entity)) { $query->condition('entity_id', $entity->id()); } // Count the number of flaggings to delete. $count = $query->count() ->execute(); $this->eventDispatcher->dispatch(FlagEvents::FLAG_RESET, new FlagResetEvent($flag, $count)); $flaggings = $this->flagService->getFlaggings($flag, $entity); foreach ($flaggings as $flagging) { $flagging->delete(); } return $count; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // Toggle the flag state. if ($this->flag->isEnabled()) { $this->flag->disable(); } else { $this->flag->enable(); } // Save The flag entity. $this->flag->save(); // Redirect to the flag admin page. $form_state->setRedirect('entity.flag.collection'); }
/** * Assert editing an invalid flagging throws an exception. */ public function doBadEditFlagField() { $flag_id = $this->flag->id(); // Test a good flag ID param, but a bad flaggable ID param. $this->drupalGet('flag/details/edit/' . $flag_id . '/-9999'); $this->assertResponse('404', 'Editing an invalid flagging path: good flag, bad entity.'); // Test a bad flag ID param, but a good flaggable ID param. $this->drupalGet('flag/details/edit/jibberish/' . $this->nodeId); $this->assertResponse('404', 'Editing an invalid flagging path: bad flag, good entity'); // Test editing a unflagged entity. $unlinked_node = $this->drupalCreateNode(['type' => $this->nodeType]); $this->drupalGet('flag/details/edit/' . $flag_id . '/' . $unlinked_node->id()); $this->assertResponse('404', 'Editing an invalid flagging path: good flag, good entity, but not flagged'); }
/** * Delete the flag. */ public function doFlagDelete() { // Flag node. $this->drupalGet('node/' . $this->nodeId); $this->assertLink($this->flagShortText); // Go to the delete form for the flag. $this->drupalGet('admin/structure/flags/manage/' . $this->flag->id() . '/delete'); $this->assertText($this->t('Are you sure you want to delete the flag @this_label?', ['@this_label' => $this->label])); $this->drupalPostForm(NULL, [], $this->t('Delete')); // Check the flag has been deleted. $result = $this->flagService->getFlagById($this->flagId); $this->assertNull($result, 'The flag was deleted.'); $this->drupalGet('node/' . $this->nodeId); $this->assertText($this->node->label()); $this->assertNoLink($this->flagShortText); }
/** * Tests flaggings and counts are deleted when its user is deleted. */ public function testUserDeletion() { $auth_user = $this->createUser(); // Create a flag. $user_flag = Flag::create([ 'id' => strtolower($this->randomMachineName()), 'label' => $this->randomString(), 'entity_type' => 'user', 'flag_type' => 'entity:user', 'link_type' => 'reload', 'flagTypeConfig' => [], 'linkTypeConfig' => [], ]); $user_flag->save(); $article = Node::create([ 'type' => 'article', 'title' => $this->randomMachineName(8), ]); $article->save(); $this->flagService->flag($user_flag, $auth_user, $this->adminUser); $this->flagService->flag($this->flag, $article, $auth_user); $user_before_count = $this->flagCountService->getEntityFlagCounts($auth_user); $this->assertEqual($user_before_count[$user_flag->id()], 1, 'The user has been flagged.'); $article_count_before = $this->flagCountService->getEntityFlagCounts($article); $this->assertEqual($article_count_before[$this->flag->id()], 1, 'The article has been flagged by the user.'); $auth_user->delete(); $flaggings_after = $this->flagService->getFlaggings($user_flag); $this->assertEmpty($flaggings_after, 'The user flaggings were removed when the user was deleted.'); $flaggings_after = $this->flagService->getFlaggings($this->flag); $this->assert(empty($flaggings_after), 'The node flaggings were removed when the user was deleted'); }
/** * Checks access to the 'unflag' action. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * * @return string * A \Drupal\Core\Access\AccessInterface constant value. */ public function access(FlagInterface $flag) { return AccessResult::allowedIf($flag->hasActionAccess('unflag')); }
/** * 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."); }
/** * 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."); }
/** * Title callback when editing an existing flagging. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param int $entity_id * The entity ID to unflag. * * @return string * The flag field entry form title. */ public function editTitle(FlagInterface $flag, $entity_id) { $link_type = $flag->getLinkTypePlugin(); return $link_type->getEditFlaggingTitle(); }
/** * Generates a render array of the applicable bundles for the flag.. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * * @return array * A render array of the applicable bundles for the flag.. */ protected function getBundles(FlagInterface $flag) { $bundles = $flag->getBundles(); if (empty($bundles)) { return [ '#markup' => '<em>' . $this->t('All') . '</em>', '#allowed_tags' => ['em'], ]; } return [ '#markup' => implode(', ', $bundles), ]; }
/** * {@inheritdoc} */ public function unflag(FlagInterface $flag, EntityInterface $entity, AccountInterface $account = NULL) { $bundles = $flag->getBundles(); // Check the entity type corresponds to the flag type. if ($flag->getFlaggableEntityTypeId() != $entity->getEntityTypeId()) { throw new \LogicException('The flag does not apply to entities of this type.'); } // Check the bundle is allowed by the flag. if (!empty($bundles) && !in_array($entity->bundle(), $bundles)) { throw new \LogicException('The flag does not apply to the bundle of the entity.'); } $flagging = $this->getFlagging($flag, $entity, $account); // Check whether there is an existing flagging for the combination of flag, // entity, and user. if (!$flagging) { throw new \LogicException('The entity is not flagged by the user.'); } $this->eventDispatcher->dispatch(FlagEvents::ENTITY_UNFLAGGED, new FlaggingEvent($flag, $entity)); $flagging->delete(); }
/** * 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); }
/** * Resets loaded flag counts. * * @param \Drupal\Core\Entity\EntityInterface $entity * The flagged entity. * @param \Drupal\flag\FlagInterface $flag * The flag. */ protected function resetLoadedCounts(EntityInterface $entity, FlagInterface $flag) { // @todo Consider updating them instead of just clearing it. unset($this->entityCounts[$entity->getEntityTypeId()][$entity->id()]); unset($this->flagCounts[$flag->id()]); unset($this->flagEntityCounts[$flag->id()]); unset($this->userFlagCounts[$flag->id()]); }
/** * Helper for assertPseudofield() and assertNoPseudofield(). * * It is not recommended to call this function directly. * * @param \Drupal\flag\FlagInterface $flag * The flag to look for. * @param \Drupal\Core\Entity\EntityInterface $entity * The flaggable entity the flag is on. * @param string $message * Message to display. * @param bool $exists * TRUE if the flag link should exist, FALSE if it should not exist. */ protected function assertPseudofieldHelper(FlagInterface $flag, EntityInterface $entity, $message, $exists) { $xpath = $this->xpath("//*[contains(@class, 'node__content')]/a[@id = :id]", [ ':id' => 'flag-' . $flag->id() . '-id-' . $entity->id(), ]); $this->assert(count($xpath) == ($exists ? 1 : 0), $message); }
/** * Grants flag and unflag permission to the given flag. * * @param \Drupal\flag\FlagInterface $flag * The flag on which to grant permissions. * @param array|string $role_id * (optional) The ID of the role to grant permissions. If omitted, the * authenticated role is assumed. * @param bool $can_flag * (optional) TRUE to grant the role flagging permission, FALSE to not grant * flagging permission to the role. If omitted, TRUE is assumed. * @param bool $can_unflag * Optional TRUE to grant the role unflagging permission, FALSE to not grant * unflagging permission to the role. If omitted, TRUE is assumed. */ protected function grantFlagPermissions(FlagInterface $flag, $role_id = RoleInterface::AUTHENTICATED_ID, $can_flag = TRUE, $can_unflag = TRUE) { // Grant the flag permissions to the authenticated role, so that both // users have the same roles and share the render cache. $role = Role::load($role_id); if ($can_flag) { $role->grantPermission('flag ' . $flag->id()); } if ($can_unflag) { $role->grantPermission('unflag ' . $flag->id()); } $role->save(); }
/** * {@inheritdoc} */ public function getLink(FlagInterface $flag, EntityInterface $entity) { $action = $flag->isFlagged($entity) ? 'unflag' : 'flag'; if ($flag->hasActionAccess($action)) { $link = $this->buildLink($action, $flag, $entity); // The actual render array must be in a nested key, due to a bug in // lazy builder handling that does not properly render top-level #type // elements. return ['link' => $link]; } return []; }
/** * Generates a response object after handing the un/flag request. * * Depending on the wrapper format of the request, it will either redirect * or return an ajax response. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse * The response object. */ protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request) { if ($request->get(MainContentViewSubscriber::WRAPPER_FORMAT) == 'drupal_ajax') { // Create a new AJAX response. $response = new AjaxResponse(); // Get the link type plugin. $link_type = $flag->getLinkTypePlugin(); // Generate the link render array and get the link CSS ID. $link = $link_type->getLink($flag, $entity); $link_id = '#' . $link['link']['#attributes']['id']; // Create a new JQuery Replace command to update the link display. $replace = new ReplaceCommand($link_id, $this->renderer->renderPlain($link)); $response->addCommand($replace); return $response; } else { // Redirect back to the entity. A passed in destination query parameter // will automatically override this. $url_info = $entity->toUrl(); return $this->redirect($url_info->getRouteName(), $url_info->getRouteParameters()); } }