Skip to content
Snippets Groups Projects
Verified Commit 2d61a0ef authored by Dave Long's avatar Dave Long
Browse files

Issue #3047110 by pavlosdan, Rajeshreeputra, Manuel Garcia, slydevil,...

Issue #3047110 by pavlosdan, Rajeshreeputra, Manuel Garcia, slydevil, hugronaphor, dhirendra.mishra, vsujeetkumar, amateescu, n4r3n, kreynen, acbramley, quietone: Enable Content Moderation integration for taxonomy terms

(cherry picked from commit 07473ef2)
parent b727c14d
No related branches found
No related tags found
27 merge requests!11769Issue #3517987: Add option to contextual filters to encode slashes in query parameter.,!11185Issue #3477324 by andypost, alexpott: Fix usage of str_getcsv() and fgetcsv() for PHP 8.4,!10602Issue #3438769 by vinmayiswamy, antonnavi, michelle, amateescu: Sub workspace does not clear,!10301Issue #3469309 by mstrelan, smustgrave, moshe weitzman: Use one-time login...,!10187Issue #3487488 by dakwamine: ExtensionMimeTypeGuesser::guessMimeType must support file names with "0" (zero) like foo.0.zip,!9944Issue #3483353: Consider making the createCopy config action optionally fail...,!9929Issue #3445469 by pooja_sharma, smustgrave: Add additional test coverage for...,!9787Resolve issue 3479427 - bootstrap barrio issue under Windows,!9742Issue #3463908 by catch, quietone: Split OptionsFieldUiTest into two,!9526Issue #3458177 by mondrake, catch, quietone, godotislate, longwave, larowlan,...,!8738Issue #3424162 by camilledavis, dineshkumarbollu, smustgrave: Claro...,!8704Make greek characters available in ckeditor5,!8597Draft: Issue #3442259 by catch, quietone, dww: Reduce time of Migrate Upgrade tests...,!8533Issue #3446962 by kim.pepper: Remove incorrectly added...,!8517Issue #3443748 by NexusNovaz, smustgrave: Testcase creates false positive,!8325Update file Sort.php,!8095Expose document root on install,!7930Resolve #3427374 "Taxonomytid viewsargumentdefault plugin",!7627Issue #3439440 by nicxvan, Binoli Lalani, longwave: Remove country support from DateFormatter,!7445Issue #3440169: When using drupalGet(), provide an associative array for $headers,!7401#3271894 Fix documented StreamWrapperInterface return types for realpath() and dirname(),!7384Add constraints to system.advisories,!7078Issue #3320569 by Spokje, mondrake, smustgrave, longwave, quietone, Lendude,...,!6622Issue #2559833 by piggito, mohit_aghera, larowlan, guptahemant, vakulrai,...,!6502Draft: Resolve #2938524 "Plach testing issue",!38582585169-10.1.x,!3226Issue #2987537: Custom menu link entity type should not declare "bundle" entity key
Pipeline #109507 passed with warnings
Pipeline: drupal

#109515

    <?php
    namespace Drupal\content_moderation\Entity\Handler;
    use Drupal\Core\Form\FormStateInterface;
    /**
    * Customizations for taxonomy term entities.
    *
    * @internal
    */
    class TaxonomyTermModerationHandler extends ModerationHandler {
    /**
    * {@inheritdoc}
    */
    public function enforceRevisionsEntityFormAlter(array &$form, FormStateInterface $form_state, $form_id): void {
    $form['revision']['#default_value'] = TRUE;
    $form['revision']['#disabled'] = TRUE;
    $form['revision']['#description'] = $this->t('Revisions must be required when moderation is enabled.');
    }
    /**
    * {@inheritdoc}
    */
    public function enforceRevisionsBundleFormAlter(array &$form, FormStateInterface $form_state, $form_id): void {
    $form['revision']['#default_value'] = TRUE;
    $form['revision']['#disabled'] = TRUE;
    $form['revision']['#description'] = $this->t('Revisions must be required when moderation is enabled.');
    }
    }
    ......@@ -20,6 +20,7 @@
    use Drupal\content_moderation\Entity\Handler\BlockContentModerationHandler;
    use Drupal\content_moderation\Entity\Handler\ModerationHandler;
    use Drupal\content_moderation\Entity\Handler\NodeModerationHandler;
    use Drupal\content_moderation\Entity\Handler\TaxonomyTermModerationHandler;
    use Drupal\content_moderation\Entity\Routing\EntityModerationRouteProvider;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    ......@@ -80,6 +81,7 @@ class EntityTypeInfo implements ContainerInjectionInterface {
    protected $moderationHandlers = [
    'node' => NodeModerationHandler::class,
    'block_content' => BlockContentModerationHandler::class,
    'taxonomy_term' => TaxonomyTermModerationHandler::class,
    ];
    /**
    ......@@ -144,7 +146,6 @@ public function entityTypeAlter(array &$entity_types) {
    $entity_type_to_exclude = [
    'path_alias',
    'workspace',
    'taxonomy_term',
    ];
    if ($entity_type->isRevisionable() && !$entity_type->isInternal() && !in_array($entity_type_id, $entity_type_to_exclude)) {
    $entity_types[$entity_type_id] = $this->addModerationToEntityType($entity_type);
    ......
    <?php
    declare(strict_types=1);
    namespace Drupal\Tests\content_moderation\Functional;
    use Drupal\Core\Language\LanguageInterface;
    use Drupal\taxonomy\Entity\Term;
    use Drupal\taxonomy\Entity\Vocabulary;
    /**
    * Tests the taxonomy term moderation handler.
    *
    * @group content_moderation
    */
    class ModerationStateTaxonomyTermTest extends ModerationStateTestBase {
    /**
    * {@inheritdoc}
    */
    protected $defaultTheme = 'stark';
    /**
    * {@inheritdoc}
    */
    protected function setUp(): void {
    parent::setUp();
    // Create a "Tags" vocabulary.
    $bundle = Vocabulary::create([
    'vid' => 'tags',
    'name' => 'Tags',
    'new_revision' => FALSE,
    ])->save();
    }
    /**
    * Tests the taxonomy term moderation handler alters the forms as intended.
    *
    * @covers \Drupal\content_moderation\Entity\Handler\TaxonomyTermModerationHandler::enforceRevisionsEntityFormAlter
    * @covers \Drupal\content_moderation\Entity\Handler\TaxonomyTermModerationHandler::enforceRevisionsBundleFormAlter
    */
    public function testEnforceRevisionsEntityFormAlter(): void {
    $this->drupalLogin($this->adminUser);
    // Enable moderation for the tags vocabulary.
    $edit['bundles[tags]'] = TRUE;
    $this->drupalGet('/admin/config/workflow/workflows/manage/editorial/type/taxonomy_term');
    $this->submitForm($edit, 'Save');
    // Check that revision is checked by default when content moderation is
    // enabled for the vocabulary.
    $this->drupalGet('/admin/structure/taxonomy/manage/tags');
    $this->assertSession()->checkboxChecked('revision');
    $this->assertSession()->pageTextContains('Revisions must be required when moderation is enabled.');
    $this->assertSession()->fieldDisabled('revision');
    // Create a taxonomy term and save it as draft.
    $term = Term::create([
    'name' => 'Test tag',
    'vid' => 'tags',
    'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
    ]);
    $term->save();
    // Check that revision is checked by default when editing a term and
    // content moderation is enabled for the term's vocabulary.
    $this->drupalGet($term->toUrl('edit-form'));
    $this->assertSession()->checkboxChecked('revision');
    $this->assertSession()->pageTextContains('Revisions must be required when moderation is enabled.');
    $this->assertSession()->fieldDisabled('revision');
    }
    }
    ......@@ -49,6 +49,7 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
    'use editorial transition archive',
    'use editorial transition archived_draft',
    'use editorial transition archived_published',
    'administer taxonomy',
    ];
    /**
    ......@@ -69,6 +70,7 @@ abstract class ModerationStateTestBase extends BrowserTestBase {
    'block_content',
    'node',
    'entity_test',
    'taxonomy',
    ];
    /**
    ......
    ......@@ -94,6 +94,7 @@ protected function setUp(): void {
    $this->installEntitySchema('block_content');
    $this->installEntitySchema('media');
    $this->installEntitySchema('file');
    $this->installEntitySchema('taxonomy_term');
    $this->installEntitySchema('content_moderation_state');
    $this->installConfig('content_moderation');
    $this->installSchema('file', 'file_usage');
    ......@@ -174,6 +175,9 @@ public static function basicModerationTestCases() {
    'Nodes' => [
    'node',
    ],
    'Taxonomy term' => [
    'taxonomy_term',
    ],
    'Block content' => [
    'block_content',
    ],
    ......@@ -298,7 +302,7 @@ public function testContentModerationStateTranslationDataRemoval($entity_type_id
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $this->createEntity($entity_type_id, 'published');
    $langcode = 'fr';
    $translation = $entity->addTranslation($langcode, ['title' => 'French title test']);
    $translation = $entity->addTranslation($langcode, [$entity->getEntityType()->getKey('label') => 'French title test']);
    // Make sure we add values for all of the required fields.
    if ($entity_type_id == 'block_content') {
    $translation->info = $this->randomString();
    ......@@ -813,14 +817,4 @@ protected function assertDefaultRevision(EntityInterface $entity, int $revision_
    }
    }
    /**
    * Tests that the 'taxonomy_term' entity type cannot be moderated.
    */
    public function testTaxonomyTermEntityTypeModeration() {
    /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
    $moderation_info = \Drupal::service('content_moderation.moderation_information');
    $entity_type = \Drupal::entityTypeManager()->getDefinition('taxonomy_term');
    $this->assertFalse($moderation_info->canModerateEntitiesOfEntityType($entity_type));
    }
    }
    <?php
    declare(strict_types=1);
    namespace Drupal\Tests\taxonomy\Functional;
    use Drupal\Core\Url;
    use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
    use Drupal\workflows\Entity\Workflow;
    /**
    * Tests taxonomy terms with Content Moderation.
    *
    * @group content_moderation
    * @group taxonomy
    */
    class TaxonomyTermContentModerationTest extends TaxonomyTestBase {
    use ContentModerationTestTrait;
    /**
    * {@inheritdoc}
    */
    protected $defaultTheme = 'stark';
    /**
    * The vocabulary used for creating terms.
    *
    * @var \Drupal\taxonomy\VocabularyInterface
    */
    protected $vocabulary;
    /**
    * {@inheritdoc}
    */
    protected static $modules = ['content_moderation'];
    /**
    * {@inheritdoc}
    */
    protected function setUp(): void {
    parent::setUp();
    $this->createEditorialWorkflow();
    $this->drupalLogin($this->drupalCreateUser([
    'administer taxonomy',
    'use editorial transition create_new_draft',
    'use editorial transition publish',
    'view any unpublished content',
    'view latest version',
    ]));
    $this->vocabulary = $this->createVocabulary();
    // Set the vocabulary as moderated.
    $workflow = Workflow::load('editorial');
    $workflow->getTypePlugin()->addEntityTypeAndBundle('taxonomy_term', $this->vocabulary->id());
    $workflow->save();
    }
    /**
    * Tests taxonomy term parents on a moderated vocabulary.
    */
    public function testTaxonomyTermParents(): void {
    $assert_session = $this->assertSession();
    // Create a simple hierarchy in the vocabulary, a root term and three parent
    // terms.
    $root = $this->createTerm($this->vocabulary, ['langcode' => 'en', 'moderation_state' => 'published']);
    $parent_1 = $this->createTerm($this->vocabulary, [
    'langcode' => 'en',
    'moderation_state' => 'published',
    'parent' => $root->id(),
    ]);
    $parent_2 = $this->createTerm($this->vocabulary, [
    'langcode' => 'en',
    'moderation_state' => 'published',
    'parent' => $root->id(),
    ]);
    $parent_3 = $this->createTerm($this->vocabulary, [
    'langcode' => 'en',
    'moderation_state' => 'published',
    'parent' => $root->id(),
    ]);
    // Create a child term and assign one of the parents above.
    $child = $this->createTerm($this->vocabulary, [
    'langcode' => 'en',
    'moderation_state' => 'published',
    'parent' => $parent_1->id(),
    ]);
    /** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
    $taxonomy_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
    $validation_message = 'You can only change the hierarchy for the published version of this term.';
    // Add a pending revision without changing the term parent.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['moderation_state[0][state]' => 'draft'], 'Save');
    $assert_session->pageTextNotContains($validation_message);
    // Add a pending revision and change the parent.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['parent[]' => [$parent_2->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
    // Check that parents were not changed.
    $assert_session->pageTextContains($validation_message);
    $taxonomy_storage->resetCache();
    $this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
    // Add a pending revision and add a new parent.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['parent[]' => [$parent_1->id(), $parent_3->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
    // Check that parents were not changed.
    $assert_session->pageTextContains($validation_message);
    $taxonomy_storage->resetCache();
    $this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
    // Add a pending revision and use the root term as a parent.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['parent[]' => [$root->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
    // Check that parents were not changed.
    $assert_session->pageTextContains($validation_message);
    $taxonomy_storage->resetCache();
    $this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
    // Add a pending revision and remove the parent.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['parent[]' => [], 'moderation_state[0][state]' => 'draft'], 'Save');
    // Check that parents were not changed.
    $assert_session->pageTextContains($validation_message);
    $taxonomy_storage->resetCache();
    $this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
    // Add a published revision.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['moderation_state[0][state]' => 'published'], 'Save');
    // Change the parents.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['parent[]' => [$parent_2->id()]], 'Save');
    // Check that parents were changed.
    $assert_session->pageTextNotContains($validation_message);
    $taxonomy_storage->resetCache();
    $this->assertNotEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
    // Add a pending revision and change the weight.
    $this->drupalGet($child->toUrl('edit-form'));
    $this->submitForm(['weight' => 10, 'moderation_state[0][state]' => 'draft'], 'Save');
    // Check that weight was not changed.
    $assert_session->pageTextContains($validation_message);
    // Add a new term without any parent and publish it.
    $edit = [
    'name[0][value]' => $this->randomMachineName(),
    'moderation_state[0][state]' => 'published',
    ];
    $this->drupalGet(Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $this->vocabulary->id()]));
    $this->submitForm($edit, 'Save');
    // Add a pending revision without any changes.
    $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['name' => $edit['name[0][value]']]);
    $term = reset($terms);
    $this->drupalGet($term->toUrl('edit-form'));
    $this->submitForm(['moderation_state[0][state]' => 'draft'], 'Save');
    $assert_session->pageTextNotContains($validation_message);
    }
    /**
    * Tests changing field values in pending revisions of taxonomy terms.
    */
    public function testTaxonomyTermPendingRevisions(): void {
    $assert_session = $this->assertSession();
    $default_term_name = 'term - default revision';
    $default_term_description = 'The default revision of a term.';
    $term = $this->createTerm($this->vocabulary, [
    'name' => $default_term_name,
    'description' => $default_term_description,
    'langcode' => 'en',
    'moderation_state' => 'published',
    ]);
    // Add a pending revision without changing the term parent.
    $this->drupalGet($term->toUrl('edit-form'));
    $assert_session->pageTextContains($default_term_name);
    $assert_session->pageTextContains($default_term_description);
    // Check the revision log message field does not appear on the term edit
    // page.
    $this->drupalGet($term->toUrl('edit-form'));
    $assert_session->fieldNotExists('revision_log_message[0][value]');
    $pending_term_name = 'term - pending revision';
    $pending_term_description = 'The pending revision of a term.';
    $edit = [
    'name[0][value]' => $pending_term_name,
    'description[0][value]' => $pending_term_description,
    'moderation_state[0][state]' => 'draft',
    ];
    $this->drupalGet($term->toUrl('edit-form'));
    $this->submitForm($edit, 'Save');
    $assert_session->pageTextContains($pending_term_name);
    $assert_session->pageTextContains($pending_term_description);
    $assert_session->pageTextNotContains($default_term_description);
    // Check that the default revision of the term contains the correct values.
    $this->drupalGet('taxonomy/term/' . $term->id());
    $assert_session->pageTextContains($default_term_name);
    $assert_session->pageTextContains($default_term_description);
    }
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment