Skip to content
Snippets Groups Projects
Commit 1b3d8c51 authored by dpi's avatar dpi
Browse files

Issue #3191357 by dpi, sime: Override transition revision log individually

parent dca11ede
Branches 8.x-1.x
Tags 8.x-1.1
No related merge requests found
Showing
with 540 additions and 17 deletions
......@@ -13,5 +13,8 @@
"drush.services.yml": "^9"
}
}
},
"suggest": {
"drupal/token": "Shows Token UI on Add Scheduled Transitions form."
}
}
......@@ -7,3 +7,4 @@ automation:
message_transition_latest: 'Scheduled transition: transitioning latest revision from [scheduled-transitions:from-state] to [scheduled-transitions:to-state]'
message_transition_historical: 'Scheduled transition: copied revision #[scheduled-transitions:from-revision-id] and changed from [scheduled-transitions:from-state] to [scheduled-transitions:to-state]'
message_transition_copy_latest_draft: 'Scheduled transition: reverted [scheduled-transitions:latest-state] revision #[scheduled-transitions:latest-revision-id] back to top'
message_override: false
......@@ -34,6 +34,9 @@ scheduled_transitions.settings:
message_transition_copy_latest_draft:
type: string
label: 'Revision log message used when shifting a former unpublished revision back on top.'
message_override:
type: boolean
label: 'Whether users are permitted to override revision log templates.'
# Schema for \Drupal\scheduled_transitions\Plugin\views\field\ScheduledTransitionRevisionLinkField plugin.
views.field.scheduled_transitions_revision_link:
......
......@@ -78,3 +78,16 @@ function scheduled_transitions_update_8005(): void {
$entityType->setLinkTemplate('reschedule-form', '/admin/scheduled-transition/{scheduled_transition}/reschedule');
$definitionUpdateManager->updateEntityType($entityType);
}
/**
* Adds revision log override config.
*
* @param array $sandbox
* Sandbox.
*/
function scheduled_transitions_update_8006(array &$sandbox): void {
$configFactory = \Drupal::configFactory();
$configFactory->getEditable('scheduled_transitions.settings')
->set('message_override', FALSE)
->save(TRUE);
}
services:
scheduled_transitions.utility:
class: 'Drupal\scheduled_transitions\ScheduledTransitionsUtility'
arguments: ['@config.factory', '@cache.default', '@entity_type.manager', '@entity_type.bundle.info', '@content_moderation.moderation_information']
arguments: ['@config.factory', '@cache.default', '@entity_type.manager', '@entity_type.bundle.info', '@content_moderation.moderation_information', '@token', '@string_translation']
scheduled_transitions.runner:
class: 'Drupal\scheduled_transitions\ScheduledTransitionsRunner'
arguments: ['@entity_type.manager', '@config.factory', '@datetime.time', '@logger.channel.scheduled_transitions', '@content_moderation.moderation_information', '@token', '@event_dispatcher']
arguments: ['@entity_type.manager', '@config.factory', '@datetime.time', '@logger.channel.scheduled_transitions', '@content_moderation.moderation_information', '@token', '@event_dispatcher', '@scheduled_transitions.utility']
scheduled_transitions.jobs:
class: 'Drupal\scheduled_transitions\ScheduledTransitionsJobs'
......
......@@ -226,7 +226,7 @@ class ScheduledTransition extends ContentEntityBase implements ScheduledTransiti
/**
* {@inheritdoc}
*/
public function getState(): string {
public function getState(): ?string {
return $this->get('moderation_state')->value;
}
......
......@@ -150,7 +150,7 @@ interface ScheduledTransitionInterface extends ContentEntityInterface {
* @return string|null
* The state ID.
*/
public function getState(): string;
public function getState(): ?string;
/**
* Get the time this scheduled transition was created.
......
......@@ -14,8 +14,10 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Element\Tableselect;
use Drupal\Core\Render\Markup;
use Drupal\scheduled_transitions\Entity\ScheduledTransition;
use Drupal\workflows\Transition;
use Drupal\workflows\WorkflowInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -79,6 +81,7 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
$instance->stateTransitionValidation = $container->get('content_moderation.state_transition_validation');
$instance->languageManager = $container->get('language_manager');
$instance->scheduledTransitionsUtility = $container->get('scheduled_transitions.utility');
$instance->configFactory = $container->get('config.factory');
return $instance;
}
......@@ -141,9 +144,10 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
$form['scheduled_transitions']['new_meta'] = [
'#type' => 'container',
'#attributes' => ['class' => ['container-inline']],
'#prefix' => '<div id="' . $newMetaWrapperId . '">',
'#suffix' => '</div>',
'#attributes' => [
'id' => $newMetaWrapperId,
'class' => ['container-inline'],
],
];
$workflow = $this->moderationInformation->getWorkflowForEntity($entity);
......@@ -218,6 +222,8 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
];
}
$form['scheduled_transitions']['revision_metadata'] = $this->getRevisionMetadata($form_state, $workflow, $entity, $entityRevision ?? NULL);
return $form;
}
......@@ -258,6 +264,13 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
return $form['scheduled_transitions']['new_meta'];
}
/**
* Ajax handler for revision log preview.
*/
public function reloadRevisionLogPreview(array &$form, FormStateInterface $form_state): array {
return $form['scheduled_transitions']['revision_metadata']['revision_log']['preview'];
}
/**
* {@inheritdoc}
*/
......@@ -287,6 +300,14 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
$entityRevisionId = $revisionOption;
}
/** @var array|null $revisionMetadataValues */
$revisionMetadataValues = $form_state->getValue(['revision_metadata']);
if ($revisionMetadataValues['revision_log']['override'] ?? NULL) {
$message = $revisionMetadataValues['revision_log']['custom']['message'] ?? '';
$options['revision_log_override'] = TRUE;
$options['revision_log'] = $message;
}
$workflow = $this->moderationInformation->getWorkflowForEntity($entity);
$transition = $form_state->getValue(['transition']);
$workflowPlugin = $workflow->getTypePlugin();
......@@ -442,4 +463,120 @@ class ScheduledTransitionAddForm extends ContentEntityForm {
return $options;
}
/**
* Generate revision metadata section of the form.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
* @param \Drupal\workflows\WorkflowInterface|null $workflow
* The workflow.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being transitioned.
* @param \Drupal\Core\Entity\EntityInterface|null $entityRevision
* The revision being transitioned, if available.
*
* @return array
* A form array.
*/
protected function getRevisionMetadata(FormStateInterface $form_state, ?WorkflowInterface $workflow, EntityInterface $entity, ?EntityInterface $entityRevision): array {
$form = [
'#tree' => TRUE,
];
$settings = $this->configFactory->get('scheduled_transitions.settings');
$form['revision_log'] = [
'#type' => 'details',
'#open' => FALSE,
'#title' => $this->t('Revision Log'),
'#access' => (bool) $settings->get('message_override'),
];
$overrideCheckboxName = 'revision_metadata[revision_log][override]';
$form['revision_log']['override'] = [
'#type' => 'checkbox',
'#title' => $this->t('Override revision log message'),
'#description' => $this->t('Override revision log message, otherwise a revision log will be generated automatically.'),
'#name' => $overrideCheckboxName,
'#ajax' => [
'callback' => '::reloadRevisionLogPreview',
'wrapper' => 'revision-log-preview',
'effect' => 'fade',
],
];
$form['revision_log']['custom'] = [
'#type' => 'container',
'#states' => [
'visible' => [
[':input[name="' . $overrideCheckboxName . '"]' => ['checked' => TRUE]],
],
],
];
$form['revision_log']['custom']['message'] = [
'#type' => 'textarea',
'#title' => $this->t('Revision log'),
'#description' => $this->t('The revision log applied to the newly created revision.'),
];
$form['revision_log']['custom']['tokens'] = [
'#theme' => 'token_tree_link',
'#token_types' => [
'scheduled-transitions',
],
];
// This shows the Revision log if it was executed at this time with the
// current selected contexts.
$form['revision_log']['preview'] = [
'#type' => 'fieldset',
'#title' => $this->t('Preview'),
'#prefix' => '<div id="revision-log-preview">',
'#suffix' => '</div>',
];
$form['revision_log']['preview_reload'] = [
// @todo Hide this button later, but click and debounce automatically.
// when form elements change.
'#type' => 'button',
'#value' => $this->t('Reload preview'),
'#name' => 'revision_log_preview_reload',
'#ajax' => $form['revision_log']['override']['#ajax'],
// Trick handleErrorsWithLimitedValidation into giving us our values,
// same as if a non button (e.g select) added #ajax.
'#limit_validation_errors' => NULL,
];
$scheduledTransitionStorage = $this->entityTypeManager->getStorage('scheduled_transition');
/** @var \Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface $scheduledTransition */
// Create an unused Scheduled Transition.
$scheduledTransition = $scheduledTransitionStorage->create([]);
$transitionValue = $form_state->getValue(['transition']);
if ($transitionValue) {
$workflowPlugin = $workflow->getTypePlugin();
$newState = $workflowPlugin->getTransition($transitionValue)->to()->id();
$scheduledTransition->setState($workflow, $newState);
}
/** @var array|null $revisionMetadataValues */
$revisionMetadataValues = $form_state->getValue(['revision_metadata']);
if ($revisionMetadataValues['revision_log']['override'] ?? NULL) {
$message = $revisionMetadataValues['revision_log']['custom']['message'] ?? '';
$scheduledTransition->setOptions([
'revision_log_override' => TRUE,
'revision_log' => $message,
]);
}
// Use entity revision if determinable, otherwise the default.
$rawRevisionLog = $this->scheduledTransitionsUtility->generateRevisionLog($scheduledTransition, $entityRevision ?? $entity);
$form['revision_log']['preview']['revision_log'] = [
'#type' => 'inline_template',
'#template' => '<blockquote>{{ revision_log }}</blockquote>',
'#context' => [
'revision_log' => Markup::create(Xss::filter($rawRevisionLog, Xss::getHtmlTagList())),
],
];
return $form;
}
}
......@@ -240,6 +240,13 @@ class ScheduledTransitionsSettingsForm extends ConfigFormBase {
'#title' => $this->t('Messages'),
'#open' => TRUE,
];
$form['message_override'] = [
'#type' => 'checkbox',
'#title' => $this->t('Revision log override'),
'#group' => 'messages',
'#default_value' => $settings->get('message_override'),
'#description' => $this->t('Whether users are permitted to override revision log templates per scheduled transition.'),
];
$form['message_transition_latest'] = [
'#type' => 'textarea',
'#title' => $this->t('Latest'),
......@@ -273,6 +280,7 @@ class ScheduledTransitionsSettingsForm extends ConfigFormBase {
->set('mirror_operations.add scheduled transition', $form_state->getValue('mirror_operation_add'))
->set('mirror_operations.reschedule scheduled transitions', $form_state->getValue('mirror_operation_reschedule'))
->set('automation.cron_create_queue_items', (bool) $form_state->getValue('cron_create_queue_items'))
->set('message_override', $form_state->getValue('message_override'))
->set('message_transition_latest', $form_state->getValue('message_transition_latest'))
->set('message_transition_historical', $form_state->getValue('message_transition_historical'))
->set('message_transition_copy_latest_draft', $form_state->getValue('message_transition_copy_latest_draft'));
......
......@@ -81,6 +81,13 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
*/
protected $eventDispatcher;
/**
* Utilities for Scheduled Transitions module.
*
* @var \Drupal\scheduled_transitions\ScheduledTransitionsUtilityInterface
*/
protected $scheduledTransitionsUtility;
/**
* Constructs a new ScheduledTransitionsRunner.
*
......@@ -98,8 +105,10 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
* The token replacement system.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The event dispatcher.
* @param \Drupal\scheduled_transitions\ScheduledTransitionsUtilityInterface $scheduledTransitionsUtility
* Utilities for Scheduled Transitions module.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $configFactory, TimeInterface $time, LoggerInterface $logger, ModerationInformationInterface $moderationInformation, Token $token, EventDispatcherInterface $eventDispatcher) {
public function __construct(EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $configFactory, TimeInterface $time, LoggerInterface $logger, ModerationInformationInterface $moderationInformation, Token $token, EventDispatcherInterface $eventDispatcher, ScheduledTransitionsUtilityInterface $scheduledTransitionsUtility) {
$this->entityTypeManager = $entityTypeManager;
$this->configFactory = $configFactory;
$this->time = $time;
......@@ -107,6 +116,7 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
$this->moderationInformation = $moderationInformation;
$this->token = $token;
$this->eventDispatcher = $eventDispatcher;
$this->scheduledTransitionsUtility = $scheduledTransitionsUtility;
}
/**
......@@ -192,6 +202,9 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
// Start the transition process.
// Determine if latest before calling setNewRevision on $newRevision.
$newIsLatest = $newRevision->getRevisionId() === $latest->getRevisionId();
$revisionLog = $newRevision instanceof RevisionLogInterface
? $this->scheduledTransitionsUtility->generateRevisionLog($scheduledTransition, $newRevision)
: NULL;
// Creating revisions via createRevision to invoke
// setRevisionTranslationAffected and whatever other logic doesn't happen
......@@ -208,10 +221,9 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
// If publishing the latest revision, then only set moderation state.
if ($newIsLatest) {
$this->log(LogLevel::INFO, 'Transitioning latest revision from @original_state to @new_state', $replacements);
if ($newRevision instanceof RevisionLogInterface) {
$template = $settings->get('message_transition_latest');
if ($newRevision instanceof RevisionLogInterface && $revisionLog) {
$newRevision
->setRevisionLogMessage($this->tokenReplace($template, $replacements))
->setRevisionLogMessage($revisionLog)
->setRevisionCreationTime($this->time->getRequestTime());
}
$newRevision->save();
......@@ -219,10 +231,9 @@ class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface
// Otherwise if publishing a revision not on HEAD, create new revisions.
else {
$this->log(LogLevel::INFO, 'Copied revision #@revision_id and changed from @original_state to @new_state', $replacements);
if ($newRevision instanceof RevisionLogInterface) {
$template = $settings->get('message_transition_historical');
if ($newRevision instanceof RevisionLogInterface && $revisionLog) {
$newRevision
->setRevisionLogMessage($this->tokenReplace($template, $replacements))
->setRevisionLogMessage($revisionLog)
->setRevisionCreationTime($this->time->getRequestTime());
}
$newRevision->save();
......
......@@ -96,7 +96,7 @@ class ScheduledTransitionsTokenReplacements {
return $this->cachedReplacements = [
'from-revision-id' => $entityRevisionId,
'from-state' => $originalNewRevisionState ? $originalNewRevisionState->label() : $this->t('- Unknown state -'),
'to-state' => $newState->label(),
'to-state' => $newState ? $newState->label() : $this->t('- Unknown state -'),
'latest-revision-id' => $this->latest->getRevisionId(),
'latest-state' => $originalLatestState ? $originalLatestState->label() : $this->t('- Unknown state -'),
];
......
......@@ -11,6 +11,11 @@ use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Utility\Token;
use Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface;
use Drupal\scheduled_transitions\Exception\ScheduledTransitionMissingEntity;
use Drupal\scheduled_transitions\Form\ScheduledTransitionsSettingsForm as SettingsForm;
/**
......@@ -53,6 +58,20 @@ class ScheduledTransitionsUtility implements ScheduledTransitionsUtilityInterfac
*/
protected $moderationInformation;
/**
* The token replacement system.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* String translation manager.
*
* @var \Drupal\Core\StringTranslation\TranslationInterface
*/
protected $stringTranslation;
/**
* Cache bin ID for enabled bundled cache.
*/
......@@ -76,13 +95,19 @@ class ScheduledTransitionsUtility implements ScheduledTransitionsUtilityInterfac
* The bundle information service.
* @param \Drupal\content_moderation\ModerationInformationInterface $moderationInformation
* General service for moderation-related questions about Entity API.
* @param \Drupal\Core\Utility\Token $token
* The token replacement system.
* @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
* String translation manager.
*/
public function __construct(ConfigFactoryInterface $configFactory, CacheBackendInterface $cache, EntityTypeManagerInterface $entityTypeManager, EntityTypeBundleInfoInterface $bundleInfo, ModerationInformationInterface $moderationInformation) {
public function __construct(ConfigFactoryInterface $configFactory, CacheBackendInterface $cache, EntityTypeManagerInterface $entityTypeManager, EntityTypeBundleInfoInterface $bundleInfo, ModerationInformationInterface $moderationInformation, Token $token, TranslationInterface $stringTranslation) {
$this->configFactory = $configFactory;
$this->cache = $cache;
$this->entityTypeManager = $entityTypeManager;
$this->bundleInfo = $bundleInfo;
$this->moderationInformation = $moderationInformation;
$this->token = $token;
$this->stringTranslation = $stringTranslation;
}
/**
......@@ -163,6 +188,37 @@ class ScheduledTransitionsUtility implements ScheduledTransitionsUtilityInterfac
return array_keys($ids);
}
/**
* {@inheritdoc}
*/
public function generateRevisionLog(ScheduledTransitionInterface $scheduledTransition, RevisionLogInterface $newRevision): string {
$entityStorage = $this->entityTypeManager->getStorage($newRevision->getEntityTypeId());
$latestRevisionId = $entityStorage->getLatestRevisionId($newRevision->id());
if ($latestRevisionId) {
/** @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface $latest */
$latest = $entityStorage->loadRevision($latestRevisionId);
}
if (!isset($latest)) {
throw new ScheduledTransitionMissingEntity(sprintf('Could not determine latest revision.'));
}
$options = $scheduledTransition->getOptions();
if (($options['revision_log_override'] ?? NULL) === TRUE) {
$template = $options['revision_log'] ?? '';
}
else {
$newIsLatest = $newRevision->getRevisionId() === $latest->getRevisionId();
$settings = $this->configFactory->get('scheduled_transitions.settings');
$template = $newIsLatest
? $settings->get('message_transition_latest')
: $settings->get('message_transition_historical');
}
$replacements = new ScheduledTransitionsTokenReplacements($scheduledTransition, $newRevision, $latest);
$replacements->setStringTranslation($this->stringTranslation);
return $this->tokenReplace($template, $replacements);
}
/**
* Creates a cache tag for scheduled transitions related to an entity.
*
......@@ -176,4 +232,20 @@ class ScheduledTransitionsUtility implements ScheduledTransitionsUtilityInterfac
return sprintf('scheduled_transitions_for:%s:%s', $entity->getEntityTypeId(), $entity->id());
}
/**
* Replaces all tokens in a given string with appropriate values.
*
* @param string $text
* A string containing replaceable tokens.
* @param \Drupal\scheduled_transitions\ScheduledTransitionsTokenReplacements $replacements
* A replacements object.
*
* @return string
* The string with the tokens replaced.
*/
protected function tokenReplace(string $text, ScheduledTransitionsTokenReplacements $replacements): string {
$tokenData = ['scheduled-transitions' => $replacements->getReplacements()];
return $this->token->replace($text, $tokenData);
}
}
......@@ -5,6 +5,8 @@ declare(strict_types = 1);
namespace Drupal\scheduled_transitions;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface;
/**
* Utilities for Scheduled Transitions module.
......@@ -51,4 +53,20 @@ interface ScheduledTransitionsUtilityInterface {
*/
public function getTargetRevisionIds(EntityInterface $entity, string $language): array;
/**
* Generates a revision log for a ready to save revision.
*
* @param \Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface $scheduledTransition
* The scheduled transition for the associated revision.
* @param \Drupal\Core\Entity\RevisionLogInterface $newRevision
* The entity a transition is created for.
*
* @return string
* A revision log with replaced tokens.
*
* @throws \Drupal\scheduled_transitions\Exception\ScheduledTransitionMissingEntity
* Thrown if latest revision of a entity could not be determined.
*/
public function generateRevisionLog(ScheduledTransitionInterface $scheduledTransition, RevisionLogInterface $newRevision): string;
}
......@@ -5,6 +5,7 @@
<div class="scheduled-updates-add__meta">
{{ form.new_meta }}
{{ form.to_options }}
{{ form.revision_metadata }}
</div>
</div>
{{ form|without('new_meta', 'to_options', 'revision') }}
{{ form|without('new_meta', 'to_options', 'revision', 'revision_metadata') }}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\scheduled_transitions\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\scheduled_transitions\Routing\ScheduledTransitionsRouteProvider;
use Drupal\scheduled_transitions_test\Entity\ScheduledTransitionsTestEntity;
use Drupal\scheduled_transitions\ScheduledTransitionsPermissions as Permissions;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
use Drupal\Tests\scheduled_transitions\Traits\ScheduledTransitionTestTrait;
/**
* Tests the route to add a new transition to an entity (modal form).
*
* @group scheduled_transitions
* @coversDefaultClass \Drupal\scheduled_transitions\Form\Entity\ScheduledTransitionAddForm
*/
class ScheduledTransitionModalFormJavascriptTest extends WebDriverTestBase {
use ContentModerationTestTrait;
use ScheduledTransitionTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity_test_revlog',
'scheduled_transitions_target_revisions_test',
'scheduled_transitions_test',
'scheduled_transitions',
'content_moderation',
'workflows',
'dynamic_entity_reference',
'user',
'system',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'classy';
/**
* Tests revision logs.
*/
public function testRevisionLogOverride() {
// Enable users to override messages.
\Drupal::configFactory()->getEditable('scheduled_transitions.settings')
->set('message_override', TRUE)
->save(TRUE);
$this->enabledBundles([['st_entity_test', 'st_entity_test']]);
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('st_entity_test', 'st_entity_test');
$workflow->save();
$currentUser = $this->drupalCreateUser([
'administer st_entity_test entities',
'use editorial transition create_new_draft',
'use editorial transition publish',
'use editorial transition archive',
Permissions::addScheduledTransitionsPermission('st_entity_test', 'st_entity_test'),
]);
$this->drupalLogin($currentUser);
$entity = ScheduledTransitionsTestEntity::create(['type' => 'st_entity_test']);
$entity->name = 'revision 1';
$entity->save();
$entity->name = 'revision 2';
$entity->setNewRevision(TRUE);
$entity->save();
$entity->name = 'revision 3';
$entity->setNewRevision(TRUE);
$entity->save();
$this->drupalGet($entity->toUrl());
// Access the modal directly.
$this->drupalGet($entity->toUrl(ScheduledTransitionsRouteProvider::LINK_TEMPLATE_ADD));
// Open the details element.
$this->getSession()->getPage()->find('css', '#edit-revision-metadata-revision-log > summary')->click();
// The default revision log is shown.
$this->assertSession()->pageTextContains('Scheduled transition: transitioning latest revision from Draft to - Unknown state -');
$this->getSession()->getPage()->fillField('transition', 'archive');
$this->getSession()->getPage()->pressButton('Reload preview');
$this->assertSession()->assertWaitOnAjaxRequest();
$this->assertSession()->pageTextContains('Scheduled transition: transitioning latest revision from Draft to Archived');
$this->getSession()->getPage()->fillField('revision', 2);
$this->getSession()->getPage()->checkField('revision_metadata[revision_log][override]');
$this->assertSession()->assertWaitOnAjaxRequest();
$this->getSession()->getPage()->fillField('revision_metadata[revision_log][custom][message]', 'Test message. Transitioning from revision #[scheduled-transitions:from-revision-id].');
$this->getSession()->getPage()->pressButton('Reload preview');
$this->assertSession()->assertWaitOnAjaxRequest();
$this->assertSession()->pageTextContains('Test message. Transitioning from revision #2');
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\scheduled_transitions\Unit;
use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\RevisionableStorageInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Utility\Token;
use Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface;
use Drupal\scheduled_transitions\ScheduledTransitionsUtility;
use Drupal\Tests\UnitTestCase;
/**
* Tests scheduled transactions utility.
*
* @coversDefaultClass \Drupal\scheduled_transitions\ScheduledTransitionsUtility
* @group scheduled_transitions
*/
class ScheduledTransitionsUtilityUnitTest extends UnitTestCase {
/**
* Tests revision log generator.
*
* @param string $transitioningRevisionId
* Revision ID of the transitioning revision.
* @param string $latestRevisionId
* Revision ID of the latest revision of an entity..
* @param array $options
* Scheduled transitions entity options.
* @param string $expectedRevisionLog
* The expected revision log.
*
* @covers ::generateRevisionLog
* @dataProvider providerGenerateRevisionLog
*/
public function testGenerateRevisionLog(string $transitioningRevisionId, string $latestRevisionId, array $options, string $expectedRevisionLog): void {
$configFactory = $this->createMock(ConfigFactoryInterface::class);
$settings = $this->createMock(ImmutableConfig::class);
$settings->expects($this->any())
->method('get')
->willReturnMap([
['message_transition_latest', 'template for latest revision'],
['message_transition_historical', 'template for historical revision'],
]);
$configFactory->expects($this->any())
->method('get')
->with('scheduled_transitions.settings')
->willReturn($settings);
$cache = $this->createMock(CacheBackendInterface::class);
$entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
$entityStorage = $this->createMock(RevisionableStorageInterface::class);
$latest = $this->createMock(RevisionLogInterface::class);
$latest->expects($this->any())
->method('getRevisionId')
->willReturn($latestRevisionId);
$entityStorage->expects($this->once())
->method('getLatestRevisionId')
->with('1337')
->willReturn('2000');
$entityStorage->expects($this->once())
->method('loadRevision')
->with('2000')
->willReturn($latest);
$entityTypeManager->expects($this->once())
->method('getStorage')
->with('test_entity_type')
->willReturn($entityStorage);
$bundleInfo = $this->createMock(EntityTypeBundleInfoInterface::class);
$moderationInformation = $this->createMock(ModerationInformationInterface::class);
$token = $this->createMock(Token::class);
$token->expects($this->once())
->method('replace')
->willReturnArgument(0);
$translation = $this->createMock(TranslationInterface::class);
$utility = new ScheduledTransitionsUtility(
$configFactory,
$cache,
$entityTypeManager,
$bundleInfo,
$moderationInformation,
$token,
$translation
);
$scheduledTransition = $this->createMock(ScheduledTransitionInterface::class);
$scheduledTransition->expects($this->once())
->method('getOptions')
->willReturn($options);
$newRevision = $this->createMock(RevisionLogInterface::class);
$newRevision->expects($this->once())
->method('id')
->willReturn(1337);
$newRevision->expects($this->once())
->method('getEntityTypeId')
->willReturn('test_entity_type');
$newRevision->expects($this->any())
->method('getRevisionId')
->willReturn($transitioningRevisionId);
$this->assertEquals(
$expectedRevisionLog,
$utility->generateRevisionLog($scheduledTransition, $newRevision)
);
}
/**
* Data provider for testGenerateRevisionLog.
*/
public function providerGenerateRevisionLog(): array {
$scenarios = [];
$scenarios['historical'] = [
// Transitioning different revisions.
'333',
'444',
[],
'template for historical revision',
];
$scenarios['latest'] = [
// Revision IDs are the same:
'444',
'444',
[],
'template for latest revision',
];
$scenarios['custom'] = [
// Revision IDs are irrelevant.
'444',
'444',
[
'revision_log_override' => TRUE,
'revision_log' => 'custom revision log',
],
'custom revision log',
];
return $scenarios;
}
}
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