diff --git a/docs/VERSION.txt b/docs/VERSION.txt index 0a3c91a..598264a 100644 --- a/docs/VERSION.txt +++ b/docs/VERSION.txt @@ -1 +1 @@ -3.1.6.4 +3.1.6.5 diff --git a/lib/workflow/workflowutil.inc.php b/lib/workflow/workflowutil.inc.php index 42cfc3c..522def0 100644 --- a/lib/workflow/workflowutil.inc.php +++ b/lib/workflow/workflowutil.inc.php @@ -788,7 +788,44 @@ class KTWorkflowUtil { } return $aGuards; } -} + + + function replaceState($oState, $oReplacement) { + $state_id = KTUtil::getId($oState); + $replacement_id = KTUtil::getId($oReplacement); + + // we need to convert: + // - documents + // - transitions + // before we do a delete. + $doc = KTUtil::getTableName('document_metadata_version'); + $aDocQuery = array( + 'UPDATE $doc SET workflow_state_id = ? WHERE workflow_state_id = ?', + array($state_id, $replacement_id), + ); + $res = DBUtil::runQuery($aDocQuery); + if (PEAR::isError($res)) { return $res; } + + $wf = KTUtil::getTableName('workflow_transitions'); + $aTransitionQuery = array( + 'UPDATE $wf SET target_state_id = ? WHERE workflow_state_id = ?', + array($state_id, $replacement_id), + ); + $res = DBUtil::runQuery($aTransitionQuery); + if (PEAR::isError($res)) { return $res; } + + $wf = KTUtil::getTableName('workflow_state_transitions'); + $aTransitionQuery = array( + 'DELETE FROM $wf WHERE state_id = ?', + array($state_id), + ); + $res = DBUtil::runQuery($aTransitionQuery); + if (PEAR::isError($res)) { return $res; } + + Document::clearAllCaches(); + KTWorkflowTransitions::clearAllCaches(); + } +} class KTWorkflowTriggerRegistry { var $triggers; @@ -832,5 +869,5 @@ class KTWorkflowTriggerRegistry { // FIXME do we want to order this alphabetically? return $triggerlist; } -} +} diff --git a/plugins/ktcore/admin/workflowsv2.php b/plugins/ktcore/admin/workflowsv2.php index 27ef5ca..252d3e6 100644 --- a/plugins/ktcore/admin/workflowsv2.php +++ b/plugins/ktcore/admin/workflowsv2.php @@ -803,8 +803,83 @@ class KTWorkflowAdminV2 extends KTAdminDispatcher { $this->errorRedirectTo("basic", sprintf(_kt("Failed to clear transition: %s"), $res->getMessage())); } - $this->successRedirectTo('basic', _kt("Transition updated.")); + $this->successRedirectTo('basic', _kt("Transition deleted.")); } + + function form_deletestate() { + $oForm = new KTForm; + $oForm->setOptions(array( + 'label' => _kt("Delete Existing State"), + 'identifier' => 'ktcore.workflow.deletestate', + 'action' => 'deletestate', + 'cancel_action' => 'basic', + 'fail_action' => 'replacestate', + 'submit_label' => _kt("Delete State"), + 'context' => $this, + )); + $other_states = sprintf('id != %d', $this->oState->getId()); + $oForm->setWidgets(array( + array('ktcore.widgets.entityselection', array( + 'vocab' => KTWorkflowState::getList($other_states), + 'label' => _kt("Replacement State"), + 'description' => _kt("In order to remove this state from the system, please select a new state which will take its place. All references to the state you are deleting will be replaced by this new state."), + 'important_description' => _kt("All references will be changed, including on old documents."), + 'label_method' => 'getName', + 'name' => 'replacement', + 'required' => true, + )), + )); + $oForm->setValidators(array( + array('ktcore.validators.entity', array( + 'test' => 'replacement', + 'output' => 'replacement', + 'class' => 'KTWorkflowState', + )), + )); + return $oForm; + } + + function do_replacestate() { + $oForm = $this->form_deletestate(); + return $oForm->renderPage(_kt("Delete State")); + } + + function do_deletestate() { + $oForm = $this->form_deletestate(); + $res = $oForm->validate(); + + $errors = $res['errors']; + $data = $res['results']; + + if (!empty($errors)) { + return $oForm->handleError(); + } + + $this->startTransaction(); + + if (is_null($this->oState)) { + return $this->errorRedirectTo("basic", _kt("No state selected")); + } + + $replacement = $data['replacement']; + + KTWorkflowUtil::replaceState($this->oState, $replacement); + + if ($this->oWorkflow->getStartStateId() == $this->oState->getId()) { + $this->oWorkflow->setStartStateId($replacement->getId()); + $res = $this->oWorkflow->update(); + if (PEAR::isError($res)) { + $this->errorRedirectTo("basic", sprintf(_kt("Failed to update workflow: %s"), $res->getMessage())); + } + } + + $res = $this->oState->delete(); + if (PEAR::isError($res)) { + $this->errorRedirectTo("basic", sprintf(_kt("Failed to delete state: %s"), $res->getMessage())); + } + + $this->successRedirectTo('basic', _kt("State deleted.")); + } // ----------------- Security --------------------- function do_security() { diff --git a/sql/mysql/upgrade/3.1.6.5/workflow-state-referencefixes.sql b/sql/mysql/upgrade/3.1.6.5/workflow-state-referencefixes.sql new file mode 100644 index 0000000..0fc4408 --- /dev/null +++ b/sql/mysql/upgrade/3.1.6.5/workflow-state-referencefixes.sql @@ -0,0 +1,8 @@ +ALTER TABLE `workflow_state_permission_assignments` + DROP FOREIGN KEY `workflow_state_permission_assignments_ibfk_7`, + DROP FOREIGN KEY `workflow_state_permission_assignments_ibfk_8`; + + +ALTER TABLE `workflow_state_permission_assignments` + ADD CONSTRAINT `workflow_state_permission_assignments_ibfk_7` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `workflow_state_permission_assignments_ibfk_8` FOREIGN KEY (`permission_descriptor_id`) REFERENCES `permission_descriptors` (`id`) ON DELETE CASCADE; diff --git a/templates/ktcore/workflow/admin/basic_overview.smarty b/templates/ktcore/workflow/admin/basic_overview.smarty index ae799e1..adba0ee 100644 --- a/templates/ktcore/workflow/admin/basic_overview.smarty +++ b/templates/ktcore/workflow/admin/basic_overview.smarty @@ -33,7 +33,7 @@ which documents follow (e.g. "submit for review" or "publish").

Edit State - Delete State + Delete State {/foreach}