-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[4.0] Workflow prevent trashing of used stages/workflows #21579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
f64c9ca
61d9c0b
6be26a1
b25c0b3
647092d
b1eebd6
ab6369e
0a2cb77
f21b84b
d4428d7
974c564
272fcf8
fac863e
102d260
85b4ff1
069fc8b
899805c
85223e5
07b7a44
9305a49
ff70dc6
e93e017
e762553
d9b2b2d
e204edf
22b2446
9c066cc
10d8bc0
14fcc14
0843fbc
4e68625
5f31e9f
a9b60ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,8 +6,8 @@ | |
| PLG_CONTENT_JOOMLA="Content - Joomla" | ||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_DESC="Check that categories are fully empty before they are deleted." | ||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_LABEL="Check Category Deletion" | ||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_DESC="Check that states are not assigned to an item before they are deleted." | ||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_LABEL="Check States Deletion" | ||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_WORKFLOW_DESC="Check that stages/workflows are not assigned to an item before they are deleted." | ||
|
||
| PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_WORKFLOW_LABEL="Check Stages/Workflow Deletion" | ||
| PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_DESC="Email users if 'Send email' is on when there is a new article submitted via the Frontend." | ||
| PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_LABEL="Email on New Site Article" | ||
| PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_STAGE_DESC="Email users if 'Send email' is on when there is a status change of an article." | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,8 @@ | |
| use Joomla\Component\Content\Administrator\Table\ArticleTable; | ||
| use Joomla\CMS\Workflow\Workflow; | ||
| use Joomla\Utilities\ArrayHelper; | ||
| use Joomla\Component\Workflow\Administrator\Table\StageTable; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please sort in alpha order. See this PR #21577. |
||
| use Joomla\Component\Workflow\Administrator\Table\WorkflowTable; | ||
|
|
||
| /** | ||
| * Example Content Plugin | ||
|
|
@@ -137,10 +139,35 @@ public function onContentBeforeDelete($context, $data) | |
| return $this->_canDeleteCategories($data); | ||
|
|
||
| case 'com_workflow.stage': | ||
| return $this->_canDeleteStages($data->id); | ||
| return $this->_canDeleteStage($data->id); | ||
| } | ||
| } | ||
|
|
||
| public function onContentBeforeChangeState($context, $pks, $value) | ||
| { | ||
| if ($value != -2 || !in_array($context, ['com_workflow.workflow', 'com_workflow.stage'])) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| $result = true; | ||
|
|
||
| foreach ($pks as $id) | ||
| { | ||
| switch ($context) | ||
| { | ||
| case 'com_workflow.workflow': | ||
| return $result && $this->_canDeleteWorkflow($id); | ||
|
|
||
| case 'com_workflow.stage': | ||
| $result = $result && $this->_canDeleteStage($id); | ||
| } | ||
| } | ||
|
|
||
| return $result; | ||
|
|
||
|
||
| } | ||
|
|
||
| /** | ||
| * Checks if a given category can be deleted | ||
| * | ||
|
|
@@ -218,18 +245,18 @@ private function _canDeleteCategories($data) | |
| } | ||
|
|
||
| /** | ||
| * Checks if a given stage can be deleted | ||
| * Checks if a given workflow can be deleted | ||
| * | ||
| * @param int $pk The stage ID | ||
| * | ||
| * @return boolean | ||
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| private function _canDeleteStages($pk) | ||
| private function _canDeleteWorkflow($pk) | ||
| { | ||
| // Check if this function is enabled. | ||
| if (!$this->params->def('check_stages', 1)) | ||
| if (!$this->params->def('check_states_workflow', 1)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
@@ -239,15 +266,27 @@ private function _canDeleteStages($pk) | |
| // Default to true if not a core extension | ||
| $result = true; | ||
|
|
||
| // Check if this workflow is the default stage | ||
| $table = new WorkflowTable($this->db); | ||
|
|
||
| $table->load($pk); | ||
|
|
||
| if ($table->default) | ||
| { | ||
| throw new Exception(Text::_('COM_WORKFLOW_MSG_DELETE_IS_DEFAULT')); | ||
| } | ||
|
|
||
| $tableInfo = [ | ||
| 'com_content' => array('table_name' => '#__content') | ||
| ]; | ||
|
|
||
| // Now check to see if this is a known core extension | ||
| if (isset($tableInfo[$extension])) | ||
| { | ||
| $table = $tableInfo[$extension]['table_name']; | ||
|
|
||
| // See if this category has any content items | ||
| $count = $this->_countItemsFromState($extension, $pk, $tableInfo[$extension]); | ||
| $count = $this->_countItemsFromWorkflow($extension, $pk, $table); | ||
|
|
||
| // Return false if db error | ||
| if ($count === false) | ||
|
|
@@ -259,9 +298,69 @@ private function _canDeleteStages($pk) | |
| // Show error if items are found assigned to the stage | ||
| if ($count > 0) | ||
| { | ||
| $msg = Text::_('COM_WORKFLOW_MSG_DELETE_IS_ASSIGNED'); | ||
| Factory::getApplication()->enqueueMessage($msg, 'error'); | ||
| $result = false; | ||
| throw new Exception(Text::_('COM_WORKFLOW_MSG_DELETE_IS_ASSIGNED')); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if a given stage can be deleted | ||
| * | ||
| * @param int $pk The stage ID | ||
| * | ||
| * @return boolean | ||
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| private function _canDeleteStage($pk) | ||
| { | ||
| // Check if this function is enabled. | ||
| if (!$this->params->def('check_states_workflow', 1)) | ||
|
||
| { | ||
| return true; | ||
| } | ||
|
|
||
| $extension = Factory::getApplication()->input->getString('extension'); | ||
|
|
||
| // Default to true if not a core extension | ||
| $result = true; | ||
|
|
||
| // Check if this stage is the default stage | ||
| $table = new StageTable($this->db); | ||
|
|
||
| $table->load($pk); | ||
|
|
||
| if ($table->default) | ||
| { | ||
| throw new Exception(Text::_('COM_WORKFLOW_MSG_DELETE_IS_DEFAULT')); | ||
| } | ||
|
|
||
| $tableInfo = [ | ||
| 'com_content' => array('table_name' => '#__content') | ||
| ]; | ||
|
|
||
| // Now check to see if this is a known core extension | ||
| if (isset($tableInfo[$extension])) | ||
| { | ||
| $table = $tableInfo[$extension]['table_name']; | ||
|
|
||
| // See if this state has any content items | ||
| $count = $this->_countItemsFromState($extension, $pk, $table); | ||
|
|
||
| // Return false if db error | ||
| if ($count === false) | ||
| { | ||
| $result = false; | ||
| } | ||
| else | ||
| { | ||
| // Show error if items are found assigned to the stage | ||
| if ($count > 0) | ||
| { | ||
| throw new Exception(Text::_('COM_WORKFLOW_MSG_DELETE_IS_ASSIGNED')); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -397,6 +496,44 @@ private function _countItemsFromState($extension, $stage_id, $table) | |
| return $count; | ||
| } | ||
|
|
||
| /** | ||
| * Get count of items assigned to a stage | ||
| * | ||
| * @param string $extension The extension to search for | ||
| * @param integer $stage_id ID of the stage to check | ||
| * @param string $table The table to search for | ||
| * | ||
| * @return mixed count of items found or false if db error | ||
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| private function _countItemsFromWorkflow($extension, $workflow_id, $table) | ||
| { | ||
| $query = $this->db->getQuery(true); | ||
|
|
||
| $query ->select('COUNT(' . $this->db->quoteName('wa.item_id') . ')') | ||
| ->from($query->quoteName('#__workflow_associations', 'wa')) | ||
| ->from($query->quoteName('#__workflow_stages', 's')) | ||
| ->from($this->db->quoteName($table, 'b')) | ||
| ->where($this->db->quoteName('wa.stage_id') . ' = ' . $this->db->quoteName('s.id')) | ||
| ->where($this->db->quoteName('wa.item_id') . ' = ' . $this->db->quoteName('b.id')) | ||
| ->where($this->db->quoteName('s.workflow_id') . ' = ' . (int) $workflow_id) | ||
| ->where($this->db->quoteName('wa.extension') . ' = ' . $this->db->quote($extension)); | ||
|
|
||
| try | ||
| { | ||
| $count = $this->db->setQuery($query)->loadResult(); | ||
| } | ||
| catch (RuntimeException $e) | ||
| { | ||
| Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| return $count; | ||
| } | ||
|
|
||
| /** | ||
| * Change the state in core_content if the stage in a table is changed | ||
| * | ||
|
|
@@ -416,7 +553,7 @@ public function onContentChangeState($context, $pks, $value) | |
| { | ||
| foreach ($pks as $pk) | ||
| { | ||
| if (!$this->_canDeleteStates($pk)) | ||
| if (!$this->_canDeleteStage($pk)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,11 +31,11 @@ | |
| <option value="1">JYES</option> | ||
| </field> | ||
| <field | ||
| name="check_states" | ||
| name="check_states_workflow" | ||
| type="radio" | ||
| class="switcher" | ||
| label="PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_LABEL" | ||
| description="PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_DESC" | ||
| label="PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_WORKFLOW_LABEL" | ||
|
||
| description="PLG_CONTENT_JOOMLA_FIELD_CHECK_STATES_WORKFLOW_DESC" | ||
| default="1" | ||
| > | ||
| <option value="0">JNO</option> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a . at the end