Issue #2766957 by timmillwood, vijaycs85, plach, Sam152, Gábor Hojtsy, catch, dawehner, alexpott, hchonov: Forward revisions + translation UI can result in forked draft revisions
parent
db4cb40e13
commit
75fdbf087c
|
@ -13,6 +13,7 @@ use Drupal\content_moderation\Plugin\Action\ModerationOptOutUnpublishNode;
|
|||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
|
@ -20,7 +21,6 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\workflows\WorkflowInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\node\Plugin\Action\PublishNode;
|
||||
use Drupal\node\Plugin\Action\UnpublishNode;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
@ -131,34 +131,34 @@ function content_moderation_entity_view(array &$build, EntityInterface $entity,
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_access().
|
||||
* Implements hook_entity_access().
|
||||
*
|
||||
* Nodes in particular should be viewable if unpublished and the user has
|
||||
* the appropriate permission. This permission is therefore effectively
|
||||
* mandatory for any user that wants to moderate things.
|
||||
* Entities should be viewable if unpublished and the user has the appropriate
|
||||
* permission. This permission is therefore effectively mandatory for any user
|
||||
* that wants to moderate things.
|
||||
*/
|
||||
function content_moderation_node_access(NodeInterface $node, $operation, AccountInterface $account) {
|
||||
function content_moderation_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
/** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
|
||||
$moderation_info = Drupal::service('content_moderation.moderation_information');
|
||||
|
||||
$access_result = NULL;
|
||||
if ($operation === 'view') {
|
||||
$access_result = (!$node->isPublished())
|
||||
$access_result = (($entity instanceof EntityPublishedInterface) && !$entity->isPublished())
|
||||
? AccessResult::allowedIfHasPermission($account, 'view any unpublished content')
|
||||
: AccessResult::neutral();
|
||||
|
||||
$access_result->addCacheableDependency($node);
|
||||
$access_result->addCacheableDependency($entity);
|
||||
}
|
||||
elseif ($operation === 'update' && $moderation_info->isModeratedEntity($node) && $node->moderation_state) {
|
||||
elseif ($operation === 'update' && $moderation_info->isModeratedEntity($entity) && $entity->moderation_state) {
|
||||
/** @var \Drupal\content_moderation\StateTransitionValidation $transition_validation */
|
||||
$transition_validation = \Drupal::service('content_moderation.state_transition_validation');
|
||||
|
||||
$valid_transition_targets = $transition_validation->getValidTransitions($node, $account);
|
||||
$valid_transition_targets = $transition_validation->getValidTransitions($entity, $account);
|
||||
$access_result = $valid_transition_targets ? AccessResult::neutral() : AccessResult::forbidden();
|
||||
|
||||
$access_result->addCacheableDependency($node);
|
||||
$access_result->addCacheableDependency($entity);
|
||||
$access_result->addCacheableDependency($account);
|
||||
$workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($node);
|
||||
$workflow = $moderation_info->getWorkflowForEntity($entity);
|
||||
$access_result->addCacheableDependency($workflow);
|
||||
foreach ($valid_transition_targets as $valid_transition_target) {
|
||||
$access_result->addCacheableDependency($valid_transition_target);
|
||||
|
|
|
@ -33,6 +33,11 @@ class ModerationHandler implements ModerationHandlerInterface, EntityHandlerInte
|
|||
// This is probably not necessary if configuration is setup correctly.
|
||||
$entity->setNewRevision(TRUE);
|
||||
$entity->isDefaultRevision($default_revision);
|
||||
if ($entity->hasField('revision_translation_affected')) {
|
||||
// @todo remove this when revision and translation issues have been
|
||||
// resolved. https://www.drupal.org/node/2860097
|
||||
$entity->set('revision_translation_affected', TRUE);
|
||||
}
|
||||
|
||||
// Update publishing status if it can be updated and if it needs updating.
|
||||
if (($entity instanceof EntityPublishedInterface) && $entity->isPublished() !== $published_state) {
|
||||
|
|
|
@ -237,6 +237,13 @@ class EntityOperations implements ContainerInjectionInterface {
|
|||
if ($this->moderationInfo->isLiveRevision($entity)) {
|
||||
return;
|
||||
}
|
||||
// Don't display the moderation form when when:
|
||||
// - The revision is not translation affected.
|
||||
// - There are more than one translation languages.
|
||||
// - The entity has forward revisions.
|
||||
if (!$this->moderationInfo->isForwardRevisionAllowed($entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$component = $display->getComponent('content_moderation_control');
|
||||
if ($component) {
|
||||
|
|
|
@ -59,6 +59,13 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The state transition validation service.
|
||||
*
|
||||
* @var \Drupal\content_moderation\StateTransitionValidationInterface
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* A keyed array of custom moderation handlers for given entity types.
|
||||
*
|
||||
|
@ -85,12 +92,13 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* Current user.
|
||||
*/
|
||||
public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info, AccountInterface $current_user) {
|
||||
public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info, AccountInterface $current_user, StateTransitionValidationInterface $validator) {
|
||||
$this->stringTranslation = $translation;
|
||||
$this->moderationInfo = $moderation_information;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->bundleInfo = $bundle_info;
|
||||
$this->currentUser = $current_user;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +110,8 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
$container->get('content_moderation.moderation_information'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$container->get('current_user')
|
||||
$container->get('current_user'),
|
||||
$container->get('content_moderation.state_transition_validation')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -282,12 +291,57 @@ class EntityTypeInfo implements ContainerInjectionInterface {
|
|||
$this->entityTypeManager->getHandler($type->getBundleOf(), 'moderation')->enforceRevisionsBundleFormAlter($form, $form_state, $form_id);
|
||||
}
|
||||
}
|
||||
elseif ($form_object instanceof ContentEntityFormInterface) {
|
||||
elseif ($form_object instanceof ContentEntityFormInterface && in_array($form_object->getOperation(), ['edit', 'default'])) {
|
||||
$entity = $form_object->getEntity();
|
||||
if ($this->moderationInfo->isModeratedEntity($entity)) {
|
||||
$this->entityTypeManager
|
||||
->getHandler($entity->getEntityTypeId(), 'moderation')
|
||||
->enforceRevisionsEntityFormAlter($form, $form_state, $form_id);
|
||||
|
||||
if (!$this->moderationInfo->isForwardRevisionAllowed($entity)) {
|
||||
$latest_revision = $this->moderationInfo->getLatestRevision($entity->getEntityTypeId(), $entity->id());
|
||||
if ($entity->bundle()) {
|
||||
$bundle_type_id = $entity->getEntityType()->getBundleEntityType();
|
||||
$bundle = $this->entityTypeManager->getStorage($bundle_type_id)->load($entity->bundle());
|
||||
$type_label = $bundle->label();
|
||||
}
|
||||
else {
|
||||
$type_label = $entity->getEntityType()->getLabel();
|
||||
}
|
||||
|
||||
$translation = $this->moderationInfo->getAffectedRevisionTranslation($latest_revision);
|
||||
$args = [
|
||||
'@type_label' => $type_label,
|
||||
'@latest_revision_edit_url' => $translation->toUrl('edit-form', ['language' => $translation->language()])->toString(),
|
||||
'@latest_revision_delete_url' => $translation->toUrl('delete-form', ['language' => $translation->language()])->toString(),
|
||||
];
|
||||
$label = $this->t('Unable to save this @type_label.', $args);
|
||||
$message = $this->t('<a href="@latest_revision_edit_url">Publish</a> or <a href="@latest_revision_delete_url">delete</a> the latest draft revision to allow all workflow transitions.', $args);
|
||||
$full_message = $this->t('Unable to save this @type_label. <a href="@latest_revision_edit_url">Publish</a> or <a href="@latest_revision_delete_url">delete</a> the latest draft revision to allow all workflow transitions.', $args);
|
||||
drupal_set_message($full_message, 'error');
|
||||
|
||||
$form['actions']['#access'] = FALSE;
|
||||
$form['invalid_transitions'] = [
|
||||
'label' => [
|
||||
'#type' => 'item',
|
||||
'#prefix' => '<strong class="label">',
|
||||
'#markup' => $label,
|
||||
'#suffix' => '</strong>',
|
||||
],
|
||||
'message' => [
|
||||
'#type' => 'item',
|
||||
'#markup' => $message,
|
||||
],
|
||||
'#weight' => 999,
|
||||
'#no_valid_transitions' => TRUE,
|
||||
];
|
||||
|
||||
if ($form['footer']) {
|
||||
$form['footer']['invalid_transitions'] = $form['invalid_transitions'];
|
||||
unset($form['invalid_transitions']);
|
||||
}
|
||||
}
|
||||
|
||||
// Submit handler to redirect to the latest version, if available.
|
||||
$form['actions']['submit']['#submit'][] = [EntityTypeInfo::class, 'bundleFormRedirect'];
|
||||
}
|
||||
|
|
|
@ -112,6 +112,25 @@ class ModerationInformation implements ModerationInformationInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAffectedRevisionTranslation(ContentEntityInterface $entity) {
|
||||
foreach ($entity->getTranslationLanguages() as $language) {
|
||||
$translation = $entity->getTranslation($language->getId());
|
||||
if (!$translation->isDefaultRevision() && $translation->isRevisionTranslationAffected()) {
|
||||
return $translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isForwardRevisionAllowed(ContentEntityInterface $entity) {
|
||||
return !(!$entity->isRevisionTranslationAffected() && count($entity->getTranslationLanguages()) > 1 && $this->hasForwardRevision($entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -89,6 +89,30 @@ interface ModerationInformationInterface {
|
|||
*/
|
||||
public function getDefaultRevisionId($entity_type_id, $entity_id);
|
||||
|
||||
/**
|
||||
* Returns the revision translation affected translation of a revision.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The content entity.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* The revision translation affected translation.
|
||||
*/
|
||||
public function getAffectedRevisionTranslation(ContentEntityInterface $entity);
|
||||
|
||||
/**
|
||||
* Determines if forward revisions are allowed.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The content entity.
|
||||
*
|
||||
* @return bool
|
||||
* If forward revisions are allowed.
|
||||
*/
|
||||
public function isForwardRevisionAllowed(ContentEntityInterface $entity);
|
||||
|
||||
/**
|
||||
* Determines if an entity is a latest revision.
|
||||
*
|
||||
|
|
|
@ -92,13 +92,12 @@ class EntityRevisionConverter extends EntityConverter {
|
|||
$entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults);
|
||||
$latest_revision = $this->moderationInformation->getLatestRevision($entity_type_id, $value);
|
||||
|
||||
// If the entity type is translatable, ensure we return the proper
|
||||
// translation object for the current context.
|
||||
if ($latest_revision instanceof EntityInterface && $entity instanceof TranslatableInterface) {
|
||||
$latest_revision = $this->entityManager->getTranslationFromContext($latest_revision, NULL, ['operation' => 'entity_upcast']);
|
||||
}
|
||||
|
||||
if ($latest_revision instanceof EntityInterface && $latest_revision->isRevisionTranslationAffected()) {
|
||||
if ($latest_revision instanceof EntityInterface) {
|
||||
// If the entity type is translatable, ensure we return the proper
|
||||
// translation object for the current context.
|
||||
if ($entity instanceof TranslatableInterface) {
|
||||
$latest_revision = $this->entityManager->getTranslationFromContext($latest_revision, NULL, ['operation' => 'entity_upcast']);
|
||||
}
|
||||
$entity = $latest_revision;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,18 @@ use Drupal\workflows\Entity\Workflow;
|
|||
*/
|
||||
class ModerationFormTest extends ModerationStateTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'content_moderation',
|
||||
'locale',
|
||||
'content_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -205,4 +217,238 @@ class ModerationFormTest extends ModerationStateTestBase {
|
|||
$this->assertText('by ' . $another_user->getAccountName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translated and moderated nodes.
|
||||
*/
|
||||
public function testContentTranslationNodeForm() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Add French language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
// Enable content translation on articles.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][moderated_content][translatable]' => TRUE,
|
||||
'settings[node][moderated_content][settings][language][language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
|
||||
// Adding languages requires a container rebuild in the test running
|
||||
// environment so that multilingual services are used.
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Create new moderated content in draft (revision 1).
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Some moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
], t('Save and Create New Draft'));
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Some moderated content');
|
||||
$this->assertTrue($node->language(), 'en');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
$translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
|
||||
$latest_version_path = sprintf('node/%d/latest', $node->id());
|
||||
$french = \Drupal::languageManager()->getLanguage('fr');
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertSession()->statusCodeEquals('403');
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Add french translation (revision 2).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
], t('Save and Publish (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertSession()->statusCodeEquals('403');
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Add french forward revision (revision 3).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Third version of the content.',
|
||||
], t('Save and Create New Draft (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// It should not be possible to add a new english revision.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->assertSession()->pageTextContains('Unable to save this Moderated content.');
|
||||
|
||||
$this->clickLink('Publish');
|
||||
$this->assertSession()->fieldValueEquals('body[0][value]', 'Third version of the content.');
|
||||
|
||||
$this->drupalGet($edit_path);
|
||||
$this->clickLink('Delete');
|
||||
$this->assertSession()->buttonExists('Delete');
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Publish the french forward revision (revision 4).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Fifth version of the content.',
|
||||
], t('Save and Publish (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Now we can publish the english (revision 5).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Sixth version of the content.',
|
||||
], t('Save and Publish (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Make sure we're allowed to create a forward french revision.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
|
||||
// Add a english forward revision (revision 6).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Seventh version of the content.',
|
||||
], t('Save and Create New Draft (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Make sure we're not allowed to create a forward french revision.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->assertSession()->pageTextContains('Unable to save this Moderated content.');
|
||||
|
||||
$this->drupalGet($latest_version_path, ['language' => $french]);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// We should be able to publish the english forward revision (revision 7)
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Eighth version of the content.',
|
||||
], t('Save and Publish (this translation)'));
|
||||
|
||||
$this->drupalGet($latest_version_path);
|
||||
$this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
|
||||
|
||||
// Make sure we're allowed to create a forward french revision.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
|
||||
// Make sure we're allowed to create a forward english revision.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
|
||||
// Create new moderated content. (revision 1).
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Second moderated content',
|
||||
'body[0][value]' => 'First version of the content.',
|
||||
], t('Save and Publish'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Second moderated content');
|
||||
$this->assertTrue($node->language(), 'en');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
$translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
|
||||
|
||||
// Add a forward revision (revision 2).
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [
|
||||
'body[0][value]' => 'Second version of the content.',
|
||||
], t('Save and Create New Draft (this translation)'));
|
||||
|
||||
// It shouldn't be possible to translate as we have a forward revision.
|
||||
$this->drupalGet($translate_path);
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->assertSession()->pageTextContains('Unable to save this Moderated content.');
|
||||
|
||||
// Create new moderated content (revision 1).
|
||||
$this->drupalPostForm('node/add/moderated_content', [
|
||||
'title[0][value]' => 'Third moderated content',
|
||||
], t('Save and Publish'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle('Third moderated content');
|
||||
$this->assertTrue($node->language(), 'en');
|
||||
$edit_path = sprintf('node/%d/edit', $node->id());
|
||||
$translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
|
||||
|
||||
// Translate it, without updating data (revision 2).
|
||||
$this->drupalGet($translate_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)'));
|
||||
|
||||
// Add another draft for the translation (revision 3).
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)'));
|
||||
|
||||
// Editing the original translation should not be possible.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->assertSession()->pageTextContains('Unable to save this Moderated content.');
|
||||
|
||||
// Updating and publishing the french translation is still possible.
|
||||
$this->drupalGet($edit_path, ['language' => $french]);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [], t('Save and Publish (this translation)'));
|
||||
|
||||
// Now the french translation is published, an english draft can be added.
|
||||
$this->drupalGet($edit_path);
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
|
||||
$this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
|
||||
$this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -144,12 +144,9 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertEqual($french_node->getTitle(), 'Translated node', 'The default revision of the published translation remains the same.');
|
||||
|
||||
// Publish the draft.
|
||||
$edit = [
|
||||
'new_state' => 'published',
|
||||
];
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/latest', $edit, t('Apply'));
|
||||
$this->assertText(t('The moderation state has been updated.'));
|
||||
// Publish the French article before testing the archive transition.
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$this->assertText(t('Article New draft of translated node has been updated.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertEqual($french_node->moderation_state->value, 'published');
|
||||
|
@ -173,43 +170,6 @@ class ModerationLocaleTest extends ModerationStateTestBase {
|
|||
$this->assertFalse($english_node->isPublished());
|
||||
$this->assertEqual($french_node->moderation_state->value, 'archived');
|
||||
$this->assertFalse($french_node->isPublished());
|
||||
|
||||
// Create another article with its translation. This time publishing english
|
||||
// after creating a forward french revision.
|
||||
$edit = [
|
||||
'title[0][value]' => 'An english node',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and Create New Draft'));
|
||||
$this->assertText(t('Article An english node has been created.'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node');
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
|
||||
// Add a French translation.
|
||||
$this->drupalGet('node/' . $english_node->id() . '/translations');
|
||||
$this->clickLink(t('Add'));
|
||||
$edit = [
|
||||
'title[0][value]' => 'A french node',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and Publish (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
|
||||
// Create a forward revision
|
||||
$this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Create New Draft (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertFalse($english_node->isPublished());
|
||||
|
||||
// Publish the english node and the default french node not the latest
|
||||
// french node should be used.
|
||||
$this->drupalPostForm('/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
|
||||
$english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertTrue($french_node->isPublished());
|
||||
$this->assertTrue($english_node->isPublished());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue