Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1471 from ec-europa/ISAICP-4993
Browse files Browse the repository at this point in the history
Isaicp 4993: Ensure proper dates are set as created date in community content.
  • Loading branch information
claudiu-cristea authored Jan 31, 2019
2 parents e548ce6 + eee7b98 commit 4a24792
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 23 deletions.
20 changes: 13 additions & 7 deletions tests/features/community_content/add_community_content.feature
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,11 @@ Feature: Add community content

Scenario Outline: Publishing a content for the first time updates the creation time
Given users:
| Username | E-mail | First name | Family name |
| Publisher | publisher-example@test.com | Publihser | Georgakopoulos |
| Username | E-mail | First name | Family name | Roles |
| Publisher | publisher-example@test.com | Publihser | Georgakopoulos | moderator |
And the following collection:
| title | The afternoon shift |
| state | validated |
And the following collection user membership:
| collection | user | role |
| The afternoon shift | Publisher | facilitator |
And discussion content:
| title | content | author | state | collection | created |
| Sample discussion | Sample content. | Publisher | draft | The afternoon shift | 01-01-2010 |
Expand All @@ -90,8 +87,17 @@ Feature: Add community content
And I click "Edit" in the "Entity actions" region
And I press "Publish"
Then I should see the heading "Sample <content type>"
# The created date has been updated.
And I should not see the text "01/01/2010"
And the latest version of the "Sample <content type>" <content type> should have a different created date than the last unpublished version

When I click "Revisions" in the "Entity actions" region
And I click the last "Revert" link
And I press "Revert"
And I go to the "Sample <content type>" <content type>

When I click "Edit" in the "Entity actions" region
And I press "Publish"
Then I should see the heading "Sample <content type>"
Then the latest version of the "Sample <content type>" <content type> should have the same created date as the last published version

# The document is not tested as the creation date is not shown in the page. For documents, the document publication
# date is the one shown and this field is exposed to the user.
Expand Down
41 changes: 39 additions & 2 deletions tests/src/Traits/NodeTrait.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?php

declare(strict_types = 1);

namespace Drupal\joinup\Traits;

use Drupal\node\NodeInterface;

/**
* Helper methods when dealing with Nodes.
*/
Expand All @@ -17,13 +21,13 @@ trait NodeTrait {
* @param string $bundle
* Optional content entity bundle.
*
* @return \Drupal\node\Entity\Node
* @return \Drupal\node\NodeInterface
* The node.
*
* @throws \InvalidArgumentException
* Thrown when a node with the given name does not exist.
*/
public static function getNodeByTitle($title, $bundle = NULL) {
public function getNodeByTitle(string $title, string $bundle = NULL): ?NodeInterface {
$query = \Drupal::entityQuery('node')
->condition('title', $title)
->range(0, 1);
Expand All @@ -47,4 +51,37 @@ public static function getNodeByTitle($title, $bundle = NULL) {
return \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($id);
}

/**
* Returns a list of revision IDs.
*
* @param string $title
* The title of the node.
* @param string $bundle
* The type of the node.
* @param bool $published
* Whether to request the last published or last unpublished verion.
*
* @return array
* A list of revision IDs.
*/
public function getNodeRevisionIdsList(string $title, string $bundle, bool $published = NULL): array {
$current_revision = $this->getNodeByTitle($title, $bundle);
// We gather all revisions and then filter out the one we want as filtering
// by vid will lead in false results.
// @see: https://www.drupal.org/project/drupal/issues/2766135
$query = \Drupal::entityQuery('node')
->allRevisions()
->condition('type', $bundle);
if ($published !== NULL) {
$published = (int) $published;
$query->condition('status', $published);
}

$revisions = $query->condition('nid', $current_revision->id())
->sort('vid', 'DESC')
->execute();

return empty($revisions) ? [] : array_keys($revisions);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@

/**
* @file
* Contains \SolutionSubContext.
* Contains \JoinupCommunityContentSubContext.
*/

declare(strict_types = 1);

use Drupal\DrupalExtension\Context\DrupalSubContextBase;
use Drupal\DrupalExtension\Context\DrupalSubContextInterface;
use Drupal\joinup\Traits\NodeTrait;
use Drupal\joinup\Traits\TraversingTrait;
use PHPUnit\Framework\Assert;

/**
* Behat step definitions to test common community content functionality.
*/
class JoinupCommunityContentSubContext extends DrupalSubContextBase implements DrupalSubContextInterface {

use TraversingTrait;
use NodeTrait;

/**
* Asserts that a tile is not marked as shared from another collection.
Expand All @@ -27,7 +32,7 @@ class JoinupCommunityContentSubContext extends DrupalSubContextBase implements D
*
* @Then the :heading tile should not be marked as shared
*/
public function assertTileNotMarkedAsShared($heading) {
public function assertTileNotMarkedAsShared(string $heading): void {
$element = $this->getTileByHeading($heading);

if ($element->find('css', '.icon--shared')) {
Expand All @@ -49,7 +54,7 @@ class JoinupCommunityContentSubContext extends DrupalSubContextBase implements D
*
* @Then the :heading tile should be marked as shared from :collection
*/
public function assertTileMarkedAsShared($heading, $collection) {
public function assertTileMarkedAsShared(string $heading, string $collection): void {
$element = $this->getTileByHeading($heading);

$share = $element->find('css', '.icon--shared');
Expand All @@ -69,4 +74,84 @@ class JoinupCommunityContentSubContext extends DrupalSubContextBase implements D
}
}

/**
* Asserts that the created time differs between published and unpublished.
*
* @param string $title
* The title of the content.
* @param string $type
* The type of the content.
* @param string $published
* Whether to request the published or unpublished version. Allowed values
* are 'published' and 'unpublished'.
*
* @throws \InvalidArgumentException
* Thrown if $published has an invalid value.
* @throws \Exception
* Thrown if the expected and the actual values match.
*
* @Given the latest version of the :title :type should have a different created date than the last :published version
*/
public function assertDifferentCreatedTimeWithUnpublishedVersion(string $title, string $type, string $published): void {
if (!in_array($published, ['published', 'unpublished'])) {
throw new Exception('Only "published" and "unpublished" values are allowed for variable $published.');
}
$published = $published === 'published';
$revision_list = $this->getNodeRevisionIdsList($title, $type);
$revision_id = reset($revision_list);
$latest_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);

$previous_revision_list = $this->getNodeRevisionIdsList($title, $type, $published);
// If both requested versions are of the same status, the pre-last revision
// is the correct one.
$index = array_search($revision_id, $previous_revision_list);
if ($index !== FALSE) {
unset($previous_revision_list[$index]);
}
$previous_id = reset($previous_revision_list);
$previous_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($previous_id);

Assert::assertNotEquals($latest_revision->getCreatedTime(), $previous_revision->getCreatedTime());
}

/**
* Asserts that the created time is the same with the last published version.
*
* @param string $title
* The title of the content.
* @param string $type
* The type of the content.
* @param string $published
* Whether to request the published or unpublished version. Allowed values
* are 'published' and 'unpublished'.
*
* @throws \InvalidArgumentException
* Thrown if $published has an invalid value.
* @throws \Exception
* Thrown if the expected and the actual values do not match.
*
* @Given the latest version of the :title :type should have the same created date as the last :published version
*/
public function assertSameCreatedTimeWithLastVersion(string $title, string $type, string $published): void {
if (!in_array($published, ['published', 'unpublished'])) {
throw new InvalidArgumentException('Only "published" and "unpublished" values are allowed for variable $published.');
}
$published = $published === 'published';
$revision_list = $this->getNodeRevisionIdsList($title, $type);
$revision_id = reset($revision_list);
$latest_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);

$previous_revision_list = $this->getNodeRevisionIdsList($title, $type, $published);
// If both requested versions are of the same status, the pre-last revision
// is the correct one.
$index = array_search($revision_id, $previous_revision_list);
if ($index !== FALSE) {
unset($previous_revision_list[$index]);
}
$previous_id = reset($previous_revision_list);
$previous_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($previous_id);

Assert::assertEquals($latest_revision->getCreatedTime(), $previous_revision->getCreatedTime());
}

}
34 changes: 27 additions & 7 deletions web/modules/custom/joinup_core/joinup_core.behat.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

/**
* @file
* Contains \JoinupSubContext.
* Contains \JoinupCoreSubContext.
*/

declare(strict_types = 1);

use Behat\Gherkin\Node\TableNode;
use Drupal\DrupalExtension\Context\DrupalSubContextBase;
use Drupal\joinup\Traits\TraversingTrait;
Expand Down Expand Up @@ -37,7 +39,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
*
* @Then the page should show( only) the chips:
*/
public function assertChipElements(TableNode $table) {
public function assertChipElements(TableNode $table): void {
$chips = $this->getSession()->getPage()->findAll('css', '.mdl-chip__text');
$found = array_map(function ($element) {
/** @var \Behat\Mink\Element\NodeElement $element */
Expand All @@ -59,7 +61,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
*
* @Then I press the remove button on the chip :text
*/
public function clickRemoveChipButton($text) {
public function clickRemoveChipButton(string $text): void {
// Find the element that contains the user name.
$xpath = "//span[contains(concat(' ', normalize-space(@class), ' '), ' mdl-chip__text ')][contains(text(), '$text')]";
$chip = $this->getSession()->getPage()->find('xpath', $xpath);
Expand All @@ -85,7 +87,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
*
* @Given I go to the :name (taxonomy )term( page)
*/
public function visitTaxonomyTermPage(string $name) {
public function visitTaxonomyTermPage(string $name): void {
$term = static::getEntityByLabel('taxonomy_term', $name);
$this->visitPath($term->toUrl()->toString());
}
Expand Down Expand Up @@ -150,7 +152,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
*
* @Then the content type of the response should be :content_type
*/
public function assertResponseContentType($content_type) {
public function assertResponseContentType(string $content_type): void {
$this->assertSession()->responseHeaderEquals('Content-Type', $content_type);
}

Expand All @@ -173,7 +175,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
* @Then the :group_label :group_type should have a custom page titled :group_title
* @Then the :group_label :group_type should have a community content titled :group_title
*/
public function assertNodeOgMembership($group_label, $group_type, $content_title) {
public function assertNodeOgMembership(string $group_label, string $group_type, string $content_title): void {
$group = $this->getRdfEntityByLabel($group_label, $group_type);
$node = $this->getNodeByTitle($content_title);
if ($node->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->target_id !== $group->id()) {
Expand All @@ -186,7 +188,7 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
*
* @Then I should see the following group menu items in the specified order:
*/
public function assertRepeatedElementContainsText(TableNode $table) {
public function assertRepeatedElementContainsText(TableNode $table): void {
$parent = $this->getSession()->getPage()->findAll('css', '.block-group-menu-blocknavigation li.sidebar-menu__item');
$i = 0;
foreach ($table->getHash() as $repeatedElement) {
Expand All @@ -197,4 +199,22 @@ class JoinupCoreSubContext extends DrupalSubContextBase {
}
}

/**
* Searches for links matching the criteria and clicks on the last of them.
*
* Since the results are sequential, the last link in the results is also the
* last instance of the link in the page matching the given criteria.
*
* @param string $link
* The link locator.
*
* @Given I click the last :link link
*/
public function assertClickLastLink(string $link): void {
$locator = ['link', $link];
$links = $this->getSession()->getPage()->findAll('named', $locator);
$link = end($links);
$link->click();
}

}
22 changes: 18 additions & 4 deletions web/modules/custom/joinup_core/joinup_core.module
Original file line number Diff line number Diff line change
Expand Up @@ -845,16 +845,30 @@ function joinup_core_node_presave(EntityInterface $entity) {
// Set the update time as the created time only if this is the first time this
// entity is published.
$published_revisions = \Drupal::entityQuery('node')
->allRevisions()
->condition('type', $entity->bundle())
->condition('status', 1)
->condition('nid', $entity->id())
->count()
->sort('vid', 'ASC')
->range(0, 1)
->execute();
if ($published_revisions != 0) {
return;

if (count($published_revisions) === 0) {
$entity->set('created', \Drupal::time()->getRequestTime());
}
else {
// If the node is reverted into a previously created draft version, the
// created time is a date different than the first publication date. For
// that case, always set the created time from the first published revision
// every time a community content is saved.
$revision_ids = array_keys($published_revisions);
$revision_id = reset($revision_ids);
$revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);
if (!empty($revision)) {
$entity->set('created', $revision->getCreatedTime());
}
}

$entity->set('created', \Drupal::time()->getRequestTime());
}

/**
Expand Down

0 comments on commit 4a24792

Please sign in to comment.