Source of file LeftAndMainCMSWorkflow.php
Size: 19,789 Bytes - Last Modified: 2021-12-23T10:28:49+00:00
/var/www/docs.ssmods.com/process/src/code/LeftAndMainCMSWorkflow.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 | <?php class LeftAndMainCMSWorkflow extends LeftAndMainDecorator { private static $prompt_admin_for_comments = true; public static $allowed_actions = array( 'cms_requestpublication', 'cms_requestdeletefromlive', 'cms_denypublication', 'cms_denydeletion', 'cms_setembargoexpiry', 'cms_comment', 'cms_approve', 'cms_cancelexpiry', 'cms_requestedit', 'cms_deny', 'cms_cancel', 'cms_publishwithcomment', ); public static function set_prompt_admin_for_comments($enable) { self::$prompt_admin_for_comments = $enable; } public function cms_setembargoexpiry($data) { $wfRequest = DataObject::get_by_id('WorkflowRequest', $data['wfRequest']); if ($wfRequest) { if (!$wfRequest->CanChangeEmbargoExpiry()) { $result = array( 'status' => 'failed', 'message' => 'you cannot change the embargo/expiry dates at this time' ); } else { if (isset($data['ResetEmbargo'])) { $wfRequest->EmbargoDate = null; $wfRequest->write(); $result = array( 'status' => 'success' ); } elseif (isset($data['ResetExpiry'])) { $wfRequest->Page()->ExpiryDate = null; $wfRequest->Page()->write(); $result = array( 'status' => 'success' ); } else { $expiryTimestamp = $embargoTimestamp = null; $embargoField = $wfRequest->EmbargoField(); $expiryField = $wfRequest->ExpiryField(); if (isset($data['EmbargoDate'])) { $embargoField->setValue($data['EmbargoDate']); $tz = @$data['EmbargoDate']['timezone']; if ($tz) { $embargoField->setConfig('usertimezone', $tz); } $embargoDate = $embargoField->Value(); $embargoTimestamp = strtotime($embargoField->Value()); } if (isset($data['ExpiryDate'])) { $expiryField->setValue($data['ExpiryDate']); $tz = @$data['ExpiryDate']['timezone']; if ($tz) { $expiryField->setConfig('usertimezone', $tz); } $expiryDate = $expiryField->Value(); $expiryTimestamp = strtotime($expiryField->Value()); } $embargoField->saveInto($wfRequest); $expiryField->saveInto($wfRequest->Page()); $embargoTimestamp = strtotime($embargoField->dataValue()); $expiryTimestamp = strtotime($expiryField->dataValue()); // Validation time $error = false; if (isset($data['EmbargoDate']) && !$embargoTimestamp) { $error = "Embargo date/time is not valid"; } elseif (isset($data['ExpiryDate']) && !$expiryTimestamp) { $error = "Expiry date/time is not valid"; } elseif (isset($data['EmbargoDate']) && $embargoTimestamp < time()) { $error = "Embargo date/time must be AFTER the current server date/time"; } elseif (isset($data['ExpiryDate']) && $expiryTimestamp < time()) { $error = "Expiry date/time must be AFTER the current server date/time"; } elseif ($embargoTimestamp && $expiryTimestamp && $embargoTimestamp > $expiryTimestamp) { $error = "Embargo date/time must be BEFORE the expiry date/time"; } else { $wfRequest->write(); $wfRequest->Page()->write(); $result = array( 'status' => 'success', 'message' => array( 'embargo' => date('j M Y H:i', strtotime($embargoField->dataValue())), 'expiry' => date('j M Y H:i', strtotime($expiryField->dataValue())) ) ); } if ($error) { $result = array( 'status' => 'failed', 'message' => $error ); } } } } else { $result = array( 'status' => 'failed', 'message' => 'workflow request not found' ); } return Convert::array2json($result); } public function init() { // We need to make sure these CMSMain scripts are included first Requirements::javascript('cms/javascript/CMSMain.js'); Requirements::javascript('cms/javascript/CMSMain_left.js'); Requirements::javascript('cms/javascript/CMSMain_right.js'); CMSBatchActionHandler::register('batchCmsWorkflowSetEmbargo', 'BatchSetEmbargo'); CMSBatchActionHandler::register('batchCmsWorkflowSetExpiry', 'BatchSetExpiry'); CMSBatchActionHandler::register('batchCmsWorkflowResetEmbargo', 'BatchResetEmbargo'); CMSBatchActionHandler::register('batchCmsWorkflowResetExpiry', 'BatchResetExpiry'); Requirements::javascript('cmsworkflow/javascript/LeftAndMainCMSWorkflow.js'); Requirements::customScript("CMSWorkflow.setOption('noPromptForAdmin', " . Convert::raw2json(!self::$prompt_admin_for_comments) . ')'); RSSFeed::linkToFeed(Director::absoluteURL('admin/cms/changes.rss'), 'All content changes'); } // Request /** * Handler for the CMS button */ public function cms_requestpublication($data, $form) { return $this->workflowAction('WorkflowPublicationRequest', 'request', $data['ID'], $data['WorkflowComment']); } public function cms_requestdeletefromlive($data, $form) { return $this->workflowAction('WorkflowDeletionRequest', 'request', $data['ID'], $data['WorkflowComment']); } // Approve public function cms_approve($data, $form) { return $this->workflowAction('WorkflowRequest', 'approve', $data['ID'], $data['WorkflowComment']); } // Cancel expiry public function cms_cancelexpiry($data, $form) { $id = Convert::raw2sql($data['ID']); $page = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\" = '$id'"); if ($page) { $page->cancelexpiry(); } FormResponse::get_page($data['ID']); FormResponse::status_message(_t('SiteTreeCMSWorkflow.EXPIRYCANCELLED', 'Expiry cancelled.'), 'good'); return FormResponse::respond(); } /** * When a page is saved, we need to check if there is an in-progress * workflow request, and if applicable, set it back to AwaitingApproval */ public function onAfterSave($record) { if ($record->hasMethod('openWorkflowRequest') && $wf = $record->openWorkflowRequest()) { if ($wf->Status != 'AwaitingApproval' && $wf->Status != 'AwaitingEdit') { $wf->request("Page was resaved, automatically set workflow request back to awaiting approval", null, false); FormResponse::add("$('Form_EditForm').getPageFromServer($record->ID);"); } } } public function onBeforeRollback($pageID) { $record = DataObject::get_by_id('Page', $pageID); if ($record && $record->hasMethod('openWorkflowRequest') && $wf = $record->openWorkflowRequest()) { $wf->cancel('Draft changes were cancelled, automatically closed workflow request'); } } public function cms_publishwithcomment($urlParams, $form) { $className = 'SiteTree'; $SQL_id = Convert::raw2sql($_REQUEST['ID']); if (substr($SQL_id, 0, 3) != 'new') { $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; $record = DataObject::get_one($className, "{$bt}$className{$bt}.{$bt}ID{$bt} = {$SQL_id}"); if ($record && !$record->canEdit()) { return Security::permissionFailure($this); } } else { if (!singleton($this->stat('tree_class'))->canCreate()) { return Security::permissionFailure($this); } $record = $this->getNewItem($SQL_id, false); } // We don't want to save a new version if there are no changes $dataFields_new = $form->Fields()->dataFields(); $dataFields_old = $record->getAllFields(); $changed = false; $hasNonRecordFields = false; foreach ($dataFields_new as $datafield) { // if the form has fields not belonging to the record if (!isset($dataFields_old[$datafield->Name()])) { $hasNonRecordFields = true; } // if field-values have changed if (!isset($dataFields_old[$datafield->Name()]) || $dataFields_old[$datafield->Name()] != $datafield->dataValue()) { $changed = true; } } if (!$changed && !$hasNonRecordFields) { // Tell the user we have saved even though we haven't, as not to confuse them if (is_a($record, "Page")) { $record->Status = "Saved (update)"; } FormResponse::status_message(_t('LeftAndMain.SAVEDUP', "Saved"), "good"); FormResponse::update_status($record->Status); return FormResponse::respond(); } $form->dataFieldByName('ID')->Value = 0; if (isset($urlParams['Sort']) && is_numeric($urlParams['Sort'])) { $record->Sort = $urlParams['Sort']; } // HACK: This should be turned into something more general $originalClass = $record->ClassName; $originalStatus = $record->Status; $originalParentID = $record->ParentID; $record->HasBrokenLink = 0; $record->HasBrokenFile = 0; $record->writeWithoutVersion(); // HACK: This should be turned into something more general $originalURLSegment = $record->URLSegment; $form->saveInto($record, true); if (is_a($record, "Page")) { $record->Status = ($record->Status == "New page" || $record->Status == "Saved (new)") ? "Saved (new)" : "Saved (update)"; } if (Director::is_ajax()) { if ($SQL_id != $record->ID) { FormResponse::add("$('sitetree').setNodeIdx(\"{$SQL_id}\", \"$record->ID\");"); FormResponse::add("$('Form_EditForm').elements.ID.value = \"$record->ID\";"); } if ($added = DataObjectLog::getAdded('SiteTree')) { foreach ($added as $page) { if ($page->ID != $record->ID) { FormResponse::add($this->addTreeNodeJS($page)); } } } if ($deleted = DataObjectLog::getDeleted('SiteTree')) { foreach ($deleted as $page) { if ($page->ID != $record->ID) { FormResponse::add($this->deleteTreeNodeJS($page)); } } } if ($changed = DataObjectLog::getChanged('SiteTree')) { foreach ($changed as $page) { if ($page->ID != $record->ID) { $title = Convert::raw2js($page->TreeTitle()); FormResponse::add("$('sitetree').setNodeTitle($page->ID, \"$title\");"); } } } $message = _t('LeftAndMain.SAVEDUP'); // Update the class instance if necessary if ($originalClass != $record->ClassName) { $newClassName = $record->ClassName; // The records originally saved attribute was overwritten by $form->saveInto($record) before. // This is necessary for newClassInstance() to work as expected, and trigger change detection // on the ClassName attribute $record->setClassName($originalClass); // Replace $record with a new instance $record = $record->newClassInstance($newClassName); // update the tree icon FormResponse::add("if(\$('sitetree').setNodeIcon) \$('sitetree').setNodeIcon($record->ID, '$originalClass', '$record->ClassName');"); } // HACK: This should be turned into somethign more general if (($record->class == 'VirtualPage' && $originalURLSegment != $record->URLSegment) || ($originalClass != $record->ClassName) || LeftAndMain::$ForceReload == true) { FormResponse::add("$('Form_EditForm').getPageFromServer($record->ID);"); } // After reloading action if ($originalStatus != $record->Status) { $message .= sprintf(_t('LeftAndMain.STATUSTO', " Status changed to '%s'"), $record->Status); } if ($originalParentID != $record->ParentID) { FormResponse::add("if(\$('sitetree').setNodeParentID) \$('sitetree').setNodeParentID($record->ID, $record->ParentID);"); } $record->write(); // if changed to a single_instance_only page type if ($record->stat('single_instance_only')) { FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').addClass('{$record->stat('single_instance_only_css_class')}');"); FormResponse::add($this->hideSingleInstanceOnlyFromCreateFieldJS($record)); } else { FormResponse::add("jQuery('#sitetree li.{$record->ClassName}').removeClass('{$record->stat('single_instance_only_css_class')}');"); } // if chnaged from a single_instance_only page type $sampleOriginalClassObject = new $originalClass(); if ($sampleOriginalClassObject->stat('single_instance_only')) { FormResponse::add($this->showSingleInstanceOnlyInCreateFieldJS($sampleOriginalClassObject)); } if (($record->class != 'VirtualPage') && $originalURLSegment != $record->URLSegment) { $message .= sprintf(_t('LeftAndMain.CHANGEDURL', " Changed URL to '%s'"), $record->URLSegment); FormResponse::add("\$('Form_EditForm').elements.URLSegment.value = \"$record->URLSegment\";"); FormResponse::add("\$('Form_EditForm_StageURLSegment').value = \"{$record->URLSegment}\";"); } // Update classname with original and get new instance (see above for explanation) $record->setClassName($originalClass); $publishedRecord = $record->newClassInstance($record->ClassName); return $this->workflowAction('WorkflowPublicationRequest', 'saveAndPublish', $urlParams['ID'], $urlParams['WorkflowComment']); // return $this->owner->tellBrowserAboutPublicationChange( // $publishedRecord, // sprintf( // _t( // 'LeftAndMain.STATUSPUBLISHEDSUCCESS', // "Published '%s' successfully", // PR_MEDIUM, // 'Status message after publishing a page, showing the page title' // ), // $record->Title // ) // ); } } // Request edit public function cms_requestedit($data, $form) { return $this->workflowAction('WorkflowRequest', 'requestedit', $data['ID'], $data['WorkflowComment']); } // Deny public function cms_deny($data, $form) { return $this->workflowAction('WorkflowRequest', 'deny', $data['ID'], $data['WorkflowComment']); } // Cancel public function cms_cancel($data, $form) { return $this->workflowAction('WorkflowRequest', 'cancel', $data['ID'], $data['WorkflowComment']); } // Comment (no workflow status change) public function cms_comment($data, $form) { return $this->workflowAction('WorkflowRequest', 'comment', $data['ID'], $data['WorkflowComment']); } /** * Process a workflow action. * @param string $workflowClass The sub-class of WorkflowRequest that is expected. * @param string $actionName The action method to call on the given WorkflowRequest objec.t * @param int $id The ID# of the page. * @param string $comment The comment to attach. * @param string $successMessage The message to show on success. */ public function workflowAction($workflowClass, $actionName, $id, $comment) { if (is_numeric($id)) { // For 2.3 and 2.4 compatibility $bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`"; $page = DataObject::get_by_id("SiteTree", $id); if (!$page) { $page = Versioned::get_one_by_stage("SiteTree", "Live", "{$bt}SiteTree{$bt}.{$bt}ID{$bt} = $id"); } if (!$page) { return new HTTPResponse("Can't find Page #$id", 400); } } else { return new HTTPResponse("Bad ID", 400); } // If we are creating and approving a workflow in one step, then don't bother emailing $notify = !($actionName == 'action' && !$page->openWorkflowRequest($workflowClass)); if ($request = $page->openOrNewWorkflowRequest($workflowClass, $notify)) { $request->clearMembersEmailed(); if ($successMessage = $request->$actionName($comment, null, $notify)) { FormResponse::get_page($id); $title = Convert::raw2js($page->TreeTitle()); FormResponse::add("$('sitetree').setNodeTitle($id, \"$title\");"); // gather members for status output if ($notify) { $peeps = $request->getMembersEmailed(); if ($peeps && $peeps->Count()) { $emails = ''; foreach ($peeps as $peep) { if ($peep->Email) { $emails .= $peep->Email.', '; } } $emails = trim($emails, ', '); } else { $emails = 'no-one'; } } else { $emails = "no-one"; } if ($successMessage) { FormResponse::status_message(sprintf($successMessage, $emails), 'good'); return FormResponse::respond(); } else { return; } } } // Failure FormResponse::status_message(_t('SiteTreeCMSWorkflow.WORKFLOW_ACTION_FAILED', "There was an error when processing your workflow request."), 'bad'); return FormResponse::respond(); } } |