diff --git a/composer.json b/composer.json index a3b78293..89bed20a 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "phpunit/phpunit": "^9.6", "squizlabs/php_codesniffer": "^3", "silverstripe/standards": "^1", - "phpstan/extension-installer": "^1.3" + "phpstan/extension-installer": "^1.3", + "silverstripe-terraformers/embargo-expiry": "^2.0" }, "extra": { "expose": [ @@ -40,7 +41,8 @@ ] }, "suggest": { - "symbiote/silverstripe-queuedjobs": "Allow automated workflow transitions with queued system jobs" + "symbiote/silverstripe-queuedjobs": "Allow automated workflow transitions with queued system jobs", + "silverstripe-terraformers/embargo-expiry": "Allow automated workflow transitions with embargo & expiry dates." }, "autoload": { "psr-4": { diff --git a/docs/en/configuration.md b/docs/en/configuration.md index 5cf89a5c..420edccc 100644 --- a/docs/en/configuration.md +++ b/docs/en/configuration.md @@ -17,7 +17,7 @@ extending from `ModelAdmin`. `mysite/_config/config.yml`: extensions: - AdvancedWorkflowExtension -We strongly recommend also setting the `NotifyUsersWorkflowAction` configuration parameter `whitelist_template_variables` +We strongly recommend also setting the `NotifyUsersWorkflowAction` configuration parameter `whitelist_template_variables` to true on new projects. This configuration will achieve this: :::yml @@ -27,23 +27,22 @@ to true on new projects. This configuration will achieve this: See the Security section below for more details. ### Embargo and Expiry -This add-on functionality allows you to embargo some content changes to only appear as published at some future date. To enable it, -add the `WorkflowEmbargoExpiryExtension`. - :::yml - SiteTree: - extensions: - - WorkflowEmbargoExpiryExtension +You can optionally add the [Embargy & Expiry](https://github.com/silverstripe-terraformers/silverstripe-embargo-expiry) +module to your project to allow changes to be published (and/or unpublished) at future dates. + +**Note:** You will need to use version 1.2.1 or greater. -Make sure the [QueuedJobs](https://github.com/nyeholt/silverstripe-queuedjobs) -module is installed and configured correctly. -You should have a cronjob similar to the following in place, running -as the webserver user. +#### Migrating from an older Workflow version - */1 * * * * cd && sudo -u www php /var/www/framework/cli-script.php dev/tasks/ProcessJobQueueTask +If you have an existing project which used the `WorkflowEmbargoExpiryExtension`, then you will need to go through a +couple of migration steps. -It also allows for an optional subsequent expiry date. Note: Changes to these dates also constitute modifications to the content and as such -are subject to the same workflow approval processes, where a particular workflow instance is in effect. The embargo export functionality can also be used independently of any workflow. +1) Update usages of `WorkflowEmbargoExpiryExtension` to `EmbargoExpiryExtension` (from the Terraformers module) +2) Run the `EmbargoExpiryMigrationTask` to migrate over any existing Workflow jobs to the new Terraformers' jobs + * This task will require you to define some basic configuration where you tell us what classes you have applied the + `EmbargoExpiryExtension` to. Other than that, you just need to run it + * See the class for more info ### Sending reminder emails @@ -57,4 +56,4 @@ Periodically run the Workflow Reminder Task by adding a task like this one to th This is an example only. The key is to run the task as the same user as the web server. -You can run the task manually for testing by visiting the `/dev/tasks/WorkflowReminderTask` URL of your site. \ No newline at end of file +You can run the task manually for testing by visiting the `/dev/tasks/WorkflowReminderTask` URL of your site. diff --git a/lang/ar.yml b/lang/ar.yml index 096c80e6..e9bc02bf 100644 --- a/lang/ar.yml +++ b/lang/ar.yml @@ -161,18 +161,8 @@ ar: WORKFLOW: 'سير العمل' WORKFLOWACTIVEIINSTANCES: 'أمثلة مهام سير العمل النشطة' WORKFLOWCOMPLETEDIINSTANCES: 'حالات مهام سير العمل المكتملة' - WorkflowEmbargoExpiryExtension: ActiveWorkflowStateTitle: نشط CompletedWorkflowStateTitle: أكتمل - PUBLISH_ON: 'موعد النشر المحدد' - REQUESTED_PUBLISH_DATE: 'موعد النشر المطلوب' - REQUESTED_PUBLISH_DATE_H3: 'انتهاء الصلاحية و الحظر' - REQUESTED_PUBLISH_DATE_INTRO: 'قم بإدخال تاريخ و/أو وقت لتحديد موعد الحظر و مواعيد انتهاء الصلاحية.' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: 'هذه الإعدادات لن تنفذ حتى يتم اتخاذ إجراءات الموافقة' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: 'إذا تم بالفعل تطبيق الحظر, فإن إضافة موعد حظر جديد قبل هذا الموعد سوف يقوم باستبدال هذا الموعد' - REQUESTED_UNPUBLISH_DATE: 'موعد مطلوب لعدم النشر' - TabTitle: 'نشر الجدول الزمني' - UNPUBLISH_ON: 'موعد محدد لعد النشر' WorkflowField: AddTransitionAction: 'أضف انتقال' CreateAction: 'قم بعمل نشاط' diff --git a/lang/de.yml b/lang/de.yml index 3a1ad6fb..fd88686f 100644 --- a/lang/de.yml +++ b/lang/de.yml @@ -155,16 +155,11 @@ de: WORKFLOW: Arbeitsablauf WORKFLOWACTIVEIINSTANCES: 'Aktive Arbeitsablaufinstanzen' WORKFLOWCOMPLETEDIINSTANCES: 'Abgeschlossene Arbeitsablaufinstanzen' + ActiveWorkflowStateTitle: Aktiv + CompletedWorkflowStateTitle: Fertiggestellt WorkflowDefinitionImporter: INVALID_YML_FORMAT_NO_HEADER: 'Ungültiges YAML-Format.' INVALID_YML_FORMAT_NO_PARSE: 'Ungültiges YAML-Format. Kann nicht eingelesen werden.' - WorkflowEmbargoExpiryExtension: - ActiveWorkflowStateTitle: Aktiv - CompletedWorkflowStateTitle: Fertiggestellt - PUBLISH_ON: 'Geplantes Veröffentlichungsdatum' - REQUESTED_PUBLISH_DATE: 'Gewünschtes Veröffentlichungsdatum' - REQUESTED_PUBLISH_DATE_H3: 'Ablauf und Embargo' - TabTitle: Veröffentlichungsplan WorkflowField: AddTransitionAction: 'Übergang hinzufügen' CreateAction: 'Aktion erstellen' diff --git a/lang/en.yml b/lang/en.yml index 7a722582..97ff869b 100755 --- a/lang/en.yml +++ b/lang/en.yml @@ -213,14 +213,6 @@ en: Symbiote\AdvancedWorkflow\Extensions\WorkflowApplicable: has_one_WorkflowDefinition: 'Workflow definition' many_many_AdditionalWorkflowDefinitions: 'Additional workflow definitions' - Symbiote\AdvancedWorkflow\Extensions\WorkflowEmbargoExpiryExtension: - db_AllowEmbargoedEditing: 'Allow embargoed editing' - db_DesiredPublishDate: 'Desired publish date' - db_DesiredUnPublishDate: 'Desired un publish date' - db_PublishOnDate: 'Publish on date' - db_UnPublishOnDate: 'Un publish on date' - has_one_PublishJob: 'Publish job' - has_one_UnPublishJob: 'Un publish job' Symbiote\AdvancedWorkflow\Forms\GridField\GridFieldExportAction: Export: Export UnpublishItemWorkflowAction: @@ -269,28 +261,11 @@ en: WORKFLOW: Workflow WORKFLOWACTIVEIINSTANCES: 'Active Workflow Instances' WORKFLOWCOMPLETEDIINSTANCES: 'Completed Workflow Instances' + ActiveWorkflowStateTitle: Active + CompletedWorkflowStateTitle: Completed WorkflowDefinitionImporter: INVALID_YML_FORMAT_NO_HEADER: 'Invalid YAML format.' INVALID_YML_FORMAT_NO_PARSE: 'Invalid YAML format. Unable to parse.' - WorkflowEmbargoExpiryExtension: - ActiveWorkflowStateTitle: Active - BADGE_PUBLISH: Embargo - BADGE_PUBLISH_UNPUBLISH: Embargo+Expiry - BADGE_UNPUBLISH: Expiry - CompletedWorkflowStateTitle: Completed - INVALIDEXPIRY: 'The unpublish date cannot be before the publish date.' - INVALIDSAMEEMBARGOEXPIRY: 'The publish date and unpublish date cannot be the same.' - PUBLISH_ON: 'Scheduled publish date' - REQUESTED_PUBLISH_DATE: 'Requested publish date' - REQUESTED_PUBLISH_DATE_H3: 'Expiry and Embargo' - REQUESTED_PUBLISH_DATE_INTRO: 'Enter a date and/or time to specify embargo and expiry dates.' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: "These settings won't take effect until any approval actions are run" - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: "If an embargo is already set, adding a new one prior to that date's passing will overwrite it" - REQUESTED_PUBLISH_DATE_RIGHT_TITLE: 'To request this page to be published immediately leave the date and time fields blank' - REQUESTED_UNPUBLISH_DATE: 'Requested un-publish date' - REQUESTED_UNPUBLISH_DATE_RIGHT_TITLE: 'To request this page to never expire leave the date and time fields blank' - TabTitle: 'Publishing Schedule' - UNPUBLISH_ON: 'Scheduled un-publish date' WorkflowField: AddTransitionAction: 'Add Transition' CreateAction: 'Create an action' diff --git a/lang/eo.yml b/lang/eo.yml index 54bd691a..204a89dc 100644 --- a/lang/eo.yml +++ b/lang/eo.yml @@ -213,14 +213,6 @@ eo: Symbiote\AdvancedWorkflow\Extensions\WorkflowApplicable: has_one_WorkflowDefinition: 'Laborflua difino' many_many_AdditionalWorkflowDefinitions: 'Kromaj laborfluoj' - Symbiote\AdvancedWorkflow\Extensions\WorkflowEmbargoExpiryExtension: - db_AllowEmbargoedEditing: 'Permesi embargitan redaktadon' - db_DesiredPublishDate: 'Dezirata publikiga dato' - db_DesiredUnPublishDate: 'Dezirata malpublikiga dato' - db_PublishOnDate: 'Publikigi je dato' - db_UnPublishOnDate: 'Malpublikigi je dato' - has_one_PublishJob: 'Publikigi taskon' - has_one_UnPublishJob: 'Malpublikigi taskon' Symbiote\AdvancedWorkflow\Forms\GridField\GridFieldExportAction: Export: Eksporti UnpublishItemWorkflowAction: @@ -269,27 +261,11 @@ eo: WORKFLOW: Laborfluo WORKFLOWACTIVEIINSTANCES: 'Aktivaj laborfluaj ekzemploj' WORKFLOWCOMPLETEDIINSTANCES: 'Kompletaj laborfluaj ekzemploj' + ActiveWorkflowStateTitle: Aktiva + CompletedWorkflowStateTitle: Kompletigita WorkflowDefinitionImporter: INVALID_YML_FORMAT_NO_HEADER: 'Nevalida YAML-formato.' INVALID_YML_FORMAT_NO_PARSE: 'Nevalida YAML-formato. Ne povas analizi.' - WorkflowEmbargoExpiryExtension: - ActiveWorkflowStateTitle: Aktiva - BADGE_PUBLISH_UNPUBLISH: Embargo+eksvalidiĝo - BADGE_UNPUBLISH: Eksvalidiĝo - CompletedWorkflowStateTitle: Kompletigita - INVALIDEXPIRY: 'La dato de malpublikigo ne povas esti antaŭ la dato de publikigo.' - INVALIDSAMEEMBARGOEXPIRY: 'La dato de dato de publikigo kaj la dato demalpublikigo ne povas esti samaj.' - PUBLISH_ON: 'Planita publikiga dato' - REQUESTED_PUBLISH_DATE: 'Petita publikiga dato' - REQUESTED_PUBLISH_DATE_H3: 'Malvalidiĝo kaj embargo' - REQUESTED_PUBLISH_DATE_INTRO: 'Enigu daton kaj/aŭ horon por agordi embargan kaj malvalidiĝan datojn.' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: 'Tiuj agordoj ekefikos nur kiam eventualaj agoj estas rulitaj' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: 'Se embargo jam estas agordita, aldoni novan antaŭ la paso de ties dato anstataŭos ĝin' - REQUESTED_PUBLISH_DATE_RIGHT_TITLE: 'Por peti ke ĉi tiu paĝo tuj publikiĝu lasu vakaj la datan kaj horan kampojn' - REQUESTED_UNPUBLISH_DATE: 'Petita malpublikiga dato' - REQUESTED_UNPUBLISH_DATE_RIGHT_TITLE: 'Por peti ke ĉi tiu paĝo neniam eksvalidiĝu lasu vakaj la datan kaj horan kampojn' - TabTitle: 'Publikiga plano' - UNPUBLISH_ON: 'Planita malpublikiga dato' WorkflowField: AddTransitionAction: 'Aldoni transiron' CreateAction: 'Krei agon' @@ -300,6 +276,7 @@ eo: ActionLogTitle: Protokolo EXECUTE_EXCEPTION: 'Provis startigi nevalidan laborfluan ekzemplon #%s!' REASSIGN_HEADER: 'Reagordi laborfluon' + TITLE_FOR_DO: '%s - %s' TITLE_STUB: 'Ekzemplo #%s el %s' TargetClassLabel: 'Cela klaso' TargetIDLabel: Celo diff --git a/lang/es.yml b/lang/es.yml index fcef950a..0e86f9c7 100644 --- a/lang/es.yml +++ b/lang/es.yml @@ -165,21 +165,11 @@ es: WORKFLOW: 'Flujo de trabajo' WORKFLOWACTIVEIINSTANCES: 'Instancias activas de flujo de trabajo' WORKFLOWCOMPLETEDIINSTANCES: 'Instancias del flujo de trabajo completadas' + ActiveWorkflowStateTitle: Activo + CompletedWorkflowStateTitle: Completo WorkflowDefinitionImporter: INVALID_YML_FORMAT_NO_HEADER: 'Formato YAML inválido.' INVALID_YML_FORMAT_NO_PARSE: 'Formato YAML inválido. Imposible analizar.' - WorkflowEmbargoExpiryExtension: - ActiveWorkflowStateTitle: Activo - CompletedWorkflowStateTitle: Completo - PUBLISH_ON: 'Fecha prevista de publicación' - REQUESTED_PUBLISH_DATE: 'Fecha solicitada de publicación' - REQUESTED_PUBLISH_DATE_H3: 'Caducidad y Embargo' - REQUESTED_PUBLISH_DATE_INTRO: 'Ingresar una fecha y/u hora para especificar las fechas de embargo y caducidad.' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: 'Estos parámetros no tendrán efecto hasta que se ejecuten las acciones de aprobación' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: 'Si ya se estableció un embargo, agregar uno nuevo antes que pase esa fecha, lo sobrescribirá.' - REQUESTED_UNPUBLISH_DATE: 'Fecha solicitada para anular la publicación' - TabTitle: 'Horario de publicación' - UNPUBLISH_ON: 'Fecha prevista para anular la publicación' WorkflowField: AddTransitionAction: 'Agregar transición' CreateAction: 'Crear una acción' diff --git a/lang/fi_FI.yml b/lang/fi_FI.yml index 3f20dc40..3f9fe553 100644 --- a/lang/fi_FI.yml +++ b/lang/fi_FI.yml @@ -58,7 +58,6 @@ fi_FI: WorkflowDefinition: DESCRIPTION: Kuvaus TITLE: Otsikko - WorkflowEmbargoExpiryExtension: ActiveWorkflowStateTitle: Aktiivinen CompletedWorkflowStateTitle: Valmistunut WorkflowField: diff --git a/lang/id.yml b/lang/id.yml index 083fac52..62edf536 100644 --- a/lang/id.yml +++ b/lang/id.yml @@ -65,7 +65,6 @@ id: WorkflowDefinition: DESCRIPTION: Deskripsi TITLE: Judul - WorkflowEmbargoExpiryExtension: ActiveWorkflowStateTitle: Aktif WorkflowField: CreateLabel: Buat diff --git a/lang/it.yml b/lang/it.yml index 54de7cf3..3997a124 100644 --- a/lang/it.yml +++ b/lang/it.yml @@ -110,12 +110,11 @@ it: TITLE: Titolo USERS: 'Ristretto agli Utenti' WORKFLOW: 'Flusso di lavoro' + ActiveWorkflowStateTitle: Attivo + CompletedWorkflowStateTitle: Completato WorkflowDefinitionImporter: INVALID_YML_FORMAT_NO_HEADER: 'Formatto YAML non valido' INVALID_YML_FORMAT_NO_PARSE: 'Formatto YAML non valido. Impossibile fare il parse.' - WorkflowEmbargoExpiryExtension: - ActiveWorkflowStateTitle: Attivo - CompletedWorkflowStateTitle: Completato WorkflowField: AddTransitionAction: 'Aggiungi Transazione' CreateAction: 'Crea un azione' diff --git a/lang/mi.yml b/lang/mi.yml index 40e9a37d..e523d2f6 100644 --- a/lang/mi.yml +++ b/lang/mi.yml @@ -157,18 +157,8 @@ mi: WORKFLOW: Reremahi WORKFLOWACTIVEIINSTANCES: 'Ngā Tauira Reremahi Hohe' WORKFLOWCOMPLETEDIINSTANCES: 'Ngā Tauira Reremahi Oti' - WorkflowEmbargoExpiryExtension: ActiveWorkflowStateTitle: Hohe CompletedWorkflowStateTitle: 'Kua Oti' - PUBLISH_ON: 'Rā whakaputa kua whakaritea' - REQUESTED_PUBLISH_DATE: 'I tonoa te rā whakaputa' - REQUESTED_PUBLISH_DATE_H3: 'Mōnehutanga me te Rāhui' - REQUESTED_PUBLISH_DATE_INTRO: 'Tāurua he rā, he wā hoki/rānei hei whakarite rā rāhui me te mōnehu.' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: 'Kāore ēnei tautuhinga e whai mana kia whakahaeretia rā anō ngā hohenga whakaaetanga' - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: 'Mēnā kua tautuhi kētia tētahi rāhuitanga, ka tuhiruatia mā te tāpiri i te mea hou i mua i te hipa o taua rā' - REQUESTED_UNPUBLISH_DATE: 'I tonoa te rā wetewhakaputa' - TabTitle: 'Hōtaka Whakaputa' - UNPUBLISH_ON: 'Rā wetewhakaputa kua whakaritea' WorkflowField: AddTransitionAction: 'Tāpiri Whakawhiti' CreateAction: 'Hangaia he hohenga' diff --git a/lang/sv.yml b/lang/sv.yml index 822a78db..0d96f076 100644 --- a/lang/sv.yml +++ b/lang/sv.yml @@ -60,8 +60,6 @@ sv: WorkflowDefinition: DESCRIPTION: Beskrivning TITLE: Titel - WorkflowEmbargoExpiryExtension: - BADGE_UNPUBLISH: 'Går ut' WorkflowField: CreateLabel: Skapa DeleteAction: Radera diff --git a/lang/zh.yml b/lang/zh.yml index 05b42c29..8dfc76ae 100644 --- a/lang/zh.yml +++ b/lang/zh.yml @@ -161,18 +161,8 @@ zh: WORKFLOW: 工作流 WORKFLOWACTIVEIINSTANCES: 活动的工作流实例 WORKFLOWCOMPLETEDIINSTANCES: 完成的工作流实例 - WorkflowEmbargoExpiryExtension: ActiveWorkflowStateTitle: 活跃的 CompletedWorkflowStateTitle: 已完成 - PUBLISH_ON: 安排的发布日期 - REQUESTED_PUBLISH_DATE: 请求的发布日期 - REQUESTED_PUBLISH_DATE_H3: 到期和禁止 - REQUESTED_PUBLISH_DATE_INTRO: 欲指定禁止和到期日,请输入一个日期和/或时间。 - REQUESTED_PUBLISH_DATE_INTRO_BULLET_1: 批准动作执行之前,这些设置不会生效 - REQUESTED_PUBLISH_DATE_INTRO_BULLET_2: 如果已经设置了禁令,在该日期之前添加新的可覆盖该设置 - REQUESTED_UNPUBLISH_DATE: 请求未发布的日期 - TabTitle: 发布日程表 - UNPUBLISH_ON: 安排未发布的日期 WorkflowField: AddTransitionAction: 添加转换 CreateAction: 制定计划 diff --git a/src/Actions/PublishItemWorkflowAction.php b/src/Actions/PublishItemWorkflowAction.php index 2bbb2286..aa7bf721 100644 --- a/src/Actions/PublishItemWorkflowAction.php +++ b/src/Actions/PublishItemWorkflowAction.php @@ -2,17 +2,12 @@ namespace Symbiote\AdvancedWorkflow\Actions; -use SilverStripe\Forms\CheckboxField; -use SilverStripe\Forms\FieldGroup; -use SilverStripe\Forms\LabelField; use SilverStripe\Forms\NumericField; use SilverStripe\ORM\DataObject; +use SilverStripe\Versioned\Versioned; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowAction; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowInstance; -use Symbiote\AdvancedWorkflow\Extensions\WorkflowEmbargoExpiryExtension; -use Symbiote\AdvancedWorkflow\Jobs\WorkflowPublishTargetJob; -use Symbiote\QueuedJobs\Services\AbstractQueuedJob; -use Symbiote\QueuedJobs\Services\QueuedJobService; +use Terraformers\EmbargoExpiry\Extension\EmbargoExpiryExtension; /** * Publishes an item @@ -21,17 +16,13 @@ * @license BSD License (http://silverstripe.org/bsd-license/) * @package advancedworkflow * @subpackage actions + * @property int $PublishDelay */ class PublishItemWorkflowAction extends WorkflowAction { - private static $db = array( - 'PublishDelay' => 'Int', - 'AllowEmbargoedEditing' => 'Boolean', - ); - - private static $defaults = array( - 'AllowEmbargoedEditing' => true - ); + private static $db = [ + 'PublishDelay' => 'Int', + ]; private static $icon = 'symbiote/silverstripe-advancedworkflow:images/publish.png'; @@ -39,50 +30,19 @@ class PublishItemWorkflowAction extends WorkflowAction public function execute(WorkflowInstance $workflow) { - if (!$target = $workflow->getTarget()) { + $target = $workflow->getTarget(); + + if (!$target) { return true; } - if (class_exists(AbstractQueuedJob::class) && $this->PublishDelay) { - $job = new WorkflowPublishTargetJob($target); - $days = $this->PublishDelay; - $after = date('Y-m-d H:i:s', strtotime("+$days days")); - - // disable editing, and embargo the delay if using WorkflowEmbargoExpiryExtension - if ($target->hasExtension(WorkflowEmbargoExpiryExtension::class)) { - $target->AllowEmbargoedEditing = $this->AllowEmbargoedEditing; - $target->PublishOnDate = $after; - $target->write(); - } else { - singleton(QueuedJobService::class)->queueJob($job, $after); - } - } elseif ($target->hasExtension(WorkflowEmbargoExpiryExtension::class)) { - $target->AllowEmbargoedEditing = $this->AllowEmbargoedEditing; - // setting future date stuff if needbe - - // set this value regardless - $target->UnPublishOnDate = $target->DesiredUnPublishDate; - $target->DesiredUnPublishDate = ''; - - // Publish dates - if ($target->DesiredPublishDate) { - // Hand-off desired publish date - $target->PublishOnDate = $target->DesiredPublishDate; - $target->DesiredPublishDate = ''; - $target->write(); - } else { - // Ensure previously modified DesiredUnPublishDate values are written - $target->write(); - if ($target->hasMethod('publishRecursive')) { - $target->publishRecursive(); - $this->extend('onAfterWorkflowPublish', $target); - } - } - } else { - if ($target->hasMethod('publishRecursive')) { - $target->publishRecursive(); - $this->extend('onAfterWorkflowPublish', $target); - } + if ($this->targetRequestsDelayedAction($target)) { + $this->queueEmbargoExpiryJobs($target); + + $target->write(); + } elseif ($target->hasExtension(Versioned::class)) { + /** @var DataObject|Versioned $target */ + $target->publishRecursive(); } return true; @@ -92,15 +52,11 @@ public function getCMSFields() { $fields = parent::getCMSFields(); - if (class_exists(AbstractQueuedJob::class)) { - $fields->addFieldsToTab('Root.Main', [ - CheckboxField::create( - 'AllowEmbargoedEditing', - _t( - __CLASS__ . '.ALLOWEMBARGOEDEDITING', - 'Allow editing while item is embargoed? (does not apply without embargo)' - ) - ), + // We don't have access to our Target in this context, so we'll just perform a sanity check to see if the + // Embargo & Expiry module is (generally) present + if (class_exists(EmbargoExpiryExtension::class)) { + $fields->addFieldToTab( + 'Root.Main', NumericField::create( 'PublishDelay', _t('PublishItemWorkflowAction.PUBLICATIONDELAY', 'Publication Delay') @@ -108,7 +64,7 @@ public function getCMSFields() __CLASS__ . '.PublicationDelayDescription', 'Delay publiation by the specified number of days' )) - ]); + ); } return $fields; @@ -124,4 +80,57 @@ public function canPublishTarget(DataObject $target) { return true; } + + /** + * @param DataObject|EmbargoExpiryExtension $target + */ + public function targetRequestsDelayedAction(DataObject $target): bool + { + // Delayed actions are only supported if the Embargo & Expiry module is present for the Target + if (!$this->targetHasEmbargoExpiryModules($target)) { + // E&E is not present on the target, so it cannot have delayed actions + return false; + } + + // Check to see if the Target has requested an embargo or expiry time + if ($target->getDesiredPublishDateAsTimestamp() > 0 + || $target->getDesiredUnPublishDateAsTimestamp() > 0 + ) { + // One (or both) have been requested + return true; + } + + // For Publish workflow actions, we'll also check if the reviewer set a PublishDelay + if ($this->PublishDelay) { + return true; + } + + // No embargo, expiry, or delay was requested + return false; + } + + /** + * @param DataObject|EmbargoExpiryExtension $target + */ + public function queueEmbargoExpiryJobs(DataObject $target): void + { + // Can't queue any jobs if we're missing the Embargo & Expiry module + if (!$this->targetHasEmbargoExpiryModules($target)) { + return; + } + + // Queue UnPublishJob if it's required + $target->ensureUnPublishJob(); + + // Queue PublishJob if it's required. PublishDelay always take priority over DesiredPublishDate, so exit early + // if we queue a job here + if ($this->PublishDelay) { + $target->createOrUpdatePublishJob(strtotime("+{$this->PublishDelay} days")); + + return; + } + + // Queue PublishJob if it's required + $target->ensurePublishJob(); + } } diff --git a/src/Actions/UnpublishItemWorkflowAction.php b/src/Actions/UnpublishItemWorkflowAction.php index d3903cfa..6f86ef53 100644 --- a/src/Actions/UnpublishItemWorkflowAction.php +++ b/src/Actions/UnpublishItemWorkflowAction.php @@ -6,26 +6,25 @@ use SilverStripe\Forms\LabelField; use SilverStripe\Forms\NumericField; use SilverStripe\ORM\DataObject; +use SilverStripe\Versioned\Versioned; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowAction; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowInstance; -use Symbiote\AdvancedWorkflow\Extensions\WorkflowEmbargoExpiryExtension; -use Symbiote\AdvancedWorkflow\Jobs\WorkflowPublishTargetJob; -use Symbiote\QueuedJobs\Services\AbstractQueuedJob; -use Symbiote\QueuedJobs\Services\QueuedJobService; +use Terraformers\EmbargoExpiry\Extension\EmbargoExpiryExtension; /** - * Unpublishes an item + * Unpublishes an item or approves it for publishing/un-publishing through queued jobs. * * @author marcus@symbiote.com.au * @license BSD License (http://silverstripe.org/bsd-license/) * @package advancedworkflow * @subpackage actions + * @property int $UnpublishDelay */ class UnpublishItemWorkflowAction extends WorkflowAction { - private static $db = array( - 'UnpublishDelay' => 'Int' - ); + private static $db = [ + 'UnpublishDelay' => 'Int', + ]; private static $icon = 'symbiote/silverstripe-advancedworkflow:images/unpublish.png'; @@ -33,30 +32,19 @@ class UnpublishItemWorkflowAction extends WorkflowAction public function execute(WorkflowInstance $workflow) { - if (!$target = $workflow->getTarget()) { + $target = $workflow->getTarget(); + + if (!$target) { return true; } - if (class_exists(AbstractQueuedJob::class) && $this->UnpublishDelay) { - $job = new WorkflowPublishTargetJob($target, "unpublish"); - $days = $this->UnpublishDelay; - $after = date('Y-m-d H:i:s', strtotime("+$days days")); - singleton(QueuedJobService::class)->queueJob($job, $after); - } elseif ($target->hasExtension(WorkflowEmbargoExpiryExtension::class)) { - // setting future date stuff if needbe - - // set these values regardless - $target->DesiredUnPublishDate = ''; - $target->DesiredPublishDate = ''; - $target->write(); + if ($this->targetRequestsDelayedAction($target)) { + $this->queueEmbargoExpiryJobs($target); - if ($target->hasMethod('doUnpublish')) { - $target->doUnpublish(); - } - } else { - if ($target->hasMethod('doUnpublish')) { - $target->doUnpublish(); - } + $target->write(); + } elseif ($target->hasExtension(Versioned::class)) { + /** @var DataObject|Versioned $target */ + $target->doUnpublish(); } return true; @@ -66,7 +54,9 @@ public function getCMSFields() { $fields = parent::getCMSFields(); - if (class_exists(AbstractQueuedJob::class)) { + // We don't have access to our Target in this context, so we'll just perform a sanity check to see if the + // Embargo & Expiry module is (generally) present + if (class_exists(EmbargoExpiryExtension::class)) { $before = _t('UnpublishItemWorkflowAction.DELAYUNPUBDAYSBEFORE', 'Delay unpublishing by '); $after = _t('UnpublishItemWorkflowAction.DELAYUNPUBDAYSAFTER', ' days'); @@ -89,4 +79,51 @@ public function canPublishTarget(DataObject $target) { return false; } + + /** + * @param DataObject|EmbargoExpiryExtension $target + */ + public function targetRequestsDelayedAction(DataObject $target) + { + if (!$this->targetHasEmbargoExpiryModules($target)) { + return false; + } + + if ($target->getDesiredPublishDateAsTimestamp() > 0 + || $target->getDesiredUnPublishDateAsTimestamp() > 0 + ) { + return true; + } + + if ($this->UnpublishDelay) { + return true; + } + + return false; + } + + /** + * @param DataObject|EmbargoExpiryExtension $target + */ + public function queueEmbargoExpiryJobs(DataObject $target): void + { + // Can't queue any jobs if we're missing the Embargo & Expiry module + if (!$this->targetHasEmbargoExpiryModules($target)) { + return; + } + + // Queue PublishJob if it's required + $target->ensurePublishJob(); + + // Queue UnPublishJob if it's required. UnpublishDelay always take priority over DesiredUnPublishDate, so exit + // early if we queue a job here + if ($this->UnpublishDelay) { + $target->createOrUpdateUnPublishJob(strtotime("+{$this->UnpublishDelay} days")); + + return; + } + + // Queue UnPublishJob if it's required + $target->ensureUnPublishJob(); + } } diff --git a/src/DataObjects/WorkflowAction.php b/src/DataObjects/WorkflowAction.php index d962f6a7..a800347e 100644 --- a/src/DataObjects/WorkflowAction.php +++ b/src/DataObjects/WorkflowAction.php @@ -16,6 +16,7 @@ use SilverStripe\Security\Member; use SilverStripe\Security\Permission; use SilverStripe\Security\Security; +use Terraformers\EmbargoExpiry\Extension\EmbargoExpiryExtension; /** * A workflow action describes a the 'state' a workflow can be in, and @@ -310,4 +311,13 @@ public function Icon() $icon = $this->config()->get('icon'); return ModuleResourceLoader::singleton()->resolveURL($icon); } + + public function targetHasEmbargoExpiryModules(?DataObject $target): bool + { + if (!$target) { + return false; + } + + return $target->hasExtension(EmbargoExpiryExtension::class); + } } diff --git a/src/DataObjects/WorkflowDefinition.php b/src/DataObjects/WorkflowDefinition.php index 3c10baac..45c66860 100644 --- a/src/DataObjects/WorkflowDefinition.php +++ b/src/DataObjects/WorkflowDefinition.php @@ -382,13 +382,13 @@ public function getCMSFields() $fields->findOrMakeTab( 'Root.Active', - _t('WorkflowEmbargoExpiryExtension.ActiveWorkflowStateTitle', 'Active') + _t('WorkflowDefinition.ActiveWorkflowStateTitle', 'Active') ); $fields->addFieldToTab('Root.Active', $active); $fields->findOrMakeTab( 'Root.Completed', - _t('WorkflowEmbargoExpiryExtension.CompletedWorkflowStateTitle', 'Completed') + _t('WorkflowDefinition.CompletedWorkflowStateTitle', 'Completed') ); $fields->addFieldToTab('Root.Completed', $completed); } diff --git a/src/Extensions/WorkflowApplicable.php b/src/Extensions/WorkflowApplicable.php index 65142a95..37a84595 100644 --- a/src/Extensions/WorkflowApplicable.php +++ b/src/Extensions/WorkflowApplicable.php @@ -27,7 +27,8 @@ use Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowInstance; use Symbiote\AdvancedWorkflow\Services\WorkflowService; -use Symbiote\QueuedJobs\Services\AbstractQueuedJob; +use Terraformers\EmbargoExpiry\Extension\EmbargoExpiryExtension; +use Terraformers\EmbargoExpiry\Job\State\ActionProcessingState; /** * DataObjects that have the WorkflowApplicable extension can have a @@ -37,7 +38,8 @@ * @author marcus@symbiote.com.au * @license BSD License (http://silverstripe.org/bsd-license/) * @package advancedworkflow - * + * @property DataObject|EmbargoExpiryExtension|$this $owner + * @property int $WorkflowDefinitionID * @method WorkflowDefinition WorkflowDefinition() * @method ManyManyList AdditionalWorkflowDefinitions() * @@ -57,49 +59,12 @@ class WorkflowApplicable extends DataExtension 'workflowService' => '%$' . WorkflowService::class, ]; - /** - * - * Used to flag to this extension if there's a WorkflowPublishTargetJob running. - * @var boolean - */ - public $isPublishJobRunning = false; - - /** - * - * @param boolean $truth - */ - public function setIsPublishJobRunning($truth) - { - $this->isPublishJobRunning = $truth; - } - - /** - * - * @return boolean - */ - public function getIsPublishJobRunning() - { - return $this->isPublishJobRunning; - } - - /** - * - * @see {@link $this->isPublishJobRunning} - * @return boolean - */ - public function isPublishJobRunning() - { - $propIsSet = (bool) $this->getIsPublishJobRunning(); - return class_exists(AbstractQueuedJob::class) && $propIsSet; - } - /** * @var WorkflowService */ public $workflowService; /** - * * A cache var for the current workflow instance * * @var WorkflowInstance @@ -128,7 +93,7 @@ public function updateCMSFields(FieldList $fields) public function updateFields(FieldList $fields) { if (!$this->owner->ID) { - return $fields; + return; } $tab = $fields->fieldByName('Root') ? $fields->findOrMakeTab('Root.Workflow') : $fields; @@ -328,8 +293,9 @@ public function LinkToPendingItems() public function onAfterWrite() { $instance = $this->getWorkflowInstance(); + if ($instance && $instance->CurrentActionID) { - $action = $instance->CurrentAction()->BaseAction()->targetUpdated($instance); + $instance->CurrentAction()->BaseAction()->targetUpdated($instance); } } @@ -391,12 +357,13 @@ public function RecentWorkflowComment($limit = 10) public function canPublish() { // Override any default behaviour, to allow queuedjobs to complete - if ($this->isPublishJobRunning()) { + if ($this->isEmbargoExpiryJobRunning()) { return true; } if ($active = $this->getWorkflowInstance()) { - $publish = $active->canPublishTarget($this->owner); + $publish = $active->canPublishTarget(); + if (!is_null($publish)) { return $publish; } @@ -409,29 +376,46 @@ public function canPublish() if (!Security::getCurrentUser()) { return false; } + $member = Security::getCurrentUser(); $canPublish = $definition->canWorkflowPublish($member, $this->owner); return $canPublish; } + + // Don't affect the canPublish() result one way or the other + return null; } /** * Can only edit content that's NOT in another person's content changeset * - * @return bool + * @return bool|null */ public function canEdit($member) { // Override any default behaviour, to allow queuedjobs to complete - if ($this->isPublishJobRunning()) { + if ($this->owner->isEmbargoExpiryJobRunning()) { return true; } if ($active = $this->getWorkflowInstance()) { return $active->canEditTarget(); } + + // Don't affect the canEdit() result one way or the other + return null; + } + + public function isEmbargoExpiryJobRunning(): bool + { + // Can't be running any Embargo/Expiry jobs if the Extension isn't present on the $owner + if (!$this->owner->hasExtension(EmbargoExpiryExtension::class)) { + return false; + } + + return ActionProcessingState::singleton()->getActionIsProcessing(); } /** @@ -442,9 +426,11 @@ public function canEdit($member) public function canEditWorkflow() { $active = $this->getWorkflowInstance(); + if ($active) { return $active->canEdit(); } + return false; } @@ -455,6 +441,7 @@ public function canEditWorkflow() public function setWorkflowService(WorkflowService $workflowService) { $this->workflowService = $workflowService; + return $this; } @@ -465,4 +452,16 @@ public function getWorkflowService() { return $this->workflowService; } + + public function preventEmbargoExpiryQueueJobs(): bool + { + // If there is an active WorkflowInstance, then we don't want to allow Embargo & Expiry to queue jobs. We'll do + // that ourselves later + if ($this->getWorkflowInstance()) { + return true; + } + + // Similarly, if there is any assigned WorkflowDefinition, then we don't want to queue Jobs in this way + return (bool) $this->getWorkflowService()->getDefinitionFor($this->owner); + } } diff --git a/src/Extensions/WorkflowEmbargoExpiryExtension.php b/src/Extensions/WorkflowEmbargoExpiryExtension.php deleted file mode 100644 index d05242c8..00000000 --- a/src/Extensions/WorkflowEmbargoExpiryExtension.php +++ /dev/null @@ -1,587 +0,0 @@ - - */ -class WorkflowEmbargoExpiryExtension extends DataExtension -{ - private static $db = array( - 'DesiredPublishDate' => 'DBDatetime', - 'DesiredUnPublishDate' => 'DBDatetime', - 'PublishOnDate' => 'DBDatetime', - 'UnPublishOnDate' => 'DBDatetime', - 'AllowEmbargoedEditing' => 'Boolean', - ); - - private static $has_one = array( - 'PublishJob' => QueuedJobDescriptor::class, - 'UnPublishJob' => QueuedJobDescriptor::class, - ); - - private static $dependencies = array( - 'workflowService' => '%$' . WorkflowService::class, - ); - - private static $defaults = array( - 'AllowEmbargoedEditing' => true - ); - - /** - * @var WorkflowService - */ - protected $workflowService; - - /** - * Is a workflow in effect? - * - * @var bool - */ - public $isWorkflowInEffect = false; - - /** - * A basic extended validation routine method return format - * - * @var array - */ - public static $extendedMethodReturn = array( - 'fieldName' => null, - 'fieldField' => null, - 'fieldMsg' => null, - 'fieldValid' => true, - ); - - /** - * @param FieldList $fields - */ - public function updateCMSFields(FieldList $fields) - { - // requirements - // ------------ - $module = 'symbiote/silverstripe-advancedworkflow'; - Requirements::add_i18n_javascript($module . ':client/lang'); - Requirements::css($module . ':client/dist/styles/advancedworkflow.css'); - Requirements::javascript($module . ':client/dist/js/advancedworkflow.js'); - - // Fields - // ------ - - // we never show these explicitly in admin - $fields->removeByName('PublishJobID'); - $fields->removeByName('UnPublishJobID'); - - $this->setIsWorkflowInEffect(); - - $fields->findOrMakeTab( - 'Root.PublishingSchedule', - _t('WorkflowEmbargoExpiryExtension.TabTitle', 'Publishing Schedule') - ); - if ($this->getIsWorkflowInEffect()) { - // add fields we want in this context - $fields->addFieldsToTab('Root.PublishingSchedule', array( - HeaderField::create( - 'PublishDateHeader', - _t('WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_H3', 'Expiry and Embargo'), - 3 - ), - LiteralField::create('PublishDateIntro', $this->getIntroMessage('PublishDateIntro')), - $dt = DatetimeField::create( - 'DesiredPublishDate', - _t('WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE', 'Requested publish date') - )->setRightTitle( - DBHTMLText::create()->setValue(_t( - 'WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_RIGHT_TITLE', - 'To request this page to be published immediately ' - . 'leave the date and time fields blank' - )) - ), - $ut = DatetimeField::create( - 'DesiredUnPublishDate', - _t('WorkflowEmbargoExpiryExtension.REQUESTED_UNPUBLISH_DATE', 'Requested un-publish date') - )->setRightTitle( - DBHTMLText::create()->setValue(_t( - 'WorkflowEmbargoExpiryExtension.REQUESTED_UNPUBLISH_DATE_RIGHT_TITLE', - 'To request this page to never expire leave the date and time fields blank' - )) - ), - DatetimeField::create( - 'PublishOnDate', - _t('WorkflowEmbargoExpiryExtension.PUBLISH_ON', 'Scheduled publish date') - )->setDisabled(true), - DatetimeField::create( - 'UnPublishOnDate', - _t('WorkflowEmbargoExpiryExtension.UNPUBLISH_ON', 'Scheduled un-publish date') - )->setDisabled(true) - )); - } else { - // remove fields that have been automatically added that we don't want - $fields->removeByName('DesiredPublishDate'); - $fields->removeByName('DesiredUnPublishDate'); - - // add fields we want in this context - $fields->addFieldsToTab('Root.PublishingSchedule', array( - HeaderField::create( - 'PublishDateHeader', - _t('WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_H3', 'Expiry and Embargo'), - 3 - ), - LiteralField::create('PublishDateIntro', $this->getIntroMessage('PublishDateIntro')), - $dt = DatetimeField::create( - 'PublishOnDate', - _t('WorkflowEmbargoExpiryExtension.PUBLISH_ON', 'Scheduled publish date') - ), - $ut = DatetimeField::create( - 'UnPublishOnDate', - _t('WorkflowEmbargoExpiryExtension.UNPUBLISH_ON', 'Scheduled un-publish date') - ), - )); - } - } - - /** - * Clears any existing publish job against this dataobject - */ - public function clearPublishJob() - { - $job = $this->owner->PublishJob(); - if ($job && $job->exists() && !$job->JobFinished) { - $job->delete(); - } - $this->owner->PublishJobID = 0; - } - - /** - * Clears any existing unpublish job - */ - public function clearUnPublishJob() - { - // Cancel any in-progress unpublish job - $job = $this->owner->UnPublishJob(); - if ($job && $job->exists() && !$job->JobFinished) { - $job->delete(); - } - $this->owner->UnPublishJobID = 0; - } - - /** - * Ensure the existence of a publish job at the specified time - * - * @param int $when Timestamp to start this job, or null to start immediately - */ - protected function ensurePublishJob($when) - { - // Check if there is a prior job - if ($this->owner->PublishJobID) { - $job = $this->owner->PublishJob(); - // Use timestamp for sake of comparison. - if ($job && $job->exists() && DBDatetime::create()->setValue($job->StartAfter)->getTimestamp() == $when) { - return; - } - $this->clearPublishJob(); - } - - // Create a new job with the specified schedule - $job = new WorkflowPublishTargetJob($this->owner, 'publish'); - $this->owner->PublishJobID = Injector::inst()->get(QueuedJobService::class) - ->queueJob($job, $when ? date('Y-m-d H:i:s', $when) : null); - } - - /** - * Ensure the existence of an unpublish job at the specified time - * - * @param int $when Timestamp to start this job, or null to start immediately - */ - protected function ensureUnPublishJob($when) - { - // Check if there is a prior job - if ($this->owner->UnPublishJobID) { - $job = $this->owner->UnPublishJob(); - // Use timestamp for sake of comparison. - if ($job && $job->exists() && DBDatetime::create()->setValue($job->StartAfter)->getTimestamp() == $when) { - return; - } - $this->clearUnPublishJob(); - } - - // Create a new job with the specified schedule - $job = new WorkflowPublishTargetJob($this->owner, 'unpublish'); - $this->owner->UnPublishJobID = Injector::inst()->get(QueuedJobService::class) - ->queueJob($job, $when ? date('Y-m-d H:i:s', $when) : null); - } - - public function onBeforeDuplicate($original, $doWrite) - { - $clone = $this->owner; - - $clone->PublishOnDate = null; - $clone->UnPublishOnDate = null; - $clone->clearPublishJob(); - $clone->clearUnPublishJob(); - } - - /** - * {@see PublishItemWorkflowAction} for approval of requested publish dates - */ - public function onBeforeWrite() - { - parent::onBeforeWrite(); - - // only operate on staging content for this extension; otherwise, you - // need to publish the page to be able to set a 'future' publish... - // while the same could be said for the unpublish, the 'publish' state - // is the one that must be avoided so we allow setting the 'unpublish' - // date for as-yet-not-published content. - if (Versioned::get_stage() === Versioned::LIVE) { - return; - } - - /* - * Without checking if there's actually a workflow in effect, simply saving - * as draft, would clear the Scheduled Publish & Unpublish date fields, which we obviously - * don't want during a workflow: These date fields should be treated as a content - * change that also requires approval (where such an approval step exists). - * - * - Check to see if we've got 'desired' publish/unpublish date(s). - * - Check if there's a workflow attached to this content - * - Reset values if it's safe to do so - */ - if (!$this->getIsWorkflowInEffect()) { - $resetPublishOnDate = $this->owner->DesiredPublishDate && $this->owner->PublishOnDate; - if ($resetPublishOnDate) { - $this->owner->PublishOnDate = null; - } - - $resetUnPublishOnDate = $this->owner->DesiredUnPublishDate && $this->owner->UnPublishOnDate; - if ($resetUnPublishOnDate) { - $this->owner->UnPublishOnDate = null; - } - } - - // Jobs can only be queued for records that already exist - if (!$this->owner->ID) { - return; - } - - if ($this->owner->hasMethod('isPublishJobRunning') && $this->owner->isPublishJobRunning()) { - return; - } - - // Check requested dates of publish / unpublish, and whether the page should have already been unpublished - $now = DBDatetime::now()->getTimestamp(); - $publishTime = $this->owner->dbObject('PublishOnDate')->getTimestamp(); - $unPublishTime = $this->owner->dbObject('UnPublishOnDate')->getTimestamp(); - - // We should have a publish job if: - // if no unpublish or publish time, then the Workflow Publish Action will publish without a job - if ((!$unPublishTime && $publishTime) // the unpublish date is not set - || ( - // unpublish date has not passed - $unPublishTime > $now - // publish date not set or happens before unpublish date - && ($publishTime && ($publishTime < $unPublishTime)) - ) - ) { - // Trigger time immediately if passed - $this->ensurePublishJob($publishTime < $now ? null : $publishTime); - } else { - $this->clearPublishJob(); - } - - // We should have an unpublish job if: - if ($unPublishTime // we have an unpublish date - && - $publishTime < $unPublishTime // publish date is before to unpublish date - ) { - // Trigger time immediately if passed - $this->ensureUnPublishJob($unPublishTime < $now ? null : $unPublishTime); - } else { - $this->clearUnPublishJob(); - } - } - - /** - * Add badges to the site tree view to show that a page has been scheduled for publishing or unpublishing - * - * @param $flags - */ - public function updateStatusFlags(&$flags) - { - $embargo = $this->getIsPublishScheduled(); - $expiry = $this->getIsUnPublishScheduled(); - - if ($embargo || $expiry) { - unset($flags['addedtodraft'], $flags['modified']); - } - - if ($embargo && $expiry) { - $flags['embargo_expiry'] = array( - 'text' => _t('WorkflowEmbargoExpiryExtension.BADGE_PUBLISH_UNPUBLISH', 'Embargo+Expiry'), - 'title' => sprintf( - '%s: %s, %s: %s', - _t('WorkflowEmbargoExpiryExtension.PUBLISH_ON', 'Scheduled publish date'), - $this->owner->PublishOnDate, - _t('WorkflowEmbargoExpiryExtension.UNPUBLISH_ON', 'Scheduled un-publish date'), - $this->owner->UnPublishOnDate - ), - ); - } elseif ($embargo) { - $flags['embargo'] = array( - 'text' => _t('WorkflowEmbargoExpiryExtension.BADGE_PUBLISH', 'Embargo'), - 'title' => sprintf( - '%s: %s', - _t('WorkflowEmbargoExpiryExtension.PUBLISH_ON', 'Scheduled publish date'), - $this->owner->PublishOnDate - ), - ); - } elseif ($expiry) { - $flags['expiry'] = array( - 'text' => _t('WorkflowEmbargoExpiryExtension.BADGE_UNPUBLISH', 'Expiry'), - 'title' => sprintf( - '%s: %s', - _t('WorkflowEmbargoExpiryExtension.UNPUBLISH_ON', 'Scheduled un-publish date'), - $this->owner->UnPublishOnDate - ), - ); - } - } - - /* - * Define an array of message-parts for use by {@link getIntroMessage()} - * - * @param string $key - * @return array - */ - public function getIntroMessageParts($key) - { - $parts = array( - 'PublishDateIntro' => array( - 'INTRO'=>_t( - 'WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_INTRO', - 'Enter a date and/or time to specify embargo and expiry dates.' - ), - 'BULLET_1'=>_t( - 'WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_INTRO_BULLET_1', - 'These settings won\'t take effect until any approval actions are run' - ), - 'BULLET_2'=>_t( - 'WorkflowEmbargoExpiryExtension.REQUESTED_PUBLISH_DATE_INTRO_BULLET_2', - 'If an embargo is already set, adding a new one prior to that date\'s passing will overwrite it' - ) - ) - ); - // If there's no effective workflow, no need for the first bullet-point - if (!$this->getIsWorkflowInEffect()) { - $parts['PublishDateIntro']['BULLET_1'] = false; - } - return $parts[$key]; - } - - /* - * Display some messages to the user, a little more complex that a simple one-liner - * - * @param string $key - * @return string - */ - public function getIntroMessage($key) - { - $msg = $this->getIntroMessageParts($key); - $curr = Controller::curr(); - $msg = $curr->customise($msg)->renderWith('Includes/embargoIntro'); - return $msg; - } - - /* - * Validate - */ - public function getCMSValidator() - { - $required = new AWRequiredFields(); - $required->setCaller($this); - return $required; - } - - /** - * This is called in the AWRequiredFields class, this validates whether an Embargo and Expiry are not equal and that - * Embargo is before Expiry, returning the appropriate message when it fails. - * - * @param $data - * @return array - */ - public function extendedRequiredFieldsEmbargoExpiry($data) - { - $response = array( - 'fieldName' => 'DesiredUnPublishDate[date]', - 'fieldField' => null, - 'fieldMsg' => null, - 'fieldValid' => true - ); - - if (isset($data['DesiredPublishDate'], $data['DesiredUnPublishDate'])) { - $publish = DBDatetime::create()->setValue($data['DesiredPublishDate'])->getTimestamp(); - $unpublish = DBDatetime::create()->setValue($data['DesiredUnPublishDate'])->getTimestamp(); - - // the times are the same - if ($publish && $unpublish && $publish == $unpublish) { - $response = array_merge($response, array( - 'fieldMsg' => _t( - 'WorkflowEmbargoExpiryExtension.INVALIDSAMEEMBARGOEXPIRY', - 'The publish date and unpublish date cannot be the same.' - ), - 'fieldValid' => false - )); - } elseif ($publish && $unpublish && $publish > $unpublish) { - $response = array_merge($response, array( - 'fieldMsg' => _t( - 'WorkflowEmbargoExpiryExtension.INVALIDEXPIRY', - 'The unpublish date cannot be before the publish date.' - ), - 'fieldValid' => false - )); - } - } - - return $response; - } - - /** - * Format a date according to member/user preferences - * - * @param string $date - * @return string $date - */ - public function getUserDate($date) - { - $date = DBDatetime::create()->setValue($date); - $member = Security::getCurrentUser(); - return $date->FormatFromSettings($member); - } - - /* - * Sets property as boolean true|false if an effective workflow is found or not - */ - public function setIsWorkflowInEffect() - { - // if there is a workflow applied, we can't set the publishing date directly, only the 'desired' publishing date - $effective = $this->getWorkflowService()->getDefinitionFor($this->owner); - $this->isWorkflowInEffect = $effective ? true : false; - } - - public function getIsWorkflowInEffect() - { - return $this->isWorkflowInEffect; - } - - /** - * Returns whether a publishing date has been set and is after the current date - * - * @return bool - */ - public function getIsPublishScheduled() - { - if (!$this->owner->PublishOnDate) { - return false; - } - $now = DBDatetime::now()->getTimestamp(); - $publish = $this->owner->dbObject('PublishOnDate')->getTimestamp(); - - return $now < $publish; - } - - /** - * Returns whether an unpublishing date has been set and is after the current date - * - * @return bool - */ - public function getIsUnPublishScheduled() - { - if (!$this->owner->UnPublishOnDate) { - return false; - } - $now = DBDatetime::now()->getTimestamp(); - $unpublish = $this->owner->dbObject('UnPublishOnDate')->getTimestamp(); - - return $now < $unpublish; - } - - /** - * Add edit check for when publishing has been scheduled and if any workflow definitions want the item to be - * disabled. - * - * @param Member $member - * @return bool|null - */ - public function canEdit($member) - { - if (!Permission::check('EDIT_EMBARGOED_WORKFLOW') && // not given global/override permission to edit - !$this->owner->AllowEmbargoedEditing) { // item flagged as not editable - $publishTime = $this->owner->dbObject('PublishOnDate'); - - if ($publishTime && $publishTime->InFuture() || // when scheduled publish date is in the future - // when there isn't a publish date, but a Job is in place (publish immediately, but queued jobs is - // waiting) - (!$publishTime && $this->owner->PublishJobID != 0) - ) { - return false; - } - } - } - - /** - * Set the workflow service instance - * - * @param WorkflowService $workflowService - * @return $this - */ - public function setWorkflowService(WorkflowService $workflowService) - { - $this->workflowService = $workflowService; - return $this; - } - - /** - * Get the workflow service instance - * - * @return WorkflowService - */ - public function getWorkflowService() - { - return $this->workflowService; - } -} diff --git a/src/Jobs/WorkflowPublishTargetJob.php b/src/Jobs/WorkflowPublishTargetJob.php deleted file mode 100644 index e4bbdf8e..00000000 --- a/src/Jobs/WorkflowPublishTargetJob.php +++ /dev/null @@ -1,64 +0,0 @@ -setObject($obj); - $this->publishType = $type ? strtolower($type) : 'publish'; - $this->totalSteps = 1; - } - } - - public function getTitle() - { - return _t( - 'AdvancedWorkflowPublishJob.SCHEDULEJOBTITLE', - "Scheduled {type} of {object}", - "", - array( - 'type' => $this->publishType, - 'object' => $this->getObject()->Title - ) - ); - } - - public function process() - { - if ($target = $this->getObject()) { - if ($this->publishType == 'publish') { - $target->setIsPublishJobRunning(true); - $target->PublishOnDate = ''; - $target->writeWithoutVersion(); - $target->publishRecursive(); - $this->extend('onAfterWorkflowPublish', $target); - } elseif ($this->publishType == 'unpublish') { - $target->setIsPublishJobRunning(true); - $target->UnPublishOnDate = ''; - $target->writeWithoutVersion(); - $target->doUnpublish(); - $this->extend('onAfterWorkflowUnublish', $target); - } - } - $this->currentStep = 1; - $this->isComplete = true; - } -} diff --git a/src/Tasks/EmbargoExpiryMigrationTask.php b/src/Tasks/EmbargoExpiryMigrationTask.php new file mode 100644 index 00000000..631767c5 --- /dev/null +++ b/src/Tasks/EmbargoExpiryMigrationTask.php @@ -0,0 +1,72 @@ +config()->get('classes') as $className) { + if (!DataObject::singleton($className)->hasExtension(EmbargoExpiryExtension::class)) { + continue; + } + + /** @var DataList|DataObject[]|EmbargoExpiryExtension[] $dataObjects */ + $dataObjects = DataObject::get($className); + + foreach ($dataObjects as $dataObject) { + $updated = false; + + if ($dataObject->PublishOnDate) { + $dataObject->createOrUpdatePublishJob(strtotime($dataObject->PublishOnDate)); + + $updated = true; + } + + if ($dataObject->UnPublishOnDate) { + $dataObject->createOrUpdateUnPublishJob(strtotime($dataObject->UnPublishOnDate)); + + $updated = true; + } + + if ($updated) { + $dataObject->write(); + } + } + } + } +} diff --git a/tests/php/WorkflowEmbargoExpiry.yml b/tests/php/WorkflowEmbargoExpiry.yml index 345932e2..e69de29b 100644 --- a/tests/php/WorkflowEmbargoExpiry.yml +++ b/tests/php/WorkflowEmbargoExpiry.yml @@ -1,53 +0,0 @@ -Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition: - requestPublication: - Title: 'Request Publish' - approvePublication: - Title: 'Approve Publish' - -Symbiote\AdvancedWorkflow\Actions\SimpleApprovalWorkflowAction: - requestPublication: - Title: 'Approve' - WorkflowDefID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication - -Symbiote\AdvancedWorkflow\Actions\PublishItemWorkflowAction: - approvePublication: - Title: 'Publish' - WorkflowDefID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.approvePublication - -SilverStripe\CMS\Model\SiteTree: - emptyEmbargoExpiry: - Title: 'Empty embargo and expiry' - pastEmbargo: - Title: 'Embargo in the past' - DesiredPublishDate: 2013-01-15 - pastExpiry: - Title: 'Expiry in the past' - DesiredUnPublishDate: 2013-03-15 - pastEmbargoExpiry: - Title: 'Embargo and expiry in the past' - DesiredPublishDate: 2013-01-15 - DesiredUnPublishDate: 2013-03-15 - pastEmbargoFutureExpiry: - Title: 'Embargo in the past and expiry in the future' - DesiredPublishDate: 2013-01-15 - DesiredUnPublishDate: 2015-03-15 - futureEmbargoExpiry: - Title: 'Embargo and expiry in the future' - DesiredPublishDate: 2015-01-15 - DesiredUnPublishDate: 2015-03-15 - pastEmbargoAfterExpiry: - Title: 'Embargo after expiry in the past' - DesiredPublishDate: 2013-03-15 - DesiredUnPublishDate: 2013-01-15 - futureEmbargoAfterExpiry: - Title: 'Embargo after expiry in the future' - DesiredPublishDate: 2015-03-15 - DesiredUnPublishDate: 2015-01-15 - pastSameEmbargoExpiry: - Title: 'Embargo and expiry are the same in the past' - DesiredPublishDate: 2013-01-15 - DesiredUnPublishDate: 2013-01-15 - futureSameEmbargoExpiry: - Title: 'Embargo and expiry are the same in the future' - DesiredPublishDate: 2015-01-15 - DesiredUnPublishDate: 2015-01-15 diff --git a/tests/php/WorkflowEmbargoExpiryTest.php b/tests/php/WorkflowEmbargoExpiryTest.php index 1fd402da..8b399976 100644 --- a/tests/php/WorkflowEmbargoExpiryTest.php +++ b/tests/php/WorkflowEmbargoExpiryTest.php @@ -7,17 +7,12 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\FieldType\DBDatetime; -use SilverStripe\Translatable\Model\Translatable; -use SilverStripe\Security\Member; -use SilverStripe\Subsites\Extensions\SiteTreeSubsites; use SilverStripe\Versioned\Versioned; -use Symbiote\AdvancedWorkflow\DataObjects\WorkflowAction; use Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition; -use Symbiote\AdvancedWorkflow\DataObjects\WorkflowTransition; -use Symbiote\AdvancedWorkflow\Extensions\WorkflowEmbargoExpiryExtension; +use Symbiote\AdvancedWorkflow\Extensions\WorkflowApplicable; use Symbiote\AdvancedWorkflow\Services\WorkflowService; -use Symbiote\QueuedJobs\Services\AbstractQueuedJob; use Symbiote\QueuedJobs\Services\QueuedJobService; +use Terraformers\EmbargoExpiry\Extension\EmbargoExpiryExtension; /** * @author marcus@symbiote.com.au @@ -25,72 +20,36 @@ */ class WorkflowEmbargoExpiryTest extends SapphireTest { - protected static $fixture_file = 'WorkflowEmbargoExpiry.yml'; + protected static $fixture_file = 'WorkflowEmbargoExpiryTest.yml'; + + protected static $required_extensions = [ + SiteTree::class => [ + WorkflowApplicable::class, + EmbargoExpiryExtension::class, + ], + ]; protected function setUp(): void { - // Prevent failure if queuedjobs module isn't installed. - if (!class_exists(AbstractQueuedJob::class)) { - static::$fixture_file = ''; - parent::setUp(); - $this->markTestSkipped("This test requires queuedjobs"); - } - parent::setUp(); - DBDatetime::set_mock_now('2014-01-05 12:00:00'); // This doesn't play nicely with PHPUnit Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false); + + parent::setUp(); } protected function tearDown(): void { DBDatetime::clear_mock_now(); - parent::tearDown(); - } - - /** - * @var array - */ - protected static $required_extensions = array( - SiteTree::class => array( - WorkflowEmbargoExpiryExtension::class, - Versioned::class, - ), - ); - /** - * @var array - */ - protected static $illegal_extensions = array( - SiteTree::class => array( - Translatable::class, - SiteTreeSubsites::class, - ), - ); - - /** - * Start a workflow for a page, - * this will set it into a state where a workflow is currently being processes - * - * @param DataObject $obj - * @return DataObject - */ - private function startWorkflow($obj) - { - $workflow = $this->objFromFixture(WorkflowDefinition::class, 'requestPublication'); - $obj->WorkflowDefinitionID = $workflow->ID; - $obj->write(); - - $svc = singleton(WorkflowService::class); - $svc->startWorkflow($obj, $obj->WorkflowDefinitionID); - return $obj; + parent::tearDown(); } /** * Start and finish a workflow which will publish the page immediately basically. * - * @param DataObject $obj + * @param DataObject|mixed $obj * @return DataObject */ private function finishWorkflow($obj) @@ -127,362 +86,146 @@ private function getLive($obj) * * No jobs should be created, but page is published by the workflow action. */ - public function testEmptyEmbargoExpiry() + public function testEmptyEmbargoExpiry(): void { + /** @var SiteTree|EmbargoExpiryExtension $page */ $page = $this->objFromFixture(SiteTree::class, 'emptyEmbargoExpiry'); $page->Content = 'Content to go live'; - $live = $this->getLive($page); - - $this->assertEmpty($live->Content); + // This record should not yet be published. + $this->assertFalse($page->isPublished()); $this->assertEquals(0, $page->PublishJobID); $this->assertEquals(0, $page->UnPublishJobID); $page = $this->finishWorkflow($page); + /** @var SiteTree|EmbargoExpiryExtension $live */ $live = $this->getLive($page); $this->assertNotEmpty($live->Content); - $this->assertEquals(0, $page->PublishJobID); - $this->assertEquals(0, $page->UnPublishJobID); + $this->assertEquals(0, $live->PublishJobID); + $this->assertEquals(0, $live->UnPublishJobID); } /** - * Test for embargo in the past + * Test when both embargo and expiry dates are set. * - * Creates a publish job which is queued for immediately + * Jobs should be created, and the page should not be published as part of the workflow action. */ - public function testPastEmbargo() + public function testProcessEmbargoExpiry(): void { - $page = $this->objFromFixture(SiteTree::class, 'pastEmbargo'); - - $page = $this->finishWorkflow($page); - - $this->assertNotEquals(0, $page->PublishJobID); - $this->assertEquals(0, $page->UnPublishJobID); + /** @var SiteTree|EmbargoExpiryExtension $page */ + $page = $this->objFromFixture(SiteTree::class, 'processEmbargoExpiry'); - $publish = strtotime($page->PublishJob()->StartAfter ?? ''); - $this->assertFalse($publish); - } - - /** - * Test for expiry in the past - * - * Creates an unpublish job which is queued for immediately - */ - public function testPastExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'pastExpiry'); + $page->Content = 'Content to go live'; + $page->DesiredPublishDate = '2014-01-06 12:00:00'; + $page->DesiredUnPublishDate = '2014-01-08 12:00:00'; - $page = $this->finishWorkflow($page); + // Jobs would ordinarily be queued at this time, but because we have a Workflow applied (in the fixture), we + // should halt that from happening. + $page->write(); + $this->assertNotNull($page->DesiredPublishDate); + $this->assertNotNull($page->DesiredUnPublishDate); + $this->assertNull($page->PublishOnDate); + $this->assertNull($page->UnPublishOnDate); $this->assertEquals(0, $page->PublishJobID); - $this->assertNotEquals(0, $page->UnPublishJobID); - - $unpublish = strtotime($page->UnPublishJob()->StartAfter ?? ''); - - $this->assertFalse($unpublish); - } - - /** - * Test for embargo and expiry in the past - * - * Creates an unpublish job which is queued for immediately - */ - public function testPastEmbargoExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'pastEmbargoExpiry'); + $this->assertEquals(0, $page->UnPublishJobID); + /** @var SiteTree|EmbargoExpiryExtension $page */ $page = $this->finishWorkflow($page); - $this->assertEquals(0, $page->PublishJobID); - $this->assertNotEquals(0, $page->UnPublishJobID); - - $unpublish = strtotime($page->UnPublishJob()->StartAfter ?? ''); + // Check that the Jobs have been created, and that the object fields were correctly updated. + $this->assertNull($page->DesiredPublishDate); + $this->assertNull($page->DesiredUnPublishDate); + $this->assertNotNull($page->PublishOnDate); + $this->assertNotNull($page->UnPublishOnDate); + $this->assertNotNull($page->PublishJob()); + $this->assertNotNull($page->UnPublishJob()); - $this->assertFalse($unpublish); + // This record should not yet be published. + $this->assertFalse($page->isPublished()); } /** - * Test for embargo in the past and expiry in the future + * Test when only an embargo date is set. * - * Creates a publish job which is queued for immediately and an unpublish job which is queued for later - */ - public function testPastEmbargoFutureExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'pastEmbargoFutureExpiry'); - - $page = $this->finishWorkflow($page); - - $this->assertNotEquals(0, $page->PublishJobID); - $this->assertNotEquals(0, $page->UnPublishJobID); - - $publish = strtotime($page->PublishJob()->StartAfter ?? ''); - $unpublish = strtotime($page->UnPublishJob()->StartAfter ?? ''); - - $this->assertFalse($publish); - $this->assertNotFalse($unpublish); - } - - /** - * Test for embargo and expiry in the future + * A publish job should be created, and the page should not be published as part of the workflow action. * - * Creates a publish and unpublish job which are queued for immediately + * No un-publish job should be created. */ - public function testFutureEmbargoExpiry() + public function testProcessEmbargo(): void { - $page = $this->objFromFixture(SiteTree::class, 'futureEmbargoExpiry'); - - $page = $this->finishWorkflow($page); - - $this->assertNotEquals(0, $page->PublishJobID); - $this->assertNotEquals(0, $page->UnPublishJobID); - - $publish = strtotime($page->PublishJob()->StartAfter ?? ''); - $unpublish = strtotime($page->UnPublishJob()->StartAfter ?? ''); + /** @var SiteTree|EmbargoExpiryExtension $page */ + $page = $this->objFromFixture(SiteTree::class, 'processEmbargo'); - $this->assertNotFalse($publish); - $this->assertNotFalse($unpublish); - } - - /** - * Test for embargo after expiry in the past - * - * No jobs should be created, invalid option - */ - public function testPastEmbargoAfterExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'pastEmbargoAfterExpiry'); + $page->Content = 'Content to go live'; + $page->DesiredPublishDate = '2014-01-06 12:00:00'; - $page = $this->finishWorkflow($page); + // Jobs would ordinarily be queued at this time, but because we have a Workflow applied (in the fixture), we + // should halt that from happening. + $page->write(); + $this->assertNotNull($page->DesiredPublishDate); + $this->assertNull($page->DesiredUnPublishDate); + $this->assertNull($page->PublishOnDate); + $this->assertNull($page->UnPublishOnDate); $this->assertEquals(0, $page->PublishJobID); $this->assertEquals(0, $page->UnPublishJobID); - } - - /** - * Test for embargo after expiry in the future - * - * No jobs should be created, invalid option - */ - public function testFutureEmbargoAfterExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'futureEmbargoAfterExpiry'); + /** @var SiteTree|EmbargoExpiryExtension $page */ $page = $this->finishWorkflow($page); - $this->assertEquals(0, $page->PublishJobID); + // Check that the Jobs have been created, and that the object fields were correctly updated. + $this->assertNull($page->DesiredPublishDate); + $this->assertNull($page->DesiredUnPublishDate); + $this->assertNotNull($page->PublishOnDate); + $this->assertNull($page->UnPublishOnDate); + $this->assertTrue($page->PublishJob()->exists()); $this->assertEquals(0, $page->UnPublishJobID); - } - - /** - * Test for embargo and expiry in the past, both have the same value - * - * No jobs should be created, invalid option - */ - public function testPastSameEmbargoExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'pastSameEmbargoExpiry'); - - $page = $this->finishWorkflow($page); - $this->assertEquals(0, $page->PublishJobID); - $this->assertEquals(0, $page->UnPublishJobID); + // This record should not yet be published. + $this->assertFalse($page->isPublished()); } /** - * Test for embargo and expiry in the future, both have the same value + * Test when only an expiry date is set. * - * No jobs should be created, invalid option - */ - public function testFutureSameEmbargoExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'futureSameEmbargoExpiry'); - - $page = $this->finishWorkflow($page); - - $this->assertEquals(0, $page->PublishJobID); - $this->assertEquals(0, $page->UnPublishJobID); - } - - /** - * When an item is queued for publishing or unpublishing and new dates are entered + * An un-publish job should be created, and the page should not be published as part of the workflow action. * - * The existing queued jobs should be cleared + * No publish job should be created. */ - public function testDesiredRemovesJobs() + public function testProcessExpiry(): void { - $page = $this->objFromFixture(SiteTree::class, 'futureEmbargoExpiry'); - - $page = $this->finishWorkflow($page); - - $this->assertNotEquals(0, $page->PublishJobID); - $this->assertNotEquals(0, $page->UnPublishJobID); + /** @var SiteTree|EmbargoExpiryExtension $page */ + $page = $this->objFromFixture(SiteTree::class, 'processExpiry'); - $page->DesiredPublishDate = '2020-02-01 00:00:00'; - $page->DesiredUnPublishDate = '2020-02-01 02:00:00'; + $page->Content = 'Content to go live'; + $page->DesiredUnPublishDate = '2014-01-08 12:00:00'; + // Jobs would ordinarily be queued at this time, but because we have a Workflow applied (in the fixture), we + // should halt that from happening. $page->write(); + $this->assertNull($page->DesiredPublishDate); + $this->assertNotNull($page->DesiredUnPublishDate); + $this->assertNull($page->PublishOnDate); + $this->assertNull($page->UnPublishOnDate); $this->assertEquals(0, $page->PublishJobID); $this->assertEquals(0, $page->UnPublishJobID); - } - - /** - * Tests that checking for publishing scheduled state is working - */ - public function testIsPublishScheduled() - { - $page = SiteTree::create(); - $page->Title = 'My page'; - $page->PublishOnDate = '2010-01-01 00:00:00'; - $page->AllowEmbargoedEditing = false; - $page->write(); - - $this->assertFalse($page->getIsPublishScheduled()); - - $page->PublishOnDate = '2016-02-01 00:00:00'; - DBDatetime::set_mock_now('2016-01-16 00:00:00'); - $this->assertTrue($page->getIsPublishScheduled()); - DBDatetime::set_mock_now('2016-02-16 00:00:00'); - $this->assertFalse($page->getIsPublishScheduled()); - } - - /** - * Tests that checking for un-publishing scheduled state is working - */ - public function testIsUnPublishScheduled() - { - $page = SiteTree::create(); - $page->Title = 'My page'; - $page->PublishOnDate = '2010-01-01 00:00:00'; - $page->AllowEmbargoedEditing = false; - $page->write(); - - $this->assertFalse($page->getIsUnPublishScheduled()); - - $page->UnPublishOnDate = '2016-02-01 00:00:00'; - DBDatetime::set_mock_now('2016-01-16 00:00:00'); - $this->assertTrue($page->getIsUnPublishScheduled()); - - DBDatetime::set_mock_now('2016-02-16 00:00:00'); - $this->assertFalse($page->getIsUnPublishScheduled()); - } - - /** - * Tests that status flags (badges) are added properly for a page - */ - public function testStatusFlags() - { - $page = SiteTree::create(); - $page->Title = 'stuff'; - DBDatetime::set_mock_now('2016-01-16 00:00:00'); - - $flags = $page->getStatusFlags(false); - $this->assertNotContains('embargo_expiry', array_keys($flags ?? [])); - $this->assertNotContains('embargo', array_keys($flags ?? [])); - $this->assertNotContains('expiry', array_keys($flags ?? [])); - - $page->PublishOnDate = '2016-02-01 00:00:00'; - $page->UnPublishOnDate = null; - $flags = $page->getStatusFlags(false); - $this->assertNotContains('embargo_expiry', array_keys($flags ?? [])); - $this->assertContains('embargo', array_keys($flags ?? [])); - $this->assertNotContains('expiry', array_keys($flags ?? [])); - - $page->PublishOnDate = null; - $page->UnPublishOnDate = '2016-02-01 00:00:00'; - $flags = $page->getStatusFlags(false); - $this->assertNotContains('embargo_expiry', array_keys($flags ?? [])); - $this->assertNotContains('embargo', array_keys($flags ?? [])); - $this->assertContains('expiry', array_keys($flags ?? [])); - - $page->PublishOnDate = '2016-02-01 00:00:00'; - $page->UnPublishOnDate = '2016-02-08 00:00:00'; - $flags = $page->getStatusFlags(false); - $this->assertContains('embargo_expiry', array_keys($flags ?? [])); - $this->assertNotContains('embargo', array_keys($flags ?? [])); - $this->assertNotContains('expiry', array_keys($flags ?? [])); - } - - /** - * Test workflow definition "Can disable edits during embargo" - * Make sure page cannot be edited when an embargo is in place - */ - public function testCanEditConfig() - { - $this->logOut(); - - $page = SiteTree::create(); - $page->Title = 'My page'; - $page->PublishOnDate = '2010-01-01 00:00:00'; - $page->write(); - - $memberID = $this->logInWithPermission('SITETREE_EDIT_ALL'); - $this->assertTrue($page->canEdit(), 'Can edit page without embargo and no permission'); - - $page->PublishOnDate = '2020-01-01 00:00:00'; - $page->AllowEmbargoedEditing = false; - $page->write(); - $this->assertFalse($page->canEdit(), 'Cannot edit page with embargo and no permission'); - - $this->logOut(); - $memberID = $this->logInWithPermission('ADMIN'); - $this->assertTrue($page->canEdit(), 'Can edit page with embargo as Admin'); - - $this->logOut(); - $memberID = $this->logInWithPermission(array('SITETREE_EDIT_ALL', 'EDIT_EMBARGOED_WORKFLOW')); - $this->assertTrue($page->canEdit(), 'Can edit page with embargo and permission'); - - $page->PublishOnDate = '2010-01-01 00:00:00'; - $page->write(); - $this->assertTrue($page->canEdit(), 'Can edit page without embargo and permission'); - } - - protected function createDefinition() - { - $definition = new WorkflowDefinition(); - $definition->Title = 'Dummy Workflow Definition'; - $definition->write(); - - $stepOne = new WorkflowAction(); - $stepOne->Title = 'Step One'; - $stepOne->WorkflowDefID = $definition->ID; - $stepOne->write(); - - $stepTwo = new WorkflowAction(); - $stepTwo->Title = 'Step Two'; - $stepTwo->WorkflowDefID = $definition->ID; - $stepTwo->write(); - - $transitionOne = new WorkflowTransition(); - $transitionOne->Title = 'Step One T1'; - $transitionOne->ActionID = $stepOne->ID; - $transitionOne->NextActionID = $stepTwo->ID; - $transitionOne->write(); - - return $definition; - } - - /** - * Make sure that publish and unpublish dates are not carried over to the duplicates. - */ - public function testDuplicateRemoveEmbargoExpiry() - { - $page = $this->objFromFixture(SiteTree::class, 'futureEmbargoExpiry'); - - // fake publish jobs + /** @var SiteTree|EmbargoExpiryExtension $page */ $page = $this->finishWorkflow($page); - $dupe = $page->duplicate(); - $this->assertNotNull($page->PublishOnDate, 'Not blank publish on date'); - $this->assertNotNull($page->UnPublishOnDate, 'Not blank unpublish on date'); - $this->assertNotEquals($page->PublishJobID, 0, 'Publish job ID still set'); - $this->assertNotEquals($page->UnPublishJobID, 0, 'Unpublish job ID still set'); - $this->assertNull($dupe->PublishOnDate, 'Blank publish on date'); - $this->assertNull($dupe->UnPublishOnDate, 'Blank unpublish on date'); - $this->assertEquals($dupe->PublishJobID, 0, 'Publish job ID unset'); - $this->assertEquals($dupe->UnPublishJobID, 0, 'Unpublish job ID unset'); + // Check that the Jobs have been created, and that the object fields were correctly updated. + $this->assertNull($page->DesiredPublishDate); + $this->assertNull($page->DesiredUnPublishDate); + $this->assertNull($page->PublishOnDate); + $this->assertNotNull($page->UnPublishOnDate); + $this->assertEquals(0, $page->PublishJobID); + $this->assertTrue($page->UnPublishJob()->exists()); + + // This record should not yet be published. + $this->assertFalse($page->isPublished()); } } diff --git a/tests/php/WorkflowEmbargoExpiryTest.yml b/tests/php/WorkflowEmbargoExpiryTest.yml new file mode 100644 index 00000000..08ac3611 --- /dev/null +++ b/tests/php/WorkflowEmbargoExpiryTest.yml @@ -0,0 +1,29 @@ +Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition: + requestPublication: + Title: 'Request Publish' + approvePublication: + Title: 'Approve Publish' + +Symbiote\AdvancedWorkflow\Actions\SimpleApprovalWorkflowAction: + requestPublication: + Title: 'Approve' + WorkflowDefID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication + +Symbiote\AdvancedWorkflow\Actions\PublishItemWorkflowAction: + approvePublication: + Title: 'Publish' + WorkflowDefID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.approvePublication + +SilverStripe\CMS\Model\SiteTree: + emptyEmbargoExpiry: + Title: 'Empty embargo and expiry' + WorkflowDefinitionID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication + processEmbargoExpiry: + Title: 'Process embargo and expiry' + WorkflowDefinitionID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication + processEmbargo: + Title: 'Process embargo' + WorkflowDefinitionID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication + processExpiry: + Title: 'Process expiry' + WorkflowDefinitionID: =>Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition.requestPublication