The ContentModeration class ignores the language being saved when it determines the initial moderation state for an entity which had been saved prior to the enabling of content moderation.

Comments

bkline created an issue. See original summary.

bkline’s picture

Status: Active » Needs review
StatusFileSize
new1.28 KB
sam152’s picture

Status: Needs review » Postponed (maintainer needs more info)
+++ b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
@@ -306,11 +306,14 @@ class ContentModeration extends WorkflowTypeBase implements ContentModerationInt
-    return $this->getState(!empty($this->configuration['default_moderation_state']) ? $this->configuration['default_moderation_state'] : 'draft');

It does use the configured default moderation state? It's only hard-coded when the entity already had publishing values before moderation was enabled.

Am I missing something?

bkline’s picture

The "entity" (meaning the content item with all its translations) may not be new, and some of its translations may already have moderation state history. However, when the translation being saved is new, it is supposed to start off with the initial default moderation state configured for the workflow connected with the content item's type. Each translation has its own workflow history, which is supposed to be independent of where the other translations are in the workflow (as can be seen by examining the database tables).

Even though the $entity being passed into this method represents the individual translation, the implementation of the isNew() method is answering the question for the entire content item with all its translations, not for this translation. If you have a node (or media or any other entity type instance) for which 50 revisions exist in English, and a new Swedish translation is being created, for which no rows exist in any of the database tables, the answer you get back when you invoke isNew() on an object representing this new translation will be FALSE, because isNew() answers the question by checking to see whether there is an entity ID for the content item. In our context, that's not the answer to the question we need to have answered. We need to know if the translation represented by the object is new.

Does this help clear things up?

bkline’s picture

Ah, I see the use case the code was trying to address (content which existed before content_moderation is installed/enabled). Let me re-roll a patch which handles that case if the translation being saved is really not being saved for the first time.

bkline’s picture

Status: Postponed (maintainer needs more info) » Needs work
bkline’s picture

Title: Use the default moderation state configured for the workflow » Use language for determining initial moderation state
Status: Needs work » Needs review
StatusFileSize
new3.64 KB

Status: Needs review » Needs work

The last submitted patch, 7: 3045648-7.patch, failed testing. View results

bkline’s picture

Issue summary: View changes
bkline’s picture

Status: Needs work » Needs review
StatusFileSize
new3.49 KB

Modified patch to avoid querying the revision table for entity types which do not support revisions.

Status: Needs review » Needs work

The last submitted patch, 10: 3045648-10.patch, failed testing. View results

bkline’s picture

Well, the number of failures is decreasing, so at least I'm moving in the right direction. If I can figure out how to run the tests locally, that will help.

bkline’s picture

Status: Needs work » Needs review
StatusFileSize
new3.55 KB

Well, I'm making good progress. I've figured out how to run the tests locally. And apparently EntityTypeInterface::isRevisionable() doesn't mean what I thought it meant. 😉

Status: Needs review » Needs work

The last submitted patch, 13: 3045648-13.patch, failed testing. View results

bkline’s picture

Status: Needs work » Needs review
StatusFileSize
new4.57 KB

This patch passes the tests on my local instance (the previous version cast its net too wide in looking for publishable revisions).

sam152’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I think a functional test illustrating where the state is being initialised incorrectly according to your use-case would be helpful in understanding this. I'm lukewarm on adding this much complexity to a fairly low level part of the module unless there is a pretty glaring bug which makes the system unusable without it.

bkline’s picture

Status: Needs work » Needs review
StatusFileSize
new11.56 KB

I have created the functional test for this ticket. However, it will not pass, even with the rest of the patch, until several other bugs have been corrected (either separately, or by being folded into this issue).

The test case creates a workflow with three states: draft, published, and editing, with the default initial state set to draft. The allowed transitions are:

  • draft -> draft
  • draft -> published
  • published -> editing
  • editing -> published

This workflow is a much abbreviated version of the workflow in our system, reduced to follow the principle of including only as much as necessary in a repro case.

The test ...

  1. creates a content node in English, saving it as published
  2. installs the content_moderation module
  3. creates a French translation of the node
  4. saves the new translation with the moderation state of "draft"
  5. verifies that the expected string for a successful save of the translation appears on the returned page.

The expected behavior runs into a number of hurdles along the way.

The first problem is that when the user clicks the Translate link the form which is generated has a picklist which contains the wrong set of valid values, and an InvalidArgumentException is thrown with the following error message:

Input "moderation_state[0][state]" cannot take "draft" as a value (possible values: editing).

This happens because the content_moderation module thinks that because the original English version of the node is published, the only valid state for the French translation is editing, as if the new translation's moderation state were not supposed to be tracked separately from the other language translations of the node. This bug is reported as https://www.drupal.org/project/drupal/issues/3021222.

I suppressed this bug by including in the patch a testing module with an entity_translation_create hook to change the initial moderation state value from 'published' to the default value for the state.

After getting past that first hurdle, the test is now able to set the state of the moderation field for saving the translation as "draft" without triggering the InvalidArgumentException thrown by the form validation. The test then encounters a second bug, which is that, even though content moderation was not enabled until after the English node was saved, and all four of the new content_moderation_* tables are empty, the isFirstTimeModeration() method returns FALSE, because the loaded $original_entity object has a moderation_state field value set to "published," which is made up from the field definition. The result of this second bug is that, even though this is the first save with moderation of any translation, and we should proceed to invoking the workflow type's getInitialState() method, we never get that far, and the software thinks the user is trying to transition from published to draft, which is not an allowed transition for this workflow.

The fix for this bug would be to use an entity query with a language-specific condition for the moderation state field, so that the answer to the question "has the entity stored a moderation state for this language before" comes from the database, and not from the loaded entity object, some of whose fields are made-up default values.

I have not yet reported this bug, but there is a closely related bug report for the fact that the isFirstTimeModeration() method looks at the moderation state for the latest revision of the entity, not the latest revision for the language being saved (see https://www.drupal.org/project/drupal/issues/3029219).

Once all of these bugs (including the one for which this test was created) have been fixed, the test passes.

bkline’s picture

Issue tags: -Needs tests

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

sam152’s picture

Status: Needs review » Closed (duplicate)
Related issues: +#3150294: New translations for moderated nodes are not created in the initial workflow state

I think this intersects with this issue enough that it should be a duplicate. Will link this one from there too.