Commit 414283b2 authored by jonathan1055's avatar jonathan1055 Committed by jonathan1055

Issue #2824015 by jonathan1055: Inconsistency in "changed" timestamp when publishing in the past

parent 174ca09a
......@@ -6,6 +6,7 @@ default_expand_fieldset: 'when_required'
default_fields_display_mode: 'vertical_tab'
default_publish_enable: false
default_publish_past_date: 'error'
default_publish_past_date_created: false
default_publish_required: false
default_publish_revision: false
default_publish_touch: false
......
......@@ -28,6 +28,9 @@ scheduler.settings:
default_publish_past_date:
type: string
label: 'Default value for nodetype setting publish_past_date'
default_publish_past_date_created:
type: boolean
label: 'Default value for nodetype setting publish_past_date_created'
default_publish_required:
type: boolean
label: 'Default value for nodetype setting publish_required'
......@@ -78,6 +81,9 @@ node.type.*.third_party.scheduler:
publish_past_date:
type: string
label: 'Action to be taken for publication dates in the past'
publish_past_date_created:
type: boolean
label: 'Change content creation date for past dates to avoid "changed" being earlier than "created"'
publish_required:
type: boolean
label: 'Require scheduled publishing'
......
......@@ -92,6 +92,21 @@ function _scheduler_form_node_type_form_alter(array &$form, FormStateInterface $
'schedule' => t('Schedule the content for publication on the next cron run'),
],
];
$form['scheduler']['publish']['advanced']['scheduler_publish_past_date_created'] = [
'#type' => 'checkbox',
'#title' => t("Change content creation time to match the published time for dates before the content was created"),
'#description' => t("The created time will only be altered when the scheduled publishing time is earlier than the existing content creation time"),
'#default_value' => $type->getThirdPartySetting('scheduler', 'publish_past_date_created', $config->get('default_publish_past_date_created')),
// This option is not relevant if the full 'change creation time' option is
// selected, or when past dates are not allowed. Hence only show it when
// the main option is not checked and the past dates option is not 'error'.
'#states' => [
'visible' => [
':input[name="scheduler_publish_touch"]' => ['checked' => FALSE],
':input[name="scheduler_publish_past_date"]' => ['!value' => 'error'],
],
],
];
// Unpublishing options.
$form['scheduler']['unpublish'] = [
......@@ -144,7 +159,6 @@ function _scheduler_form_node_type_form_alter(array &$form, FormStateInterface $
],
],
];
// @todo Worthwhile to port this to D8 now form displays are configurable?
$form['scheduler']['node_edit_layout']['scheduler_fields_display_mode'] = [
'#type' => 'radios',
'#title' => t('Display scheduling options as'),
......@@ -176,6 +190,7 @@ function scheduler_form_node_type_form_builder($entity_type, NodeTypeInterface $
$type->setThirdPartySetting('scheduler', 'fields_display_mode', $form_state->getValue('scheduler_fields_display_mode'));
$type->setThirdPartySetting('scheduler', 'publish_enable', $form_state->getValue('scheduler_publish_enable'));
$type->setThirdPartySetting('scheduler', 'publish_past_date', $form_state->getValue('scheduler_publish_past_date'));
$type->setThirdPartySetting('scheduler', 'publish_past_date_created', $form_state->getValue('scheduler_publish_past_date_created'));
$type->setThirdPartySetting('scheduler', 'publish_required', $form_state->getValue('scheduler_publish_required'));
$type->setThirdPartySetting('scheduler', 'publish_revision', $form_state->getValue('scheduler_publish_revision'));
$type->setThirdPartySetting('scheduler', 'publish_touch', $form_state->getValue('scheduler_publish_touch'));
......
......@@ -374,8 +374,12 @@ function scheduler_node_presave(EntityInterface $node) {
\Drupal::service('event_dispatcher')->dispatch(SchedulerEvents::PRE_PUBLISH_IMMEDIATELY, $event);
$node = $event->getNode();
// Set the 'changed' timestamp to match what would have been done had this
// content been published via cron.
$node->setChangedTime($node->publish_on->value);
// If required, set the created date to match published date.
if ($entity->getThirdPartySetting('scheduler', 'publish_touch', $config->get('default_publish_touch'))) {
if ($entity->getThirdPartySetting('scheduler', 'publish_touch', $config->get('default_publish_touch')) ||
($node->getCreatedTime() > $node->publish_on->value && $entity->getThirdPartySetting('scheduler', 'publish_past_date_created', $config->get('default_publish_past_date_created')))) {
$node->setCreatedTime($node->publish_on->value);
}
$node->publish_on->value = NULL;
......
......@@ -153,7 +153,7 @@ class SchedulerManager {
continue;
}
// $node->set('changed', $publish_on) will fail badly if an API call has
// $node->setChangedTime($publish_on) will fail badly if an API call has
// removed the date. Trap this as an exception here and give a
// meaningful message.
// @TODO This will now never be thrown due to the empty(publish_on)
......@@ -170,10 +170,14 @@ class SchedulerManager {
$this->eventDispatcher->dispatch(SchedulerEvents::PRE_PUBLISH, $event);
$node = $event->getNode();
// Update timestamps.
$node->set('changed', $publish_on);
// Update 'changed' timestamp.
$node->setChangedTime($publish_on);
$old_creation_date = $node->getCreatedTime();
if ($touch = $node->type->entity->getThirdPartySetting('scheduler', 'publish_touch', $this->setting('default_publish_touch'))) {
$msg_extra = '';
// If required, set the created date to match published date.
if ($node->type->entity->getThirdPartySetting('scheduler', 'publish_touch', $this->setting('default_publish_touch')) ||
($node->getCreatedTime() > $publish_on && $node->type->entity->getThirdPartySetting('scheduler', 'publish_past_date_created', $this->setting('default_publish_past_date_created')))
) {
$node->setCreatedTime($publish_on);
$msg_extra = $this->t('The previous creation date was @old_creation_date, now updated to match the publishing date.', [
'@old_creation_date' => $this->dateFormatter->format($old_creation_date, 'short'),
......@@ -184,12 +188,9 @@ class SchedulerManager {
if ($create_publishing_revision) {
$node->setNewRevision();
// Use a core date format to guarantee a time is included.
$revision_log_message = $this->t('Published by Scheduler. The scheduled publishing date was @publish_on.', [
$revision_log_message = rtrim($this->t('Published by Scheduler. The scheduled publishing date was @publish_on.', [
'@publish_on' => $this->dateFormatter->format($publish_on, 'short'),
]);
if ($touch) {
$revision_log_message .= ' ' . $msg_extra;
}
]) . ' ' . $msg_extra);
$node->setRevisionLogMessage($revision_log_message)
->setRevisionCreationTime($this->time->getRequestTime());
}
......@@ -300,7 +301,7 @@ class SchedulerManager {
continue;
}
// $node->set('changed', $unpublish_on) will fail badly if an API call
// $node->setChangedTime($unpublish_on) will fail badly if an API call
// has removed the date. Trap this as an exception here and give a
// meaningful message.
// @TODO This will now never be thrown due to the empty(unpublish_on)
......@@ -317,8 +318,8 @@ class SchedulerManager {
$this->eventDispatcher->dispatch(SchedulerEvents::PRE_UNPUBLISH, $event);
$node = $event->getNode();
// Update timestamps.
$node->set('changed', $unpublish_on);
// Update 'changed' timestamp.
$node->setChangedTime($unpublish_on);
$create_unpublishing_revision = $node->type->entity->getThirdPartySetting('scheduler', 'unpublish_revision', $this->setting('default_unpublish_revision'));
if ($create_unpublishing_revision) {
......
......@@ -18,12 +18,10 @@ class SchedulerPastDatesTest extends SchedulerBrowserTestBase {
// Log in.
$this->drupalLogin($this->schedulerUser);
// Ensure that neither of the scheduling dates are set to be required.
$this->nodetype->setThirdPartySetting('scheduler', 'publish_required', FALSE)
->setThirdPartySetting('scheduler', 'unpublish_required', FALSE)->save();
// Create an unpublished page node.
/** @var NodeInterface $node */
$node = $this->drupalCreateNode(['type' => $this->type, 'status' => FALSE]);
$created_time = $node->getCreatedTime();
// Test the default behavior: an error message should be shown when the user
// enters a publication date that is in the past.
......@@ -46,25 +44,31 @@ class SchedulerPastDatesTest extends SchedulerBrowserTestBase {
$this->assertNoText("The 'publish on' date must be in the future", 'No error message is shown when the publication date is in the past and the "publish" behavior is chosen.');
$this->assertText(sprintf('%s %s has been updated.', $this->typeName, Html::escape($edit['title[0][value]'])), 'The node is saved successfully when the publication date is in the past and the "publish" behavior is chosen.');
// Reload the changed node and check that it is published.
// Reload the node.
$this->nodeStorage->resetCache([$node->id()]);
/** @var NodeInterface $node */
$node = $this->nodeStorage->load($node->id());
// Check that the node is published and has the expected timestamps.
$this->assertTrue($node->isPublished(), 'The node has been published immediately when the publication date is in the past and the "publish" behavior is chosen.');
$this->assertNull($node->publish_on->value, 'The node publish_on date has been removed after publishing when the "publish" behavior is chosen.');
$this->assertEquals($node->getChangedTime(), strtotime('-1 day', $this->requestTime), 'The changed time of the node has been updated to the publish_on time when published immediately.');
$this->assertEquals($node->getCreatedTime(), $created_time, 'The created time of the node has not been changed when the "publish" behavior is chosen.');
// Test the 'schedule' behavior: the node should be unpublished and become
// published on the next cron run.
// published on the next cron run. Use a new unpublished node.
$this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', 'schedule')->save();
$node = $this->drupalCreateNode(['type' => $this->type, 'status' => FALSE]);
$created_time = $node->getCreatedTime();
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertNoText("The 'publish on' date must be in the future", 'No error message is shown when the publication date is in the past and the "schedule" behavior is chosen.');
$this->assertText(sprintf('%s %s has been updated.', $this->typeName, Html::escape($edit['title[0][value]'])), 'The node is saved successfully when the publication date is in the past and the "schedule" behavior is chosen.');
$this->assertText('will be published', 'The node is scheduled to be published when the publication date is in the past and the "schedule" behavior is chosen.');
// Reload the node and check that it is unpublished but scheduled correctly.
// Reload the node.
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
// Check that the node is unpublished but scheduled correctly.
$this->assertFalse($node->isPublished(), 'The node has been unpublished when the publication date is in the past and the "schedule" behavior is chosen.');
$this->assertEquals(strtotime('-1 day', $this->requestTime), (int) $node->publish_on->value, 'The node has the correct publish_on date stored.');
......@@ -73,6 +77,37 @@ class SchedulerPastDatesTest extends SchedulerBrowserTestBase {
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$this->assertTrue($node->isPublished(), 'The node with publication date in the past and the "schedule" behavior has now been published by cron.');
$this->assertEquals($node->getChangedTime(), strtotime('-1 day', $this->requestTime), 'The changed time of the node has been updated to the publish_on time when published via cron.');
$this->assertEquals($node->getCreatedTime(), $created_time, 'The created time of the node has not been changed when the "schedule" behavior is chosen.');
// Test the option to alter the creation time if the publishing time is
// earlier than the node created time.
$this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date_created', TRUE)->save();
$past_date_options = [
'publish' => 'publish',
'schedule' => 'schedule',
];
foreach ($past_date_options as $key => $option) {
$this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', $key)->save();
// Create a new node, edit and save.
$node = $this->drupalCreateNode(['type' => $this->type, 'status' => FALSE]);
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
if ($option == 'schedule') {
scheduler_cron();
}
// Reload the node.
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
// Check that the created time has been altered to match publishing time.
$this->assertEquals($node->getCreatedTime(), strtotime('-1 day', $this->requestTime), sprintf('The created time of the node has not been changed when the %s option is chosen.', $option));
}
// Check that an Unpublish date in the past fails validation.
$edit = [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment