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
Branches
Tags
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
Checking pipeline status
<?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.
Please register or to comment