Skip to content
Snippets Groups Projects
Commit 63b04fc6 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3504261 by alexpott: Allow a default unpublished status to be set so a...

Issue #3504261 by alexpott: Allow a default unpublished status to be set so a user doesn't have to set every entity
parent 535f1058
Branches
Tags
1 merge request!14Initial implementation
Pipeline #415518 passed
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
use Drupal\entity_usage_updater\EntityReferenceRevisionsItem; use Drupal\entity_usage_updater\EntityReferenceRevisionsItem;
use Drupal\workflows\WorkflowInterface;
/** /**
* Implements hook_field_info_alter(). * Implements hook_field_info_alter().
...@@ -15,3 +16,13 @@ function entity_usage_updater_field_info_alter(array &$info): void { ...@@ -15,3 +16,13 @@ function entity_usage_updater_field_info_alter(array &$info): void {
$info['entity_reference_revisions']['class'] = EntityReferenceRevisionsItem::class; $info['entity_reference_revisions']['class'] = EntityReferenceRevisionsItem::class;
} }
} }
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function entity_usage_updater_workflow_presave(WorkflowInterface $entity): void {
$state_id = $entity->getThirdPartySetting('entity_usage_updater', 'default_unpublished_state');
if ($state_id !== NULL && !$entity->getTypePlugin()->hasState($state_id)) {
$entity->setThirdPartySetting('entity_usage_updater', 'default_unpublished_state', NULL);
}
}
...@@ -5,7 +5,9 @@ declare(strict_types=1); ...@@ -5,7 +5,9 @@ declare(strict_types=1);
namespace Drupal\entity_usage_updater\Form; namespace Drupal\entity_usage_updater\Form;
use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\NestedArray;
use Drupal\content_moderation\ContentModerationState;
use Drupal\content_moderation\ModerationInformationInterface; use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\content_moderation\Plugin\WorkflowType\ContentModeration;
use Drupal\content_moderation\StateTransitionValidationInterface; use Drupal\content_moderation\StateTransitionValidationInterface;
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
...@@ -96,6 +98,11 @@ class LinkRemoverForm extends FormBase { ...@@ -96,6 +98,11 @@ class LinkRemoverForm extends FormBase {
'#rows' => 10, '#rows' => 10,
]; ];
$form['unpublish'] = [
'#title' => $this->t("Unpublish content"),
'#type' => 'checkbox',
];
$form['buttons'] = [ $form['buttons'] = [
'#type' => 'actions', '#type' => 'actions',
]; ];
...@@ -174,6 +181,7 @@ class LinkRemoverForm extends FormBase { ...@@ -174,6 +181,7 @@ class LinkRemoverForm extends FormBase {
* Form state. * Form state.
*/ */
public function removeUsages(array &$form, FormStateInterface $form_state): void { public function removeUsages(array &$form, FormStateInterface $form_state): void {
$form_state->set('unpublish', (bool) $form_state->getValue('unpublish'));
$form_state->setRebuild(); $form_state->setRebuild();
} }
...@@ -198,11 +206,14 @@ class LinkRemoverForm extends FormBase { ...@@ -198,11 +206,14 @@ class LinkRemoverForm extends FormBase {
$this->t('Entity type'), $this->t('Entity type'),
$this->t('Active usage count'), $this->t('Active usage count'),
$this->t('Moderation state'), $this->t('Moderation state'),
$this->t('Update moderation state to'),
], ],
'#tree' => TRUE, '#tree' => TRUE,
]; ];
if ($form_state->get('unpublish')) {
$form['table']['#header'][] = $this->t('Update moderation state to');
}
foreach ($this->getEntitiesFromArgument($form_state) as $entity) { foreach ($this->getEntitiesFromArgument($form_state) as $entity) {
$usage_count = array_reduce(EntityUsageUpdater::getUsages($entity), function ($result, $item) { $usage_count = array_reduce(EntityUsageUpdater::getUsages($entity), function ($result, $item) {
return $result + count($item); return $result + count($item);
...@@ -220,12 +231,7 @@ class LinkRemoverForm extends FormBase { ...@@ -220,12 +231,7 @@ class LinkRemoverForm extends FormBase {
$form['table'][$key]['usage_count'] = [ $form['table'][$key]['usage_count'] = [
'#markup' => $usage_count, '#markup' => $usage_count,
]; ];
$current_moderation_state = ''; $this->addContentModerationInfo($form['table'][$key], $entity, $form_state->get('unpublish'));
$moderation_form = $this->contentModerationForm($entity, $current_moderation_state);
$form['table'][$key]['current_moderation_state'] = [
'#markup' => $current_moderation_state,
];
$form['table'][$key]['moderation'] = $moderation_form;
} }
$form['description'] = ['#markup' => $this->t('Are you sure you want to remove links to the listed entities?')]; $form['description'] = ['#markup' => $this->t('Are you sure you want to remove links to the listed entities?')];
...@@ -277,40 +283,51 @@ class LinkRemoverForm extends FormBase { ...@@ -277,40 +283,51 @@ class LinkRemoverForm extends FormBase {
public function cancelForm(array &$form, FormStateInterface $form_state): void { public function cancelForm(array &$form, FormStateInterface $form_state): void {
$storage = &$form_state->getStorage(); $storage = &$form_state->getStorage();
NestedArray::unsetValue($storage, ['argument']); NestedArray::unsetValue($storage, ['argument']);
NestedArray::unsetValue($storage, ['unpublish']);
$form_state->setRebuild(); $form_state->setRebuild();
} }
/** /**
* Gets a form element to change an entity's moderation state. * Adds info about an entity's moderation state to a row in the form.
* *
* @param array $row
* The row to add moderation information to.
* @param \Drupal\Core\Entity\EntityInterface $entity * @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to add the moderation form for. * The entity to add the moderation form for.
* @param string|\Stringable $current_moderation_state * @param bool $add_form
* The current moderation state label will be set in this argument to allow * Determines whether to return a form, if necessary to change the state.
* the to use it.
*
* @return array
* The form to display to the user to select a new moderation state.
*/ */
public function contentModerationForm(EntityInterface $entity, string|\Stringable &$current_moderation_state): array { public function addContentModerationInfo(array &$row, EntityInterface $entity, bool $add_form): void {
if ($this->moderationInfo === NULL || !$this->moderationInfo->isModeratedEntity($entity)) { if ($this->moderationInfo === NULL || !$this->moderationInfo->isModeratedEntity($entity)) {
if (!$entity instanceof EntityPublishedInterface) { if (!$entity instanceof EntityPublishedInterface) {
return []; return;
} }
$target_states = [ $target_states = [
'unpublished' => $this->t('Unpublished'), 'unpublished' => $this->t('Unpublished'),
'published' => $this->t('Published'), 'published' => $this->t('Published'),
]; ];
$current_state = $entity->isPublished() ? 'published' : 'unpublished'; $current_state = $entity->isPublished() ? 'published' : 'unpublished';
$current_moderation_state = $target_states[$current_state]; $row['current_moderation_state'] = [
'#markup' => $target_states[$current_state],
];
if (!$add_form) {
return;
}
$default_value = 'unpublished';
} }
else { else {
assert($entity instanceof ContentEntityInterface); assert($entity instanceof ContentEntityInterface);
$current_state = $entity->moderation_state->value; $default_value = $current_state = $entity->moderation_state->value;
// Get the label for the current state. // Get the label for the current state.
$workflow = $this->moderationInfo->getWorkflowForEntity($entity); $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
$current_moderation_state = $workflow->getTypePlugin()->getState($current_state)->label(); $row['current_moderation_state'] = [
'#markup' => $workflow->getTypePlugin()->getState($current_state)->label(),
];
if (!$add_form) {
return;
}
/** @var \Drupal\workflows\Transition[] $transitions */ /** @var \Drupal\workflows\Transition[] $transitions */
$transitions = $this->contentModerationValidation->getValidTransitions($entity, $this->currentUser()); $transitions = $this->contentModerationValidation->getValidTransitions($entity, $this->currentUser());
...@@ -318,12 +335,35 @@ class LinkRemoverForm extends FormBase { ...@@ -318,12 +335,35 @@ class LinkRemoverForm extends FormBase {
foreach ($transitions as $transition) { foreach ($transitions as $transition) {
$target_states[$transition->to()->id()] = $transition->to()->label(); $target_states[$transition->to()->id()] = $transition->to()->label();
$to = $transition->to();
// Remove the transition if we know it is to a published state.
if ($to instanceof ContentModerationState && $to->isPublishedState()) {
unset($target_states[$transition->to()->id()]);
}
}
$default_content_moderation_unpublish_state = $workflow->getThirdPartySetting('entity_usage_updater', 'default_unpublished_state');
if ($default_content_moderation_unpublish_state !== NULL && isset($target_states[$default_content_moderation_unpublish_state])) {
$default_value = $default_content_moderation_unpublish_state;
}
// Fallback to transition to a state that is unpublished and the default
// revision.
elseif ($workflow->getTypePlugin() instanceof ContentModeration) {
foreach ($transitions as $transition) {
/** @var \Drupal\content_moderation\ContentModerationState $to */
$to = $transition->to();
if ($to->isDefaultRevisionState() && !$to->isPublishedState()) {
$default_value = $to->id();
}
}
} }
} }
if (!$entity->access('update')) { if (!$entity->access('update')) {
// @todo Add text. $row['moderation'] = [
return ['#markup' => $this->t('You do not have permission to change.')]; '#markup' => $this->t('You do not have permission to change.'),
];
return;
} }
// Remove the current state as there is no point changing to it. // Remove the current state as there is no point changing to it.
...@@ -332,15 +372,15 @@ class LinkRemoverForm extends FormBase { ...@@ -332,15 +372,15 @@ class LinkRemoverForm extends FormBase {
// If there are no target states then there is nothing for the user to // If there are no target states then there is nothing for the user to
// select. // select.
if (count($target_states) < 1) { if (count($target_states) < 1) {
return []; return;
} }
return [ $row['moderation'] = [
'#type' => 'select', '#type' => 'select',
'#empty_option' => $this->t('- Select to change -'), '#empty_option' => $this->t('- Select to change -'),
'#title' => $this->t('Update moderation state to'), '#title' => $this->t('Update moderation state to'),
'#title_display' => 'invisible', '#title_display' => 'invisible',
'#default_value' => $current_state, '#default_value' => isset($target_states[$default_value]) ? $default_value : NULL,
'#options' => $target_states, '#options' => $target_states,
]; ];
} }
......
...@@ -10,6 +10,7 @@ use Drupal\Core\Form\FormStateInterface; ...@@ -10,6 +10,7 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState; use Drupal\Core\Form\SubformState;
use Drupal\Core\Plugin\PluginFormInterface; use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Render\Element; use Drupal\Core\Render\Element;
use Drupal\workflows\Entity\Workflow;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
...@@ -24,12 +25,18 @@ final class SettingsForm extends ConfigFormBase { ...@@ -24,12 +25,18 @@ final class SettingsForm extends ConfigFormBase {
*/ */
protected PluginManagerInterface $pluginManager; protected PluginManagerInterface $pluginManager;
/**
* Flag indicating if content moderation is enabled.
*/
protected bool $contentModerationEnabled;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
$form = parent::create($container); $form = parent::create($container);
$form->pluginManager = $container->get('plugin.manager.entity_usage_updater'); $form->pluginManager = $container->get('plugin.manager.entity_usage_updater');
$form->contentModerationEnabled = $container->get('module_handler')->moduleExists('content_moderation');
return $form; return $form;
} }
...@@ -62,6 +69,30 @@ final class SettingsForm extends ConfigFormBase { ...@@ -62,6 +69,30 @@ final class SettingsForm extends ConfigFormBase {
} }
} }
if ($this->contentModerationEnabled) {
foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
$options = [];
foreach ($workflow->getTypePlugin()->getStates() as $state) {
/** @var \Drupal\content_moderation\ContentModerationState $state */
if (!$state->isPublishedState() && $state->isDefaultRevisionState()) {
$options[$state->id()] = $state->label();
}
}
if (!empty($options)) {
$form['workflow'][$workflow->id()] = [
'#type' => 'select',
'#options' => $options,
'#title' => $this->t('Select default unpublished state for %label workflow', ['%label' => $workflow->label()]),
];
}
}
if (isset($form['workflow'])) {
$form['workflow']['#type'] = 'fieldset';
$form['workflow']['#title'] = $this->t('Workflow settings');
}
}
return $form; return $form;
} }
...@@ -96,6 +127,20 @@ final class SettingsForm extends ConfigFormBase { ...@@ -96,6 +127,20 @@ final class SettingsForm extends ConfigFormBase {
} }
$config->save(); $config->save();
if ($this->contentModerationEnabled) {
$form_workflow_value = $form_state->getValue('workflow') ?? [];
foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
if (isset($form_workflow_value[$workflow->id()])) {
$workflow
->setThirdPartySetting('entity_usage_updater', 'default_unpublished_state', $form_workflow_value[$workflow->id()])
->save();
}
elseif ($workflow->getThirdPartySetting('entity_usage_updater', 'default_unpublished_state') !== NULL) {
$workflow->unsetThirdPartySetting('entity_usage_updater', 'default_unpublished_state')->save();
}
}
}
parent::submitForm($form, $form_state); parent::submitForm($form, $form_state);
} }
......
...@@ -7,6 +7,7 @@ namespace Drupal\Tests\entity_usage_updater\Functional; ...@@ -7,6 +7,7 @@ namespace Drupal\Tests\entity_usage_updater\Functional;
use Drupal\filter\Entity\FilterFormat; use Drupal\filter\Entity\FilterFormat;
use Drupal\Tests\content_moderation\Functional\ModerationStateTestBase; use Drupal\Tests\content_moderation\Functional\ModerationStateTestBase;
use Drupal\Tests\entity_usage\Traits\EntityUsageLastEntityQueryTrait; use Drupal\Tests\entity_usage\Traits\EntityUsageLastEntityQueryTrait;
use Drupal\user\Entity\Role;
/** /**
* Tests the Link Remover form with content moderation. * Tests the Link Remover form with content moderation.
...@@ -36,6 +37,7 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase { ...@@ -36,6 +37,7 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase {
*/ */
public function setUp(): void { public function setUp(): void {
$this->permissions[] = 'update referenced entities'; $this->permissions[] = 'update referenced entities';
$this->permissions[] = 'administer site configuration';
parent::setUp(); parent::setUp();
$this->drupalLogin($this->adminUser); $this->drupalLogin($this->adminUser);
...@@ -62,16 +64,220 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase { ...@@ -62,16 +64,220 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase {
$config = \Drupal::configFactory()->getEditable('entity_usage.settings'); $config = \Drupal::configFactory()->getEditable('entity_usage.settings');
$config->set('site_domains', [$current_request->getHttpHost() . $current_request->getBasePath()]); $config->set('site_domains', [$current_request->getHttpHost() . $current_request->getBasePath()]);
$config->save(); $config->save();
$this->config('entity_usage.settings')->set('local_task_enabled_entity_types', ['node'])->save(); $this->config('entity_usage.settings')
->set('local_task_enabled_entity_types', ['node'])
->save();
\Drupal::service('router.builder')->rebuild(); \Drupal::service('router.builder')->rebuild();
} }
/** /**
* Tests the link remover. * Tests the link remover.
* *
* @testWith [true]
* [false]
*
* @covers \Drupal\entity_usage_updater\Form\LinkRemoverForm * @covers \Drupal\entity_usage_updater\Form\LinkRemoverForm
*/ */
public function testLinkRemover(): void { public function testLinkRemover(bool $unpublish): void {
[$node1, $node2, $node3] = $this->createContent();
$this->drupalGet('admin/config/content/link-remover');
$this->assertSession()->fieldExists('links')->setValue(implode("\n", [
$node1->toUrl()->setAbsolute()->toString(),
$node2->toUrl()->setAbsolute()->toString(),
]));
$this->assertSession()->fieldExists('unpublish')->setValue($unpublish);
$this->assertSession()->buttonExists('Remove')->press();
if ($unpublish) {
// Ensure the content moderation options are as expected.
$this->assertSession()->fieldExists('table[node|1][moderation]');
$this->assertSession()->optionNotExists('table[node|1][moderation]', 'published');
$this->assertSession()->optionExists('table[node|1][moderation]', 'draft');
$this->assertSession()->fieldValueEquals('table[node|1][moderation]', 'archived');
// There are no valid options to change the entity to in order to
// unpublish it.
$this->assertSession()->fieldNotExists('table[node|2][moderation]');
}
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[1]', (string) $node1->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[2]', (string) $node1->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[3]', '1');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[4]', 'Published');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[1]', (string) $node2->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[2]', (string) $node2->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[3]', '2');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[4]', 'Draft');
$this->assertSession()->buttonExists('Submit')->press();
// Process the batch.
$this->checkForMetaRefresh();
$this->assertSession()->pageTextContains('Updated one entity for references to Node 1.');
$this->assertSession()->pageTextContains('Updated 2 entities for references to Node 2.');
if ($unpublish) {
$this->assertSession()->pageTextContains('Updated moderation state for Node 1 to Archived.');
$this->assertSession()->pageTextNotContains('Updated moderation state for Node 2');
}
// Check to see if the links have been removed.
$this->drupalGet('node/3');
$this->assertSession()->linkByHrefNotExists($node1->toUrl()->toString());
$this->drupalGet('node/4');
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
// Check to see if the link node 2 has been removed but the link to node 3
// is still there.
$this->drupalGet('node/5');
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
$this->assertSession()->linkByHrefExists($node3->toUrl()->toString());
if ($unpublish) {
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node_storage->resetCache();
$node1 = $node_storage->load($node1->id());
$node2 = $node_storage->load($node2->id());
$this->assertSame('archived', $node1->get('moderation_state')->value, 'Node 1 is archived.');
$this->assertSame('draft', $node2->get('moderation_state')->value, 'Node 2 is a draft.');
}
}
/**
* Tests the link remover with content moderation and a default state set.
*
* @covers \Drupal\entity_usage_updater\Form\LinkRemoverForm
*/
public function testLinkRemoverWithContentModerationDefault(): void {
$this->drupalGet('admin/config/content/entity-usage-updater');
$this->assertCount(1, $this->assertSession()
->fieldExists('workflow[editorial]')
->findAll('css', 'option'));
$this->drupalGet('admin/config/workflow/workflows/manage/editorial/add_state');
$this->assertSession()->fieldExists('label')->setValue('Links removed');
$this->assertSession()->fieldExists('id')->setValue('links_removed');
$this->assertSession()
->fieldExists('type_settings[default_revision]')
->check();
$this->assertSession()->buttonExists('Save')->press();
$this->assertSession()->pageTextContains('Created Links removed state.');
$this->getSession()->getPage()->clickLink('Add a new transition');
$this->assertSession()->fieldExists('label')->setValue('Links remover');
$this->assertSession()->fieldExists('id')->setValue('links_remover');
foreach ($this->assertSession()->elementExists('css', '#edit-from')->findAll('css', 'input[type=\'checkbox\']') as $checkbox) {
$checkbox->check();
}
$this->assertSession()->fieldExists('to')->selectOption('links_removed');
$this->assertSession()->buttonExists('Save')->press();
$this->assertSession()
->pageTextContains('Created Links remover transition.');
$this->drupalGet('admin/config/content/entity-usage-updater');
$this->assertCount(2, $this->assertSession()
->fieldExists('workflow[editorial]')
->findAll('css', 'option'));
$this->assertSession()
->fieldExists('workflow[editorial]')
->selectOption('links_removed');
$this->assertSession()->buttonExists('Save')->press();
// Allow the user to use the new transition.
$role_ids = $this->adminUser->getRoles(TRUE);
$role_id = reset($role_ids);
$role = Role::load($role_id);
$role->grantPermission('use editorial transition links_remover')->save();
[$node1, $node2] = $this->createContent();
$this->drupalGet('admin/config/content/link-remover');
$this->assertSession()->fieldExists('links')->setValue(implode("\n", [
$node1->toUrl()->setAbsolute()->toString(),
$node2->toUrl()->setAbsolute()->toString(),
]));
$this->assertSession()->fieldExists('unpublish')->check();
$this->assertSession()->buttonExists('Remove')->press();
// Ensure the content moderation options are as expected.
$this->assertSession()->optionNotExists('table[node|1][moderation]', 'published');
$this->assertSession()->optionExists('table[node|1][moderation]', 'draft');
$this->assertSession()->fieldValueEquals('table[node|1][moderation]', 'links_removed');
$this->assertSession()->optionNotExists('table[node|2][moderation]', 'draft');
$this->assertSession()->optionNotExists('table[node|2][moderation]', 'published');
$this->assertSession()->optionNotExists('table[node|2][moderation]', 'archived');
$this->assertSession()->fieldValueEquals('table[node|1][moderation]', 'links_removed');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[1]', (string) $node1->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[2]', (string) $node1->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[3]', '1');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[4]', 'Published');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[1]', (string) $node2->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[2]', (string) $node2->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[3]', '2');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[4]', 'Draft');
$this->assertSession()->buttonExists('Submit')->press();
// Process the batch.
$this->checkForMetaRefresh();
$this->assertSession()->pageTextContains('Updated one entity for references to Node 1.');
$this->assertSession()->pageTextContains('Updated 2 entities for references to Node 2.');
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node_storage->resetCache();
$node1 = $node_storage->load($node1->id());
$node2 = $node_storage->load($node2->id());
$this->assertSame('links_removed', $node1->get('moderation_state')->value, 'Node 1 is in link_removed state.');
$this->assertSame('links_removed', $node2->get('moderation_state')->value, 'Node 2 is in link_removed state.');
}
/**
* Tests entity_usage_updater_workflow_presave().
*/
public function testWorkflowStateRemoval(): void {
$this->drupalGet('admin/config/content/entity-usage-updater');
$this->assertCount(1, $this->assertSession()->fieldExists('workflow[editorial]')->findAll('css', 'option'));
$this->drupalGet('admin/config/workflow/workflows/manage/editorial/add_state');
$this->assertSession()->fieldExists('label')->setValue('Links removed');
$this->assertSession()->fieldExists('id')->setValue('links_removed');
$this->assertSession()->fieldExists('type_settings[default_revision]')->check();
$this->assertSession()->buttonExists('Save')->press();
$this->assertSession()->pageTextContains('Created Links removed state.');
$this->getSession()->getPage()->clickLink('Add a new transition');
$this->assertSession()->fieldExists('label')->setValue('Links remover');
$this->assertSession()->fieldExists('id')->setValue('links_remover');
foreach ($this->assertSession()->elementExists('css', '#edit-from')->findAll('css', 'input[type=\'checkbox\']') as $checkbox) {
$checkbox->check();
}
$this->assertSession()->fieldExists('to')->selectOption('links_removed');
$this->assertSession()->buttonExists('Save')->press();
$this->assertSession()->pageTextContains('Created Links remover transition.');
$this->drupalGet('admin/config/content/entity-usage-updater');
$this->assertCount(2, $this->assertSession()->fieldExists('workflow[editorial]')->findAll('css', 'option'));
$this->assertSession()->fieldExists('workflow[editorial]')->selectOption('links_removed');
$this->assertSession()->buttonExists('Save')->press();
$workflow_storage = \Drupal::entityTypeManager()->getStorage('workflow');
/** @var \Drupal\workflows\WorkflowInterface $workflow */
$workflow = $workflow_storage->load('editorial');
$this->assertSame('links_removed', $workflow->getThirdPartySetting('entity_usage_updater', 'default_unpublished_state'));
$this->drupalGet('admin/config/workflow/workflows/manage/editorial/state/links_removed/delete');
$this->assertSession()->buttonExists('Delete')->press();
$workflow_storage->resetCache();
$workflow = $workflow_storage->load('editorial');
$this->assertNull($workflow->getThirdPartySetting('entity_usage_updater', 'default_unpublished_state'));
}
/**
* Creates content for testing.
*
* @return \Drupal\node\NodeInterface[]
* The created content in an array.
*/
private function createContent(): array {
$session = $this->getSession(); $session = $this->getSession();
$page = $session->getPage(); $page = $session->getPage();
$assert_session = $this->assertSession(); $assert_session = $this->assertSession();
...@@ -122,57 +328,7 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase { ...@@ -122,57 +328,7 @@ class ContentModerationLinkRemoverFormTest extends ModerationStateTestBase {
$this->assertSession()->linkByHrefExists($node3->toUrl()->toString()); $this->assertSession()->linkByHrefExists($node3->toUrl()->toString());
$this->assertSession()->linkByHrefExists($node2->toUrl()->toString()); $this->assertSession()->linkByHrefExists($node2->toUrl()->toString());
$this->drupalGet('admin/config/content/link-remover'); return [$node1, $node2, $node3, $node4, $node5];
$this->assertSession()->fieldExists('links')->setValue(implode("\n", [
$node1->toUrl()->setAbsolute()->toString(),
$node2->toUrl()->setAbsolute()->toString(),
]));
$this->assertSession()->buttonExists('Remove')->press();
// Ensure the content moderation options are as expected.
$this->assertSession()->optionNotExists('table[node|1][moderation]', 'published');
$this->assertSession()->optionExists('table[node|1][moderation]', 'draft');
$this->assertSession()->fieldExists('table[node|1][moderation]')->selectOption('archived');
$this->assertSession()->optionNotExists('table[node|2][moderation]', 'draft');
$this->assertSession()->optionExists('table[node|2][moderation]', 'published');
$this->assertSession()->optionNotExists('table[node|2][moderation]', 'archived');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[1]', (string) $node1->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[2]', (string) $node1->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[3]', '1');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[4]', 'Published');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[1]', (string) $node2->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[2]', (string) $node2->getEntityType()->getLabel());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[3]', '2');
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[2]/td[4]', 'Draft');
$this->assertSession()->buttonExists('Submit')->press();
// Process the batch.
$this->checkForMetaRefresh();
$this->assertSession()->pageTextContains('Updated one entity for references to Node 1.');
$this->assertSession()->pageTextContains('Updated 2 entities for references to Node 2.');
$this->assertSession()->pageTextContains('Updated moderation state for Node 1 to Archived.');
$this->assertSession()->pageTextNotContains('Updated moderation state for Node 2');
// Check to see if the links have been removed.
$this->drupalGet('node/3');
$this->assertSession()->linkByHrefNotExists($node1->toUrl()->toString());
$this->drupalGet('node/4');
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
// Check to see if the link node 2 has been removed but the link to node 3
// is still there.
$this->drupalGet('node/5');
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
$this->assertSession()->linkByHrefExists($node3->toUrl()->toString());
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node_storage->resetCache();
$node1 = $node_storage->load($node1->id());
$node2 = $node_storage->load($node2->id());
$this->assertSame('archived', $node1->get('moderation_state')->value, 'Node 1 is archived.');
$this->assertSame('draft', $node2->get('moderation_state')->value, 'Node 2 is a draft.');
} }
} }
...@@ -140,6 +140,7 @@ class LinkRemoverFormTest extends BrowserTestBase { ...@@ -140,6 +140,7 @@ class LinkRemoverFormTest extends BrowserTestBase {
$node1->toUrl()->setAbsolute()->toString(), $node1->toUrl()->setAbsolute()->toString(),
$node2->toUrl()->setAbsolute()->toString(), $node2->toUrl()->setAbsolute()->toString(),
])); ]));
$this->assertSession()->fieldExists('unpublish')->setValue($unpublish);
$this->assertSession()->buttonExists('Remove')->press(); $this->assertSession()->buttonExists('Remove')->press();
...@@ -155,11 +156,12 @@ class LinkRemoverFormTest extends BrowserTestBase { ...@@ -155,11 +156,12 @@ class LinkRemoverFormTest extends BrowserTestBase {
$node1->toUrl()->setAbsolute()->toString(), $node1->toUrl()->setAbsolute()->toString(),
$node2->toUrl()->setAbsolute()->toString(), $node2->toUrl()->setAbsolute()->toString(),
])); ]));
$this->assertSession()->fieldExists('unpublish')->setValue($unpublish);
$this->assertSession()->buttonExists('Remove')->press(); $this->assertSession()->buttonExists('Remove')->press();
$this->assertSession()->pageTextNotContains('You do not have permission to change.'); $this->assertSession()->pageTextNotContains('You do not have permission to change.');
$this->assertSession()->fieldExists('table[node|1][moderation]')->selectOption('unpublished'); $this->assertSession()->fieldExists('table[node|1][moderation]')->selectOption('unpublished');
$this->assertSession()->fieldExists('table[node|2][moderation]'); $this->assertSession()->fieldExists('table[node|2][moderation]')->selectOption('');
} }
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[1]', (string) $node1->label()); $this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[1]', (string) $node1->label());
$this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[2]', (string) $node1->getEntityType()->getLabel()); $this->assertSession()->elementTextEquals('xpath', '//table[@id="edit-table"]/tbody/tr[1]/td[2]', (string) $node1->getEntityType()->getLabel());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment