From f7db0e2c6e5a7ade56196f718aa322fa5ad718f8 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Sat, 14 Mar 2020 20:55:46 +0100 Subject: [PATCH 01/90] Remove condition from workflow component (#52) --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 11 +++---- .../updates/postgresql/4.0.0-2018-05-15.sql | 11 +++---- .../com_workflow/forms/filter_stages.xml | 10 ------ .../components/com_workflow/forms/stage.xml | 7 ---- .../com_workflow/src/Model/StagesModel.php | 12 +------ .../src/Model/TransitionsModel.php | 4 +-- .../com_workflow/src/Model/WorkflowModel.php | 5 --- .../com_workflow/src/Model/WorkflowsModel.php | 2 +- .../com_workflow/src/View/Stages/HtmlView.php | 5 --- .../com_workflow/tmpl/stage/edit.php | 1 - .../com_workflow/tmpl/stages/default.php | 20 +----------- .../com_workflow/tmpl/transitions/default.php | 32 ------------------- installation/sql/mysql/joomla.sql | 11 +++---- installation/sql/postgresql/joomla.sql | 11 +++---- 14 files changed, 24 insertions(+), 118 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 7bbedc437e6d4..69ac6bf9d5671 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -64,7 +64,6 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( `published` tinyint(1) NOT NULL DEFAULT 0, `title` varchar(255) NOT NULL, `description` text NOT NULL, - `condition` int(10) DEFAULT 0, `default` tinyint(1) NOT NULL DEFAULT 0, `checked_out_time` datetime, `checked_out` int(10) NOT NULL DEFAULT 0, @@ -80,11 +79,11 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- Dumping data for table `#__workflow_stages` -- -INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `condition`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 0, 1, NULL, 0), -(2, 0, 2, 1, 1, 'JPUBLISHED', '', 1, 0, NULL, 0), -(3, 0, 3, 1, 1, 'JTRASHED', '', -2, 0, NULL, 0), -(4, 0, 4, 1, 1, 'JARCHIVED', '', 2, 0, NULL, 0); +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES +(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), +(2, 0, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), +(3, 0, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), +(4, 0, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); -- -- Table structure for table `#__workflow_transitions` diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index a41ff39e4f764..652805aecf746 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -64,7 +64,6 @@ CREATE TABLE IF NOT EXISTS "#__workflow_stages" ( "published" smallint NOT NULL DEFAULT 0, "title" varchar(255) NOT NULL, "description" text NOT NULL, - "condition" bigint DEFAULT 0 NOT NULL, "default" smallint NOT NULL DEFAULT 0, "checked_out_time" timestamp without time zone, "checked_out" bigint DEFAULT 0 NOT NULL, @@ -80,11 +79,11 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- Dumping data for table "#__workflow_stages" -- -INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "condition", "default", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 0, 1, NULL, 0), -(2, 0, 2, 1, 1, 'JPUBLISHED', '', 1, 0, NULL, 0), -(3, 0, 3, 1, 1, 'JTRASHED', '', -2, 0, NULL, 0), -(4, 0, 4, 1, 1, 'JARCHIVED', '', 2, 0, NULL, 0); +INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES +(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), +(2, 0, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), +(3, 0, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), +(4, 0, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); -- -- Table structure for table "#__workflow_transitions" diff --git a/administrator/components/com_workflow/forms/filter_stages.xml b/administrator/components/com_workflow/forms/filter_stages.xml index bf9da05b14531..830e16abaf336 100644 --- a/administrator/components/com_workflow/forms/filter_stages.xml +++ b/administrator/components/com_workflow/forms/filter_stages.xml @@ -17,14 +17,6 @@ > - - - @@ -43,8 +35,6 @@ - - diff --git a/administrator/components/com_workflow/forms/stage.xml b/administrator/components/com_workflow/forms/stage.xml index af53ea3f2606d..407b1c485aa0a 100644 --- a/administrator/components/com_workflow/forms/stage.xml +++ b/administrator/components/com_workflow/forms/stage.xml @@ -24,13 +24,6 @@ rows="3" cols="60" /> -
diff --git a/administrator/components/com_workflow/src/Model/StagesModel.php b/administrator/components/com_workflow/src/Model/StagesModel.php index 85f9da4441937..27a46555f2162 100644 --- a/administrator/components/com_workflow/src/Model/StagesModel.php +++ b/administrator/components/com_workflow/src/Model/StagesModel.php @@ -37,7 +37,6 @@ public function __construct($config = array()) 'id', 's.id', 'title', 's.title', 'ordering','s.ordering', - 'condition','s.condition', 'published', 's.published' ); } @@ -134,7 +133,6 @@ public function getListQuery() 's.id', 's.title', 's.ordering', - 's.condition', 's.default', 's.published', 's.checked_out', @@ -153,21 +151,13 @@ public function getListQuery() $query->where($db->quoteName('s.workflow_id') . ' = ' . $workflowID); } - $condition = $this->getState('filter.condition'); - - // Filter by condition - if (is_numeric($condition)) - { - $query->where($db->quoteName('s.condition') . ' = ' . (int) $db->escape($condition)); - } - // Join over the users for the checked out user. $query->select($db->quoteName('uc.name', 'editor')) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('s.checked_out')); $status = (string) $this->getState('filter.published'); - // Filter by condition + // Filter by publish state if (is_numeric($status)) { $query->where($db->quoteName('s.published') . ' = ' . (int) $status); diff --git a/administrator/components/com_workflow/src/Model/TransitionsModel.php b/administrator/components/com_workflow/src/Model/TransitionsModel.php index 37672982485ea..587d2f5c313fb 100644 --- a/administrator/components/com_workflow/src/Model/TransitionsModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionsModel.php @@ -146,9 +146,7 @@ public function getListQuery() ); $select[] = $db->quoteName('f_stage.title', 'from_stage'); - $select[] = $db->quoteName('f_stage.condition', 'from_condition'); $select[] = $db->quoteName('t_stage.title', 'to_stage'); - $select[] = $db->quoteName('t_stage.condition', 'to_condition'); $joinTo = $db->quoteName('#__workflow_stages', 't_stage') . ' ON ' . $db->quoteName('t_stage.id') . ' = ' . $db->quoteName('t.to_stage_id'); @@ -172,7 +170,7 @@ public function getListQuery() $status = $this->getState('filter.published'); - // Filter by condition + // Filter by status if (is_numeric($status)) { $query->where($db->quoteName('t.published') . ' = ' . (int) $status); diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index a588e9a5ff7d8..2a75d94ed3751 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -113,23 +113,19 @@ public function save($data) $stages = [ [ 'title' => 'JUNPUBLISHED', - 'condition' => Workflow::CONDITION_UNPUBLISHED, 'default' => 1, 'transition' => 'Unpublish' ], [ 'title' => 'JPUBLISHED', - 'condition' => Workflow::CONDITION_PUBLISHED, 'transition' => 'Publish' ], [ 'title' => 'JTRASHED', - 'condition' => Workflow::CONDITION_TRASHED, 'transition' => 'Trash' ], [ 'title' => 'JARCHIVED', - 'condition' => Workflow::CONDITION_ARCHIVED, 'transition' => 'Archive' ] ]; @@ -144,7 +140,6 @@ public function save($data) $table->id = 0; $table->title = $stage['title']; $table->workflow_id = $workflow_id; - $table->condition = $stage['condition']; $table->published = 1; $table->default = (int) !empty($stage['default']); $table->description = ''; diff --git a/administrator/components/com_workflow/src/Model/WorkflowsModel.php b/administrator/components/com_workflow/src/Model/WorkflowsModel.php index 779c9260a51dc..5473a1840d2c2 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowsModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowsModel.php @@ -217,7 +217,7 @@ public function getListQuery() $status = (string) $this->getState('filter.published'); - // Filter by condition + // Filter by status if (is_numeric($status)) { $query->where($db->quoteName('w.published') . ' = ' . (int) $status); diff --git a/administrator/components/com_workflow/src/View/Stages/HtmlView.php b/administrator/components/com_workflow/src/View/Stages/HtmlView.php index 7614fd95cd5ef..4b0e8c6fcfd57 100644 --- a/administrator/components/com_workflow/src/View/Stages/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Stages/HtmlView.php @@ -130,11 +130,6 @@ public function display($tpl = null) { $extension = Factory::getApplication()->input->getCmd('extension'); $workflow = new Workflow(['extension' => $extension]); - - foreach ($this->stages as $i => $item) - { - $item->condition = $workflow->getConditionName((int) $item->condition); - } } $this->addToolbar(); diff --git a/administrator/components/com_workflow/tmpl/stage/edit.php b/administrator/components/com_workflow/tmpl/stage/edit.php index 220038f1a04d4..f8bc54f05fa7b 100644 --- a/administrator/components/com_workflow/tmpl/stage/edit.php +++ b/administrator/components/com_workflow/tmpl/stage/edit.php @@ -39,7 +39,6 @@
- form->renderField('condition'); ?> form->renderField('description'); ?>
diff --git a/administrator/components/com_workflow/tmpl/stages/default.php b/administrator/components/com_workflow/tmpl/stages/default.php index 7bb3b46c7719c..9ea5bb8ae8e52 100644 --- a/administrator/components/com_workflow/tmpl/stages/default.php +++ b/administrator/components/com_workflow/tmpl/stages/default.php @@ -67,7 +67,7 @@ - + @@ -75,9 +75,6 @@ - - - @@ -133,21 +130,6 @@
escape(Text::_($item->description)); ?>
- - condition == 'JARCHIVED'): - $icon = 'icon-archive'; - elseif ($item->condition == 'JTRASHED'): - $icon = 'icon-trash'; - elseif ($item->condition == 'JPUBLISHED'): - $icon = 'icon-publish'; - elseif ($item->condition == 'JUNPUBLISHED'): - $icon = 'icon-unpublish'; - endif; - ?> - - condition); ?> - id; ?> diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index af7d6107a2b3e..1873e827b5796 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -133,42 +133,10 @@ from_stage_id < 0): ?> - from_condition == Workflow::CONDITION_ARCHIVED): - $icon = 'icon-archive'; - $condition = Text::_('JARCHIVED'); - elseif ($item->from_condition == Workflow::CONDITION_TRASHED): - $icon = 'icon-trash'; - $condition = Text::_('JTRASHED'); - elseif ($item->from_condition == Workflow::CONDITION_PUBLISHED): - $icon = 'icon-publish'; - $condition = Text::_('JPUBLISHED'); - elseif ($item->from_condition == Workflow::CONDITION_UNPUBLISHED): - $icon = 'icon-unpublish'; - $condition = Text::_('JUNPUBLISHED'); - endif; ?> - - escape(Text::_($item->from_stage)); ?> - to_condition == Workflow::CONDITION_ARCHIVED): - $icon = 'icon-archive'; - $condition = Text::_('JARCHIVED'); - elseif ($item->to_condition == Workflow::CONDITION_TRASHED): - $icon = 'icon-trash'; - $condition = Text::_('JTRASHED'); - elseif ($item->to_condition == Workflow::CONDITION_PUBLISHED): - $icon = 'icon-publish'; - $condition = Text::_('JPUBLISHED'); - elseif ($item->to_condition == Workflow::CONDITION_UNPUBLISHED): - $icon = 'icon-unpublish'; - $condition = Text::_('JUNPUBLISHED'); - endif; ?> - - escape(Text::_($item->to_stage)); ?> diff --git a/installation/sql/mysql/joomla.sql b/installation/sql/mysql/joomla.sql index 2836697b0edce..7c2d266639def 100644 --- a/installation/sql/mysql/joomla.sql +++ b/installation/sql/mysql/joomla.sql @@ -2369,7 +2369,6 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( `published` tinyint(1) NOT NULL DEFAULT 0, `title` varchar(255) NOT NULL, `description` text NOT NULL, - `condition` int(10) DEFAULT 0, `default` tinyint(1) NOT NULL DEFAULT 0, `checked_out_time` datetime, `checked_out` int(10) NOT NULL DEFAULT 0, @@ -2385,11 +2384,11 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- Dumping data for table `#__workflow_stages` -- -INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `condition`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 57, 1, 1, 1, 'JUNPUBLISHED', '', 0, 1, NULL, 0), -(2, 58, 2, 1, 1, 'JPUBLISHED', '', 1, 0, NULL, 0), -(3, 59, 3, 1, 1, 'JTRASHED', '', -2, 0, NULL, 0), -(4, 60, 4, 1, 1, 'JARCHIVED', '', 2, 0, NULL, 0); +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES +(1, 57, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), +(2, 58, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), +(3, 59, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), +(4, 60, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); -- -- Table structure for table `#__workflow_transitions` diff --git a/installation/sql/postgresql/joomla.sql b/installation/sql/postgresql/joomla.sql index 28cba57814a00..9a5b441404e79 100644 --- a/installation/sql/postgresql/joomla.sql +++ b/installation/sql/postgresql/joomla.sql @@ -2371,7 +2371,6 @@ CREATE TABLE IF NOT EXISTS "#__workflow_stages" ( "published" smallint NOT NULL DEFAULT 0, "title" varchar(255) NOT NULL, "description" text NOT NULL, - "condition" bigint DEFAULT 0 NOT NULL, "default" smallint NOT NULL DEFAULT 0, "checked_out_time" timestamp without time zone, "checked_out" bigint DEFAULT 0 NOT NULL, @@ -2387,11 +2386,11 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- Dumping data for table "#__workflow_stages" -- -INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "condition", "default", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 0, 1, NULL, 0), -(2, 0, 2, 1, 1, 'JPUBLISHED', '', 1, 0, NULL, 0), -(3, 0, 3, 1, 1, 'JTRASHED', '', -2, 0, NULL, 0), -(4, 0, 4, 1, 1, 'JARCHIVED', '', 2, 0, NULL, 0); +INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES +(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), +(2, 0, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), +(3, 0, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), +(4, 0, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); SELECT setval('#__workflow_stages_id_seq', 5, false); -- From 5a32050db8c3c37b3a3b184c49b084a334d2cd6c Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Sat, 14 Mar 2020 20:56:26 +0100 Subject: [PATCH 02/90] Workflow remove (#51) * Remove workflow from com_content frontend * Remove workflow from content helper * Remove workflow from modules * Remove workflow from plugin pagenavigation --- .../com_content/src/Model/ArchiveModel.php | 16 ++------------ .../com_content/src/Model/ArticleModel.php | 16 ++------------ .../com_content/src/Model/ArticlesModel.php | 20 ++++++----------- .../com_content/src/Model/CategoryModel.php | 2 +- .../com_content/src/Model/FeaturedModel.php | 2 +- .../com_content/tmpl/article/default.php | 2 +- .../com_content/tmpl/category/blog_item.php | 4 ++-- .../tmpl/category/default_articles.php | 4 ++-- libraries/src/Helper/ContentHelper.php | 22 +------------------ .../src/Helper/ArticlesArchiveHelper.php | 8 ++----- .../src/Helper/RelatedItemsHelper.php | 8 ++----- modules/mod_stats/src/Helper/StatsHelper.php | 13 +++-------- .../content/pagenavigation/pagenavigation.php | 7 +++--- 13 files changed, 29 insertions(+), 95 deletions(-) diff --git a/components/com_content/src/Model/ArchiveModel.php b/components/com_content/src/Model/ArchiveModel.php index 83ee2e9c274e7..162d014815f93 100644 --- a/components/com_content/src/Model/ArchiveModel.php +++ b/components/com_content/src/Model/ArchiveModel.php @@ -199,20 +199,8 @@ public function getYears() $years = $query->year($db->quoteName('c.created')); $query->select('DISTINCT ' . $years) - ->from( - [ - $db->quoteName('#__content', 'c'), - $db->quoteName('#__workflow_associations', 'wa'), - $db->quoteName('#__workflow_stages', 'ws'), - ] - ) - ->where( - [ - $db->quoteName('c.id') . ' = ' . $db->quoteName('wa.item_id'), - $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id'), - $db->quoteName('ws.condition') . ' = ' . ContentComponent::CONDITION_ARCHIVED, - ] - ) + ->from($db->quoteName('#__content', 'c')) + ->where($db->quoteName('c.state') . ' = ' . ContentComponent::CONDITION_ARCHIVED) ->extendWhere( 'AND', [ diff --git a/components/com_content/src/Model/ArticleModel.php b/components/com_content/src/Model/ArticleModel.php index 614c1d08d1515..c856d5ae0e97a 100644 --- a/components/com_content/src/Model/ArticleModel.php +++ b/components/com_content/src/Model/ArticleModel.php @@ -138,7 +138,6 @@ public function getItem($pk = null) [ $db->quoteName('fp.featured_up'), $db->quoteName('fp.featured_down'), - $db->quoteName('ws.condition'), $db->quoteName('c.title', 'category_title'), $db->quoteName('c.alias', 'category_alias'), $db->quoteName('c.access', 'category_access'), @@ -156,16 +155,6 @@ public function getItem($pk = null) ] ) ->from($db->quoteName('#__content', 'a')) - ->join( - 'INNER', - $db->quoteName('#__workflow_associations', 'wa'), - $db->quoteName('a.id') . ' = ' . $db->quoteName('wa.item_id') - ) - ->join( - 'INNER', - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('wa.stage_id') . ' = ' . $db->quoteName('ws.id') - ) ->join( 'INNER', $db->quoteName('#__categories', 'c'), @@ -178,7 +167,6 @@ public function getItem($pk = null) ->where( [ $db->quoteName('a.id') . ' = :pk', - $db->quoteName('wa.extension') . ' = ' . $db->quote('com_content'), $db->quoteName('c.published') . ' > 0', ] ) @@ -222,7 +210,7 @@ public function getItem($pk = null) if (is_numeric($published)) { - $query->whereIn($db->quoteName('ws.condition'), [(int) $published, (int) $archived]); + $query->whereIn($db->quoteName('a.state'), [(int) $published, (int) $archived]); } $db->setQuery($query); @@ -235,7 +223,7 @@ public function getItem($pk = null) } // Check for published state if filter set. - if ((is_numeric($published) || is_numeric($archived)) && ($data->condition != $published && $data->condition != $archived)) + if ((is_numeric($published) || is_numeric($archived)) && ($data->state != $published && $data->state != $archived)) { throw new \Exception(Text::_('COM_CONTENT_ERROR_ARTICLE_NOT_FOUND'), 404); } diff --git a/components/com_content/src/Model/ArticlesModel.php b/components/com_content/src/Model/ArticlesModel.php index 29f523ce54d93..9b28bf79b8735 100644 --- a/components/com_content/src/Model/ArticlesModel.php +++ b/components/com_content/src/Model/ArticlesModel.php @@ -52,7 +52,6 @@ public function __construct($config = array()) 'checked_out_time', 'a.checked_out_time', 'catid', 'a.catid', 'category_title', 'state', 'a.state', - 'stage_condition', 'ws.condition', 'access', 'a.access', 'access_level', 'created', 'a.created', 'created_by', 'a.created_by', @@ -243,13 +242,10 @@ protected function getListQuery() [ $db->quoteName('fp.featured_up'), $db->quoteName('fp.featured_down'), - $db->quoteName('wa.stage_id', 'stage_id'), - $db->quoteName('ws.title', 'state_title'), - $db->quoteName('ws.condition', 'stage_condition'), // Published/archived article in archived category is treated as archived article. If category is not published then force 0. - 'CASE WHEN ' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('ws.condition') . ' > 0 THEN ' . $conditionArchived + 'CASE WHEN ' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('a.state') . ' > 0 THEN ' . $conditionArchived . ' WHEN ' . $db->quoteName('c.published') . ' != 1 THEN ' . $conditionUnpublished - . ' ELSE ' . $db->quoteName('ws.condition') . ' END AS ' . $db->quoteName('state'), + . ' ELSE ' . $db->quoteName('a.state') . ' END AS ' . $db->quoteName('state'), $db->quoteName('c.title', 'category_title'), $db->quoteName('c.path', 'category_route'), $db->quoteName('c.access', 'category_access'), @@ -270,8 +266,6 @@ protected function getListQuery() ] ) ->from($db->quoteName('#__content', 'a')) - ->join('LEFT', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->join('LEFT', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) ->join('LEFT', $db->quoteName('#__categories', 'c'), $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid')) ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) ->join('LEFT', $db->quoteName('#__users', 'uam'), $db->quoteName('uam.id') . ' = ' . $db->quoteName('a.modified_by')) @@ -341,8 +335,8 @@ protected function getListQuery() * If category is archived then article has to be published or archived. * Or categogy is published then article has to be archived. */ - $query->where('((' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('ws.condition') . ' > :conditionUnpublished)' - . ' OR (' . $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('ws.condition') . ' = :conditionArchived))' + $query->where('((' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('a.state') . ' > :conditionUnpublished)' + . ' OR (' . $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state') . ' = :conditionArchived))' ) ->bind(':conditionUnpublished', $conditionUnpublished, ParameterType::INTEGER) ->bind(':conditionArchived', $conditionArchived, ParameterType::INTEGER); @@ -352,14 +346,14 @@ protected function getListQuery() $condition = (int) $condition; // Category has to be published - $query->where($db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('ws.condition') . ' = :wsCondition') - ->bind(':wsCondition', $condition, ParameterType::INTEGER); + $query->where($db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state') . ' = :condition') + ->bind(':condition', $condition, ParameterType::INTEGER); } elseif (is_array($condition)) { // Category has to be published $query->where( - $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('ws.condition') + $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state') . ' IN (' . implode(',', $query->bindArray($condition)) . ')' ); } diff --git a/components/com_content/src/Model/CategoryModel.php b/components/com_content/src/Model/CategoryModel.php index 4070055ae7c6a..0dd8b69b3d8ca 100644 --- a/components/com_content/src/Model/CategoryModel.php +++ b/components/com_content/src/Model/CategoryModel.php @@ -173,7 +173,7 @@ protected function populateState($ordering = null, $direction = null) } else { - $this->setState('filter.condition', array(0, 1)); + $this->setState('filter.condition', [0, 1]); } // Process show_noauth parameter diff --git a/components/com_content/src/Model/FeaturedModel.php b/components/com_content/src/Model/FeaturedModel.php index df200a6debca7..604379498d4c5 100644 --- a/components/com_content/src/Model/FeaturedModel.php +++ b/components/com_content/src/Model/FeaturedModel.php @@ -84,7 +84,7 @@ protected function populateState($ordering = null, $direction = null) } else { - $this->setState('filter.condition', array(ContentComponent::CONDITION_UNPUBLISHED, ContentComponent::CONDITION_PUBLISHED)); + $this->setState('filter.condition', [ContentComponent::CONDITION_UNPUBLISHED, ContentComponent::CONDITION_PUBLISHED]); } // Process show_noauth parameter diff --git a/components/com_content/tmpl/article/default.php b/components/com_content/tmpl/article/default.php index e0dc72cb9a08b..3b54c1c4f2581 100644 --- a/components/com_content/tmpl/article/default.php +++ b/components/com_content/tmpl/article/default.php @@ -53,7 +53,7 @@

escape($this->item->title); ?>

- item->condition == ContentComponent::CONDITION_UNPUBLISHED) : ?> + item->state == ContentComponent::CONDITION_UNPUBLISHED) : ?> item->publish_up) > strtotime(Factory::getDate())) : ?> diff --git a/components/com_content/tmpl/category/blog_item.php b/components/com_content/tmpl/category/blog_item.php index 684404121ca6d..d2c07719042aa 100644 --- a/components/com_content/tmpl/category/blog_item.php +++ b/components/com_content/tmpl/category/blog_item.php @@ -30,7 +30,7 @@ item); ?>
- item->stage_condition == ContentComponent::CONDITION_UNPUBLISHED || strtotime($this->item->publish_up) > strtotime(Factory::getDate()) + item->state == ContentComponent::CONDITION_UNPUBLISHED || strtotime($this->item->publish_up) > strtotime(Factory::getDate()) || (!is_null($this->item->publish_down) && strtotime($this->item->publish_down) < strtotime(Factory::getDate()))) : ?>
@@ -86,7 +86,7 @@ - item->stage_condition == ContentComponent::CONDITION_UNPUBLISHED || strtotime($this->item->publish_up) > strtotime(Factory::getDate()) + item->state == ContentComponent::CONDITION_UNPUBLISHED || strtotime($this->item->publish_up) > strtotime(Factory::getDate()) || (!is_null($this->item->publish_down) && strtotime($this->item->publish_down) < strtotime(Factory::getDate()))) : ?>
diff --git a/components/com_content/tmpl/category/default_articles.php b/components/com_content/tmpl/category/default_articles.php index 522fd600e0b11..829fdd0660b50 100644 --- a/components/com_content/tmpl/category/default_articles.php +++ b/components/com_content/tmpl/category/default_articles.php @@ -180,7 +180,7 @@ items as $i => $article) : ?> - items[$i]->stage_condition == ContentComponent::CONDITION_UNPUBLISHED) : ?> + items[$i]->state == ContentComponent::CONDITION_UNPUBLISHED) : ?> @@ -225,7 +225,7 @@ - stage_condition == ContentComponent::CONDITION_UNPUBLISHED) : ?> + state == ContentComponent::CONDITION_UNPUBLISHED) : ?> diff --git a/libraries/src/Helper/ContentHelper.php b/libraries/src/Helper/ContentHelper.php index 8a11123651dec..566f1a265d408 100644 --- a/libraries/src/Helper/ContentHelper.php +++ b/libraries/src/Helper/ContentHelper.php @@ -66,8 +66,6 @@ public static function countRelations(&$items, $config) '2' => 'count_archived', ); - $usesWorkflows = (isset($config->uses_workflows) && $config->uses_workflows === true); - // Index category objects by their ID $records = array(); @@ -87,7 +85,7 @@ public static function countRelations(&$items, $config) // Table alias for related data table below will be 'c', and state / condition column is inside related data table $related_tbl = '#__' . $config->related_tbl; - $state_col = ($usesWorkflows ? 's.' : 'c.') . $config->state_col; + $state_col = 'c.' . $config->state_col; // Supported cases switch ($config->relation_type) @@ -117,24 +115,6 @@ public static function countRelations(&$items, $config) return $items; } - if ($usesWorkflows) - { - $query->from( - [ - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('#__workflow_associations', 'a'), - ] - ) - ->where( - [ - $db->quoteName('s.id') . ' = ' . $db->quoteName('a.stage_id'), - $db->quoteName('a.extension') . ' = :component', - $db->quoteName('a.item_id') . ' = ' . $db->quoteName('c.id'), - ] - ) - ->bind(':component', $config->workflows_component); - } - /** * Get relation counts for all category objects with single query * NOTE: 'state IN', allows counting specific states / conditions only, also prevents warnings with custom states / conditions, do not remove diff --git a/modules/mod_articles_archive/src/Helper/ArticlesArchiveHelper.php b/modules/mod_articles_archive/src/Helper/ArticlesArchiveHelper.php index f0671a1d561ed..f06e1cc4cc083 100644 --- a/modules/mod_articles_archive/src/Helper/ArticlesArchiveHelper.php +++ b/modules/mod_articles_archive/src/Helper/ArticlesArchiveHelper.php @@ -38,19 +38,15 @@ public static function getList(&$params) { $app = Factory::getApplication(); $db = Factory::getDbo(); - $condition = ContentComponent::CONDITION_ARCHIVED; $query = $db->getQuery(true); $query->select($query->month($db->quoteName('created')) . ' AS created_month') ->select('MIN(' . $db->quoteName('created') . ') AS created') ->select($query->year($db->quoteName('created')) . ' AS created_year') ->from($db->quoteName('#__content', 'c')) - ->innerJoin($db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('c.id')) - ->innerJoin($db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('wa.stage_id') . ' = ' . $db->quoteName('ws.id')) - ->where($db->quoteName('ws.condition') . ' = :condition') + ->where($db->quoteName('c.state') . ' = ' . ContentComponent::CONDITION_ARCHIVED) ->group($query->year($db->quoteName('c.created')) . ', ' . $query->month($db->quoteName('c.created'))) - ->order($query->year($db->quoteName('c.created')) . ' DESC, ' . $query->month($db->quoteName('c.created')) . ' DESC') - ->bind(':condition', $condition, ParameterType::INTEGER); + ->order($query->year($db->quoteName('c.created')) . ' DESC, ' . $query->month($db->quoteName('c.created')) . ' DESC'); // Filter by language if ($app->getLanguageFilter()) diff --git a/modules/mod_related_items/src/Helper/RelatedItemsHelper.php b/modules/mod_related_items/src/Helper/RelatedItemsHelper.php index 6bdacc709dea5..53e707a3e6f91 100644 --- a/modules/mod_related_items/src/Helper/RelatedItemsHelper.php +++ b/modules/mod_related_items/src/Helper/RelatedItemsHelper.php @@ -41,7 +41,6 @@ public static function getList(&$params) $groups = Factory::getUser()->getAuthorisedViewLevels(); $maximum = (int) $params->get('maximum', 5); $factory = $app->bootComponent('com_content')->getMVCFactory(); - $condition = ContentComponent::CONDITION_PUBLISHED; // Get an instance of the generic articles model /** @var \Joomla\Component\Content\Site\Model\ArticlesModel $articles */ @@ -107,13 +106,10 @@ public static function getList(&$params) $query->clear() ->select($db->quoteName('a.id')) ->from($db->quoteName('#__content', 'a')) - ->join('LEFT', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->join('LEFT', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) ->where($db->quoteName('a.id') . ' != :id') - ->where($db->quoteName('ws.condition') . ' = :condition') + ->where($db->quoteName('a.state') . ' = ' . ContentComponent::CONDITION_PUBLISHED) ->whereIn($db->quoteName('a.access'), $groups) - ->bind(':id', $id, ParameterType::INTEGER) - ->bind(':condition', $condition, ParameterType::INTEGER); + ->bind(':id', $id, ParameterType::INTEGER); $binds = []; $wheres = []; diff --git a/modules/mod_stats/src/Helper/StatsHelper.php b/modules/mod_stats/src/Helper/StatsHelper.php index 76a5f125a5e13..a502f32b1a181 100644 --- a/modules/mod_stats/src/Helper/StatsHelper.php +++ b/modules/mod_stats/src/Helper/StatsHelper.php @@ -15,6 +15,7 @@ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; +use Joomla\Component\Content\Administrator\Extension\ContentComponent; /** * Helper for mod_stats @@ -94,11 +95,7 @@ public static function &getList(&$params) $query->clear() ->select('COUNT(' . $db->quoteName('c.id') . ') AS count_items') ->from($db->quoteName('#__content', 'c')) - ->leftJoin( - $db->quoteName('#__workflow_stages', 'ws') - . ' ON ' . $db->quoteName('ws.id') . ' = ' . $db->quoteName('c.state') - ) - ->where($db->quoteName('ws.condition') . ' = 1'); + ->where($db->quoteName('c.state') . ' = ' . ContentComponent::CONDITION_PUBLISHED); $db->setQuery($query); try @@ -132,11 +129,7 @@ public static function &getList(&$params) $query->clear() ->select('SUM(' . $db->quoteName('hits') . ') AS count_hits') ->from($db->quoteName('#__content')) - ->leftJoin( - $db->quoteName('#__workflow_stages', 'ws') - . ' ON ' . $db->quoteName('ws.id') . ' = ' . $db->quoteName('state') - ) - ->where($db->quoteName('ws.condition') . ' = 1'); + ->where($db->quoteName('state') . ' = ' . ContentComponent::CONDITION_PUBLISHED); $db->setQuery($query); try diff --git a/plugins/content/pagenavigation/pagenavigation.php b/plugins/content/pagenavigation/pagenavigation.php index 1510a23d19766..321a57ecd393d 100644 --- a/plugins/content/pagenavigation/pagenavigation.php +++ b/plugins/content/pagenavigation/pagenavigation.php @@ -14,6 +14,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; +use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Site\Helper\RouteHelper; /** @@ -123,7 +124,7 @@ public function onContentBeforeDisplay($context, &$row, &$params, $page = 0) break; } - $xwhere = ' AND (ws.condition = 1 OR ws.condition = -2)' + $xwhere = ' AND (a.state IN (' . ContentComponent::CONDITION_PUBLISHED . ', ' . ContentComponent::CONDITION_ARCHIVED . '))' . ' AND (publish_up IS NULL OR publish_up <= ' . $db->quote($now) . ')' . ' AND (publish_down IS NULL OR publish_down >= ' . $db->quote($now) . ')'; @@ -142,9 +143,7 @@ public function onContentBeforeDisplay($context, &$row, &$params, $page = 0) ->select($case_when) ->select($case_when1) ->from('#__content AS a') - ->join('LEFT', '#__categories AS cc ON cc.id = a.catid') - ->join('LEFT', '#__workflow_associations AS wa', 'wa.item_id = a.id') - ->join('LEFT', '#__workflow_stages AS ws', 'wa.stage_id = ws.id'); + ->join('LEFT', '#__categories AS cc ON cc.id = a.catid'); if ($order_method === 'author' || $order_method === 'rauthor') { From 26e40ea5aea8717635d5c7a49f1c6688861be10f Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Tue, 24 Mar 2020 17:00:48 +0100 Subject: [PATCH 03/90] Workflow remove (#53) * Remove workflow from com_content frontend * Remove workflow from content helper * Remove workflow from modules * Remove workflow from plugin pagenavigation * Add workflow model interface and traid * Set WorkflowBehaviorTrait function public --- .../com_content/src/Model/ArticleModel.php | 17 ++- .../src/MVC/Model/WorkflowBehaviorTrait.php | 106 ++++++++++++++++++ .../src/MVC/Model/WorkflowModelInterface.php | 36 ++++++ .../src/Workflow/WorkflowServiceInterface.php | 15 ++- .../src/Workflow/WorkflowServiceTrait.php | 59 +++++++++- 5 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 libraries/src/MVC/Model/WorkflowBehaviorTrait.php create mode 100644 libraries/src/MVC/Model/WorkflowModelInterface.php diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index c4839991de16c..c969e4bf991fd 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -13,12 +13,16 @@ use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; +use Joomla\CMS\Form\FormFactoryInterface; use Joomla\CMS\Helper\TagsHelper; use Joomla\CMS\Language\Associations; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; +use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\AdminModel; +use Joomla\CMS\MVC\Model\WorkflowBehaviorTrait; +use Joomla\CMS\MVC\Model\WorkflowModelInterface; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\String\PunycodeHelper; use Joomla\CMS\Table\Category; @@ -41,8 +45,10 @@ * @since 1.6 */ -class ArticleModel extends AdminModel +class ArticleModel extends AdminModel implements WorkflowModelInterface { + use WorkflowBehaviorTrait; + /** * The prefix to use with controller messages. * @@ -67,6 +73,13 @@ class ArticleModel extends AdminModel */ protected $associationsContext = 'com_content.item'; + public function __construct($config = array(), MVCFactoryInterface $factory = null, FormFactoryInterface $formFactory = null) { + + parent::__construct($config, $factory, $formFactory); + + $this->setUpWorkflow('com_content.article'); + } + /** * Function that can be overriden to do any data cleanup after batch copying data * @@ -1274,6 +1287,8 @@ protected function preprocessForm(Form $form, $data, $group = 'content') } } + $this->preprocessFormWorkflow($form, $data); + parent::preprocessForm($form, $data, $group); } diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php new file mode 100644 index 0000000000000..98e7ab4b47b6d --- /dev/null +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -0,0 +1,106 @@ +extension = $extension; + } + + /** + * Method to allow derived classes to preprocess the form. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + * + * @throws \Exception if there is an error in the form event. + * @since 4.0.0 + * @see FormField + */ + public function preprocessFormWorkflow(Form $form, $data) { + + // Import the appropriate plugin group. + PluginHelper::importPlugin('workflow'); + } + + /** + * Batch change workflow stage or current. + * + * @param integer $value The workflow stage ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 4.0.0 + */ + public function batchWorkflowStage(int $value, array $pks, array $contexts) { + + $user = Factory::getApplication()->getIdentity(); + /** @var $workflow */ + $workflow = Factory::getApplication()->bootComponent('com_workflow'); + + if (!$user->authorise('core.admin', $this->option)) + { + $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); + } + + // Get workflow stage information + $stage = $workflow->createTable('Stage', 'Administrator'); + + if (empty($value) || !$stage->load($value)) + { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + if (empty($pks)) + { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + $workflow = new Workflow(['extension' => $this->option]); + + // Update workflow associations + return $workflow->updateAssociations($pks, $value); + } + +} diff --git a/libraries/src/MVC/Model/WorkflowModelInterface.php b/libraries/src/MVC/Model/WorkflowModelInterface.php new file mode 100644 index 0000000000000..cba3aef197647 --- /dev/null +++ b/libraries/src/MVC/Model/WorkflowModelInterface.php @@ -0,0 +1,36 @@ + true, + 'joomla.featured' => true, + ]; + + /** + * Check if the functionality is supported by the context + * + * @param string $feature The functionality + * @param string $context The context of the functionality + * + * @return bool + */ + public function supportFunctionality($functionality, $context): bool { + + if (empty($this->supportedFunctionality[$functionality])) + { + return false; + } + + if (!is_array($this->supportedFunctionality[$functionality])) + { + return true; + } + + return in_array($context, $this->supportedFunctionality[$functionality]); + } + /** * Returns an array of possible conditions for the component. * @@ -26,8 +60,25 @@ trait WorkflowServiceTrait * * @since 4.0.0 */ - public static function getConditions(string $extension): array - { + public static function getConditions(string $extension): array { + return \defined('self::CONDITION_NAMES') ? self::CONDITION_NAMES : Workflow::CONDITION_NAMES; } + + public function isWorkflowActive($context): bool { + + $parts = explode('.', $context); + $config = ComponentHelper::getParams($parts[0]); + + if (!$config->get('workflows_enable', 1)) + { + return false; + } + + $component = $this->getMVCFactory(); + $appName = Factory::getApplication()->getName(); + $model = $component->createModel($parts[1], $appName, ['ignore_request' => true]); + + return $model instanceof WorkflowModelInterface; + } } From 54d0f94123e12df6746f412a60c062a0faec6bf5 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Tue, 24 Mar 2020 22:14:44 +0100 Subject: [PATCH 04/90] Remove condition from com_content (#54) * Remove condition from workflow component * Load Workflow plugins on transition generation * Remove condition from com_content --- .../com_content/forms/filter_articles.xml | 8 +++--- .../com_content/forms/filter_featured.xml | 8 +++--- .../com_content/src/Model/ArticleModel.php | 3 +-- .../com_content/src/Model/ArticlesModel.php | 27 +++++-------------- .../com_content/src/Model/FeaturedModel.php | 1 - .../src/View/Articles/HtmlView.php | 5 ++++ .../src/View/Featured/HtmlView.php | 5 +++- .../com_content/tmpl/articles/default.php | 8 +++--- .../src/Model/TransitionModel.php | 19 +++++++++++++ administrator/language/en-GB/joomla.ini | 1 - 10 files changed, 49 insertions(+), 36 deletions(-) diff --git a/administrator/components/com_content/forms/filter_articles.xml b/administrator/components/com_content/forms/filter_articles.xml index 8516a88df209a..c169e5c075d8b 100644 --- a/administrator/components/com_content/forms/filter_articles.xml +++ b/administrator/components/com_content/forms/filter_articles.xml @@ -34,13 +34,13 @@ - + - + select( [ $db->quoteName('w.id'), - $db->quoteName('ws.condition'), $db->quoteName('ws.id', 'stage_id'), ] ) @@ -1453,7 +1453,6 @@ protected function getWorkflowByCategory(int $catId) $query->select( [ $db->quoteName('w.id'), - $db->quoteName('ws.condition'), $db->quoteName('ws.id', 'stage_id'), ] ) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 6dcb3f047a511..21136b63346a5 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -68,7 +68,6 @@ public function __construct($config = array()) 'level', 'tag', 'rating_count', 'rating', - 'condition', 'stage', ); @@ -120,9 +119,6 @@ protected function populateState($ordering = 'a.id', $direction = 'desc') $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); $this->setState('filter.published', $published); - $condition = $this->getUserStateFromRequest($this->context . '.filter.condition', 'filter_condition', ''); - $this->setState('filter.condition', $condition); - $level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level'); $this->setState('filter.level', $level); @@ -251,7 +247,6 @@ protected function getListQuery() $db->quoteName('ua.name', 'author_name'), $db->quoteName('wa.stage_id', 'stage_id'), $db->quoteName('ws.title', 'stage_title'), - $db->quoteName('ws.condition', 'stage_condition'), $db->quoteName('ws.workflow_id', 'workflow_id'), ] ) @@ -339,20 +334,20 @@ protected function getListQuery() ->bind(':stage', $workflowStage, ParameterType::INTEGER); } - $condition = (string) $this->getState('filter.condition'); + $published = (string) $this->getState('filter.published'); - if ($condition !== '*') + if ($published !== '*') { - if (is_numeric($condition)) + if (is_numeric($published)) { - $condition = (int) $condition; - $query->where($db->quoteName('ws.condition') . ' = :condition') - ->bind(':condition', $condition, ParameterType::INTEGER); + $state = (int) $state; + $query->where($db->quoteName('a.state') . ' = :state') + ->bind(':state', $published, ParameterType::INTEGER); } elseif (!is_numeric($workflowStage)) { $query->whereIn( - $db->quoteName('ws.condition'), + $db->quoteName('a.state'), [ ContentComponent::CONDITION_PUBLISHED, ContentComponent::CONDITION_UNPUBLISHED, @@ -581,7 +576,6 @@ public function getTransitions() $db->quoteName('t.to_stage_id'), $db->quoteName('s.id', 'stage_id'), $db->quoteName('s.title', 'stage_title'), - $db->quoteName('s.condition', 'stage_condition'), $db->quoteName('s.workflow_id'), ] ) @@ -610,13 +604,6 @@ public function getTransitions() { unset($transitions[$key]); } - else - { - // Update the transition text with final state value - $conditionName = $workflow->getConditionName((int) $transition['stage_condition']); - - $transitions[$key]['text'] .= ' [' . Text::_($conditionName) . ']'; - } } $this->cache[$store] = $transitions; diff --git a/administrator/components/com_content/src/Model/FeaturedModel.php b/administrator/components/com_content/src/Model/FeaturedModel.php index 672efda533e73..e6a8fbf8d1c0d 100644 --- a/administrator/components/com_content/src/Model/FeaturedModel.php +++ b/administrator/components/com_content/src/Model/FeaturedModel.php @@ -56,7 +56,6 @@ public function __construct($config = array()) 'level', 'tag', 'rating_count', 'rating', - 'condition', 'stage', ); } diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 5a18f390c60c3..1c53b31872383 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -116,6 +116,9 @@ public function display($tpl = null) $this->filterForm->setFieldAttribute('category_id', 'language', '*,' . $forcedLanguage, 'filter'); } } + + /* + @TODO Move to the plugin $transitions = [ 'publish' => [], @@ -147,6 +150,8 @@ public function display($tpl = null) } $this->document->addScriptOptions('articles.transitions', $transitions); + + */ $articles = []; diff --git a/administrator/components/com_content/src/View/Featured/HtmlView.php b/administrator/components/com_content/src/View/Featured/HtmlView.php index d0a7e559e599b..a4b9e838b9124 100644 --- a/administrator/components/com_content/src/View/Featured/HtmlView.php +++ b/administrator/components/com_content/src/View/Featured/HtmlView.php @@ -95,7 +95,9 @@ public function display($tpl = null) unset($this->activeFilters['language']); $this->filterForm->removeField('language', 'filter'); } - + + /* + @TODO Move to plugin $transitions = [ 'publish' => [], 'unpublish' => [], @@ -126,6 +128,7 @@ public function display($tpl = null) } $this->document->addScriptOptions('articles.transitions', $transitions); + */ $articles = []; diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index efeb9c6d23520..843d68faf60d9 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -172,7 +172,9 @@ $archive = 0; $trash = 0; - foreach ($transitions as $transition) : + /* + * @TODO This should be moved to a plugin + the data attributes in the tr below + foreach ($transitions as $transition) : switch ($transition['stage_condition']) : case ContentComponent::CONDITION_PUBLISHED: ++$publish; @@ -187,7 +189,7 @@ ++$trash; break; endswitch; - endforeach; + endforeach;*/ ?> addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) ->setLayout('joomla.button.transition-button') - ->render($item->stage_condition, $i, $options, $item->publish_up, $item->publish_down); + ->render($item->state, $i, $options, $item->publish_up, $item->publish_down); ?>
diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index e0c2b3a453502..54759f45385d2 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -12,6 +12,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Factory; +use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\String\StringHelper; @@ -285,4 +286,22 @@ protected function loadFormData() return $data; } + + /** + * Trigger the form preparation for the workflow group + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * @param string $group The name of the plugin group to import (defaults to "content"). + * + * @return void + * + * @see FormField + * @since 4.0.0 + * @throws \Exception if there is an error in the form event. + */ + protected function preprocessForm(Form $form, $data, $group = 'workflow') + { + parent::preprocessForm($form, $data, $group); + } } diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index 511c9c4e01dfb..850a0af31a33f 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -909,7 +909,6 @@ JOPTION_SELECT_AUTHORS="- Select Authors -" JOPTION_SELECT_AUTHOR_ALIAS="- Select Author Alias -" JOPTION_SELECT_AUTHOR_ALIASES="- Select Author Aliases -" JOPTION_SELECT_CATEGORY="- Select Category -" -JOPTION_SELECT_CONDITION="- Select Condition -" JOPTION_SELECT_EDITOR="- Select Editor -" JOPTION_SELECT_FEATURED="- Select Featured -" JOPTION_SELECT_IMAGE="- Select Image -" From d6d9e6cdd5cab3daf5a2b36f16f0276de66f4ee1 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Wed, 25 Mar 2020 02:03:32 +0100 Subject: [PATCH 05/90] Workflow v3 content (#55) * Remove condition from workflow component * Load Workflow plugins on transition generation * Remove condition from com_content * Cleanup content from workflow --- .../src/Extension/ContentComponent.php | 17 +---- .../com_content/src/Helper/ContentHelper.php | 37 ---------- .../com_content/src/Model/ArticleModel.php | 71 +++---------------- .../src/View/Articles/HtmlView.php | 7 +- .../src/View/Featured/HtmlView.php | 4 +- .../com_content/tmpl/articles/default.php | 20 ++++-- .../com_content/tmpl/featured/default.php | 5 +- administrator/language/en-GB/joomla.ini | 2 +- api/language/en-GB/joomla.ini | 2 +- libraries/src/Workflow/Workflow.php | 35 --------- .../src/Workflow/WorkflowServiceInterface.php | 12 ---- 11 files changed, 37 insertions(+), 175 deletions(-) diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index 6681a88c13910..af81c0fdaaccc 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -223,7 +223,7 @@ public function countItems(array $items, string $section) { $config = (object) array( 'related_tbl' => 'content', - 'state_col' => 'condition', + 'state_col' => 'state', 'group_col' => 'catid', 'relation_type' => 'category_or_group', 'uses_workflows' => true, @@ -272,19 +272,4 @@ public function prepareForm(Form $form, $data) { ContentHelper::onPrepareForm($form, $data); } - - /** - * Method to change state of multiple ids - * - * @param array $pks Array of IDs - * @param int $condition Condition of the workflow state - * - * @return boolean - * - * @since 4.0.0 - */ - public static function updateContentState(array $pks, int $condition): bool - { - return ContentHelper::updateContentState($pks, $condition); - } } diff --git a/administrator/components/com_content/src/Helper/ContentHelper.php b/administrator/components/com_content/src/Helper/ContentHelper.php index 95d645301ae10..74415090f6fc1 100644 --- a/administrator/components/com_content/src/Helper/ContentHelper.php +++ b/administrator/components/com_content/src/Helper/ContentHelper.php @@ -73,43 +73,6 @@ function ($var) use ($pk, $workflow_id) ); } - /** - * Method to change state of multiple ids - * - * @param array $pks Array of IDs - * @param int $condition Condition of the workflow state - * - * @return boolean - * - * @since 4.0.0 - */ - public static function updateContentState(array $pks, int $condition): bool - { - if (empty($pks)) - { - return false; - } - - try - { - $db = Factory::getDbo(); - $query = $db->getQuery(true); - - $query->update($db->quoteName('#__content')) - ->set($db->quoteName('state') . ' = :condition') - ->whereIn($db->quoteName('id'), $pks) - ->bind(':condition', $condition, ParameterType::INTEGER); - - $db->setQuery($query)->execute(); - } - catch (\Exception $e) - { - return false; - } - - return true; - } - /** * Prepares a form * diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index 889849ebc076c..2a75d1a93395c 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -194,8 +194,7 @@ protected function batchWorkflowStage(int $value, array $pks, array $contexts) $workflow = new Workflow(['extension' => 'com_content']); // Update content state value and workflow associations - return ContentHelper::updateContentState($pks, (int) $stage->condition) - && $workflow->updateAssociations($pks, $value); + return $workflow->updateAssociations($pks, $value); } /** @@ -312,23 +311,12 @@ protected function batchMove($value, $pks, $contexts) */ protected function canDelete($record) { - if (!empty($record->id)) + if (empty($record->id) || $record->state != -2) { - $stage = new StageTable($this->getDbo()); - - $workflow = new Workflow(['extension' => 'com_content']); - - $assoc = $workflow->getAssociation((int) $record->id); - - if (!$stage->load($assoc->stage_id) || ($stage->condition != ContentComponent::CONDITION_TRASHED && !Factory::getApplication()->isClient('api'))) - { - return false; - } - - return Factory::getUser()->authorise('core.delete', 'com_content.article.' . (int) $record->id); + return false; } - return false; + return Factory::getUser()->authorise('core.delete', 'com_content.article.' . (int) $record->id); } /** @@ -958,50 +946,6 @@ public function save($data) $data['state'] = (int) $workflow->condition; } - // Calculate new status depending on transition - if (!empty($data['transition'])) - { - // Check if the user is allowed to execute this transition - if (!$user->authorise('core.execute.transition', 'com_content.transition.' . (int) $data['transition'])) - { - $this->setError(Text::_('COM_CONTENT_WORKFLOW_TRANSITION_NOT_ALLOWED')); - - return false; - } - - // Set the new state - $query = $db->getQuery(true); - $transition = (int) $data['transition']; - - $query->select($db->quoteName(['ws.id', 'ws.condition'])) - ->from( - [ - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflow_transitions', 'wt'), - ] - ) - ->where( - [ - $db->quoteName('wt.to_stage_id') . ' = ' . $db->quoteName('ws.id'), - $db->quoteName('wt.id') . ' = :transition', - $db->quoteName('ws.published') . ' = 1', - $db->quoteName('wt.published') . ' = 1', - ] - ) - ->bind(':transition', $transition, ParameterType::INTEGER); - - $stage = $db->setQuery($query)->loadObject(); - - if (empty($stage->id)) - { - $this->setError(Text::_('COM_CONTENT_WORKFLOW_TRANSITION_NOT_ALLOWED')); - - return false; - } - - $data['state'] = (int) $stage->condition; - } - // Automatic handling of alias for empty fields if (in_array($input->get('task'), array('apply', 'save', 'save2new')) && (!isset($data['id']) || (int) $data['id'] == 0)) { @@ -1507,13 +1451,16 @@ public function runTransition(int $pk, int $transition_id): bool } // B/C state change trigger for UCM - $context = $this->option . '.' . $this->name; + /* @TODO Move to transition + * $context = $this->option . '.' . $this->name; // Include the plugins for the change of stage event. PluginHelper::importPlugin($this->events_map['change_state']); // Trigger the change stage event. - Factory::getApplication()->triggerEvent($this->event_change_state, [$context, [$pk], $workflow->getConditionForTransition($transition_id)]); + //Factory::getApplication()->triggerEvent($this->event_change_state, [$context, [$pk]]); + * + */ return true; } diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 1c53b31872383..484ee2b37de36 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -120,6 +120,9 @@ public function display($tpl = null) /* @TODO Move to the plugin + /* + @TODO Move to the plugin + $transitions = [ 'publish' => [], 'unpublish' => [], @@ -153,6 +156,8 @@ public function display($tpl = null) */ + */ + $articles = []; foreach ($this->items as $item) @@ -250,7 +255,7 @@ protected function addToolbar() } } - if ($this->state->get('filter.condition') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) + if ($this->state->get('filter.published') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) { $toolbar->delete('articles.delete') ->text('JTOOLBAR_EMPTY_TRASH') diff --git a/administrator/components/com_content/src/View/Featured/HtmlView.php b/administrator/components/com_content/src/View/Featured/HtmlView.php index a4b9e838b9124..a69cc24d9a782 100644 --- a/administrator/components/com_content/src/View/Featured/HtmlView.php +++ b/administrator/components/com_content/src/View/Featured/HtmlView.php @@ -95,7 +95,7 @@ public function display($tpl = null) unset($this->activeFilters['language']); $this->filterForm->removeField('language', 'filter'); } - + /* @TODO Move to plugin $transitions = [ @@ -211,7 +211,7 @@ protected function addToolbar() } } - if ($this->state->get('filter.condition') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) + if ($this->state->get('filter.published') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) { $toolbar->delete('articles.delete') ->text('JTOOLBAR_EMPTY_TRASH') diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index 843d68faf60d9..443db164c06b5 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -11,6 +11,7 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Associations; @@ -54,6 +55,10 @@ HTMLHelper::_('draggablelist.draggable'); } +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflows_enable', 1); + +if ($workflow_enabled) : + $js = <<document->addScriptDeclaration($js); -$collection = new \stdClass; +HTMLHelper::_('script', 'com_content/admin-articles-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); -$collection->publish = []; -$collection->unpublish = []; -$collection->archive = []; -$collection->trash = []; +endif; $assoc = Associations::isEnabled(); - -HTMLHelper::_('script', 'com_content/admin-articles-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); ?>
@@ -238,6 +238,8 @@
$transitions, 'stage' => Text::_($item->stage_title), @@ -255,6 +257,10 @@ ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) ->setLayout('joomla.button.transition-button') ->render($item->state, $i, $options, $item->publish_up, $item->publish_down); + + else : + echo HTMLHelper::_('jgrid.published', $item->state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); + endif; ?>
diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index eea9eec4b4bcf..bfe3d22b0fbc5 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -157,6 +157,8 @@ $archive = 0; $trash = 0; + /* + * @TODO Move to plugin foreach ($transitions as $transition) : switch ($transition['stage_condition']) : case ContentComponent::CONDITION_PUBLISHED: @@ -174,6 +176,7 @@ endswitch; endforeach; + */ ?> addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) ->setLayout('joomla.button.transition-button') - ->render($item->stage_condition, $i, $options, $item->publish_up, $item->publish_down); + ->render($item->state, $i, $options, $item->publish_up, $item->publish_down); ?> diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index 850a0af31a33f..0b57302c8210f 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -646,7 +646,7 @@ JGLOBAL_WARNCOOKIES="Warning! Cookies must be enabled to access the Administrato JGLOBAL_WARNIE="Warning! Internet Explorer should not be used for proper operation of the Administrator Backend." JGLOBAL_WARNJAVASCRIPT="Warning! JavaScript must be enabled for proper operation of the Administrator Backend." JGLOBAL_WIDTH="Width" -JGLOBAL_WORKFLOWS_ENABLE_LABEL="Edit Workflows" +JGLOBAL_WORKFLOWS_ENABLE_LABEL="Enable Workflows" JGRID_HEADING_ACCESS="Access" JGRID_HEADING_ACCESS_ASC="Access ascending" diff --git a/api/language/en-GB/joomla.ini b/api/language/en-GB/joomla.ini index a861203ccbdc0..c414348f7ee65 100644 --- a/api/language/en-GB/joomla.ini +++ b/api/language/en-GB/joomla.ini @@ -642,7 +642,7 @@ JGLOBAL_VOTES_DESC="Votes descending" JGLOBAL_WARNCOOKIES="Warning! Cookies must be enabled to access the Administrator Backend." JGLOBAL_WARNJAVASCRIPT="Warning! JavaScript must be enabled for proper operation of the Administrator Backend." JGLOBAL_WIDTH="Width" -JGLOBAL_WORKFLOWS_ENABLE_LABEL="Edit Workflows" +JGLOBAL_WORKFLOWS_ENABLE_LABEL="Enable Workflows" JGRID_HEADING_ACCESS="Access" JGRID_HEADING_ACCESS_ASC="Access ascending" diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index f82d2a9094809..ddeb536bad673 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -171,7 +171,6 @@ public function executeTransition(array $pks, int $transition_id): bool $db->quoteName('t.id'), $db->quoteName('t.to_stage_id'), $db->quoteName('t.from_stage_id'), - $db->quoteName('s.condition'), ] ) ->from($db->quoteName('#__workflow_transitions', 't')) @@ -197,13 +196,6 @@ public function executeTransition(array $pks, int $transition_id): bool } } - $component = $this->getComponent(); - - if ($component instanceof WorkflowServiceInterface) - { - $component->updateContentState($pks, (int) $transition->condition); - } - $success = $this->updateAssociations($pks, (int) $transition->to_stage_id); if ($success) @@ -223,33 +215,6 @@ public function executeTransition(array $pks, int $transition_id): bool return $success; } - /** - * Gets the condition (i.e. state value) for a transition - * - * @param integer $transition_id The transition id to get the condition of - * - * @return integer|null Integer if transition exists. Otherwise null - */ - public function getConditionForTransition(int $transition_id): ?int - { - $db = Factory::getDbo(); - $query = $db->getQuery(true); - $query->select($db->quoteName('s.condition')) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) - ->where($db->quoteName('t.id') . ' = :transition_id') - ->bind(':transition_id', $transition_id, ParameterType::INTEGER); - $db->setQuery($query); - $condition = $db->loadResult(); - - if ($condition !== null) - { - $condition = (int) $condition; - } - - return $condition; - } - /** * Creates an association for the workflow_associations table * diff --git a/libraries/src/Workflow/WorkflowServiceInterface.php b/libraries/src/Workflow/WorkflowServiceInterface.php index 6e45fa64a9004..abb81000168c8 100644 --- a/libraries/src/Workflow/WorkflowServiceInterface.php +++ b/libraries/src/Workflow/WorkflowServiceInterface.php @@ -40,18 +40,6 @@ public function supportFunctionality($functionality, $context): bool; */ public function filterTransitions(array $transitions, int $pk): array; - /** - * Method to change state of multiple ids - * - * @param array $pks Array of IDs - * @param integer $condition Condition of the workflow state - * - * @return boolean - * - * @since 4.0.0 - */ - public static function updateContentState(array $pks, int $condition): bool; - /** * Returns an array of possible conditions for the component. * From 11a029b90cd7f8a43e808995fcde99158ed1e64a Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Sat, 18 Apr 2020 05:26:52 +0200 Subject: [PATCH 06/90] Remove workflow from com_content (#56) * Remove more conditions Load transition field if component uses WorkflowModelTrait * Revert publish method to Joomla! 3 version and add workflow plugin group * Fix spelling error * Execute transition if selected in the item Add before/after item save for workflow --- .../components/com_content/forms/article.xml | 17 +- .../com_content/src/Model/ArticleModel.php | 395 +----------------- .../src/View/Articles/HtmlView.php | 5 - administrator/language/en-GB/com_content.ini | 2 +- libraries/src/Form/Field/TransitionField.php | 10 - .../src/MVC/Controller/AdminController.php | 5 +- libraries/src/MVC/Model/AdminModel.php | 3 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 366 +++++++++++++++- .../src/MVC/Model/WorkflowModelInterface.php | 60 ++- libraries/src/Workflow/Workflow.php | 13 +- 10 files changed, 453 insertions(+), 423 deletions(-) diff --git a/administrator/components/com_content/forms/article.xml b/administrator/components/com_content/forms/article.xml index 91092af9a3007..f3bc14773de4a 100644 --- a/administrator/components/com_content/forms/article.xml +++ b/administrator/components/com_content/forms/article.xml @@ -67,11 +67,18 @@ /> + name="state" + type="list" + label="JSTATUS" + class="custom-select-color-state" + size="1" + default="1" + > + + + + + setUpWorkflow('com_content.article'); @@ -126,11 +125,9 @@ protected function cleanupPostBatchCopy(TableInterface $table, $newId, $oldId) } // Copy workflow association - $workflow = new Workflow(['extension' => 'com_content']); - - $assoc = $workflow->getAssociation((int) $oldId); + $assoc = $this->workflow->getAssociation((int) $oldId); - $workflow->createAssociation((int) $newId, (int) $assoc->stage_id); + $this->workflow->createAssociation((int) $newId, (int) $assoc->stage_id); // Register FieldsHelper \JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php'); @@ -154,49 +151,6 @@ protected function cleanupPostBatchCopy(TableInterface $table, $newId, $oldId) Factory::getApplication()->triggerEvent('onContentAfterSave', array('com_content.article', &$this->table, false, $fieldsData)); } - /** - * Batch change workflow stage or current. - * - * @param integer $value The workflow stage ID. - * @param array $pks An array of row IDs. - * @param array $contexts An array of item contexts. - * - * @return mixed An array of new IDs on success, boolean false on failure. - * - * @since 4.0.0 - */ - protected function batchWorkflowStage(int $value, array $pks, array $contexts) - { - $user = Factory::getUser(); - - if (!$user->authorise('core.admin', 'com_content')) - { - $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); - } - - // Get workflow stage information - $stage = new StageTable($this->_db); - - if (empty($value) || !$stage->load($value)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - if (empty($pks)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - $workflow = new Workflow(['extension' => 'com_content']); - - // Update content state value and workflow associations - return $workflow->updateAssociations($pks, $value); - } - /** * Batch move categories to a new category. * @@ -392,114 +346,9 @@ protected function prepareTable($table) */ public function publish(&$pks, $value = 1) { - $input = Factory::getApplication()->input; - - $user = Factory::getUser(); - $table = $this->getTable(); - $pks = (array) $pks; - $value = (int) $value; - - $itrans = $input->get('publish_transitions', [], 'array'); - - // Include the plugins for the change of state event. - PluginHelper::importPlugin($this->events_map['change_state']); - - $db = $this->getDbo(); - $query = $db->getQuery(true); - - $query->select( - [ - $db->quoteName('wt.id'), - $db->quoteName('wa.item_id'), - ] - ) - ->from( - [ - $db->quoteName('#__workflow_transitions', 'wt'), - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflow_stages', 'ws2'), - $db->quoteName('#__workflow_associations', 'wa'), - ] - ) - ->where( - [ - $db->quoteName('wt.to_stage_id') . ' = ' . $db->quoteName('ws.id'), - $db->quoteName('wa.stage_id') . ' = ' . $db->quoteName('ws2.id'), - $db->quoteName('wt.workflow_id') . ' = ' . $db->quoteName('ws.workflow_id'), - $db->quoteName('wt.workflow_id') . ' = ' . $db->quoteName('ws2.workflow_id'), - $db->quoteName('wt.to_stage_id') . ' != ' . $db->quoteName('wa.stage_id'), - $db->quoteName('wa.extension') . ' = ' . $db->quote('com_content'), - $db->quoteName('ws.condition') . ' = :condition', - ] - ) - ->extendWhere( - 'AND', - [ - $db->quoteName('wt.from_stage_id') . ' = -1', - $db->quoteName('wt.from_stage_id') . ' = ' . $db->quoteName('wa.stage_id'), - ], - 'OR' - ) - ->whereIn($db->quoteName('wa.item_id'), $pks) - ->bind(':condition', $value, ParameterType::INTEGER); - - $transitions = $db->setQuery($query)->loadObjectList(); - - $items = []; - - foreach ($transitions as $transition) - { - if ($user->authorise('core.execute.transition', 'com_content.transition.' . $transition->id)) - { - if (!isset($itrans[$transition->item_id]) || $itrans[$transition->item_id] == $transition->id) - { - $items[$transition->item_id] = (int) $transition->id; - } - } - } + $this->importWorkflowPlugins(); - // Access checks. - foreach ($pks as $i => $pk) - { - $table->reset(); - - if ($table->load($pk)) - { - if (!isset($items[$pk])) - { - // Prune items that you can't change. - unset($pks[$i]); - - Log::add(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), Log::WARNING, 'jerror'); - - return false; - } - - // If the table is checked out by another user, drop it and report to the user trying to change its state. - if ($table->hasField('checked_out') && $table->checked_out && ($table->checked_out != $user->id)) - { - Log::add(Text::_('JLIB_APPLICATION_ERROR_CHECKIN_USER_MISMATCH'), Log::WARNING, 'jerror'); - - // Prune items that you can't change. - unset($pks[$i]); - - return false; - } - } - } - - foreach ($pks as $i => $pk) - { - if (!$this->runTransition($pk, $items[$pk])) - { - return false; - } - } - - // Clear the component's cache - $this->cleanCache(); - - return true; + return parent::publish($pks, $value); } /** @@ -630,18 +479,6 @@ public function getForm($data = array(), $loadData = true) $form->setFieldAttribute('catid', 'filter', 'unset'); } } - - $table = $this->getTable(); - - if ($table->load(array('id' => $id))) - { - $workflow = new Workflow(['extension' => 'com_content']); - - // Transition field - $assoc = $workflow->getAssociation($table->id); - - $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); - } } else { @@ -677,10 +514,6 @@ public function getForm($data = array(), $loadData = true) $form->setFieldAttribute('catid', 'refresh-enabled', true); $form->setFieldAttribute('catid', 'refresh-cat-id', $assignedCatids); $form->setFieldAttribute('catid', 'refresh-section', 'article'); - - $workflow = $this->getWorkflowByCategory($assignedCatids); - - $form->setFieldAttribute('transition', 'workflow_stage', (int) $workflow->stage_id); } } @@ -842,6 +675,8 @@ public function save($data) $data['images'] = (string) $registry; } + $this->workflowBeforeSave(); + // Create new category, if needed. $createCategory = true; @@ -926,26 +761,6 @@ public function save($data) } } - $stageId = 0; - - // Set status depending on category - if (empty($data['id'])) - { - $workflow = $this->getWorkflowByCategory($data['catid']); - - if (empty($workflow->id)) - { - $this->setError(Text::_('COM_CONTENT_WORKFLOW_NOT_FOUND')); - - return false; - } - - $stageId = (int) $workflow->stage_id; - - // B/C state - $data['state'] = (int) $workflow->condition; - } - // Automatic handling of alias for empty fields if (in_array($input->get('task'), array('apply', 'save', 'save2new')) && (!isset($data['id']) || (int) $data['id'] == 0)) { @@ -977,8 +792,6 @@ public function save($data) } } - $workflow = new Workflow(['extension' => 'com_content']); - if (parent::save($data)) { if (isset($data['featured'])) @@ -991,47 +804,7 @@ public function save($data) ); } - // Let's check if we have workflow association (perhaps something went wrong before) - if (empty($stageId)) - { - $assoc = $workflow->getAssociation((int) $this->getState($this->getName() . '.id')); - - // If not, reset the state and let's create the associations - if (empty($assoc->item_id)) - { - $table = $this->getTable(); - - $table->load((int) $this->getState($this->getName() . '.id')); - - $workflow = $this->getWorkflowByCategory((int) $table->catid); - - if (empty($workflow->id)) - { - $this->setError(Text::_('COM_CONTENT_WORKFLOW_NOT_FOUND')); - - return false; - } - - $stageId = (int) $workflow->stage_id; - - // B/C state - $table->state = $workflow->condition; - - $table->store(); - } - } - - // If we have a new state, create the workflow association - if (!empty($stageId)) - { - $workflow->createAssociation((int) $this->getState($this->getName() . '.id'), (int) $stageId); - } - - // Run the transition and update the workflow association - if (!empty($data['transition'])) - { - $this->runTransition((int) $this->getState($this->getName() . '.id'), (int) $data['transition']); - } + $this->workflowAfterSave($data); return true; } @@ -1232,7 +1005,7 @@ protected function preprocessForm(Form $form, $data, $group = 'content') } } - $this->preprocessFormWorkflow($form, $data); + $this->workflowPreprocessForm($form, $data); parent::preprocessForm($form, $data, $group); } @@ -1305,9 +1078,7 @@ public function delete(&$pks) $db->setQuery($query); $db->execute(); - $workflow = new Workflow(['extension' => 'com_content']); - - $workflow->deleteAssociation($pks); + $this->workflow->deleteAssociation($pks); } return $return; @@ -1320,148 +1091,4 @@ public function delete(&$pks) * * @return integer|boolean If found, the workflow ID, otherwise false */ - protected function getWorkflowByCategory(int $catId) - { - $db = $this->getDbo(); - - // Search categories and parents (if requested) for a workflow - $category = new Category($db); - - $categories = array_reverse($category->getPath($catId)); - - $workflow_id = 0; - - foreach ($categories as $cat) - { - $cat->params = new Registry($cat->params); - - $workflow_id = $cat->params->get('workflow_id'); - - if ($workflow_id == 'inherit') - { - $workflow_id = 0; - - continue; - } - elseif ($workflow_id == 'use_default') - { - $workflow_id = 0; - - break; - } - elseif ($workflow_id > 0) - { - break; - } - } - - // Check if the workflow exists - if ($workflow_id = (int) $workflow_id) - { - $query = $db->getQuery(true); - - $query->select( - [ - $db->quoteName('w.id'), - $db->quoteName('ws.id', 'stage_id'), - ] - ) - ->from( - [ - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflows', 'w'), - ] - ) - ->where( - [ - $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), - $db->quoteName('ws.default') . ' = 1', - $db->quoteName('w.published') . ' = 1', - $db->quoteName('ws.published') . ' = 1', - $db->quoteName('w.id') . ' = :workflowId', - ] - ) - ->bind(':workflowId', $workflow_id, ParameterType::INTEGER); - - $workflow = $db->setQuery($query)->loadObject(); - - if (!empty($workflow->id)) - { - return $workflow; - } - } - - // Use default workflow - $query = $db->getQuery(true); - - $query->select( - [ - $db->quoteName('w.id'), - $db->quoteName('ws.id', 'stage_id'), - ] - ) - ->from( - [ - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflows', 'w'), - ] - ) - ->where( - [ - $db->quoteName('ws.default') . ' = 1', - $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), - $db->quoteName('w.published') . ' = 1', - $db->quoteName('ws.published') . ' = 1', - $db->quoteName('w.default') . ' = 1', - ] - ); - - $workflow = $db->setQuery($query)->loadObject(); - - // Last check if we have a workflow ID - if (!empty($workflow->id)) - { - return $workflow; - } - - return false; - } - - /** - * Runs transition for item. - * - * @param integer $pk Id of article - * @param integer $transition_id Id of transition - * - * @return boolean - * - * @since 4.0.0 - */ - public function runTransition(int $pk, int $transition_id): bool - { - $workflow = new Workflow(['extension' => 'com_content']); - - $runTransaction = $workflow->executeTransition([$pk], $transition_id); - - if (!$runTransaction) - { - $this->setError(Text::_('COM_CONTENT_ERROR_UPDATE_STAGE')); - - return false; - } - - // B/C state change trigger for UCM - /* @TODO Move to transition - * $context = $this->option . '.' . $this->name; - - // Include the plugins for the change of stage event. - PluginHelper::importPlugin($this->events_map['change_state']); - - // Trigger the change stage event. - //Factory::getApplication()->triggerEvent($this->event_change_state, [$context, [$pk]]); - * - */ - - return true; - } } diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index fdae82fb336fa..e61ae552e3270 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -116,9 +116,6 @@ public function display($tpl = null) $this->filterForm->setFieldAttribute('category_id', 'language', '*,' . $forcedLanguage, 'filter'); } } - - /* - @TODO Move to the plugin /* @TODO Move to the plugin @@ -153,8 +150,6 @@ public function display($tpl = null) } $this->document->addScriptOptions('articles.transitions', $transitions); - - */ */ diff --git a/administrator/language/en-GB/com_content.ini b/administrator/language/en-GB/com_content.ini index efba71e6a34c1..7489424f6a1e1 100644 --- a/administrator/language/en-GB/com_content.ini +++ b/administrator/language/en-GB/com_content.ini @@ -168,7 +168,7 @@ COM_CONTENT_SUBMENU_CATEGORIES="Categories" COM_CONTENT_SUBMENU_FEATURED="Featured Articles" COM_CONTENT_SUBMENU_WORKFLOWS="Workflows" COM_CONTENT_TIP_ASSOCIATION="Associated articles" -COM_CONTENT_TRANSITION="Status" +COM_CONTENT_TRANSITION="Transition" COM_CONTENT_TRASHED="Trashed" COM_CONTENT_UNFEATURED="Unfeatured Article" COM_CONTENT_UNPUBLISHED="Unpublished" diff --git a/libraries/src/Form/Field/TransitionField.php b/libraries/src/Form/Field/TransitionField.php index f478e54af9de2..72a7442d4031c 100644 --- a/libraries/src/Form/Field/TransitionField.php +++ b/libraries/src/Form/Field/TransitionField.php @@ -112,7 +112,6 @@ protected function getOptions() [ $db->quoteName('t.id', 'value'), $db->quoteName('t.title', 'text'), - $db->quoteName('s.condition'), ] ) ->from( @@ -155,15 +154,6 @@ function ($item) use ($user, $extension) $items = ArrayHelper::sortObjects($items, 'value', 1, true, true); Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); - - $workflow = new Workflow(['extension' => $this->extension]); - - foreach ($items as $item) - { - $conditionName = $workflow->getConditionName((int) $item->condition); - - $item->text .= ' [' . Text::_($conditionName) . ']'; - } } // Get workflow stage title diff --git a/libraries/src/MVC/Controller/AdminController.php b/libraries/src/MVC/Controller/AdminController.php index ffa9a3d57224e..a094b1a576ff6 100644 --- a/libraries/src/MVC/Controller/AdminController.php +++ b/libraries/src/MVC/Controller/AdminController.php @@ -86,9 +86,6 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu $this->registerTask('orderup', 'reorder'); $this->registerTask('orderdown', 'reorder'); - // Transition - $this->registerTask('runTransition', 'runTransition'); - // Guess the option as com_NameOfController. if (empty($this->option)) { @@ -447,7 +444,7 @@ public function runTransition() // Get the model $model = $this->getModel(); - $return = $model->runTransition($pk, $transitionId); + $return = $model->executeTransition($pk, $transitionId); $redirect = Route::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false); diff --git a/libraries/src/MVC/Model/AdminModel.php b/libraries/src/MVC/Model/AdminModel.php index 8434153fb1216..d07be3a254832 100644 --- a/libraries/src/MVC/Model/AdminModel.php +++ b/libraries/src/MVC/Model/AdminModel.php @@ -117,8 +117,7 @@ abstract class AdminModel extends FormModel protected $batch_commands = array( 'assetgroup_id' => 'batchAccess', 'language_id' => 'batchLanguage', - 'tag' => 'batchTag', - 'workflowstage_id' => 'batchWorkflowStage', + 'tag' => 'batchTag' ); /** diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 98e7ab4b47b6d..c26c0d5ae6d73 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -10,18 +10,21 @@ \defined('JPATH_PLATFORM') or die; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Workflow\Workflow; +use Joomla\CMS\Table\Category; +use Joomla\Registry\Registry; /** * Trait which supports state behavior * * @since 4.0.0 */ -trait WorkflowBehaviorTrait { - +trait WorkflowBehaviorTrait +{ /** * The for the component. * @@ -30,14 +33,57 @@ trait WorkflowBehaviorTrait { */ protected $extension = null; + protected $section = ''; + + protected $workflowEnabled = false; + + /** + * The workflow object + * + * @var Workflow + * @since 4.0.0 + */ + protected $workflow; + /** * Set Up the workflow * * @param string $extension The option and section separated by . */ - public function setUpWorkflow($extension) { + public function setUpWorkflow($extension) + { + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (count($parts)) + { + $this->section = array_shift($parts); + } + + $this->workflow = new Workflow(['extension' => $this->extension]); + + $params = ComponentHelper::getParams($this->extension); + + $this->workflowEnabled = $params->get('workflows_enable', 1); - $this->extension = $extension; + $this->enableWorkflowBatch(); + } + + /** + * Add the workflow batch to the command list. Can be overwritten bei the child class + * + * @return void + * + * @since 4.0.0 + */ + protected function enableWorkflowBatch() + { + // Enable batch + if ($this->workflowEnabled && property_exists($this, 'batch_commands')) + { + $this->batch_commands['workflowstage_id'] = 'batchWorkflowStage'; + } } /** @@ -48,16 +94,318 @@ public function setUpWorkflow($extension) { * * @return void * - * @throws \Exception if there is an error in the form event. * @since 4.0.0 * @see FormField */ - public function preprocessFormWorkflow(Form $form, $data) { + public function workflowPreprocessForm(Form $form, $data) + { + $this->addTransitionField($form, $data); + + if (!$this->workflowEnabled) + { + return; + } + + // Import the workflow plugin group to allow form manipulation. + $this->importWorkflowPlugins(); + } + + /** + * Preparation of workflow data/plugins + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeSave() + { + if (!$this->workflowEnabled) + { + return; + } + + $this->importWorkflowPlugins(); + } + + /** + * Executing of relevant workflow methods + * + * @return void + * + * @since 4.0.0 + */ + public function workflowAfterSave($data) + { + // Regardless if workflow is active or not, we have to set the default stage + // So we can work with the workflow, when the user activates it later + $id = $this->getState($this->getName() . '.id'); + $isNew = $this->getState($this->getName() . '.new'); + + // We save the first stage + if ($isNew) + { + $form = $this->getForm(); + + $stage_id = $this->getStageForNewItem($form, $data); + + $this->workflow->createAssociation($id, $stage_id); + } + + if (!$this->workflowEnabled) + { + return; + } + + // Execute transition + if (!empty($data['transition'])) + { + $this->executeTransition($id, $data['transition']); + } + } + + /** + * Runs transition for item. + * + * @param integer $pk Id of article + * @param integer $transition_id Id of transition + * + * @return boolean + * + * @since 4.0.0 + */ + public function executeTransition(int $pk, int $transition_id): bool + { + $result = $this->workflow->executeTransition([$pk], $transition_id); + + if (!$result) + { + $this->setError(Text::_('COM_CONTENT_ERROR_UPDATE_STAGE')); + + return false; + } - // Import the appropriate plugin group. + return true; + } + + /** + * Import the Workflow plugins. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + */ + protected function importWorkflowPlugins() + { PluginHelper::importPlugin('workflow'); } + /** + * Adds a transition field to the form. Can be overwritten by the child class if not needed + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + * @since 4.0.0 + */ + protected function addTransitionField(Form $form, $data) + { + $extension = $this->extension . ($this->section ? '.' . $this->section : ''); + + $field = new \SimpleXMLElement(''); + + $field->addAttribute('name', 'transition'); + $field->addAttribute('type', $this->workflowEnabled ? 'transition' : 'hidden'); + $field->addAttribute('label', 'COM_CONTENT_TRANSITION'); + $field->addAttribute('extension', $extension); + + $form->setField($field); + + $table = $this->getTable(); + + $key = $table->getKeyName(); + + $id = isset($data->$key) ? $data->$key : $form->getValue($key); + + if ($id) + { + // Transition field + $assoc = $this->workflow->getAssociation($id); + + $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); + } + else + { + $stage_id = $this->getStageForNewItem($form, $data); + + if (!empty($stage_id)) + { + $form->setFieldAttribute('transition', 'workflow_stage', (int) $stage_id); + } + } + } + + /** + * Try to load a workflow object for newly created items + * which does not have a workflow assinged yet. If the category is not the + * carrier, overwrite it on your model and deliver your own carrier. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return boolean|object A object containing workflow information or false + * @since 4.0.0 + */ + protected function getStageForNewItem(Form $form, $data) + { + $table = $this->getTable(); + + $hasKey = $table->hasField('catid'); + + if (!$hasKey) + { + return false; + } + + $catKey = $table->getColumnAlias('catid'); + + $field = $form->getField($catKey); + + if (!$field) + { + return false; + } + + $catId = isset(((object) $data)->$catKey) ? ((object) $data)->$catKey : $form->getValue($catKey); + + // Try to get the category from the html code of the field + if (empty($catId)) + { + $catId = $field->getAttribute('default', null); + + // Choose the first category available + $xml = new \DOMDocument; + libxml_use_internal_errors(true); + $xml->loadHTML($field->__get('input')); + libxml_clear_errors(); + libxml_use_internal_errors(false); + $options = $xml->getElementsByTagName('option'); + + if (!$catId && $firstChoice = $options->item(0)) + { + $catId = $firstChoice->getAttribute('value'); + } + } + + if (empty($catId)) + { + return false; + } + + $db = Factory::getContainer()->get('DatabaseDriver'); + + // Let's check if a workflow ID is assigned to a category + $category = new Category($db); + + $categories = array_reverse($category->getPath($catId)); + + $workflow_id = 0; + + foreach ($categories as $cat) + { + $cat->params = new Registry($cat->params); + + $workflow_id = $cat->params->get('workflow_id'); + + if ($workflow_id == 'inherit') + { + $workflow_id = 0; + + continue; + } + elseif ($workflow_id == 'use_default') + { + $workflow_id = 0; + + break; + } + elseif ($workflow_id > 0) + { + break; + } + } + + // Check if the workflow exists + if ($workflow_id = (int) $workflow_id) + { + $query = $db->getQuery(true); + + $query->select( + [ + $db->quoteName('ws.id') + ] + ) + ->from( + [ + $db->quoteName('#__workflow_stages', 'ws'), + $db->quoteName('#__workflows', 'w'), + ] + ) + ->where( + [ + $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), + $db->quoteName('ws.default') . ' = 1', + $db->quoteName('w.published') . ' = 1', + $db->quoteName('ws.published') . ' = 1', + $db->quoteName('w.id') . ' = :workflowId', + ] + ) + ->bind(':workflowId', $workflow_id, ParameterType::INTEGER); + + $stage_id = (int) $db->setQuery($query)->loadResult(); + + if (!empty($stage_id)) + { + return $stage_id; + } + } + + // Use default workflow + $query = $db->getQuery(true); + + $query->select( + [ + $db->quoteName('ws.id') + ] + ) + ->from( + [ + $db->quoteName('#__workflow_stages', 'ws'), + $db->quoteName('#__workflows', 'w'), + ] + ) + ->where( + [ + $db->quoteName('ws.default') . ' = 1', + $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), + $db->quoteName('w.published') . ' = 1', + $db->quoteName('ws.published') . ' = 1', + $db->quoteName('w.default') . ' = 1', + ] + ); + + $stage_id = (int) $db->setQuery($query)->loadResult(); + + // Last check if we have a workflow ID + if (!empty($stage_id)) + { + return $stage_id; + } + + return false; + } + /** * Batch change workflow stage or current. * @@ -97,10 +445,8 @@ public function batchWorkflowStage(int $value, array $pks, array $contexts) { return false; } - $workflow = new Workflow(['extension' => $this->option]); - // Update workflow associations - return $workflow->updateAssociations($pks, $value); + return $this->workflow->updateAssociations($pks, $value); } } diff --git a/libraries/src/MVC/Model/WorkflowModelInterface.php b/libraries/src/MVC/Model/WorkflowModelInterface.php index cba3aef197647..a2bb76279c972 100644 --- a/libraries/src/MVC/Model/WorkflowModelInterface.php +++ b/libraries/src/MVC/Model/WorkflowModelInterface.php @@ -31,6 +31,64 @@ interface WorkflowModelInterface * @since 4.0.0 * @throws \Exception if there is an error in the form event. */ - public function preProcessFormWorkflow(Form $form, $data); + public function workflowPreprocessForm(Form $form, $data); + + /** + * Preparation of workflow data/plugins + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeSave(); + + /** + * Executing of relevant workflow methods + * + * @return void + * + * @since 4.0.0 + */ + public function workflowAfterSave($data); + + /** + * Method to get state variables. + * + * @param string $property Optional parameter name + * @param mixed $default Optional default value + * + * @return mixed The property where specified, the state object where omitted + * + * @since 4.0.0 + */ + public function getState($property = null, $default = null); + + /** + * Method to get the model name + * + * The model name. By default parsed using the classname or it can be set + * by passing a $config['name'] in the class constructor + * + * @return string The name of the model + * + * @since 4.0.0 + * @throws \Exception + */ + public function getName(); + + + /** + * Method to get a table object, load it if necessary. + * + * @param string $name The table name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $options Configuration array for model. Optional. + * + * @return Table A Table object + * + * @since 3.0 + * @throws \Exception + */ + public function getTable($name = '', $prefix = '', $options = array()); } diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index ddeb536bad673..5d4e7cc6dac1a 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -196,11 +196,22 @@ public function executeTransition(array $pks, int $transition_id): bool } } + $app = Factory::getApplication(); + + $app->triggerEvent( + 'onWorkflowBeforeTransition', + [ + 'pks' => $pks, + 'extension' => $this->extension, + 'user' => $app->getIdentity(), + 'transition' => $transition, + ] + ); + $success = $this->updateAssociations($pks, (int) $transition->to_stage_id); if ($success) { - $app = Factory::getApplication(); $app->triggerEvent( 'onWorkflowAfterTransition', [ From be6b633cf8cfc7db5fa9a402bb2ba74322bc361d Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Tue, 21 Apr 2020 02:28:10 +0200 Subject: [PATCH 07/90] Fix batch (#57) * Fix workflow batch --- .../com_content/tmpl/articles/default_batch_body.php | 5 ++++- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/administrator/components/com_content/tmpl/articles/default_batch_body.php b/administrator/components/com_content/tmpl/articles/default_batch_body.php index cb2f379170592..ca9925a09c373 100644 --- a/administrator/components/com_content/tmpl/articles/default_batch_body.php +++ b/administrator/components/com_content/tmpl/articles/default_batch_body.php @@ -10,6 +10,9 @@ use Joomla\CMS\Factory; use Joomla\CMS\Layout\LayoutHelper; +use Joomla\CMS\Component\ComponentHelper; + +$params = ComponentHelper::getParams('com_content'); $published = $this->state->get('filter.published'); @@ -42,7 +45,7 @@ - authorise('core.admin', 'com_content')) : ?> + authorise('core.admin', 'com_content') && $params->get('workflows_enable', 1)) : ?>
'com_content']); ?> diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index c26c0d5ae6d73..d79c79cde259c 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -417,10 +417,10 @@ protected function getStageForNewItem(Form $form, $data) * * @since 4.0.0 */ - public function batchWorkflowStage(int $value, array $pks, array $contexts) { - + public function batchWorkflowStage(int $value, array $pks, array $contexts) + { $user = Factory::getApplication()->getIdentity(); - /** @var $workflow */ + $workflow = Factory::getApplication()->bootComponent('com_workflow'); if (!$user->authorise('core.admin', $this->option)) @@ -429,7 +429,7 @@ public function batchWorkflowStage(int $value, array $pks, array $contexts) { } // Get workflow stage information - $stage = $workflow->createTable('Stage', 'Administrator'); + $stage = $workflow->getMVCFactory()->createTable('Stage', 'Administrator'); if (empty($value) || !$stage->load($value)) { From b520b5abcaa2f4bb26fa2c6778f41b100d43ecf4 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Tue, 21 Apr 2020 03:49:13 +0200 Subject: [PATCH 08/90] Rename com_content context to "com_content.article" (#60) --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 7 +++-- .../updates/postgresql/4.0.0-2018-05-15.sql | 7 +++-- .../com_content/presets/content.xml | 2 +- .../com_menus/presets/alternate.xml | 2 +- .../components/com_menus/presets/default.xml | 2 +- .../src/Controller/DisplayController.php | 19 ++++++++++++- .../src/Controller/StageController.php | 23 +++++++++++++-- .../src/Controller/StagesController.php | 21 ++++++++++++-- .../src/Controller/TransitionController.php | 19 ++++++++++++- .../src/Controller/TransitionsController.php | 25 +++++++++++++++-- .../src/Controller/WorkflowController.php | 23 +++++++++++++-- .../src/Controller/WorkflowsController.php | 21 ++++++++++++-- .../com_workflow/src/Table/StageTable.php | 15 ++++++++-- .../src/Table/TransitionTable.php | 15 ++++++++-- .../com_workflow/src/Table/WorkflowTable.php | 12 ++++++-- .../com_workflow/src/View/Stage/HtmlView.php | 22 +++++++++++++-- .../com_workflow/src/View/Stages/HtmlView.php | 18 +++++++++++- .../src/View/Transition/HtmlView.php | 28 ++++++++++++++++++- .../src/View/Transitions/HtmlView.php | 18 +++++++++++- .../src/View/Workflow/HtmlView.php | 20 ++++++++++++- .../src/View/Workflows/HtmlView.php | 24 ++++++++++++++-- installation/sql/mysql/base.sql | 5 ++-- installation/sql/postgresql/base.sql | 5 ++-- 23 files changed, 312 insertions(+), 41 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 69ac6bf9d5671..11b06791f0ad6 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `core`,`ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content', 1, 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); +(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- -- Table structure for table `#__workflow_associations` @@ -125,10 +125,11 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` -- INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); -- -- Creating Associations for existing content -- INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `id`, CASE WHEN `state` = -2 THEN 3 WHEN `state` = 0 THEN 1 WHEN `state` = 2 THEN 4 ELSE 2 END, 'com_content' FROM `#__content`; +SELECT `id`, CASE WHEN `state` = -2 THEN 3 WHEN `state` = 0 THEN 1 WHEN `state` = 2 THEN 4 ELSE 2 END, 'com_content.article' FROM `#__content`; diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 652805aecf746..5863ecfb92fd1 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -32,7 +32,7 @@ CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "core", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content', 1, 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); +(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); -- -- Table structure for table "#__workflow_associations" @@ -121,10 +121,11 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" -- INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); -- -- Creating Associations for existing content -- INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") -SELECT "id", CASE WHEN "state" = -2 THEN 3 WHEN "state" = 0 THEN 1 WHEN "state" = 2 THEN 4 ELSE 2 END, 'com_content' FROM "#__content"; +SELECT "id", CASE WHEN "state" = -2 THEN 3 WHEN "state" = 0 THEN 1 WHEN "state" = 2 THEN 4 ELSE 2 END, 'com_content.article' FROM "#__content"; diff --git a/administrator/components/com_content/presets/content.xml b/administrator/components/com_content/presets/content.xml index b91bc90f89d41..214cf4c8ce64c 100644 --- a/administrator/components/com_content/presets/content.xml +++ b/administrator/components/com_content/presets/content.xml @@ -47,7 +47,7 @@ title="COM_CONTENT_MENUS_WORKFLOW" type="component" element="com_workflow" - link="index.php?option=com_workflow&view=workflows&extension=com_content" + link="index.php?option=com_workflow&view=workflows&extension=com_content.article" /> extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { diff --git a/administrator/components/com_workflow/src/Controller/StageController.php b/administrator/components/com_workflow/src/Controller/StageController.php index 4d38fafc7b6f6..41ef5233843fa 100644 --- a/administrator/components/com_workflow/src/Controller/StageController.php +++ b/administrator/components/com_workflow/src/Controller/StageController.php @@ -40,6 +40,14 @@ class StageController extends FormController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Constructor. * @@ -69,7 +77,16 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { @@ -163,7 +180,7 @@ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') { $append = parent::getRedirectToItemAppend($recordId); - $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension; + $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } @@ -178,7 +195,7 @@ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); - $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension; + $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } diff --git a/administrator/components/com_workflow/src/Controller/StagesController.php b/administrator/components/com_workflow/src/Controller/StagesController.php index 4d78855b3e3e5..dd2aab5c6e03f 100644 --- a/administrator/components/com_workflow/src/Controller/StagesController.php +++ b/administrator/components/com_workflow/src/Controller/StagesController.php @@ -42,6 +42,14 @@ class StagesController extends AdminController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * The prefix to use with controller messages. * @@ -79,7 +87,16 @@ public function __construct(array $config = array(), MVCFactoryInterface $factor // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { @@ -182,6 +199,6 @@ public function setDefault() */ protected function getRedirectToListAppend() { - return '&extension=' . $this->extension . '&workflow_id=' . $this->workflowId; + return '&extension=' . $this->extension . ($this->section ? '.' . $this->section : '') . '&workflow_id=' . $this->workflowId; } } diff --git a/administrator/components/com_workflow/src/Controller/TransitionController.php b/administrator/components/com_workflow/src/Controller/TransitionController.php index 7fbc647c1ca68..9b565d2896876 100644 --- a/administrator/components/com_workflow/src/Controller/TransitionController.php +++ b/administrator/components/com_workflow/src/Controller/TransitionController.php @@ -39,6 +39,14 @@ class TransitionController extends FormController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Constructor. * @@ -68,7 +76,16 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { diff --git a/administrator/components/com_workflow/src/Controller/TransitionsController.php b/administrator/components/com_workflow/src/Controller/TransitionsController.php index 045e5f7dfd58a..7882376468aea 100644 --- a/administrator/components/com_workflow/src/Controller/TransitionsController.php +++ b/administrator/components/com_workflow/src/Controller/TransitionsController.php @@ -39,6 +39,14 @@ class TransitionsController extends AdminController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * The prefix to use with controller messages. * @@ -76,7 +84,16 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { @@ -110,7 +127,11 @@ public function getModel($name = 'Transition', $prefix = 'Administrator', $confi */ protected function getRedirectToListAppend() { - return '&extension=' . $this->extension + $append = parent::getRedirectToListAppend(); + + $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : '') . '&workflow_id=' . $this->workflowId; + + return $append; } } diff --git a/administrator/components/com_workflow/src/Controller/WorkflowController.php b/administrator/components/com_workflow/src/Controller/WorkflowController.php index 819ed6323586a..4c0d78a359338 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowController.php @@ -32,6 +32,14 @@ class WorkflowController extends FormController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Constructor. * @@ -50,7 +58,16 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { @@ -123,7 +140,7 @@ protected function allowEdit($data = array(), $key = 'id') protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') { $append = parent::getRedirectToItemAppend($recordId); - $append .= '&extension=' . $this->extension; + $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } @@ -138,7 +155,7 @@ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); - $append .= '&extension=' . $this->extension; + $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } diff --git a/administrator/components/com_workflow/src/Controller/WorkflowsController.php b/administrator/components/com_workflow/src/Controller/WorkflowsController.php index 552fe8643cf63..b3e776a3aa407 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowsController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowsController.php @@ -34,6 +34,14 @@ class WorkflowsController extends AdminController */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Constructor. * @@ -52,7 +60,16 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { - $this->extension = $this->input->getCmd('extension'); + $extension = $this->input->getCmd('extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (empty($this->extension)) { @@ -181,6 +198,6 @@ public function delete() */ protected function getRedirectToListAppend() { - return '&extension=' . $this->extension; + return '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); } } diff --git a/administrator/components/com_workflow/src/Table/StageTable.php b/administrator/components/com_workflow/src/Table/StageTable.php index 8b91cac144abe..31589d6180e0f 100644 --- a/administrator/components/com_workflow/src/Table/StageTable.php +++ b/administrator/components/com_workflow/src/Table/StageTable.php @@ -207,7 +207,11 @@ protected function _getAssetName() $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); - return $workflow->extension . '.stage.' . (int) $this->$k; + $parts = explode('.', $workflow->extension); + + $extension = array_shift($parts); + + return $extension . '.stage.' . (int) $this->$k; } /** @@ -235,9 +239,16 @@ protected function _getAssetTitle() protected function _getAssetParentId(Table $table = null, $id = null) { $asset = self::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo())); + $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); - $name = $workflow->extension . '.workflow.' . (int) $workflow->id; + + $parts = explode('.', $workflow->extension); + + $extension = array_shift($parts); + + $name = $extension . '.workflow.' . (int) $workflow->id; + $asset->loadByName($name); $assetId = $asset->id; diff --git a/administrator/components/com_workflow/src/Table/TransitionTable.php b/administrator/components/com_workflow/src/Table/TransitionTable.php index f2c9ad30f5a17..e6f5f240bcc2e 100644 --- a/administrator/components/com_workflow/src/Table/TransitionTable.php +++ b/administrator/components/com_workflow/src/Table/TransitionTable.php @@ -74,7 +74,11 @@ protected function _getAssetName() $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); - return $workflow->extension . '.transition.' . (int) $this->$k; + $parts = explode('.', $workflow->extension); + + $extension = array_shift($parts); + + return $extension . '.transition.' . (int) $this->$k; } /** @@ -102,9 +106,16 @@ protected function _getAssetTitle() protected function _getAssetParentId(Table $table = null, $id = null) { $asset = self::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo())); + $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); - $name = $workflow->extension . '.workflow.' . (int) $workflow->id; + + $parts = explode('.', $workflow->extension); + + $extension = array_shift($parts); + + $name = $extension . '.workflow.' . (int) $workflow->id; + $asset->loadByName($name); $assetId = $asset->id; diff --git a/administrator/components/com_workflow/src/Table/WorkflowTable.php b/administrator/components/com_workflow/src/Table/WorkflowTable.php index 502d757dc3e5f..04797b014fc51 100644 --- a/administrator/components/com_workflow/src/Table/WorkflowTable.php +++ b/administrator/components/com_workflow/src/Table/WorkflowTable.php @@ -243,7 +243,11 @@ protected function _getAssetName() { $k = $this->_tbl_key; - return $this->extension . '.workflow.' . (int) $this->$k; + $parts = explode('.', $this->extension); + + $extension = array_shift($parts); + + return $extension . '.workflow.' . (int) $this->$k; } /** @@ -272,11 +276,15 @@ protected function _getAssetParentId(Table $table = null, $id = null) { $assetId = null; + $parts = explode('.', $this->extension); + + $extension = array_shift($parts); + // Build the query to get the asset id for the parent category. $query = $this->getDbo()->getQuery(true) ->select($this->getDbo()->quoteName('id')) ->from($this->getDbo()->quoteName('#__assets')) - ->where($this->getDbo()->quoteName('name') . ' = ' . $this->getDbo()->quote($this->extension)); + ->where($this->getDbo()->quoteName('name') . ' = ' . $this->getDbo()->quote($extension)); // Get the asset id from the database. $this->getDbo()->setQuery($query); diff --git a/administrator/components/com_workflow/src/View/Stage/HtmlView.php b/administrator/components/com_workflow/src/View/Stage/HtmlView.php index 93b783558a60c..7fe44313e013c 100644 --- a/administrator/components/com_workflow/src/View/Stage/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Stage/HtmlView.php @@ -56,6 +56,14 @@ class HtmlView extends BaseHtmlView */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display item view * @@ -77,7 +85,17 @@ public function display($tpl = null) $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); - $this->extension = $this->state->get('filter.extension'); + + $extension = $this->state->get('filter.extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } // Set the toolbar $this->addToolBar(); @@ -101,7 +119,7 @@ protected function addToolbar() $userId = $user->id; $isNew = empty($this->item->id); - $canDo = StageHelper::getActions($this->extension, 'state', $this->item->id); + $canDo = StageHelper::getActions($this->extension, 'stage', $this->item->id); ToolbarHelper::title(empty($this->item->id) ? Text::_('COM_WORKFLOW_STAGE_ADD') : Text::_('COM_WORKFLOW_STAGE_EDIT'), 'address'); diff --git a/administrator/components/com_workflow/src/View/Stages/HtmlView.php b/administrator/components/com_workflow/src/View/Stages/HtmlView.php index efc87d4320b30..f773f3eddb3fd 100644 --- a/administrator/components/com_workflow/src/View/Stages/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Stages/HtmlView.php @@ -99,6 +99,14 @@ class HtmlView extends BaseHtmlView */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display the view * @@ -124,7 +132,15 @@ public function display($tpl = null) $this->workflow = $this->get('Workflow'); $this->workflowID = $this->workflow->id; - $this->extension = $this->workflow->extension; + + $parts = explode('.', $this->workflow->extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } if (!empty($this->stages)) { diff --git a/administrator/components/com_workflow/src/View/Transition/HtmlView.php b/administrator/components/com_workflow/src/View/Transition/HtmlView.php index aabab96354a4a..f4ce117154d7c 100644 --- a/administrator/components/com_workflow/src/View/Transition/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Transition/HtmlView.php @@ -72,6 +72,22 @@ class HtmlView extends BaseHtmlView */ protected $workflowID; + /** + * The name of current extension + * + * @var string + * @since 4.0.0 + */ + protected $extension; + + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display item view * @@ -96,7 +112,17 @@ public function display($tpl = null) $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); - $this->extension = $this->state->get('filter.extension'); + + $extension = $this->state->get('filter.extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } // Get the ID of workflow $this->workflowID = $this->input->getCmd("workflow_id"); diff --git a/administrator/components/com_workflow/src/View/Transitions/HtmlView.php b/administrator/components/com_workflow/src/View/Transitions/HtmlView.php index d0d70b94f300e..1eb0bac920736 100644 --- a/administrator/components/com_workflow/src/View/Transitions/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Transitions/HtmlView.php @@ -98,6 +98,14 @@ class HtmlView extends BaseHtmlView */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display the view * @@ -123,7 +131,15 @@ public function display($tpl = null) $this->workflow = $this->get('Workflow'); $this->workflowID = $this->workflow->id; - $this->extension = $this->workflow->extension; + + $parts = explode('.', $this->workflow->extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } $this->addToolbar(); diff --git a/administrator/components/com_workflow/src/View/Workflow/HtmlView.php b/administrator/components/com_workflow/src/View/Workflow/HtmlView.php index 2829f1b85eecb..a40ec43df818e 100644 --- a/administrator/components/com_workflow/src/View/Workflow/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Workflow/HtmlView.php @@ -62,6 +62,14 @@ class HtmlView extends BaseHtmlView */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display item view * @@ -77,7 +85,17 @@ public function display($tpl = null) $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); - $this->extension = $this->state->get('filter.extension'); + + $extension = $this->state->get('filter.extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } // Check for errors. if (count($errors = $this->get('Errors'))) diff --git a/administrator/components/com_workflow/src/View/Workflows/HtmlView.php b/administrator/components/com_workflow/src/View/Workflows/HtmlView.php index 91c42fcac355e..6847a17b15c69 100644 --- a/administrator/components/com_workflow/src/View/Workflows/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Workflows/HtmlView.php @@ -10,6 +10,7 @@ \defined('_JEXEC') or die; +use Joomla\CMS\Factory; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; @@ -80,6 +81,14 @@ class HtmlView extends BaseHtmlView */ protected $extension; + /** + * The section of the current extension + * + * @var string + * @since 4.0.0 + */ + protected $section; + /** * Display the view * @@ -103,7 +112,16 @@ public function display($tpl = null) throw new GenericDataException(implode("\n", $errors), 500); } - $this->extension = $this->state->get('filter.extension'); + $extension = $this->state->get('filter.extension'); + + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (!empty($parts)) + { + $this->section = array_shift($parts); + } $this->addToolbar(); @@ -119,7 +137,9 @@ public function display($tpl = null) */ protected function addToolbar() { - $canDo = ContentHelper::getActions($this->extension); + $canDo = ContentHelper::getActions($this->extension, $this->section); + + $user = Factory::getApplication()->getIdentity(); // Get the toolbar object instance $toolbar = Toolbar::getInstance('toolbar'); diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index bbe0d065ff2e3..1c080e7de83bc 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -357,7 +357,8 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, (0, 'plg_media-action_resize', 'plugin', 'resize', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_media-action_rotate', 'plugin', 'rotate', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES @@ -1084,7 +1085,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `core`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content', 1, 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); +(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 0ab60c69702ca..9430393facce9 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -363,7 +363,8 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", (0, 'plg_media-action_resize', 'plugin', 'resize', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_media-action_rotate', 'plugin', 'rotate', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES @@ -1091,7 +1092,7 @@ CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "core", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content', 1, 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); +(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); SELECT setval('#__workflows_id_seq', 2, false); From 479e4d7c0b36967bd5010ebfc1dbf1b3d1237f68 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 21 Apr 2020 03:57:44 +0200 Subject: [PATCH 09/90] Fix broken permission check for workflows --- .../components/com_workflow/src/Model/WorkflowModel.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index d1c8667deaf74..a500e53761920 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -259,6 +259,10 @@ protected function preprocessForm(Form $form, $data, $group = 'content') { $extension = Factory::getApplication()->input->get('extension'); + $parts = explode('.', $extension); + + $extension = array_shift($parts); + // Set the access control rules field component value. $form->setFieldAttribute('rules', 'component', $extension); $form->setFieldAttribute('rules', 'section', 'workflow'); From 12ca6b25bfb8fcd65c51b2a123b59eebe25ae890 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Wed, 22 Apr 2020 01:00:42 +0200 Subject: [PATCH 10/90] Workflow v3 transitions (#61) * Remove condition from workflow component * Load Workflow plugins on transition generation * First commit for the publishing plugin * Prevent saving of publishing state if workflow + plugin is active and the function is supported * Only enhance transition form, if plugin is supported * Add options field for transition plugins Fix support check for workflow publishing plugin * Set transition default values when creating a new workflow * Make publishing plugin support name generic * Allow to kill transition execution * Add missing variable assignment to kill transitions * Prevent state change on publish events * Implement finished version of the publishing plugin which now changes states of items Fix wrong contexts * Update the workflow model interface to respect all methods Secure controller execution for runTransition * Implement frontend transition with the new plugin method --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 13 +- .../updates/postgresql/4.0.0-2018-05-15.sql | 11 +- .../src/Extension/ContentComponent.php | 28 ++ .../com_content/src/Model/ArticleModel.php | 2 +- .../com_content/src/Model/ArticlesModel.php | 4 +- .../src/Model/TransitionModel.php | 23 ++ .../com_workflow/src/Model/WorkflowModel.php | 13 +- .../src/Table/TransitionTable.php | 10 + .../com_workflow/tmpl/transition/edit.php | 5 + .../en-GB/plg_workflow_publishing.ini | 12 + .../en-GB/plg_workflow_publishing.sys.ini | 7 + components/com_content/forms/article.xml | 17 +- components/com_content/tmpl/form/edit.php | 6 +- installation/sql/mysql/base.sql | 11 +- installation/sql/postgresql/base.sql | 11 +- .../src/MVC/Controller/AdminController.php | 10 + .../src/MVC/Model/WorkflowBehaviorTrait.php | 27 +- .../src/MVC/Model/WorkflowModelInterface.php | 32 ++ libraries/src/Workflow/Workflow.php | 27 +- .../src/Workflow/WorkflowServiceInterface.php | 18 + .../src/Workflow/WorkflowServiceTrait.php | 49 ++- plugins/content/joomla/joomla.php | 2 +- .../publishing/forms/workflow_publishing.xml | 19 + plugins/workflow/publishing/publishing.php | 336 ++++++++++++++++++ 24 files changed, 637 insertions(+), 56 deletions(-) create mode 100644 administrator/language/en-GB/plg_workflow_publishing.ini create mode 100644 administrator/language/en-GB/plg_workflow_publishing.sys.ini create mode 100644 plugins/workflow/publishing/forms/workflow_publishing.xml create mode 100644 plugins/workflow/publishing/publishing.php diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 11b06791f0ad6..ceef7055ca38e 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -99,6 +99,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( `description` text NOT NULL, `from_stage_id` int(10) NOT NULL, `to_stage_id` int(10) NOT NULL, + `options` text NOT NULL, `checked_out_time` datetime, `checked_out` int(10) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), @@ -114,18 +115,18 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( -- Dumping data for table `#__workflow_transitions` -- -INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, NULL, 0), -(2, 0, 1, 2, 1, 'Publish', '', -1, 2, NULL, 0), -(3, 0, 1, 3, 1, 'Trash', '', -1, 3, NULL, 0), -(4, 0, 1, 4, 1, 'Archive', '', -1, 4, NULL, 0); +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`, `checked_out_time`, `checked_out`) VALUES +(1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 0, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), +(3, 0, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), +(4, 0, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); -- -- Creating extension entry -- INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, NULL, 0, 0), (0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); -- diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 5863ecfb92fd1..107b73c480fb2 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -99,6 +99,7 @@ CREATE TABLE IF NOT EXISTS "#__workflow_transitions" ( "description" text NOT NULL, "from_stage_id" bigint DEFAULT 0 NOT NULL, "to_stage_id" bigint DEFAULT 0 NOT NULL, + "options" text NOT NULL, "checked_out_time" timestamp without time zone, "checked_out" bigint DEFAULT 0 NOT NULL, PRIMARY KEY ("id") @@ -110,11 +111,11 @@ CREATE INDEX "#__workflow_transitions_idx_to_stage_id" ON "#__workflow_transitio CREATE INDEX "#__workflow_transitions_idx_workflow_id" ON "#__workflow_transitions" ("workflow_id"); CREATE INDEX "#__workflow_transitions_idx_checked_out" ON "#__workflow_transitions" ("checked_out"); -INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, NULL, 0), -(2, 0, 1, 2, 1, 'Publish', '', -1, 2, NULL, 0), -(3, 0, 1, 3, 1, 'Trash', '', -1, 3, NULL, 0), -(4, 0, 1, 4, 1, 'Archive', '', -1, 4, NULL, 0); +INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options", "checked_out_time", "checked_out") VALUES +(1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 0, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), +(3, 0, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), +(4, 0, 1, 4, 1, 'Archive', '', -1, '{"publishing":"2"}', 4, NULL, 0); -- -- Creating extension entry diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index 552e5077b1eda..b0a05e63b1382 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -199,6 +199,34 @@ public function getWorkflowTableBySection(?string $section = null): string return '#__content'; } + /** + * Returns the model name, based on the context + * + * @param string $context The context of the workflow + * + * @return bool + */ + public function getModelName($context): string + { + $parts = explode('.', $context); + + if (count($parts) < 2) + { + return ''; + } + + array_shift($parts); + + $modelname = array_shift($parts); + + if ($modelname === 'article' && Factory::getApplication()->isClient('site')) + { + return 'Form'; + } + + return ucfirst($modelname); + } + /** * Method to filter transitions by given id of state. * diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index aef54df5bc842..3904c7205ef46 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -346,7 +346,7 @@ protected function prepareTable($table) */ public function publish(&$pks, $value = 1) { - $this->importWorkflowPlugins(); + $this->workflowBeforeStageChange(); return parent::publish($pks, $value); } diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index dc90f2cc40d48..5b6ffd6cec026 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -252,7 +252,7 @@ protected function getListQuery() ] ) ->from($db->quoteName('#__content', 'a')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content')) + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')) ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')) ->join('LEFT', $db->quoteName('#__content_frontpage', 'fp'), $db->quoteName('fp.content_id') . ' = ' . $db->quoteName('a.id')) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')) @@ -597,7 +597,7 @@ public function getTransitions() $transitions = $db->setQuery($query)->loadAssocList(); - $workflow = new Workflow(['extension' => 'com_content']); + $workflow = new Workflow(['extension' => 'com_content.article']); foreach ($transitions as $key => $transition) { diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index 7bf841ec4f2e7..8a1e043fa5dcc 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -15,6 +15,7 @@ use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\AdminModel; +use Joomla\Registry\Registry; use Joomla\String\StringHelper; /** @@ -111,6 +112,28 @@ protected function canEditState($record) return $user->authorise('core.edit.state', $extension); } + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return CMSObject|boolean Object on success, false on failure. + * + * @since 4.0.0 + */ + public function getItem($pk = null) + { + $item = parent::getItem($pk); + + if (property_exists($item, 'options')) + { + $registry = new Registry($item->options); + $item->options = $registry->toArray(); + } + + return $item; + } + /** * Method to save the form data. * diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index a500e53761920..6f20b66ac57a4 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -114,19 +114,23 @@ public function save($data) [ 'title' => 'JUNPUBLISHED', 'default' => 1, - 'transition' => 'Unpublish' + 'transition' => 'Unpublish', + 'options' => '{"publishing":"0"}' ], [ 'title' => 'JPUBLISHED', - 'transition' => 'Publish' + 'transition' => 'Publish', + 'options' => '{"publishing":"1"}' ], [ 'title' => 'JTRASHED', - 'transition' => 'Trash' + 'transition' => 'Trash', + 'options' => '{"publishing":"-2"}' ], [ 'title' => 'JARCHIVED', - 'transition' => 'Archive' + 'transition' => 'Archive', + 'options' => '{"publishing":"2"}' ] ]; @@ -155,6 +159,7 @@ public function save($data) $transition->published = 1; $transition->from_stage_id = -1; $transition->to_stage_id = (int) $table->id; + $transition->options = $stage['options']; $transition->store(); } diff --git a/administrator/components/com_workflow/src/Table/TransitionTable.php b/administrator/components/com_workflow/src/Table/TransitionTable.php index e6f5f240bcc2e..80d5cbadc9549 100644 --- a/administrator/components/com_workflow/src/Table/TransitionTable.php +++ b/administrator/components/com_workflow/src/Table/TransitionTable.php @@ -30,6 +30,16 @@ class TransitionTable extends Table */ protected $_supportNullValue = true; + /** + * An array of key names to be json encoded in the bind function + * + * @var array + * @since 4.0.0 + */ + protected $_jsonEncode = [ + 'options' + ]; + /** * Constructor * diff --git a/administrator/components/com_workflow/tmpl/transition/edit.php b/administrator/components/com_workflow/tmpl/transition/edit.php index 215b26b435cd0..857e8749d7b7a 100644 --- a/administrator/components/com_workflow/tmpl/transition/edit.php +++ b/administrator/components/com_workflow/tmpl/transition/edit.php @@ -17,6 +17,9 @@ HTMLHelper::_('behavior.formvalidator'); HTMLHelper::_('behavior.keepalive'); +$this->ignore_fieldsets = ['params', 'transition', 'permissions']; +$this->useCoreUI = true; + // In case of modal $isModal = $this->input->get('layout') === 'modal'; $layout = $isModal ? 'modal' : 'edit'; @@ -51,6 +54,8 @@
+ +
diff --git a/administrator/language/en-GB/plg_workflow_publishing.ini b/administrator/language/en-GB/plg_workflow_publishing.ini new file mode 100644 index 0000000000000..ba30a4cd2228f --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_publishing.ini @@ -0,0 +1,12 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_WORKFLOW_PUBLISHING="Workflow - Publishing" +PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing options to the workflow transitions for your items" +PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_LABEL="Transition Options" +PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_LABEL="Publishing state" +PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" +PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change" +PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the publishing state of this item. Please use a workflow transition." diff --git a/administrator/language/en-GB/plg_workflow_publishing.sys.ini b/administrator/language/en-GB/plg_workflow_publishing.sys.ini new file mode 100644 index 0000000000000..8f09ca95bbbf7 --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_publishing.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_WORKFLOW_PUBLISHING="Workflow - Publishing" +PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing options to the workflow transitions for your items" diff --git a/components/com_content/forms/article.xml b/components/com_content/forms/article.xml index d28790a36b7be..4e97bb032b630 100644 --- a/components/com_content/forms/article.xml +++ b/components/com_content/forms/article.xml @@ -55,12 +55,17 @@ /> + name="state" + type="list" + label="JSTATUS" + class="custom-select-color-state" + size="1" + default="1" + > + + + + tab_name, 'publishing', Text::_('COM_CONTENT_PUBLISHING')); ?> + + form->renderField('transition'); ?> + form->renderField('state'); ?> form->renderField('catid'); ?> form->renderField('tags'); ?> form->renderField('note'); ?> @@ -108,9 +111,6 @@ get('show_publishing_options', 1) == 1) : ?> form->renderField('created_by_alias'); ?> - item->id > 0) : ?> - form->renderField('transition'); ?> - item->params->get('access-change')) : ?> form->renderField('featured'); ?> get('show_publishing_options', 1) == 1) : ?> diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 1c080e7de83bc..00668b0b5317c 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1155,6 +1155,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( `description` text NOT NULL, `from_stage_id` int(10) NOT NULL, `to_stage_id` int(10) NOT NULL, + `options` text NOT NULL, `checked_out_time` datetime, `checked_out` int(10) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), @@ -1170,8 +1171,8 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( -- Dumping data for table `#__workflow_transitions` -- -INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `checked_out_time`, `checked_out`) VALUES -(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, NULL, 0), -(2, 62, 1, 2, 1, 'Publish', '', -1, 2, NULL, 0), -(3, 63, 1, 3, 1, 'Trash', '', -1, 3, NULL, 0), -(4, 64, 1, 4, 1, 'Archive', '', -1, 4, NULL, 0); +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`, `checked_out_time`, `checked_out`) VALUES +(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 62, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), +(3, 63, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), +(4, 64, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 9430393facce9..851940353c965 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1163,6 +1163,7 @@ CREATE TABLE IF NOT EXISTS "#__workflow_transitions" ( "description" text NOT NULL, "from_stage_id" bigint DEFAULT 0 NOT NULL, "to_stage_id" bigint DEFAULT 0 NOT NULL, + "options" text NOT NULL, "checked_out_time" timestamp without time zone, "checked_out" bigint DEFAULT 0 NOT NULL, PRIMARY KEY ("id") @@ -1174,10 +1175,10 @@ CREATE INDEX "#__workflow_transitions_idx_to_stage_id" ON "#__workflow_transitio CREATE INDEX "#__workflow_transitions_idx_workflow_id" ON "#__workflow_transitions" ("workflow_id"); CREATE INDEX "#__workflow_transitions_idx_checked_out" ON "#__workflow_transitions" ("checked_out"); -INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "checked_out_time", "checked_out") VALUES -(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, NULL, 0), -(2, 62, 1, 2, 1, 'Publish', '', -1, 2, NULL, 0), -(3, 63, 1, 3, 1, 'Trash', '', -1, 3, NULL, 0), -(4, 64, 1, 4, 1, 'Archive', '', -1, 4, NULL, 0); +INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options", "checked_out_time", "checked_out") VALUES +(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 62, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), +(3, 63, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), +(4, 64, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); SELECT setval('#__workflow_transitions_id_seq', 5, false); \ No newline at end of file diff --git a/libraries/src/MVC/Controller/AdminController.php b/libraries/src/MVC/Controller/AdminController.php index a094b1a576ff6..e43451c7f6af0 100644 --- a/libraries/src/MVC/Controller/AdminController.php +++ b/libraries/src/MVC/Controller/AdminController.php @@ -16,6 +16,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\BaseDatabaseModel; +use Joomla\CMS\MVC\Model\WorkflowModelInterface; use Joomla\CMS\Router\Route; use Joomla\Input\Input; use Joomla\Utilities\ArrayHelper; @@ -430,6 +431,9 @@ public function saveOrderAjax() */ public function runTransition() { + // Check for request forgeries + $this->checkToken(); + // Get the input $pks = $this->input->post->get('cid', array(), 'array'); @@ -444,6 +448,12 @@ public function runTransition() // Get the model $model = $this->getModel(); + + if (!$model instanceof WorkflowModelInterface) + { + return false; + } + $return = $model->executeTransition($pk, $transitionId); $redirect = Route::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false); diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index d79c79cde259c..9c07e9a657fe7 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -48,7 +48,11 @@ trait WorkflowBehaviorTrait /** * Set Up the workflow * - * @param string $extension The option and section separated by . + * @param string $extension The option and section separated by. + * + * @return void + * + * @since 4.0.0 */ public function setUpWorkflow($extension) { @@ -61,7 +65,7 @@ public function setUpWorkflow($extension) $this->section = array_shift($parts); } - $this->workflow = new Workflow(['extension' => $this->extension]); + $this->workflow = new Workflow(['extension' => $extension]); $params = ComponentHelper::getParams($this->extension); @@ -110,6 +114,23 @@ public function workflowPreprocessForm(Form $form, $data) $this->importWorkflowPlugins(); } + /** + * Let plugins access stage change events + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeStageChange() + { + if (!$this->workflowEnabled) + { + return; + } + + $this->importWorkflowPlugins(); + } + /** * Preparation of workflow data/plugins * @@ -173,7 +194,7 @@ public function workflowAfterSave($data) * * @since 4.0.0 */ - public function executeTransition(int $pk, int $transition_id): bool + public function executeTransition(int $pk, int $transition_id) { $result = $this->workflow->executeTransition([$pk], $transition_id); diff --git a/libraries/src/MVC/Model/WorkflowModelInterface.php b/libraries/src/MVC/Model/WorkflowModelInterface.php index a2bb76279c972..9e9d4586c95db 100644 --- a/libraries/src/MVC/Model/WorkflowModelInterface.php +++ b/libraries/src/MVC/Model/WorkflowModelInterface.php @@ -19,6 +19,17 @@ */ interface WorkflowModelInterface { + /** + * Set Up the workflow + * + * @param string $extension The option and section separated by. + * + * @return void + * + * @since 4.0.0 + */ + public function setUpWorkflow($extension); + /** * Method to allow derived classes to preprocess the form. * @@ -33,6 +44,15 @@ interface WorkflowModelInterface */ public function workflowPreprocessForm(Form $form, $data); + /** + * Let plugins access stage change events + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeStageChange(); + /** * Preparation of workflow data/plugins * @@ -51,6 +71,18 @@ public function workflowBeforeSave(); */ public function workflowAfterSave($data); + /** + * Runs transition for item. + * + * @param integer $pk Id of article + * @param integer $transition_id Id of transition + * + * @return boolean + * + * @since 4.0.0 + */ + public function executeTransition(int $pk, int $transition_id); + /** * Method to get state variables. * diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index 5d4e7cc6dac1a..7004c3647fbf5 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -12,7 +12,9 @@ use Joomla\CMS\Extension\ComponentInterface; use Joomla\CMS\Factory; +use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\ParameterType; +use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; /** @@ -171,19 +173,23 @@ public function executeTransition(array $pks, int $transition_id): bool $db->quoteName('t.id'), $db->quoteName('t.to_stage_id'), $db->quoteName('t.from_stage_id'), + $db->quoteName('t.options'), ] ) ->from($db->quoteName('#__workflow_transitions', 't')) ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) ->where($db->quoteName('t.id') . ' = :id') + ->where($db->quoteName('t.published') . ' = 1') ->bind(':id', $transition_id, ParameterType::INTEGER); - if (!empty($this->options['published'])) + $transition = $db->setQuery($query)->loadObject(); + + if (empty($transition->id)) { - $query->where($db->quoteName('t.published') . ' = 1'); + return false; } - $transition = $db->setQuery($query)->loadObject(); + $transition->options = new Registry($transition->options); // Check if the items can execute this transition foreach ($pks as $pk) @@ -198,16 +204,22 @@ public function executeTransition(array $pks, int $transition_id): bool $app = Factory::getApplication(); - $app->triggerEvent( + PluginHelper::importPlugin('workflow'); + + $result = $app->triggerEvent( 'onWorkflowBeforeTransition', [ + 'context' => $this->extension, 'pks' => $pks, - 'extension' => $this->extension, - 'user' => $app->getIdentity(), 'transition' => $transition, ] ); + if (\in_array(false, $result, true)) + { + return false; + } + $success = $this->updateAssociations($pks, (int) $transition->to_stage_id); if ($success) @@ -215,9 +227,8 @@ public function executeTransition(array $pks, int $transition_id): bool $app->triggerEvent( 'onWorkflowAfterTransition', [ + 'context' => $this->extension, 'pks' => $pks, - 'extension' => $this->extension, - 'user' => $app->getIdentity(), 'transition' => $transition, ] ); diff --git a/libraries/src/Workflow/WorkflowServiceInterface.php b/libraries/src/Workflow/WorkflowServiceInterface.php index abb81000168c8..83227f8a1f1b8 100644 --- a/libraries/src/Workflow/WorkflowServiceInterface.php +++ b/libraries/src/Workflow/WorkflowServiceInterface.php @@ -28,6 +28,24 @@ interface WorkflowServiceInterface { */ public function supportFunctionality($functionality, $context): bool; + /** + * Returns the model name, based on the context + * + * @param string $context The context of the workflow + * + * @return bool + */ + public function getModelName($context): string; + + /** + * Check if the workflow is active + * + * @param string $context The context of the workflow + * + * @return bool + */ + public function isWorkflowActive($context): bool; + /** * Method to filter transitions by given id of state. * diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index 7841729b21544..475771c9507ab 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -36,8 +36,8 @@ abstract function getMVCFactory(); * * @return bool */ - public function supportFunctionality($functionality, $context): bool { - + public function supportFunctionality($functionality, $context): bool + { if (empty($this->supportedFunctionality[$functionality])) { return false; @@ -51,6 +51,27 @@ public function supportFunctionality($functionality, $context): bool { return in_array($context, $this->supportedFunctionality[$functionality]); } + /** + * Returns the model name, based on the context + * + * @param string $context The context of the workflow + * + * @return bool + */ + public function getModelName($context) : string + { + $parts = explode('.', $context); + + if (count($parts) < 2) + { + return ''; + } + + array_shift($parts); + + return ucfirst(array_shift($parts)); + } + /** * Returns an array of possible conditions for the component. * @@ -60,13 +81,20 @@ public function supportFunctionality($functionality, $context): bool { * * @since 4.0.0 */ - public static function getConditions(string $extension): array { - + public static function getConditions(string $extension): array + { return \defined('self::CONDITION_NAMES') ? self::CONDITION_NAMES : Workflow::CONDITION_NAMES; } - public function isWorkflowActive($context): bool { - + /** + * Check if the workflow is active + * + * @param string $context The context of the workflow + * + * @return bool + */ + public function isWorkflowActive($context): bool + { $parts = explode('.', $context); $config = ComponentHelper::getParams($parts[0]); @@ -75,9 +103,16 @@ public function isWorkflowActive($context): bool { return false; } + $modelName = $this->getModelName($context); + + if (empty($modelName)) + { + return false; + } + $component = $this->getMVCFactory(); $appName = Factory::getApplication()->getName(); - $model = $component->createModel($parts[1], $appName, ['ignore_request' => true]); + $model = $component->createModel($modelName, $appName, ['ignore_request' => true]); return $model instanceof WorkflowModelInterface; } diff --git a/plugins/content/joomla/joomla.php b/plugins/content/joomla/joomla.php index 55c21cbc57d2c..1c2ed441993b1 100644 --- a/plugins/content/joomla/joomla.php +++ b/plugins/content/joomla/joomla.php @@ -655,7 +655,7 @@ public function onContentChangeState($context, $pks, $value) $article = new ArticleTable($db); - $workflow = new Workflow(['extension' => 'com_content']); + $workflow = new Workflow(['extension' => 'com_content.article']); foreach ($pks as $pk) { diff --git a/plugins/workflow/publishing/forms/workflow_publishing.xml b/plugins/workflow/publishing/forms/workflow_publishing.xml new file mode 100644 index 0000000000000..2cbc62a1dfe05 --- /dev/null +++ b/plugins/workflow/publishing/forms/workflow_publishing.xml @@ -0,0 +1,19 @@ + + + +
+ + + +
+
+ diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php new file mode 100644 index 0000000000000..b8e8ba3513905 --- /dev/null +++ b/plugins/workflow/publishing/publishing.php @@ -0,0 +1,336 @@ +getName(); + + // Extend the transition form + if ($context == 'com_workflow.transition') + { + return $this->enhanceTransitionForm($form, $data); + } + + return $this->enhanceItemForm($form, $data); + } + + /** + * Add different parameter options to the transition view, we need when executing the transition + * + * @param Form $form The form + * @param stdClass $data The data + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + protected function enhanceTransitionForm(Form $form, $data) + { + $model = $this->app->bootComponent('com_workflow') + ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); + + $workflow_id = !empty($data->workflow_id) ? (int) $data->workflow_id : (int) $form->getValue('workflow_id'); + + if (empty($workflow_id)) + { + $workflow_id = $this->app->input->getInt('workflow_id'); + } + + $workflow = $model->getItem($workflow_id); + + if (!$this->isSupported($workflow->extension)) + { + return true; + } + + Form::addFormPath(__DIR__ . '/forms'); + + $form->loadFile('workflow_publishing'); + + if ($workflow_id) + { + $form->setFieldAttribute('publishing', 'extension', $workflow->extension, 'options'); + } + else + { + $form->setFieldAttribute('publishing', 'disabled', 'true', 'options'); + } + + return true; + } + + /** + * Disable certain fields in the item form view, when we want to take over this function in the transition + * Check also for the workflow implementation and if the field exists + * + * @param Form $form The form + * @param stdClass $data The data + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + protected function enhanceItemForm(Form $form, $data) + { + $context = $form->getName(); + + if (!$this->isSupported($context)) + { + return true; + } + + $parts = explode('.', $context); + + $component = $this->app->bootComponent($parts[0]); + + $modelName = $component->getModelName($context); + + $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) + ->getTable(); + + $form->setFieldAttribute($table->getColumnAlias('published'), 'disabled', 'true'); + + return true; + } + + /** + * Check if we can execute the transition + * + * @param string $context The context + * @param array $pks IDs of the items + * @param object $transition The value to change to + * + * @return boolean + */ + public function onWorkflowBeforeTransition($context, $pks, $transition) + { + if (!$this->isSupported($context) || !is_numeric($transition->options->get('publishing'))) + { + return true; + } + + $value = (int) $transition->options->get('publishing'); + + // Here it becomes tricky. We would like to use the component models publish method, so we will + // Execute the normal "onContentBeforeChangeState" plugins. But they could cancel the execution, + // So we have to precheck and cancel the whole transition stuff if not allowed. + $this->app->set('plgWorkflowPublishing.' . $context, $pks); + + $result = $this->app->triggerEvent('onContentBeforeChangeState', [$context, $pks, $value]); + + // Release whitelist, the job is done + $this->app->set('plgWorkflowPublishing.' . $context, []); + + if (\in_array(false, $result, true)) + { + return false; + } + + return true; + } + + /** + * Change State of an item. Used to disable state change + * + * @param string $context The context + * @param array $pks IDs of the items + * @param object $transition The value to change to + * + * @return boolean + */ + public function onWorkflowAfterTransition($context, $pks, $transition) + { + if (!$this->isSupported($context)) + { + return true; + } + + $parts = explode('.', $context); + + // We need at least the extension + view for loading the table fields + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + $value = (int) $transition->options->get('publishing'); + + $options = [ + 'ignore_request' => true, + // We already have triggered onContentBeforeChangeState, so use our own + 'event_before_change_state' => 'onWorkflowBeforeChangeState' + ]; + + $modelName = $component->getModelName($context); + + $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), $options); + + return $model->publish($pks, $value); + } + + /** + * Change State of an item. Used to disable state change + * + * @param string $context The context + * @param array $pks IDs of the items + * @param int $value The value to change to + * @return boolean + */ + public function onContentBeforeChangeState($context, $pks, $value) + { + if (!$this->isSupported($context)) + { + return true; + } + + // We have whitelisted the pks, so we're the one who triggered + // With onWorkflowBeforeTransition => free pass + if ($this->app->get('plgWorkflowPublishing.' . $context) === $pks) + { + return true; + } + + $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED'), 'error'); + + return false; + } + + /** + * The save event. + * + * @param string $context The context + * @param object $table The item + * @param boolean $isNew Is new item + * @param array $data The validated data + * + * @return boolean + * + * @since 4.0.0 + */ + public function onContentBeforeSave($context, TableInterface $table, $isNew, $data) + { + if (!$this->isSupported($context)) + { + return true; + } + + $keyName = $table->getColumnAlias('published'); + + // Check for the old value + $article = clone $table; + + $article->load($table->id); + + // We don't allow the change of the state when we use the workflow + // As we're setting the field to disabled, no value should be there at all + if (isset($data[$keyName])) + { + $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED'), 'error'); + + return false; + } + + return true; + } + + /** + * Check if the current plugin should execute workflow related activities + * + * @param type $context + * @return boolean + */ + protected function isSupported($context) + { + $parts = explode('.', $context); + + // We need at least the extension + view for loading the table fields + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context) || !$component->supportFunctionality($this->supportname, $context)) + { + return false; + } + + $modelName = $component->getModelName($context); + + $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]); + + if (!$model instanceof DatabaseModelInterface || !method_exists($model, 'publish')) + { + return false; + } + + $table = $model->getTable(); + + if (!$table instanceof TableInterface || !$table->hasField('published')) + { + return false; + } + + return true; + } +} From 25c42a4df7eb73b859403fc5fdd9d99b476fa6be Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 22 Apr 2020 01:19:11 +0200 Subject: [PATCH 11/90] Remove stage filter when workflow is disabled --- .../com_content/src/Model/ArticlesModel.php | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 5b6ffd6cec026..8c658f54805a3 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -11,6 +11,7 @@ \defined('_JEXEC') or die; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Associations; use Joomla\CMS\Language\Text; @@ -80,6 +81,30 @@ public function __construct($config = array()) parent::__construct($config); } + /** + * Get the filter form + * + * @param array $data data + * @param boolean $loadData load current data + * + * @return Form|null The \JForm object or null if the form can't be found + * + * @since 3.2 + */ + public function getFilterForm($data = array(), $loadData = true) + { + $form = parent::getFilterForm($data, $loadData); + + $params = ComponentHelper::getParams('com_content'); + + if (!$params->get('workflows_enable')) + { + $form->removeField('stage', 'filter'); + } + + return $form; + } + /** * Method to auto-populate the model state. * @@ -199,6 +224,8 @@ protected function getListQuery() $query = $db->getQuery(true); $user = Factory::getUser(); + $params = ComponentHelper::getParams('com_content'); + // Select the required fields from the table. $query->select( $this->getState( @@ -328,7 +355,7 @@ protected function getListQuery() // Filter by published state $workflowStage = (string) $this->getState('filter.stage'); - if (is_numeric($workflowStage)) + if ($params->get('workflows_enable') && is_numeric($workflowStage)) { $workflowStage = (int) $workflowStage; $query->where($db->quoteName('wa.stage_id') . ' = :stage') From ceabd4cb0e96a564c40570bd7f1766677b9ae327 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Wed, 22 Apr 2020 21:09:03 +0200 Subject: [PATCH 12/90] Allow same and circle transitions again (#62) --- .../src/Model/TransitionModel.php | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index 8a1e043fa5dcc..0b2b2bff54cda 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -156,35 +156,6 @@ public function save($data) $isNew = false; } - if ($data['to_stage_id'] == $data['from_stage_id']) - { - $this->setError(Text::_('COM_WORKFLOW_MSG_FROM_TO_STAGE')); - - return false; - } - - $db = $this->getDbo(); - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__workflow_transitions')) - ->where($db->quoteName('from_stage_id') . ' = ' . (int) $data['from_stage_id']) - ->where($db->quoteName('to_stage_id') . ' = ' . (int) $data['to_stage_id']); - - if (!$isNew) - { - $query->where($db->quoteName('id') . ' <> ' . (int) $data['id']); - } - - $db->setQuery($query); - $duplicate = $db->loadResult(); - - if (!empty($duplicate)) - { - $this->setError(Text::_("COM_WORKFLOW_TRANSITION_DUPLICATE")); - - return false; - } - $workflowID = $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); if (empty($data['workflow_id'])) From ac6210681d2f29e862d3172ce16180f64f5d40d3 Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Fri, 24 Apr 2020 00:11:41 +0200 Subject: [PATCH 13/90] Calculate the ordering number in store (#65) * Calculate the ordering number in store * Use getNextOrder of Table/table.php * add casting for (int) --- .../components/com_workflow/src/Table/StageTable.php | 5 +++++ .../components/com_workflow/src/Table/TransitionTable.php | 7 ++++++- .../components/com_workflow/src/Table/WorkflowTable.php | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/src/Table/StageTable.php b/administrator/components/com_workflow/src/Table/StageTable.php index 31589d6180e0f..c0bcf7527657c 100644 --- a/administrator/components/com_workflow/src/Table/StageTable.php +++ b/administrator/components/com_workflow/src/Table/StageTable.php @@ -177,6 +177,11 @@ public function check() */ public function store($updateNulls = true) { + if (!(int) $this->ordering) + { + $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); + } + $table = new StageTable($this->getDbo()); if ($this->default == '1') diff --git a/administrator/components/com_workflow/src/Table/TransitionTable.php b/administrator/components/com_workflow/src/Table/TransitionTable.php index 80d5cbadc9549..c99095e4b94cb 100644 --- a/administrator/components/com_workflow/src/Table/TransitionTable.php +++ b/administrator/components/com_workflow/src/Table/TransitionTable.php @@ -65,7 +65,12 @@ public function __construct(DatabaseDriver $db) * @since 4.0.0 */ public function store($updateNulls = true) - { + { + if (!(int) $this->ordering) + { + $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); + } + return parent::store($updateNulls); } diff --git a/administrator/components/com_workflow/src/Table/WorkflowTable.php b/administrator/components/com_workflow/src/Table/WorkflowTable.php index 04797b014fc51..236913cc52360 100644 --- a/administrator/components/com_workflow/src/Table/WorkflowTable.php +++ b/administrator/components/com_workflow/src/Table/WorkflowTable.php @@ -197,6 +197,11 @@ public function store($updateNulls = true) $this->modified_by = 0; } + if (!(int) $this->ordering) + { + $this->ordering = $this->getNextOrder(); + } + if (!(int) $this->created) { $this->created = $date->toSql(); From 6c4ee9f220ee3277272da030cb95050a288712f1 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Fri, 24 Apr 2020 03:21:05 +0200 Subject: [PATCH 14/90] Workflow v3 transitions (#67) * Allow same and circle transitions again * Implement transition in the articles dropdown Make transition execution more generic --- .../com_content/src/Helper/ContentHelper.php | 2 +- .../com_content/src/Model/ArticlesModel.php | 70 +++--- .../src/View/Articles/HtmlView.php | 103 +++----- .../com_content/tmpl/articles/default.php | 53 +--- .../js/admin-articles-workflow-buttons.es6.js | 237 ------------------ .../js/admin-items-workflow-buttons.es6.js | 121 +++++++++ layouts/joomla/button/transition-button.php | 4 +- layouts/joomla/toolbar/separator.php | 4 +- .../src/MVC/Controller/AdminController.php | 6 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 8 +- .../src/MVC/Model/WorkflowModelInterface.php | 4 +- 11 files changed, 225 insertions(+), 387 deletions(-) delete mode 100644 build/media_source/com_content/js/admin-articles-workflow-buttons.es6.js create mode 100644 build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js diff --git a/administrator/components/com_content/src/Helper/ContentHelper.php b/administrator/components/com_content/src/Helper/ContentHelper.php index d11547ecb8388..664b098f2527a 100644 --- a/administrator/components/com_content/src/Helper/ContentHelper.php +++ b/administrator/components/com_content/src/Helper/ContentHelper.php @@ -67,7 +67,7 @@ public static function filterTransitions(array $transitions, int $pk, int $workf $transitions, function ($var) use ($pk, $workflow_id) { - return in_array($var['from_stage_id'], [-1, $pk]) && $var['to_stage_id'] != $pk && $workflow_id == $var['workflow_id']; + return in_array($var['from_stage_id'], [-1, $pk]) && $workflow_id == $var['workflow_id']; } ) ); diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 8c658f54805a3..9ac623f4b0931 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -580,47 +580,59 @@ public function getTransitions() return false; } - $ids = array_column($items, 'stage_id'); - $ids = ArrayHelper::toInteger($ids); - $ids = array_values(array_unique(array_filter($ids))); + $stage_ids = ArrayHelper::getColumn($items, 'stage_id'); + $stage_ids = ArrayHelper::toInteger($stage_ids); + $stage_ids = array_values(array_unique(array_filter($stage_ids))); - $ids[] = -1; + $workflow_ids = ArrayHelper::getColumn($items, 'workflow_id'); + $workflow_ids = ArrayHelper::toInteger($workflow_ids); + $workflow_ids = array_values(array_unique(array_filter($workflow_ids))); $this->cache[$store] = array(); try { - if (count($ids)) + if (count($stage_ids) || count($workflow_ids)) { Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); $query = $db->getQuery(true); - $query->select( - [ - $db->quoteName('t.id', 'value'), - $db->quoteName('t.title', 'text'), - $db->quoteName('t.from_stage_id'), - $db->quoteName('t.to_stage_id'), - $db->quoteName('s.id', 'stage_id'), - $db->quoteName('s.title', 'stage_title'), - $db->quoteName('s.workflow_id'), - ] - ) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->join( - 'LEFT', - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($ids)) . ')' - ) - ->where( + $query ->select( [ - $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), - $db->quoteName('t.published') . ' = 1', - $db->quoteName('s.published') . ' = 1', - ] - ) - ->order($db->quoteName('t.ordering')); + $db->quoteName('t.id', 'value'), + $db->quoteName('t.title', 'text'), + $db->quoteName('t.from_stage_id'), + $db->quoteName('t.to_stage_id'), + $db->quoteName('s.id', 'stage_id'), + $db->quoteName('s.title', 'stage_title'), + $db->quoteName('t.workflow_id'), + ]) + ->from($db->quoteName('#__workflow_transitions', 't')) + ->innerJoin($db->quoteName('#__workflow_stages', 's')) + ->where( + [ + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), + $db->quoteName('t.published') . ' = 1', + $db->quoteName('s.published') . ' = 1', + ] + ) + ->order($db->quoteName('t.ordering')) + ->group($db->quoteName('t.id')); + + $where = []; + + if (count($stage_ids)) + { + $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stage_ids)) . ')'; + } + + if (count($workflow_ids)) + { + $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; + } + + $query->where('(' . implode(') OR (', $where) . ')'); $transitions = $db->setQuery($query)->loadAssocList(); diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index e61ae552e3270..69a5ff68e821c 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -21,6 +21,7 @@ use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Administrator\Helper\ContentHelper; +use Joomla\CMS\Component\ComponentHelper; /** * View class for a list of articles. @@ -64,6 +65,13 @@ class HtmlView extends BaseHtmlView */ public $activeFilters; + /** + * All transition, which can be executed of one if the items + * + * @var array + */ + protected $transitions = []; + /** * Display the view * @@ -78,9 +86,13 @@ public function display($tpl = null) $this->state = $this->get('State'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); - $this->transitions = $this->get('Transitions'); $this->vote = PluginHelper::isEnabled('content', 'vote'); + if (ComponentHelper::getParams('com_content')->get('workflows_enable', 1)) + { + $this->transitions = $this->get('Transitions'); + } + // Check for errors. if ((count($errors = $this->get('Errors'))) || $this->transitions === false) { @@ -117,56 +129,6 @@ public function display($tpl = null) } } - /* - @TODO Move to the plugin - - $transitions = [ - 'publish' => [], - 'unpublish' => [], - 'archive' => [], - 'trash' => [] - ]; - - foreach ($this->transitions as $transition) - { - switch ($transition['stage_condition']) - { - case ContentComponent::CONDITION_PUBLISHED: - $transitions['publish'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_UNPUBLISHED: - $transitions['unpublish'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_ARCHIVED: - $transitions['archive'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_TRASHED: - $transitions['trash'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - } - } - - $this->document->addScriptOptions('articles.transitions', $transitions); - - */ - - $articles = []; - - foreach ($this->items as $item) - { - $articles['article-' . (int) $item->id] = Text::sprintf('COM_CONTENT_STAGE_ARTICLE_TITLE', $this->escape($item->title), (int) $item->id); - } - - $this->document->addScriptOptions('articles.items', $articles); - - Text::script('COM_CONTENT_ERROR_CANNOT_PUBLISH'); - Text::script('COM_CONTENT_ERROR_CANNOT_UNPUBLISH'); - Text::script('COM_CONTENT_ERROR_CANNOT_TRASH'); - Text::script('COM_CONTENT_ERROR_CANNOT_ARCHIVE'); - return parent::display($tpl); } @@ -192,7 +154,7 @@ protected function addToolbar() $toolbar->addNew('article.add'); } - if ($canDo->get('core.edit.state') || $canDo->get('core.execute.transition')) + if ($canDo->get('core.edit.state') || count($this->transitions)) { $dropdown = $toolbar->dropdownButton('status-group') ->text('JTOOLBAR_CHANGE_STATUS') @@ -203,15 +165,35 @@ protected function addToolbar() $childBar = $dropdown->getChildToolbar(); - if ($canDo->get('core.execute.transition')) + if (count($this->transitions)) { - $childBar->publish('articles.publish')->listCheck(true); - - $childBar->unpublish('articles.unpublish')->listCheck(true); + $childBar->separatorButton('transition-headline') + ->text('COM_CONTENT_RUN_TRANSITIONS') + ->buttonClass('text-center py-2 h3'); + + $cmd = "Joomla.submitbutton('articles.runTransition');"; + $messages = "{error: [Joomla.JText._('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST')]}"; + $alert = 'Joomla.renderMessages(' . $messages . ')'; + $cmd = 'if (document.adminForm.boxchecked.value == 0) { ' . $alert . ' } else { ' . $cmd . ' }'; + + foreach ($this->transitions as $transition) + { + $childBar->standardButton('transition') + ->text($transition['text']) + ->buttonClass('transition-' . (int) $transition['value']) + ->icon('fas fa-project-diagram') + ->onclick('document.adminForm.transition_id.value=' . (int) $transition['value'] . ';' . $cmd); + } + + $childBar->separatorButton('transition-separator'); } if ($canDo->get('core.edit.state')) { + $childBar->publish('articles.publish')->listCheck(true); + + $childBar->unpublish('articles.unpublish')->listCheck(true); + $childBar->standardButton('featured') ->text('JFEATURE') ->task('articles.featured') @@ -221,20 +203,11 @@ protected function addToolbar() ->text('JUNFEATURE') ->task('articles.unfeatured') ->listCheck(true); - } - if ($canDo->get('core.execute.transition')) - { $childBar->archive('articles.archive')->listCheck(true); - } - if ($canDo->get('core.edit.state')) - { $childBar->checkin('articles.checkin')->listCheck(true); - } - if ($canDo->get('core.execute.transition')) - { $childBar->trash('articles.trash')->listCheck(true); } diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index 8ea944bc75c9d..fa3fece984937 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -12,6 +12,7 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; use Joomla\CMS\Component\ComponentHelper; +use Joomla\Utilities\ArrayHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Associations; @@ -76,7 +77,7 @@ // @todo move the script to a file $this->document->addScriptDeclaration($js); -HTMLHelper::_('script', 'com_content/admin-articles-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); +HTMLHelper::_('script', 'com_workflow/admin-items-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); endif; @@ -97,7 +98,7 @@
- +
@@ -167,38 +168,13 @@ $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $publish = 0; - $unpublish = 0; - $archive = 0; - $trash = 0; - - /* - * @TODO This should be moved to a plugin + the data attributes in the tr below - foreach ($transitions as $transition) : - switch ($transition['stage_condition']) : - case ContentComponent::CONDITION_PUBLISHED: - ++$publish; - break; - case ContentComponent::CONDITION_UNPUBLISHED: - ++$unpublish; - break; - case ContentComponent::CONDITION_ARCHIVED: - ++$archive; - break; - case ContentComponent::CONDITION_TRASHED: - ++$trash; - break; - endswitch; - endforeach;*/ + $transition_ids = ArrayHelper::getColumn($transitions, 'value'); + $transition_ids = ArrayHelper::toInteger($transition_ids); ?> -
,
id, false, 'cid', 'cb', $item->title); ?> @@ -412,15 +388,10 @@ $this->loadTemplate('batch_body') ); ?> - Text::_('JTOOLBAR_CHANGE_STATUS'), - 'footer' => $this->loadTemplate('stage_footer'), - ), - $this->loadTemplate('stage_body') - ); ?> + + + + diff --git a/build/media_source/com_content/js/admin-articles-workflow-buttons.es6.js b/build/media_source/com_content/js/admin-articles-workflow-buttons.es6.js deleted file mode 100644 index 81ac73283f39a..0000000000000 --- a/build/media_source/com_content/js/admin-articles-workflow-buttons.es6.js +++ /dev/null @@ -1,237 +0,0 @@ -/** - * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -Joomla = window.Joomla || {}; - -/** - * Method that switches a given class to the following elements of the element provided - * - * @param {HTMLElement} element The reference element - * @param {string} className The class name to be toggled - */ -Joomla.toggleAllNextElements = (element, className) => { - const getNextSiblings = (el) => { - const siblings = []; - /* eslint-disable no-cond-assign,no-param-reassign */ - do { - siblings.push(el); - } while ((el = el.nextElementSibling) !== null); - /* eslint-enable no-cond-assign,no-param-reassign */ - return siblings; - }; - - const followingElements = getNextSiblings(element); - if (followingElements.length) { - followingElements.forEach((elem) => { - if (elem.classList.contains(className)) { - elem.classList.remove(className); - } else { - elem.classList.add(className); - } - }); - } -}; - -(() => { - 'use strict'; - - document.addEventListener('DOMContentLoaded', () => { - const dropDownBtn = document.getElementById('toolbar-dropdown-status-group'); - const publishBtn = dropDownBtn.getElementsByClassName('button-publish')[0]; - const unpublishBtn = dropDownBtn.getElementsByClassName('button-unpublish')[0]; - const archiveBtn = dropDownBtn.getElementsByClassName('button-archive')[0]; - const trashBtn = dropDownBtn.getElementsByClassName('button-trash')[0]; - const articleList = document.querySelector('#articleList'); - const modal = document.getElementById('stageModal'); - const modalcontent = document.getElementById('stageModal-content'); - const modalbutton = document.getElementById('stage-submit-button-id'); - const buttonDataSelector = 'data-submit-task'; - - let articleListRows = []; - let publishBool = false; - let unpublishBool = false; - let archiveBool = false; - let trashBool = false; - let countChecked = 0; - - if (articleList) { - articleListRows = [].slice.call(articleList.querySelectorAll('tbody tr')); - } - // TODO: remove jQuery dependency, when we have a new modal script - window.jQuery(modal).on('hide.bs.modal', () => { - modalcontent.innerHTML = ''; - }); - - function checkTransition(e, task) { - // Let's check for n:1 connections - const transitions = Joomla.getOptions('articles.transitions')[task]; - const availableTrans = {}; - let showModal = false; - - if (transitions === undefined) { - return; - } - - if (articleListRows.length) { - articleListRows.forEach((el) => { - const checkedBox = el.querySelectorAll('input[type=checkbox]')[0]; - - if (checkedBox.checked) { - const parentTr = checkedBox.closest('tr'); - const stage = parseInt(parentTr.getAttribute('data-stage_id'), 10); - const workflow = parseInt(parentTr.getAttribute('data-workflow_id'), 10); - - availableTrans[checkedBox.value] = []; - - if (transitions[workflow] === undefined) { - return; - } - - let k = 0; - - // Collect transitions - if (transitions[workflow][-1] !== undefined) { - for (let j = 0; j < transitions[workflow][-1].length; j += 1) { - if (transitions[workflow][-1][j].to_stage_id !== stage) { - availableTrans[checkedBox.value][k] = transitions[workflow][-1][j]; - - k += 1; - } - } - } - - if (transitions[workflow][stage] !== undefined) { - for (let j = 0; j < transitions[workflow][stage].length; j += 1) { - if (transitions[workflow][stage][j].to_stage_id !== stage) { - availableTrans[checkedBox.value][k] = transitions[workflow][stage][j]; - - k += 1; - } - } - } - - if (availableTrans[checkedBox.value].length > 1) { - showModal = true; - } else { - delete availableTrans[checkedBox.value]; - } - } - }); - } - - if (showModal) { - e.stopPropagation(); - - const articles = Joomla.getOptions('articles.items'); - let html = ''; - - modalbutton.setAttribute(buttonDataSelector, `articles.${task}`); - - Object.keys(availableTrans).forEach((id) => { - if (articles[`article-${id}`] !== undefined) { - html += '
'; - html += ``; - html += `'; - html += '
'; - html += ''; - } - }); - - modalcontent.innerHTML = html; - - // TODO: remove jQuery dependency, when we have a new modal script - window.jQuery(modal).modal(); - } - } - - publishBtn.parentElement.addEventListener('click', (e) => { - if (publishBtn.classList.contains('disabled')) { - e.stopImmediatePropagation(); - - Joomla.renderMessages({ error: [Joomla.JText._('COM_CONTENT_ERROR_CANNOT_PUBlISH')] }); - } else { - checkTransition(e, 'publish'); - } - }); - - unpublishBtn.parentElement.addEventListener('click', (e) => { - if (unpublishBtn.classList.contains('disabled')) { - e.stopImmediatePropagation(); - - Joomla.renderMessages({ error: [Joomla.JText._('COM_CONTENT_ERROR_CANNOT_UNPUBlISH')] }); - } else { - checkTransition(e, 'unpublish'); - } - }); - - archiveBtn.parentElement.addEventListener('click', (e) => { - if (archiveBtn.classList.contains('disabled')) { - e.stopImmediatePropagation(); - - Joomla.renderMessages({ error: [Joomla.JText._('COM_CONTENT_ERROR_CANNOT_ARCHIVE')] }); - } else { - checkTransition(e, 'archive'); - } - }); - - trashBtn.parentElement.addEventListener('click', (e) => { - if (trashBtn.classList.contains('disabled')) { - e.stopImmediatePropagation(); - - Joomla.renderMessages({ error: [Joomla.JText._('COM_CONTENT_ERROR_CANNOT_TRASH')] }); - } else { - checkTransition(e, 'trash'); - } - }); - - function setOrRemDisabled(btn, set) { - if (set) { - btn.classList.remove('disabled'); - } else { - btn.classList.add('disabled'); - } - } - - // disable or enable Buttons of transitions depending on the boolean variables - function disableButtons() { - setOrRemDisabled(publishBtn, publishBool); - setOrRemDisabled(unpublishBtn, unpublishBool); - setOrRemDisabled(archiveBtn, archiveBool); - setOrRemDisabled(trashBtn, trashBool); - } - - // check for common attributes for which the conditions for a transition are possible or not - // and save this information in a boolean variable. - function checkForAttributes(row) { - publishBool = row.getAttribute('data-condition-publish') > 0 && (countChecked === 0 || publishBool); - unpublishBool = row.getAttribute('data-condition-unpublish') > 0 && (countChecked === 0 || unpublishBool); - archiveBool = row.getAttribute('data-condition-archive') > 0 && (countChecked === 0 || archiveBool); - trashBool = row.getAttribute('data-condition-trash') > 0 && (countChecked === 0 || trashBool); - } - - // listen to click event to get selected rows - if (articleList) { - articleList.addEventListener('click', () => { - articleListRows.forEach((el) => { - const checkedBox = el.querySelectorAll('input[type=checkbox]')[0]; - - if (checkedBox.checked) { - const parentTr = checkedBox.closest('tr'); - checkForAttributes(parentTr); - countChecked += 1; - } - }); - disableButtons(); - countChecked = 0; - }); - } - }); -})(); diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js new file mode 100644 index 0000000000000..126b2f15d1902 --- /dev/null +++ b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js @@ -0,0 +1,121 @@ +/** + * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +Joomla = window.Joomla || {}; + +/** + * Method that switches a given class to the following elements of the element provided + * + * @param {HTMLElement} element The reference element + * @param {string} className The class name to be toggled + */ +Joomla.toggleAllNextElements = (element, className) => { + const getNextSiblings = (el) => { + const siblings = []; + /* eslint-disable no-cond-assign,no-param-reassign */ + do { + siblings.push(el); + } while ((el = el.nextElementSibling) !== null); + /* eslint-enable no-cond-assign,no-param-reassign */ + return siblings; + }; + + const followingElements = getNextSiblings(element); + if (followingElements.length) { + followingElements.forEach((elem) => { + if (elem.classList.contains(className)) { + elem.classList.remove(className); + } else { + elem.classList.add(className); + } + }); + } +}; + +(() => { + 'use strict'; + + document.addEventListener('DOMContentLoaded', () => { + const dropDownBtn = document.getElementById('toolbar-dropdown-status-group'); + const transitions = [].slice.call(dropDownBtn.querySelectorAll('.button-transition')); + const headline = dropDownBtn.getElementsByClassName('button-transition-headline')[0]; + const separator = dropDownBtn.getElementsByClassName('button-transition-separator')[0]; + const itemList = [].slice.call(document.querySelectorAll('table.itemList'))[0]; + + let itemListRows = []; + let transition_ids = []; + + if (itemList) { + itemListRows = [].slice.call(itemList.querySelectorAll('tbody tr')); + } + + function enableTransitions() { + if (transition_ids.length) + { + let availableTrans = transition_ids.shift(); + + while(transition_ids.length) + { + const compareTrans = transition_ids.shift(); + + availableTrans = availableTrans.filter((id) => {return compareTrans.indexOf(id) !== -1}); + } + + if (availableTrans.length) + { + if (headline) + { + headline.classList.remove('d-none'); + } + if (separator) + { + separator.classList.remove('d-none'); + } + } + + availableTrans.forEach((trans) => { + const elem = dropDownBtn.querySelector('.transition-' + trans); + + if (elem) + { + elem.parentNode.classList.remove('d-none') + } + }); + } + } + + // check for common attributes for which the conditions for a transition are possible or not + // and save this information in a boolean variable. + function collectTransitions(row) { + transition_ids.push(row.getAttribute('data-transitions').split(',')); + } + + // listen to click event to get selected rows + if (itemList) { + itemList.addEventListener('click', () => { + transitions.forEach((trans) => { + trans.parentNode.classList.add('d-none'); + }); + if (headline) + { + headline.classList.add('d-none'); + } + if (separator) + { + separator.classList.add('d-none'); + } + transition_ids = []; + itemListRows.forEach((el) => { + const checkedBox = el.querySelectorAll('input[type=checkbox]')[0]; + if (checkedBox.checked) { + const parentTr = checkedBox.closest('tr'); + collectTransitions(parentTr); + } + }); + enableTransitions(); + }); + } + }); +})(); diff --git a/layouts/joomla/button/transition-button.php b/layouts/joomla/button/transition-button.php index dc9d63c8948a5..be757b261d158 100644 --- a/layouts/joomla/button/transition-button.php +++ b/layouts/joomla/button/transition-button.php @@ -63,10 +63,10 @@ 'id' => 'transition-select_' . (int) $id, 'list.attr' => [ 'class' => 'custom-select custom-select-sm w-auto', - 'onchange' => "Joomla.listItemTask('" . $checkboxName . $this->escape($row ?? '') . "', 'articles.runTransition')"] + 'onchange' => "this.form.transition_id.value=this.value;Joomla.listItemTask('" . $checkboxName . $this->escape($row ?? '') . "', 'articles.runTransition')"] ]; - echo HTMLHelper::_('select.genericlist', $transitions, 'transition_' . (int) $id, $attribs); + echo HTMLHelper::_('select.genericlist', $transitions, '', $attribs); ?> diff --git a/layouts/joomla/toolbar/separator.php b/layouts/joomla/toolbar/separator.php index 298e5895c1080..128127c07786b 100644 --- a/layouts/joomla/toolbar/separator.php +++ b/layouts/joomla/toolbar/separator.php @@ -24,10 +24,10 @@ - - + diff --git a/libraries/src/MVC/Controller/AdminController.php b/libraries/src/MVC/Controller/AdminController.php index e43451c7f6af0..9c990825cd816 100644 --- a/libraries/src/MVC/Controller/AdminController.php +++ b/libraries/src/MVC/Controller/AdminController.php @@ -442,9 +442,7 @@ public function runTransition() return false; } - $pk = (int) $pks[0]; - - $transitionId = $this->input->post->get('transition_' . $pk, -1, 'int'); + $transitionId = (int) $this->input->post->getInt('transition_id'); // Get the model $model = $this->getModel(); @@ -454,7 +452,7 @@ public function runTransition() return false; } - $return = $model->executeTransition($pk, $transitionId); + $return = $model->executeTransition($pks, $transitionId); $redirect = Route::_('index.php?option=' . $this->option . '&view=' . $this->view_list . $this->getRedirectToListAppend(), false); diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 9c07e9a657fe7..b9bf9a70f6709 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -180,23 +180,23 @@ public function workflowAfterSave($data) // Execute transition if (!empty($data['transition'])) { - $this->executeTransition($id, $data['transition']); + $this->executeTransition([$id], $data['transition']); } } /** * Runs transition for item. * - * @param integer $pk Id of article + * @param array $pks Id of items to execute the transition * @param integer $transition_id Id of transition * * @return boolean * * @since 4.0.0 */ - public function executeTransition(int $pk, int $transition_id) + public function executeTransition(array $pks, int $transition_id) { - $result = $this->workflow->executeTransition([$pk], $transition_id); + $result = $this->workflow->executeTransition($pks, $transition_id); if (!$result) { diff --git a/libraries/src/MVC/Model/WorkflowModelInterface.php b/libraries/src/MVC/Model/WorkflowModelInterface.php index 9e9d4586c95db..0a8e6db72f7c6 100644 --- a/libraries/src/MVC/Model/WorkflowModelInterface.php +++ b/libraries/src/MVC/Model/WorkflowModelInterface.php @@ -74,14 +74,14 @@ public function workflowAfterSave($data); /** * Runs transition for item. * - * @param integer $pk Id of article + * @param array $pks Id of items to execute the transition * @param integer $transition_id Id of transition * * @return boolean * * @since 4.0.0 */ - public function executeTransition(int $pk, int $transition_id); + public function executeTransition(array $pks, int $transition_id); /** * Method to get state variables. From 2a9f2d5d625dfeab3d362a6af7ad0c2b2156ebcc Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sat, 25 Apr 2020 23:15:31 +0200 Subject: [PATCH 15/90] Add missing publishing plugin xml --- plugins/workflow/publishing/publishing.xml | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 plugins/workflow/publishing/publishing.xml diff --git a/plugins/workflow/publishing/publishing.xml b/plugins/workflow/publishing/publishing.xml new file mode 100644 index 0000000000000..d2bbfb5f0f909 --- /dev/null +++ b/plugins/workflow/publishing/publishing.xml @@ -0,0 +1,27 @@ + + + plg_workflow_publishing + Joomla! Project + March 2020 + Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 4.0.0 + PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION + + publishing.php + + + en-GB.plg_workflow_publishing.ini + en-GB.plg_workflow_publishing.sys.ini + + + +
+ +
+
+
+ +
From 38ee874de7374c7bad1d3c3913dc8a8a219f81df Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 26 Apr 2020 07:48:43 +0200 Subject: [PATCH 16/90] Kill publish approaches with an exception when workflow is enabled Fix publish tooltip when workflow is not enabled Remove unused modal files --- .../com_content/tmpl/articles/default.php | 52 +++++++++---------- .../tmpl/articles/default_stage_body.php | 23 -------- .../tmpl/articles/default_stage_footer.php | 21 -------- plugins/workflow/publishing/publishing.php | 4 +- 4 files changed, 26 insertions(+), 74 deletions(-) delete mode 100644 administrator/components/com_content/tmpl/articles/default_stage_body.php delete mode 100644 administrator/components/com_content/tmpl/articles/default_stage_footer.php diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index fa3fece984937..312a0be9da2bb 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -210,35 +210,33 @@ ?>
-
-
- $transitions, - 'stage' => Text::_($item->stage_title), - 'id' => (int) $item->id - ]; + +
+ $transitions, + 'stage' => Text::_($item->stage_title), + 'id' => (int) $item->id + ]; - echo (new PublishedButton) - ->removeState(0) - ->removeState(1) - ->removeState(2) - ->removeState(-2) - ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) - ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) - ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) - ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) - ->setLayout('joomla.button.transition-button') - ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); - else : - echo HTMLHelper::_('jgrid.published', $item->state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); - endif; - ?> -
+ echo (new PublishedButton) + ->removeState(0) + ->removeState(1) + ->removeState(2) + ->removeState(-2) + ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) + ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) + ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) + ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) + ->setLayout('joomla.button.transition-button') + ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + ?>
+ state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); + endif; + ?>
diff --git a/administrator/components/com_content/tmpl/articles/default_stage_body.php b/administrator/components/com_content/tmpl/articles/default_stage_body.php deleted file mode 100644 index 5c45de087c832..0000000000000 --- a/administrator/components/com_content/tmpl/articles/default_stage_body.php +++ /dev/null @@ -1,23 +0,0 @@ - - -
-
-
-

-
-
-
-
-
diff --git a/administrator/components/com_content/tmpl/articles/default_stage_footer.php b/administrator/components/com_content/tmpl/articles/default_stage_footer.php deleted file mode 100644 index c18ec8cfbfe67..0000000000000 --- a/administrator/components/com_content/tmpl/articles/default_stage_footer.php +++ /dev/null @@ -1,21 +0,0 @@ - 'auto', 'relative' => true]); -?> - - diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index b8e8ba3513905..8595fb11a5fa9 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -249,9 +249,7 @@ public function onContentBeforeChangeState($context, $pks, $value) return true; } - $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED'), 'error'); - - return false; + throw new Exception(Text::_('PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED')); } /** From e8dfbb46718b222cff9767d74db278fcd574f797 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Sun, 26 Apr 2020 08:57:05 +0200 Subject: [PATCH 17/90] Implement onBeforeDisplay plugin trigger (#72) Implement onBeforeDisplay plugin trigger Implement onAfterDisplay plugin trigger Disable publish calls via workflow plugin --- .../src/View/Articles/HtmlView.php | 2 + libraries/src/MVC/View/HtmlView.php | 20 +++++++ libraries/src/MVC/View/ViewInterface.php | 11 ++++ plugins/workflow/publishing/publishing.php | 59 +++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 69a5ff68e821c..fb3b7975f48ee 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -90,6 +90,8 @@ public function display($tpl = null) if (ComponentHelper::getParams('com_content')->get('workflows_enable', 1)) { + PluginHelper::importPlugin('workflow'); + $this->transitions = $this->get('Transitions'); } diff --git a/libraries/src/MVC/View/HtmlView.php b/libraries/src/MVC/View/HtmlView.php index 3cf2fb4a2a391..d756c7bfc8133 100644 --- a/libraries/src/MVC/View/HtmlView.php +++ b/libraries/src/MVC/View/HtmlView.php @@ -15,6 +15,7 @@ use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; +use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Uri\Uri; /** @@ -189,8 +190,27 @@ public function __construct($config = array()) */ public function display($tpl = null) { + $app = Factory::getApplication(); + + if ($this->option) + { + $component = $this->option; + } + else + { + $component = ApplicationHelper::getComponentName(); + } + + $context = $component . '.' . $this->getName(); + + PluginHelper::importPlugin('content'); + + $app->triggerEvent('onBeforeDisplay', [$context, $this]); + $result = $this->loadTemplate($tpl); + $app->triggerEvent('onAfterDisplay', [$context, $this, $result]); + echo $result; } diff --git a/libraries/src/MVC/View/ViewInterface.php b/libraries/src/MVC/View/ViewInterface.php index 3af625feb5ded..f955143306c25 100644 --- a/libraries/src/MVC/View/ViewInterface.php +++ b/libraries/src/MVC/View/ViewInterface.php @@ -28,4 +28,15 @@ interface ViewInterface * @since 4.0.0 */ public function display($tpl = null); + + /** + * Method to get the model object + * + * @param string $name The name of the model (optional) + * + * @return BaseDatabaseModel The model object + * + * @since 3.0 + */ + public function getModel($name = null); } diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 8595fb11a5fa9..17edd58f72bee 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -10,12 +10,15 @@ defined('_JEXEC') or die; use Joomla\CMS\Application\CMSApplicationInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\DatabaseModelInterface; +use Joomla\CMS\MVC\View\ViewInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Table\TableInterface; use Joomla\CMS\Workflow\WorkflowServiceInterface; +use Joomla\String\Inflector; /** * Workflow Publishing Plugin @@ -150,6 +153,62 @@ protected function enhanceItemForm(Form $form, $data) return true; } + /** + * Manipulate the generic list view + * + * @param type $context + * @param type $view + * @param type $result + */ + public function onAfterDisplay(string $context, ViewInterface $view, $result) + { + $parts = explode('.', $context); + + if ($parts < 2) + { + return true; + } + + $app = Factory::getApplication(); + + // We need the single model context for checking for workflow + $singularsection = Inflector::singularize($parts[1]); + + $newcontext = $parts[0] . '.' . $singularsection; + + if (!$app->isClient('administrator') || !$this->isSupported($newcontext)) + { + return true; + } + + // That's the hard coded list from the AdminController publish method => change, when it's make dynamic in the future + $states = ['publish', 'unpublish', 'archive', 'trash', 'report']; + + $js = " + document.addEventListener('DOMContentLoaded', function() + { + var dropdown = document.getElementById('toolbar-dropdown-status-group'); + + if (!dropdown) + { + reuturn; + } + + " . \json_encode($states) . ".forEach((action) => { + var button = document.getElementById('status-group-children-' + action); + + if (button) + { + button.classList.add('d-none'); + } + }); + + }); + "; + + $app->getDocument()->addScriptDeclaration($js); + } + /** * Check if we can execute the transition * From f6fbe8f6bc25bf6b93df8c1b2b6da7282d6fab4c Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Sun, 26 Apr 2020 10:52:55 +0200 Subject: [PATCH 18/90] Fix notice in article (#68) --- .../components/com_content/src/Model/ArticlesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 9ac623f4b0931..33d369f6ac8ab 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -368,7 +368,7 @@ protected function getListQuery() { if (is_numeric($published)) { - $state = (int) $state; + $state = (int) $published; $query->where($db->quoteName('a.state') . ' = :state') ->bind(':state', $published, ParameterType::INTEGER); } From 5d7ef5ad9e51ee35ec7a9314af87119f83b2cef7 Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Sun, 26 Apr 2020 10:53:30 +0200 Subject: [PATCH 19/90] Fix #70 (#71) --- .../components/com_workflow/forms/filter_stages.xml | 7 +++---- .../components/com_workflow/forms/filter_transitions.xml | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/administrator/components/com_workflow/forms/filter_stages.xml b/administrator/components/com_workflow/forms/filter_stages.xml index 830e16abaf336..1225dad03b13e 100644 --- a/administrator/components/com_workflow/forms/filter_stages.xml +++ b/administrator/components/com_workflow/forms/filter_stages.xml @@ -24,13 +24,12 @@ name="fullordering" type="list" label="JGLOBAL_SORT_BY" - statuses="*,0,1,2,-2" - onchange="this.form.submit();" default="s.ordering ASC" + onchange="this.form.submit();" > - - + + diff --git a/administrator/components/com_workflow/forms/filter_transitions.xml b/administrator/components/com_workflow/forms/filter_transitions.xml index de61e88b27ef4..fa59bb1699401 100644 --- a/administrator/components/com_workflow/forms/filter_transitions.xml +++ b/administrator/components/com_workflow/forms/filter_transitions.xml @@ -45,12 +45,11 @@ type="list" label="JGLOBAL_SORT_BY" default="t.ordering ASC" - statuses="*,0,1,2,-2" onchange="this.form.submit();" > - - + + From ffdb21d75d96b02fe828d6b81e73425b0022e2f5 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Mon, 27 Apr 2020 02:34:56 +0200 Subject: [PATCH 20/90] Codestyle fixes (#73) --- .../com_content/src/Model/ArticlesModel.php | 39 ++++++++++--------- .../src/View/Articles/HtmlView.php | 12 +++--- .../com_workflow/src/Table/StageTable.php | 2 +- .../src/Table/TransitionTable.php | 4 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 14 ++++++- .../src/Workflow/WorkflowServiceInterface.php | 13 ++++--- .../src/Workflow/WorkflowServiceTrait.php | 23 +++++++---- plugins/workflow/publishing/publishing.php | 16 +++++--- 8 files changed, 75 insertions(+), 48 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 33d369f6ac8ab..1f5b887127ba5 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -599,26 +599,27 @@ public function getTransitions() $query = $db->getQuery(true); $query ->select( + [ + $db->quoteName('t.id', 'value'), + $db->quoteName('t.title', 'text'), + $db->quoteName('t.from_stage_id'), + $db->quoteName('t.to_stage_id'), + $db->quoteName('s.id', 'stage_id'), + $db->quoteName('s.title', 'stage_title'), + $db->quoteName('t.workflow_id'), + ] + ) + ->from($db->quoteName('#__workflow_transitions', 't')) + ->innerJoin($db->quoteName('#__workflow_stages', 's')) + ->where( [ - $db->quoteName('t.id', 'value'), - $db->quoteName('t.title', 'text'), - $db->quoteName('t.from_stage_id'), - $db->quoteName('t.to_stage_id'), - $db->quoteName('s.id', 'stage_id'), - $db->quoteName('s.title', 'stage_title'), - $db->quoteName('t.workflow_id'), - ]) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->innerJoin($db->quoteName('#__workflow_stages', 's')) - ->where( - [ - $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), - $db->quoteName('t.published') . ' = 1', - $db->quoteName('s.published') . ' = 1', - ] - ) - ->order($db->quoteName('t.ordering')) - ->group($db->quoteName('t.id')); + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), + $db->quoteName('t.published') . ' = 1', + $db->quoteName('s.published') . ' = 1', + ] + ) + ->order($db->quoteName('t.ordering')) + ->group($db->quoteName('t.id')); $where = []; diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index fb3b7975f48ee..4fb64ae9957d9 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -170,8 +170,8 @@ protected function addToolbar() if (count($this->transitions)) { $childBar->separatorButton('transition-headline') - ->text('COM_CONTENT_RUN_TRANSITIONS') - ->buttonClass('text-center py-2 h3'); + ->text('COM_CONTENT_RUN_TRANSITIONS') + ->buttonClass('text-center py-2 h3'); $cmd = "Joomla.submitbutton('articles.runTransition');"; $messages = "{error: [Joomla.JText._('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST')]}"; @@ -181,10 +181,10 @@ protected function addToolbar() foreach ($this->transitions as $transition) { $childBar->standardButton('transition') - ->text($transition['text']) - ->buttonClass('transition-' . (int) $transition['value']) - ->icon('fas fa-project-diagram') - ->onclick('document.adminForm.transition_id.value=' . (int) $transition['value'] . ';' . $cmd); + ->text($transition['text']) + ->buttonClass('transition-' . (int) $transition['value']) + ->icon('fas fa-project-diagram') + ->onclick('document.adminForm.transition_id.value=' . (int) $transition['value'] . ';' . $cmd); } $childBar->separatorButton('transition-separator'); diff --git a/administrator/components/com_workflow/src/Table/StageTable.php b/administrator/components/com_workflow/src/Table/StageTable.php index c0bcf7527657c..e59f1a3847616 100644 --- a/administrator/components/com_workflow/src/Table/StageTable.php +++ b/administrator/components/com_workflow/src/Table/StageTable.php @@ -179,7 +179,7 @@ public function store($updateNulls = true) { if (!(int) $this->ordering) { - $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); + $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); } $table = new StageTable($this->getDbo()); diff --git a/administrator/components/com_workflow/src/Table/TransitionTable.php b/administrator/components/com_workflow/src/Table/TransitionTable.php index c99095e4b94cb..30447ecddc61d 100644 --- a/administrator/components/com_workflow/src/Table/TransitionTable.php +++ b/administrator/components/com_workflow/src/Table/TransitionTable.php @@ -65,10 +65,10 @@ public function __construct(DatabaseDriver $db) * @since 4.0.0 */ public function store($updateNulls = true) - { + { if (!(int) $this->ordering) { - $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); + $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); } return parent::store($updateNulls); diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index b9bf9a70f6709..a4b5d51808e0b 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -26,15 +26,27 @@ trait WorkflowBehaviorTrait { /** - * The for the component. + * The name of the component. * * @var string * @since 4.0.0 */ protected $extension = null; + /** + * The section of the component. + * + * @var string + * @since 4.0.0 + */ protected $section = ''; + /** + * Is workflow for this component enabled? + * + * @var boolean + * @since 4.0.0 + */ protected $workflowEnabled = false; /** diff --git a/libraries/src/Workflow/WorkflowServiceInterface.php b/libraries/src/Workflow/WorkflowServiceInterface.php index 83227f8a1f1b8..e24713929b40b 100644 --- a/libraries/src/Workflow/WorkflowServiceInterface.php +++ b/libraries/src/Workflow/WorkflowServiceInterface.php @@ -15,14 +15,15 @@ * * @since 4.0.0 */ -interface WorkflowServiceInterface { +interface WorkflowServiceInterface +{ /** * Check if the functionality is supported by the context * - * @param string $feature The functionality - * @param string $context The context of the functionality + * @param string $functionality The functionality + * @param string $context The context of the functionality * - * @return bool + * @return boolean * * @since 4.0.0 */ @@ -33,7 +34,7 @@ public function supportFunctionality($functionality, $context): bool; * * @param string $context The context of the workflow * - * @return bool + * @return boolean */ public function getModelName($context): string; @@ -42,7 +43,7 @@ public function getModelName($context): string; * * @param string $context The context of the workflow * - * @return bool + * @return boolean */ public function isWorkflowActive($context): bool; diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index 475771c9507ab..dfb49de7ff62f 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -10,6 +10,7 @@ use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; +use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\WorkflowModelInterface; \defined('JPATH_PLATFORM') or die; @@ -19,8 +20,16 @@ * * @since 4.0.0 */ -trait WorkflowServiceTrait { - abstract function getMVCFactory(); +trait WorkflowServiceTrait +{ + /** + * Get a MVC factory + * + * @return MVCFactoryInterface + * + * @since __DEPLOY_VERSION__ + */ + abstract public function getMVCFactory(): MVCFactoryInterface; /** @var array Supported functionality */ protected $supportedFunctionality = [ @@ -31,10 +40,10 @@ abstract function getMVCFactory(); /** * Check if the functionality is supported by the context * - * @param string $feature The functionality - * @param string $context The context of the functionality + * @param string $functionality The functionality + * @param string $context The context of the functionality * - * @return bool + * @return boolean */ public function supportFunctionality($functionality, $context): bool { @@ -56,7 +65,7 @@ public function supportFunctionality($functionality, $context): bool * * @param string $context The context of the workflow * - * @return bool + * @return boolean */ public function getModelName($context) : string { @@ -91,7 +100,7 @@ public static function getConditions(string $extension): array * * @param string $context The context of the workflow * - * @return bool + * @return boolean */ public function isWorkflowActive($context): bool { diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 17edd58f72bee..82e282b24be98 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -87,7 +87,7 @@ public function onContentPrepareForm(Form $form, $data) protected function enhanceTransitionForm(Form $form, $data) { $model = $this->app->bootComponent('com_workflow') - ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); + ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); $workflow_id = !empty($data->workflow_id) ? (int) $data->workflow_id : (int) $form->getValue('workflow_id'); @@ -146,7 +146,7 @@ protected function enhanceItemForm(Form $form, $data) $modelName = $component->getModelName($context); $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) - ->getTable(); + ->getTable(); $form->setFieldAttribute($table->getColumnAlias('published'), 'disabled', 'true'); @@ -227,9 +227,11 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) $value = (int) $transition->options->get('publishing'); - // Here it becomes tricky. We would like to use the component models publish method, so we will - // Execute the normal "onContentBeforeChangeState" plugins. But they could cancel the execution, - // So we have to precheck and cancel the whole transition stuff if not allowed. + /** + * Here it becomes tricky. We would like to use the component models publish method, so we will + * Execute the normal "onContentBeforeChangeState" plugins. But they could cancel the execution, + * So we have to precheck and cancel the whole transition stuff if not allowed. + */ $this->app->set('plgWorkflowPublishing.' . $context, $pks); $result = $this->app->triggerEvent('onContentBeforeChangeState', [$context, $pks, $value]); @@ -367,7 +369,9 @@ protected function isSupported($context) $component = $this->app->bootComponent($parts[0]); - if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context) || !$component->supportFunctionality($this->supportname, $context)) + if (!$component instanceof WorkflowServiceInterface + || !$component->isWorkflowActive($context) + || !$component->supportFunctionality($this->supportname, $context)) { return false; } From e403aded0d943a87bcca217a09bdf99287bb58d4 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Mon, 27 Apr 2020 02:36:52 +0200 Subject: [PATCH 21/90] Renaming workflows_enable parameter to workflow_enabled (#74) * Renaming workflows_enable parameter to workflow_enabled * Add missing default values Co-authored-by: Benjamin Trenkle --- administrator/components/com_content/config.xml | 4 ++-- .../components/com_content/src/Model/ArticlesModel.php | 4 ++-- .../components/com_content/src/View/Articles/HtmlView.php | 2 +- .../components/com_content/tmpl/articles/default.php | 2 +- .../com_content/tmpl/articles/default_batch_body.php | 2 +- administrator/language/en-GB/joomla.ini | 2 +- administrator/modules/mod_menu/src/Menu/CssMenu.php | 2 +- administrator/modules/mod_submenu/src/Menu/Menu.php | 2 +- api/language/en-GB/joomla.ini | 2 +- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 2 +- libraries/src/Workflow/WorkflowServiceTrait.php | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml index eded9fc00402e..705766a2741b3 100644 --- a/administrator/components/com_content/config.xml +++ b/administrator/components/com_content/config.xml @@ -1024,9 +1024,9 @@ diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 1f5b887127ba5..cc82e2f71a861 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -97,7 +97,7 @@ public function getFilterForm($data = array(), $loadData = true) $params = ComponentHelper::getParams('com_content'); - if (!$params->get('workflows_enable')) + if (!$params->get('workflow_enabled', 1)) { $form->removeField('stage', 'filter'); } @@ -355,7 +355,7 @@ protected function getListQuery() // Filter by published state $workflowStage = (string) $this->getState('filter.stage'); - if ($params->get('workflows_enable') && is_numeric($workflowStage)) + if ($params->get('workflow_enabled', 1) && is_numeric($workflowStage)) { $workflowStage = (int) $workflowStage; $query->where($db->quoteName('wa.stage_id') . ' = :stage') diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 4fb64ae9957d9..0ccad90df20cd 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -88,7 +88,7 @@ public function display($tpl = null) $this->activeFilters = $this->get('ActiveFilters'); $this->vote = PluginHelper::isEnabled('content', 'vote'); - if (ComponentHelper::getParams('com_content')->get('workflows_enable', 1)) + if (ComponentHelper::getParams('com_content')->get('workflow_enabled', 1)) { PluginHelper::importPlugin('workflow'); diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index 312a0be9da2bb..a2c3b351f64fd 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -56,7 +56,7 @@ HTMLHelper::_('draggablelist.draggable'); } -$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflows_enable', 1); +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled', 1); if ($workflow_enabled) : diff --git a/administrator/components/com_content/tmpl/articles/default_batch_body.php b/administrator/components/com_content/tmpl/articles/default_batch_body.php index ca9925a09c373..8f5a7b5bb0c1f 100644 --- a/administrator/components/com_content/tmpl/articles/default_batch_body.php +++ b/administrator/components/com_content/tmpl/articles/default_batch_body.php @@ -45,7 +45,7 @@
- authorise('core.admin', 'com_content') && $params->get('workflows_enable', 1)) : ?> + authorise('core.admin', 'com_content') && $params->get('workflow_enabled', 1)) : ?>
'com_content']); ?> diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index c1df7fd631588..21640874e5548 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -646,7 +646,7 @@ JGLOBAL_WARNCOOKIES="Warning! Cookies must be enabled to access the Administrato JGLOBAL_WARNIE="Warning! Internet Explorer should not be used for proper operation of the Administrator Backend." JGLOBAL_WARNJAVASCRIPT="Warning! JavaScript must be enabled for proper operation of the Administrator Backend." JGLOBAL_WIDTH="Width" -JGLOBAL_WORKFLOWS_ENABLE_LABEL="Enable Workflows" +JGLOBAL_WORKFLOW_ENABLED_LABEL="Enable Workflows" JGRID_HEADING_ACCESS="Access" JGRID_HEADING_ACCESS_ASC="Access ascending" diff --git a/administrator/modules/mod_menu/src/Menu/CssMenu.php b/administrator/modules/mod_menu/src/Menu/CssMenu.php index 6219a5f8300df..d25d717b4a690 100644 --- a/administrator/modules/mod_menu/src/Menu/CssMenu.php +++ b/administrator/modules/mod_menu/src/Menu/CssMenu.php @@ -376,7 +376,7 @@ protected function preprocess($parent) if (isset($query['extension'])) { - $workflow = ComponentHelper::getParams($query['extension'])->get('workflows_enable', 1); + $workflow = ComponentHelper::getParams($query['extension'])->get('workflow_enabled', 1); } if (!$workflow) diff --git a/administrator/modules/mod_submenu/src/Menu/Menu.php b/administrator/modules/mod_submenu/src/Menu/Menu.php index 69dc637f0a7b6..8f35a69726279 100644 --- a/administrator/modules/mod_submenu/src/Menu/Menu.php +++ b/administrator/modules/mod_submenu/src/Menu/Menu.php @@ -129,7 +129,7 @@ public static function preprocess($parent) if (isset($query['extension'])) { - $workflow = ComponentHelper::getParams($query['extension'])->get('workflows_enable', 1); + $workflow = ComponentHelper::getParams($query['extension'])->get('workflow_enabled', 1); } if (!$workflow) diff --git a/api/language/en-GB/joomla.ini b/api/language/en-GB/joomla.ini index 3c9b1d3fe74ae..442a7d5350a95 100644 --- a/api/language/en-GB/joomla.ini +++ b/api/language/en-GB/joomla.ini @@ -642,7 +642,7 @@ JGLOBAL_VOTES_DESC="Votes descending" JGLOBAL_WARNCOOKIES="Warning! Cookies must be enabled to access the Administrator Backend." JGLOBAL_WARNJAVASCRIPT="Warning! JavaScript must be enabled for proper operation of the Administrator Backend." JGLOBAL_WIDTH="Width" -JGLOBAL_WORKFLOWS_ENABLE_LABEL="Enable Workflows" +JGLOBAL_WORKFLOW_ENABLED_LABEL="Enable Workflows" JGRID_HEADING_ACCESS="Access" JGRID_HEADING_ACCESS_ASC="Access ascending" diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index a4b5d51808e0b..6911ef9159dbd 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -81,7 +81,7 @@ public function setUpWorkflow($extension) $params = ComponentHelper::getParams($this->extension); - $this->workflowEnabled = $params->get('workflows_enable', 1); + $this->workflowEnabled = $params->get('workflow_enabled', 1); $this->enableWorkflowBatch(); } diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index dfb49de7ff62f..20c3cc6eae4a8 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -107,7 +107,7 @@ public function isWorkflowActive($context): bool $parts = explode('.', $context); $config = ComponentHelper::getParams($parts[0]); - if (!$config->get('workflows_enable', 1)) + if (!$config->get('workflow_enabled', 1)) { return false; } From fdacb3137a1b7ec027de6d1a870b13129a8b3a86 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 29 Apr 2020 01:43:44 +0200 Subject: [PATCH 22/90] Remove unnecessary plugin type loader --- libraries/src/MVC/View/HtmlView.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/src/MVC/View/HtmlView.php b/libraries/src/MVC/View/HtmlView.php index d756c7bfc8133..7cfeccb7482c8 100644 --- a/libraries/src/MVC/View/HtmlView.php +++ b/libraries/src/MVC/View/HtmlView.php @@ -203,8 +203,6 @@ public function display($tpl = null) $context = $component . '.' . $this->getName(); - PluginHelper::importPlugin('content'); - $app->triggerEvent('onBeforeDisplay', [$context, $this]); $result = $this->loadTemplate($tpl); From d9266b2865ade898e5009d88ce619a92c9d82c87 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 29 Apr 2020 02:24:37 +0200 Subject: [PATCH 23/90] Fix transition execution check Implement featured in workflow handling --- .../src/Extension/ContentComponent.php | 4 + .../src/View/Articles/HtmlView.php | 2 +- .../src/View/Featured/HtmlView.php | 102 +++++++----------- .../com_content/tmpl/articles/default.php | 2 +- .../com_content/tmpl/featured/default.php | 95 ++++++++-------- .../src/MVC/Model/WorkflowBehaviorTrait.php | 1 + libraries/src/Workflow/Workflow.php | 13 ++- 7 files changed, 98 insertions(+), 121 deletions(-) diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index b0a05e63b1382..06265cd471be8 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -223,6 +223,10 @@ public function getModelName($context): string { return 'Form'; } + elseif ($modelname === 'featured' && Factory::getApplication()->isClient('administrator')) + { + return 'Article'; + } return ucfirst($modelname); } diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 0ccad90df20cd..6bc32c85e617b 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -11,6 +11,7 @@ \defined('_JEXEC') or die; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; @@ -21,7 +22,6 @@ use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Administrator\Helper\ContentHelper; -use Joomla\CMS\Component\ComponentHelper; /** * View class for a list of articles. diff --git a/administrator/components/com_content/src/View/Featured/HtmlView.php b/administrator/components/com_content/src/View/Featured/HtmlView.php index b99800423718f..351a55ff16b25 100644 --- a/administrator/components/com_content/src/View/Featured/HtmlView.php +++ b/administrator/components/com_content/src/View/Featured/HtmlView.php @@ -11,6 +11,7 @@ \defined('_JEXEC') or die; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; @@ -64,6 +65,13 @@ class HtmlView extends BaseHtmlView */ public $activeFilters; + /** + * All transition, which can be executed of one if the items + * + * @var array + */ + protected $transitions = []; + /** * Display the view * @@ -81,6 +89,13 @@ public function display($tpl = null) $this->transitions = $this->get('Transitions'); $this->vote = PluginHelper::isEnabled('content', 'vote'); + if (ComponentHelper::getParams('com_content')->get('workflow_enabled', 1)) + { + PluginHelper::importPlugin('workflow'); + + $this->transitions = $this->get('Transitions'); + } + // Check for errors. if (count($errors = $this->get('Errors'))) { @@ -96,54 +111,6 @@ public function display($tpl = null) $this->filterForm->removeField('language', 'filter'); } - /* - @TODO Move to plugin - $transitions = [ - 'publish' => [], - 'unpublish' => [], - 'archive' => [], - 'trash' => [] - ]; - - foreach ($this->transitions as $transition) - { - switch ($transition['stage_condition']) - { - case ContentComponent::CONDITION_PUBLISHED: - $transitions['publish'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_UNPUBLISHED: - $transitions['unpublish'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_ARCHIVED: - $transitions['archive'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - - case ContentComponent::CONDITION_TRASHED: - $transitions['trash'][$transition['workflow_id']][$transition['from_stage_id']][] = $transition; - break; - } - } - - $this->document->addScriptOptions('articles.transitions', $transitions); - */ - - $articles = []; - - foreach ($this->items as $item) - { - $articles['article-' . (int) $item->id] = Text::sprintf('COM_CONTENT_STAGE_ARTICLE_TITLE', $this->escape($item->title), (int) $item->id); - } - - $this->document->addScriptOptions('articles.items', $articles); - - Text::script('COM_CONTENT_ERROR_CANNOT_PUBLISH'); - Text::script('COM_CONTENT_ERROR_CANNOT_UNPUBLISH'); - Text::script('COM_CONTENT_ERROR_CANNOT_TRASH'); - Text::script('COM_CONTENT_ERROR_CANNOT_ARCHIVE'); - return parent::display($tpl); } @@ -169,7 +136,7 @@ protected function addToolbar() $toolbar->addNew('article.add'); } - if ($canDo->get('core.edit.state') || $canDo->get('core.execute.transition')) + if ($canDo->get('core.edit.state') || count($this->transitions)) { $dropdown = $toolbar->dropdownButton('status-group') ->text('JTOOLBAR_CHANGE_STATUS') @@ -180,33 +147,44 @@ protected function addToolbar() $childBar = $dropdown->getChildToolbar(); - if ($canDo->get('core.execute.transition')) + if (count($this->transitions)) { - $childBar->publish('articles.publish')->listCheck(true); - - $childBar->unpublish('articles.unpublish')->listCheck(true); + $childBar->separatorButton('transition-headline') + ->text('COM_CONTENT_RUN_TRANSITIONS') + ->buttonClass('text-center py-2 h3'); + + $cmd = "Joomla.submitbutton('articles.runTransition');"; + $messages = "{error: [Joomla.JText._('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST')]}"; + $alert = 'Joomla.renderMessages(' . $messages . ')'; + $cmd = 'if (document.adminForm.boxchecked.value == 0) { ' . $alert . ' } else { ' . $cmd . ' }'; + + foreach ($this->transitions as $transition) + { + $childBar->standardButton('transition') + ->text($transition['text']) + ->buttonClass('transition-' . (int) $transition['value']) + ->icon('fas fa-project-diagram') + ->onclick('document.adminForm.transition_id.value=' . (int) $transition['value'] . ';' . $cmd); + } + + $childBar->separatorButton('transition-separator'); } if ($canDo->get('core.edit.state')) { + $childBar->publish('articles.publish')->listCheck(true); + + $childBar->unpublish('articles.unpublish')->listCheck(true); + $childBar->standardButton('unfeatured') ->text('JUNFEATURE') ->task('articles.unfeatured') ->listCheck(true); - } - if ($canDo->get('core.execute.transition')) - { $childBar->archive('articles.archive')->listCheck(true); - } - if ($canDo->get('core.edit.state')) - { $childBar->checkin('articles.checkin')->listCheck(true); - } - if ($canDo->get('core.execute.transition')) - { $childBar->trash('articles.trash')->listCheck(true); } } diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index a2c3b351f64fd..dea3d07401275 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -12,7 +12,6 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; use Joomla\CMS\Component\ComponentHelper; -use Joomla\Utilities\ArrayHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Associations; @@ -23,6 +22,7 @@ use Joomla\CMS\Session\Session; use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Administrator\Helper\ContentHelper; +use Joomla\Utilities\ArrayHelper; HTMLHelper::_('behavior.multiselect'); diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 5cbca6fb03065..4a7a0537fb36c 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -11,6 +11,7 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Multilanguage; @@ -20,6 +21,7 @@ use Joomla\CMS\Session\Session; use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Administrator\Helper\ContentHelper; +use Joomla\Utilities\ArrayHelper; HTMLHelper::_('behavior.multiselect'); @@ -49,6 +51,10 @@ HTMLHelper::_('draggablelist.draggable'); } +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled', 1); + +if ($workflow_enabled) : + $js = <<document->addScriptDeclaration($js); -HTMLHelper::_('script', 'com_content/admin-articles-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); +HTMLHelper::_('script', 'com_workflow/admin-items-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); + +endif; ?> @@ -84,7 +92,7 @@
- +
@@ -152,39 +160,12 @@ $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $publish = 0; - $unpublish = 0; - $archive = 0; - $trash = 0; + $transition_ids = ArrayHelper::getColumn($transitions, 'value'); + $transition_ids = ArrayHelper::toInteger($transition_ids); - /* - * @TODO Move to plugin - foreach ($transitions as $transition) : - switch ($transition['stage_condition']) : - case ContentComponent::CONDITION_PUBLISHED: - ++$publish; - break; - case ContentComponent::CONDITION_UNPUBLISHED: - ++$unpublish; - break; - case ContentComponent::CONDITION_ARCHIVED: - ++$archive; - break; - case ContentComponent::CONDITION_TRASHED: - ++$trash; - break; - endswitch; - endforeach; - - */ ?> diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 86880b10e7530..59801c98b1e50 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -76,14 +76,13 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (54, 16, 54, 55, 2, 'com_menus.menu.1', 'Main Menu', '{}'), (55, 18, 92, 93, 2, 'com_modules.module.87', 'Sample Data', '{}'), (56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_DEFAULT_WORKFLOW', '{}'), -(57, 56, 21, 22, 3, 'com_content.state.1', 'Unpublished', '{}'), -(58, 56, 23, 24, 3, 'com_content.state.2', 'Published', '{}'), -(59, 56, 25, 26, 3, 'com_content.state.3', 'Trashed', '{}'), -(60, 56, 27, 28, 3, 'com_content.state.4', 'Archived', '{}'), -(61, 56, 29, 30, 3, 'com_content.transition.1', 'Publish', '{}'), -(62, 56, 31, 32, 3, 'com_content.transition.2', 'Unpublish', '{}'), -(63, 56, 33, 34, 3, 'com_content.transition.3', 'Archive', '{}'), -(64, 56, 35, 36, 3, 'com_content.transition.4', 'Trash', '{}'), +(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_DEFAULT', '{}'), +(58, 56, 23, 24, 3, 'com_content.transition.1', 'Publish', '{}'), +(59, 56, 25, 26, 3, 'com_content.transition.2', 'Unpublish', '{}'), +(60, 56, 27, 28, 3, 'com_content.transition.3', 'Archive', '{}'), +(61, 56, 29, 30, 3, 'com_content.transition.4', 'Trash', '{}'), +(62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), +(63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), (65, 1, 129, 130, 1, 'com_privacy', 'com_privacy', '{}'), (66, 1, 131, 132, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), @@ -1135,10 +1134,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 57, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), -(2, 58, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), -(3, 59, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), -(4, 60, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); -- -------------------------------------------------------- @@ -1173,7 +1169,9 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( -- INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`, `checked_out_time`, `checked_out`) VALUES -(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), -(2, 62, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), -(3, 63, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), -(4, 64, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); +(1, 58, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 59, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}', NULL, 0), +(3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), +(4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), +(5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 3655d76239a2b..c80fb2954f2e5 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -82,14 +82,13 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (54, 16, 54, 55, 2, 'com_menus.menu.1', 'Main Menu', '{}'), (55, 18, 92, 93, 2, 'com_modules.module.87', 'Sample Data', '{}'), (56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_DEFAULT_WORKFLOW', '{}'), -(57, 56, 21, 22, 3, 'com_content.state.1', 'Unpublished', '{}'), -(58, 56, 23, 24, 3, 'com_content.state.2', 'Published', '{}'), -(59, 56, 25, 26, 3, 'com_content.state.3', 'Trashed', '{}'), -(60, 56, 27, 28, 3, 'com_content.state.4', 'Archived', '{}'), -(61, 56, 29, 30, 3, 'com_content.transition.1', 'Publish', '{}'), -(62, 56, 31, 32, 3, 'com_content.transition.2', 'Unpublish', '{}'), -(63, 56, 33, 34, 3, 'com_content.transition.3', 'Archive', '{}'), -(64, 56, 35, 36, 3, 'com_content.transition.4', 'Trash', '{}'), +(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_DEFAULT', '{}'), +(58, 56, 23, 24, 3, 'com_content.transition.1', 'Publish', '{}'), +(59, 56, 25, 26, 3, 'com_content.transition.2', 'Unpublish', '{}'), +(60, 56, 27, 28, 3, 'com_content.transition.3', 'Archive', '{}'), +(61, 56, 29, 30, 3, 'com_content.transition.4', 'Trash', '{}'), +(62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), +(63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), (65, 1, 129, 130, 1, 'com_privacy', 'com_privacy', '{}'), (66, 1, 131, 132, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), @@ -1143,12 +1142,9 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES -(1, 57, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), -(2, 58, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), -(3, 59, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), -(4, 60, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); +(1, 57, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); -SELECT setval('#__workflow_stages_id_seq', 5, false); +SELECT setval('#__workflow_stages_id_seq', 2, false); -- -- Table structure for table `#__workflow_transitions` @@ -1177,9 +1173,11 @@ CREATE INDEX "#__workflow_transitions_idx_workflow_id" ON "#__workflow_transitio CREATE INDEX "#__workflow_transitions_idx_checked_out" ON "#__workflow_transitions" ("checked_out"); INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options", "checked_out_time", "checked_out") VALUES -(1, 61, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), -(2, 62, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), -(3, 63, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), -(4, 64, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); - -SELECT setval('#__workflow_transitions_id_seq', 5, false); +(1, 58, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), +(2, 59, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}', NULL, 0), +(3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), +(4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), +(5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); + +SELECT setval('#__workflow_transitions_id_seq', 7, false); diff --git a/libraries/src/Form/Field/TransitionField.php b/libraries/src/Form/Field/TransitionField.php index 72a7442d4031c..16fd53cf2831e 100644 --- a/libraries/src/Form/Field/TransitionField.php +++ b/libraries/src/Form/Field/TransitionField.php @@ -125,19 +125,20 @@ protected function getOptions() ->where( [ $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), - $db->quoteName('t.to_stage_id') . ' != :stage1', $db->quoteName('s.workflow_id') . ' = ' . $db->quoteName('s2.workflow_id'), - $db->quoteName('s2.id') . ' = :stage2', + $db->quoteName('s.workflow_id') . ' = ' . $db->quoteName('t.workflow_id'), + $db->quoteName('s2.id') . ' = :stage1', $db->quoteName('t.published') . ' = 1', $db->quoteName('s.published') . ' = 1', ] ) ->bind(':stage1', $workflowStage, ParameterType::INTEGER) - ->bind(':stage2', $workflowStage, ParameterType::INTEGER) ->order($db->quoteName('t.ordering')); $items = $db->setQuery($query)->loadObjectList(); + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + if (\count($items)) { $user = Factory::getUser(); @@ -152,8 +153,6 @@ function ($item) use ($user, $extension) // Sort by transition name $items = ArrayHelper::sortObjects($items, 'value', 1, true, true); - - Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); } // Get workflow stage title From cd627e899427085f3d5d6fc3d93a018d5a728433 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 10 May 2020 05:36:23 +0200 Subject: [PATCH 41/90] Rename publishing action field --- .../publishing/forms/{workflow_publishing.xml => action.xml} | 0 plugins/workflow/publishing/publishing.php | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) rename plugins/workflow/publishing/forms/{workflow_publishing.xml => action.xml} (100%) diff --git a/plugins/workflow/publishing/forms/workflow_publishing.xml b/plugins/workflow/publishing/forms/action.xml similarity index 100% rename from plugins/workflow/publishing/forms/workflow_publishing.xml rename to plugins/workflow/publishing/forms/action.xml diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 263b007a8b2bc..202738da39f01 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -103,9 +103,7 @@ protected function enhanceTransitionForm(Form $form, $data) return true; } - Form::addFormPath(__DIR__ . '/forms'); - - $form->loadFile('workflow_publishing'); + $form->loadFile(__DIR__ . '/forms/action.xml'); if ($workflow_id) { From 43530291ab733464908e50d24d42767e00b51a3d Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 10 May 2020 05:59:42 +0200 Subject: [PATCH 42/90] Fix disabled options in transition form --- .../com_workflow/src/Model/TransitionModel.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index 2681872189949..940c678ce15d8 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -257,6 +257,15 @@ public function getForm($data = array(), $loadData = true) $disableFields[] = 'title'; $disableFields[] = 'from_stage_id'; $disableFields[] = 'to_stage_id'; + + $fields = $form->getGroup('options'); + + foreach ($fields as $field) + { + $form->setFieldAttribute($field->fieldname, 'disabled', 'true', 'options'); + $form->setFieldAttribute($field->fieldname, 'required', 'false', 'options'); + $form->setFieldAttribute($field->fieldname, 'filter', 'unset', 'options'); + } } if (!$this->canEditState((object) $data) || $workflow->core) @@ -271,15 +280,6 @@ public function getForm($data = array(), $loadData = true) $form->setFieldAttribute($field, 'filter', 'unset'); } - $fields = $form->getGroup('options'); - - foreach ($fields as $field) - { - $form->setFieldAttribute($field->fieldname, 'disabled', 'true', 'options'); - $form->setFieldAttribute($field->fieldname, 'required', 'false', 'options'); - $form->setFieldAttribute($field->fieldname, 'filter', 'unset', 'options'); - } - $where = $this->getDbo()->quoteName('workflow_id') . ' = ' . (int) $data['workflow_id'] . ' AND ' . $this->getDbo()->quoteName('published') . ' = 1'; $form->setFieldAttribute('from_stage_id', 'sql_where', $where); From c0d12ce4ec5d2549149965505b7e8d3464f7e745 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Sun, 10 May 2020 21:49:47 +0200 Subject: [PATCH 43/90] Add workflow plugin trait (#94) --- .../src/Workflow/WorkflowPluginTrait.php | 77 +++++++++++++++++++ plugins/workflow/featuring/featuring.php | 53 +++++-------- plugins/workflow/publishing/publishing.php | 67 ++++++++-------- 3 files changed, 130 insertions(+), 67 deletions(-) create mode 100644 libraries/src/Workflow/WorkflowPluginTrait.php diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php new file mode 100644 index 0000000000000..bbab76c790a00 --- /dev/null +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -0,0 +1,77 @@ +getWorkflow((int) ($data->workflow_id ?? $form->getValue('workflow_id'))); + + if (empty($workflow->id) || !$this->isSupported($workflow->extension)) + { + return false; + } + + if (file_exists(__DIR__ . '/forms/action.xml')) + { + $form->loadFile(__DIR__ . '/forms/action.xml'); + } + + return $workflow; + } + + protected function getWorkflow(int $workflow_id = null) { + + $workflow_id = $workflow_id ?? $this->app->input->getInt('workflow_id'); + + if (is_array($workflow_id)) { + return false; + } + + return $this->app->bootComponent('com_workflow') + ->getMVCFactory() + ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) + ->getItem($workflow_id); + } + + + /** + * Check if the current plugin should execute workflow related activities + * + * @param string $context + * @return boolean + * + * @since 4.0.0 + */ + protected function isSupported($context) + { + return false; + } +} diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php index 84d8ae9c55795..62551a3f027c8 100644 --- a/plugins/workflow/featuring/featuring.php +++ b/plugins/workflow/featuring/featuring.php @@ -17,6 +17,7 @@ use Joomla\CMS\MVC\View\ViewInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Table\TableInterface; +use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\CMS\Workflow\WorkflowServiceInterface; use Joomla\String\Inflector; @@ -27,6 +28,8 @@ */ class PlgWorkflowFeaturing extends CMSPlugin { + use WorkflowPluginTrait; + /** * Load the language file on instantiation. * @@ -51,11 +54,12 @@ class PlgWorkflowFeaturing extends CMSPlugin */ protected $supportFunctionality = 'core.featured'; + /** * The form event. * * @param Form $form The form - * @param stdClass $data The data + * @param \stdClass $data The data * * @return boolean * @@ -66,44 +70,14 @@ public function onContentPrepareForm(Form $form, $data) $context = $form->getName(); // Extend the transition form - if ($context == 'com_workflow.transition') - { - return $this->enhanceTransitionForm($form, $data); - } - - return $this->enhanceItemForm($form, $data); - } - - /** - * Add different parameter options to the transition view, we need when executing the transition - * - * @param Form $form The form - * @param stdClass $data The data - * - * @return boolean - * - * @since __DEPLOY_VERSION__ - */ - protected function enhanceTransitionForm(Form $form, $data) - { - $model = $this->app->bootComponent('com_workflow') - ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); - - $workflow_id = (int) ($data->workflow_id ?? $form->getValue('workflow_id')); - - if (empty($workflow_id)) + if ($context === 'com_workflow.transition') { - $workflow_id = (int) $this->app->input->getInt('workflow_id'); - } - - $workflow = $model->getItem($workflow_id); + $this->enhanceWorkflowTransitionForm($form, $data); - if (!$this->isSupported($workflow->extension)) - { return true; } - $form->loadFile(__DIR__ . '/forms/action.xml'); + $this->enhanceItemForm($form, $data); return true; } @@ -184,6 +158,8 @@ protected function enhanceItemForm(Form $form, $data) * @param string $context * @param ViewInterface $view * @param string $result + * + * @since 4.0.0 */ public function onAfterDisplay(string $context, ViewInterface $view, string $result) { @@ -244,6 +220,8 @@ public function onAfterDisplay(string $context, ViewInterface $view, string $res * @param object $transition The value to change to * * @return boolean + * + * @since 4.0.0 */ public function onWorkflowBeforeTransition($context, $pks, $transition) { @@ -287,6 +265,8 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) * @param object $transition The value to change to * * @return boolean + * + * @since 4.0.0 */ public function onWorkflowAfterTransition($context, $pks, $transition) { @@ -331,7 +311,10 @@ public function onWorkflowAfterTransition($context, $pks, $transition) * @param string $context The context * @param array $pks IDs of the items * @param int $value The value to change to + * * @return boolean + * + * @since 4.0.0 */ public function onContentBeforeChangeFeatured(string $context, array $pks, int $value): bool { @@ -393,6 +376,8 @@ public function onContentBeforeSave($context, TableInterface $table, $isNew, $da * * @param string $context * @return boolean + * + * @since 4.0.0 */ protected function isSupported($context) { diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 202738da39f01..b31434fc8359e 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -17,6 +17,7 @@ use Joomla\CMS\MVC\View\ViewInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Table\TableInterface; +use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\CMS\Workflow\WorkflowServiceInterface; use Joomla\String\Inflector; @@ -27,6 +28,8 @@ */ class PlgWorkflowPublishing extends CMSPlugin { + use WorkflowPluginTrait; + /** * Load the language file on instantiation. * @@ -49,13 +52,13 @@ class PlgWorkflowPublishing extends CMSPlugin * @var string * @since __DEPLOY_VERSION__ */ - protected $supportname = 'core.state'; + protected $supportFunctionality = 'core.state'; /** * The form event. * * @param Form $form The form - * @param stdClass $data The data + * @param \stdClass $data The data * * @return boolean * @@ -66,12 +69,16 @@ public function onContentPrepareForm(Form $form, $data) $context = $form->getName(); // Extend the transition form - if ($context == 'com_workflow.transition') + if ($context === 'com_workflow.transition') { - return $this->enhanceTransitionForm($form, $data); + $this->enhanceTransitionForm($form, $data); + + return true; } - return $this->enhanceItemForm($form, $data); + $this->enhanceItemForm($form, $data); + + return true; } /** @@ -86,33 +93,14 @@ public function onContentPrepareForm(Form $form, $data) */ protected function enhanceTransitionForm(Form $form, $data) { - $model = $this->app->bootComponent('com_workflow') - ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); + $workflow = $this->enhanceWorkflowTransitionForm($form, $data); - $workflow_id = !empty($data->workflow_id) ? (int) $data->workflow_id : (int) $form->getValue('workflow_id'); - - if (empty($workflow_id)) - { - $workflow_id = $this->app->input->getInt('workflow_id'); - } - - $workflow = $model->getItem($workflow_id); - - if (!$this->isSupported($workflow->extension)) + if (!$workflow) { return true; } - $form->loadFile(__DIR__ . '/forms/action.xml'); - - if ($workflow_id) - { - $form->setFieldAttribute('publishing', 'extension', $workflow->extension, 'options'); - } - else - { - $form->setFieldAttribute('publishing', 'disabled', 'true', 'options'); - } + $form->setFieldAttribute('publishing', 'extension', $workflow->extension, 'options'); return true; } @@ -191,11 +179,13 @@ protected function enhanceItemForm(Form $form, $data) /** * Manipulate the generic list view * - * @param type $context - * @param type $view - * @param type $result + * @param string $context + * @param ViewInterface $view + * @param string $result + * + * @since 4.0.0 */ - public function onAfterDisplay(string $context, ViewInterface $view, $result) + public function onAfterDisplay(string $context, ViewInterface $view, string $result) { $parts = explode('.', $context); @@ -242,6 +232,8 @@ public function onAfterDisplay(string $context, ViewInterface $view, $result) "; $app->getDocument()->addScriptDeclaration($js); + + return true; } /** @@ -252,6 +244,8 @@ public function onAfterDisplay(string $context, ViewInterface $view, $result) * @param object $transition The value to change to * * @return boolean + * + * @since 4.0.0 */ public function onWorkflowBeforeTransition($context, $pks, $transition) { @@ -295,6 +289,8 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) * @param object $transition The value to change to * * @return boolean + * + * @since 4.0.0 */ public function onWorkflowAfterTransition($context, $pks, $transition) { @@ -339,7 +335,10 @@ public function onWorkflowAfterTransition($context, $pks, $transition) * @param string $context The context * @param array $pks IDs of the items * @param int $value The value to change to + * * @return boolean + * + * @since 4.0.0 */ public function onContentBeforeChangeState($context, $pks, $value) { @@ -399,8 +398,10 @@ public function onContentBeforeSave($context, TableInterface $table, $isNew, $da /** * Check if the current plugin should execute workflow related activities * - * @param type $context + * @param string $context * @return boolean + * + * @since 4.0.0 */ protected function isSupported($context) { @@ -416,7 +417,7 @@ protected function isSupported($context) if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context) - || !$component->supportFunctionality($this->supportname, $context)) + || !$component->supportFunctionality($this->supportFunctionality, $context)) { return false; } From 4ec424ee4f127f74d72b24900b565db406ecea89 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 10 May 2020 22:21:43 +0200 Subject: [PATCH 44/90] Load correct XML path for actions --- libraries/src/Workflow/WorkflowPluginTrait.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index bbab76c790a00..2d81c975f9e21 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -11,7 +11,7 @@ \defined('JPATH_PLATFORM') or die; use Joomla\CMS\Form\Form; -use function method_exists; +use ReflectionClass; /** * Trait for component workflow plugins. @@ -39,9 +39,12 @@ protected function enhanceWorkflowTransitionForm(Form $form, $data) { return false; } - if (file_exists(__DIR__ . '/forms/action.xml')) + // Load XML file from "parent" plugin + $path = dirname((new ReflectionClass(static::class))->getFileName()); + + if (file_exists($path . '/forms/action.xml')) { - $form->loadFile(__DIR__ . '/forms/action.xml'); + $form->loadFile($path . '/forms/action.xml'); } return $workflow; From 4b933ae41e662bb666ebc2dea39ebdec9357f5d1 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 10 May 2020 22:37:15 +0200 Subject: [PATCH 45/90] Add Publish & Feature as Transition --- .../com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql | 3 ++- .../com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql | 3 ++- installation/sql/mysql/base.sql | 4 +++- installation/sql/postgresql/base.sql | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 91e4013815e6b..6b3baa2fe9b97 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -118,7 +118,8 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` (3, 0, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), (4, 0, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), (5, 0, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), -(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); +(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0), +(7, 0, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0); -- -- Creating extension entry diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 34533def3ef39..ad60c31034d20 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -114,7 +114,8 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (3, 0, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), (4, 0, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), (5, 0, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), -(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); +(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0), +(7, 0, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0); -- -- Creating extension entry diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 59801c98b1e50..62e378878e39f 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -83,6 +83,7 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (61, 56, 29, 30, 3, 'com_content.transition.4', 'Trash', '{}'), (62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), (63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), +(64, 56, 35, 36, 3, 'com_content.transition.7', 'Publish & Feature', '{}'), (65, 1, 129, 130, 1, 'com_privacy', 'com_privacy', '{}'), (66, 1, 131, 132, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), @@ -1174,4 +1175,5 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` (3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), (4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), -(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0), +(7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0); diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index c80fb2954f2e5..12c37fa0aa985 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -89,6 +89,7 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (61, 56, 29, 30, 3, 'com_content.transition.4', 'Trash', '{}'), (62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), (63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), +(64, 56, 35, 36, 3, 'com_content.transition.7', 'Publish & Feature', '{}'), (65, 1, 129, 130, 1, 'com_privacy', 'com_privacy', '{}'), (66, 1, 131, 132, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), @@ -1178,6 +1179,7 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), (4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), -(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0), +(7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0); SELECT setval('#__workflow_transitions_id_seq', 7, false); From 03ab576cc390d5e8c028d1020fcae45624a43f08 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sun, 10 May 2020 23:09:48 +0200 Subject: [PATCH 46/90] Fix workflow ID loading for new transitions --- libraries/src/Workflow/WorkflowPluginTrait.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index 2d81c975f9e21..b74f9fef5c686 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -30,9 +30,11 @@ trait WorkflowPluginTrait { * * @since __DEPLOY_VERSION__ */ - protected function enhanceWorkflowTransitionForm(Form $form, $data) { + protected function enhanceWorkflowTransitionForm(Form $form, $data) + { + $workflow_id = (int) ($data->workflow_id ?? $form->getValue('workflow_id')); - $workflow = $this->getWorkflow((int) ($data->workflow_id ?? $form->getValue('workflow_id'))); + $workflow = $this->getWorkflow($workflow_id); if (empty($workflow->id) || !$this->isSupported($workflow->extension)) { @@ -52,7 +54,7 @@ protected function enhanceWorkflowTransitionForm(Form $form, $data) { protected function getWorkflow(int $workflow_id = null) { - $workflow_id = $workflow_id ?? $this->app->input->getInt('workflow_id'); + $workflow_id = !empty($workflow_id) ? $workflow_id : $this->app->input->getInt('workflow_id'); if (is_array($workflow_id)) { return false; From 87917110427a3729c681401bbf3b63efad6e6d23 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Mon, 11 May 2020 09:34:56 +0200 Subject: [PATCH 47/90] Use old pseudo-nulldates in 4.0.0-2018-05-15.sql (#96) --- .../com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql | 6 +++--- .../com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 6b3baa2fe9b97..9c866f0a2e1fb 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -126,9 +126,9 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` -- INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); -- -- Creating Associations for existing content diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index ad60c31034d20..1b9c0c4da36c4 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -123,8 +123,8 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES (0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); -- -- Creating Associations for existing content From f74e1c136e7b8a14684c7f52b2c00b1dc7d18af8 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Tue, 12 May 2020 03:01:02 +0200 Subject: [PATCH 48/90] Fixing codestyle (#97) * Fixing system tests and codestyle * Fixing Postgres * Adding exclusion for canDelete for API calls * Codestyle --- .../src/Model/TransitionModel.php | 3 +- .../src/Workflow/WorkflowPluginTrait.php | 33 ++++++++++++------- plugins/workflow/featuring/featuring.php | 7 +++- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index 940c678ce15d8..d6a5d4bf1d018 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -280,7 +280,8 @@ public function getForm($data = array(), $loadData = true) $form->setFieldAttribute($field, 'filter', 'unset'); } - $where = $this->getDbo()->quoteName('workflow_id') . ' = ' . (int) $data['workflow_id'] . ' AND ' . $this->getDbo()->quoteName('published') . ' = 1'; + $where = $this->getDbo()->quoteName('workflow_id') . ' = ' . (int) $data['workflow_id']; + $where .= ' AND ' . $this->getDbo()->quoteName('published') . ' = 1'; $form->setFieldAttribute('from_stage_id', 'sql_where', $where); $form->setFieldAttribute('to_stage_id', 'sql_where', $where); diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index b74f9fef5c686..1f763c1524c4f 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -11,6 +11,7 @@ \defined('JPATH_PLATFORM') or die; use Joomla\CMS\Form\Form; +use Joomla\CMS\Object\CMSObject; use ReflectionClass; /** @@ -18,12 +19,12 @@ * * @since 4.0.0 */ -trait WorkflowPluginTrait { - +trait WorkflowPluginTrait +{ /** * Add different parameter options to the transition view, we need when executing the transition * - * @param Form $form The form + * @param Form $form The form * @param \stdClass $data The data * * @return boolean @@ -52,25 +53,35 @@ protected function enhanceWorkflowTransitionForm(Form $form, $data) return $workflow; } - protected function getWorkflow(int $workflow_id = null) { - + /** + * Get the workflow for a given ID + * + * @param int|null $workflow_id ID of the workflow + * + * @return CMSObject|boolean Object on success, false on failure. + * + * @since __DEPLOY_VERSION__ + */ + protected function getWorkflow(int $workflow_id = null) + { $workflow_id = !empty($workflow_id) ? $workflow_id : $this->app->input->getInt('workflow_id'); - if (is_array($workflow_id)) { + if (is_array($workflow_id)) + { return false; } return $this->app->bootComponent('com_workflow') - ->getMVCFactory() - ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) - ->getItem($workflow_id); + ->getMVCFactory() + ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) + ->getItem($workflow_id); } - /** * Check if the current plugin should execute workflow related activities * - * @param string $context + * @param string $context Context to check + * * @return boolean * * @since 4.0.0 diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php index 62551a3f027c8..69cbb0b3856ee 100644 --- a/plugins/workflow/featuring/featuring.php +++ b/plugins/workflow/featuring/featuring.php @@ -147,7 +147,12 @@ protected function enhanceItemForm(Form $form, $data) $form->setFieldAttribute($fieldname, 'type', 'spacer'); - $form->setFieldAttribute($fieldname, 'label', Text::sprintf('PLG_WORKFLOW_FEATURING_FEATURED', '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . '')); + $label = '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . ''; + $form->setFieldAttribute( + $fieldname, + 'label', + Text::sprintf('PLG_WORKFLOW_FEATURING_FEATURED', $label) + ); return true; } From 667e90af58dffd79891284cdacb66ca0da8c1037 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 19 May 2020 01:38:41 +0200 Subject: [PATCH 49/90] Fix broken transition selection for articles view --- .../components/com_content/src/Model/ArticlesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 67f7c149118ae..9b65a05b68349 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -634,7 +634,7 @@ public function getTransitions() $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; } - $query->where('(' . implode(') OR (', $where) . ')'); + $query->where('((' . implode(') OR (', $where) . '))'); $transitions = $db->setQuery($query)->loadAssocList(); From 3f292243a99e86bb5ca660378ae5821b5cdd75b1 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Tue, 19 May 2020 02:00:42 +0200 Subject: [PATCH 50/90] Remove core workflow protection (#98) --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 5 +- .../updates/postgresql/4.0.0-2018-05-15.sql | 5 +- .../src/Controller/StageController.php | 28 +------- .../src/Controller/TransitionController.php | 13 +--- .../src/Controller/WorkflowController.php | 5 -- .../com_workflow/src/Model/StageModel.php | 11 +--- .../src/Model/TransitionModel.php | 39 +---------- .../com_workflow/src/Model/WorkflowModel.php | 7 +- .../com_workflow/src/Model/WorkflowsModel.php | 1 - .../com_workflow/src/View/Stages/HtmlView.php | 66 +++++++++---------- .../src/View/Transition/HtmlView.php | 4 +- .../src/View/Transitions/HtmlView.php | 64 +++++++++--------- .../src/View/Workflow/HtmlView.php | 2 +- .../com_workflow/tmpl/stages/default.php | 6 +- .../com_workflow/tmpl/transitions/default.php | 4 +- .../com_workflow/tmpl/workflows/default.php | 5 +- installation/sql/mysql/base.sql | 5 +- installation/sql/postgresql/base.sql | 5 +- 18 files changed, 86 insertions(+), 189 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index 9c866f0a2e1fb..c559a7478f43d 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -10,7 +10,6 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( `description` text NOT NULL, `extension` varchar(50) NOT NULL, `default` tinyint(1) NOT NULL DEFAULT 0, - `core` tinyint(1) NOT NULL DEFAULT 0, `ordering` int(11) NOT NULL DEFAULT 0, `created` datetime NOT NULL, `created_by` int(10) NOT NULL DEFAULT 0, @@ -34,8 +33,8 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- Dumping data for table `#__workflows` -- -INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `core`,`ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); +INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES +(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- -- Table structure for table `#__workflow_associations` diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 1b9c0c4da36c4..86d842eb022e5 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -10,7 +10,6 @@ CREATE TABLE IF NOT EXISTS "#__workflows" ( "description" text NOT NULL, "extension" varchar(50) NOT NULL, "default" smallint NOT NULL DEFAULT 0, - "core" smallint NOT NULL DEFAULT 0, "ordering" bigint NOT NULL DEFAULT 0, "created" timestamp without time zone NOT NULL, "created_by" bigint DEFAULT 0 NOT NULL, @@ -31,8 +30,8 @@ CREATE INDEX "#__workflows_idx_modified" ON "#__workflows" ("modified"); CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); -INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "core", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); +INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES +(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); -- -- Table structure for table "#__workflow_associations" diff --git a/administrator/components/com_workflow/src/Controller/StageController.php b/administrator/components/com_workflow/src/Controller/StageController.php index 41ef5233843fa..69e7625fec329 100644 --- a/administrator/components/com_workflow/src/Controller/StageController.php +++ b/administrator/components/com_workflow/src/Controller/StageController.php @@ -106,18 +106,7 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu */ protected function allowAdd($data = array()) { - $user = Factory::getUser(); - - $model = $this->getModel('Workflow'); - - $workflow = $model->getItem($this->workflowId); - - if ($workflow->core) - { - return false; - } - - return $user->authorise('core.create', $this->extension); + return $this->app->getIdentity()->authorise('core.create', $this->extension); } /** @@ -133,20 +122,7 @@ protected function allowAdd($data = array()) protected function allowEdit($data = array(), $key = 'id') { $recordId = isset($data[$key]) ? (int) $data[$key] : 0; - $user = Factory::getUser(); - - $model = $this->getModel(); - - $item = $model->getItem($recordId); - - $model = $this->getModel('Workflow'); - - $workflow = $model->getItem($item->workflow_id); - - if ($workflow->core) - { - return false; - } + $user = $this->app->getIdentity(); // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.stage.' . $recordId)) diff --git a/administrator/components/com_workflow/src/Controller/TransitionController.php b/administrator/components/com_workflow/src/Controller/TransitionController.php index 96660f10f3bb6..215bb5e2dde69 100644 --- a/administrator/components/com_workflow/src/Controller/TransitionController.php +++ b/administrator/components/com_workflow/src/Controller/TransitionController.php @@ -105,18 +105,7 @@ public function __construct($config = array(), MVCFactoryInterface $factory = nu */ protected function allowAdd($data = array()) { - $user = $this->app->getIdentity(); - - $model = $this->getModel('Workflow'); - - $workflow = $model->getItem($this->workflowId); - - if ($workflow->core) - { - return false; - } - - return $user->authorise('core.create', $this->extension); + return $this->app->getIdentity()->authorise('core.create', $this->extension); } /** diff --git a/administrator/components/com_workflow/src/Controller/WorkflowController.php b/administrator/components/com_workflow/src/Controller/WorkflowController.php index 4c0d78a359338..25e8b2677d958 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowController.php @@ -107,11 +107,6 @@ protected function allowEdit($data = array(), $key = 'id') $record = $this->getModel()->getItem($recordId); - if (!empty($record->id) && $record->core) - { - return false; - } - // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.workflow.' . $recordId)) { diff --git a/administrator/components/com_workflow/src/Model/StageModel.php b/administrator/components/com_workflow/src/Model/StageModel.php index c2227fa184878..f9b802861f50c 100644 --- a/administrator/components/com_workflow/src/Model/StageModel.php +++ b/administrator/components/com_workflow/src/Model/StageModel.php @@ -121,7 +121,7 @@ protected function canDelete($record) $table->load($record->workflow_id); - if (empty($record->id) || $record->published != -2 || $table->core) + if (empty($record->id) || $record->published != -2) { return false; } @@ -165,15 +165,6 @@ protected function canEditState($record) $record->workflow_id = $workflowID; } - $table = $this->getTable('Workflow', 'Administrator'); - - $table->load($record->workflow_id); - - if ($table->core) - { - return false; - } - // Check for existing workflow. if (!empty($record->id)) { diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index d6a5d4bf1d018..a6a48afcab21e 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -56,11 +56,7 @@ public function populateState() */ protected function canDelete($record) { - $table = $this->getTable('Workflow', 'Administrator'); - - $table->load($record->workflow_id); - - if (empty($record->id) || $record->published != -2 || $table->core) + if (empty($record->id) || $record->published != -2) { return false; } @@ -93,15 +89,6 @@ protected function canEditState($record) $record->workflow_id = $workflowID; } - $table = $this->getTable('Workflow', 'Administrator'); - - $table->load($record->workflow_id); - - if ($table->core) - { - return false; - } - // Check for existing workflow. if (!empty($record->id)) { @@ -245,30 +232,10 @@ public function getForm($data = array(), $loadData = true) $data['workflow_id'] = (int) $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); } - $workflow = $this->getTable('Workflow'); - - $workflow->load($data['workflow_id']); - + // Disable state when no permission to change $disableFields = []; - // Disable all fields when we edit core, but not the permissions - if ($workflow->core) - { - $disableFields[] = 'title'; - $disableFields[] = 'from_stage_id'; - $disableFields[] = 'to_stage_id'; - - $fields = $form->getGroup('options'); - - foreach ($fields as $field) - { - $form->setFieldAttribute($field->fieldname, 'disabled', 'true', 'options'); - $form->setFieldAttribute($field->fieldname, 'required', 'false', 'options'); - $form->setFieldAttribute($field->fieldname, 'filter', 'unset', 'options'); - } - } - - if (!$this->canEditState((object) $data) || $workflow->core) + if (!$this->canEditState((object) $data)) { $disableFields[] = 'published'; } diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index fd588752dd27d..7c472af3ac84d 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -309,7 +309,7 @@ public function setDefault($pk, $value = 1) */ protected function canDelete($record) { - if (empty($record->id) || $record->published != -2 || $record->core) + if (empty($record->id) || $record->published != -2) { return false; } @@ -330,11 +330,6 @@ protected function canEditState($record) { $user = Factory::getUser(); - if (!empty($record->core)) - { - return false; - } - // Check for existing workflow. if (!empty($record->id)) { diff --git a/administrator/components/com_workflow/src/Model/WorkflowsModel.php b/administrator/components/com_workflow/src/Model/WorkflowsModel.php index 210ce34a927f2..b273b96cbd7e0 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowsModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowsModel.php @@ -197,7 +197,6 @@ public function getListQuery() 'w.checked_out_time', 'w.ordering', 'w.default', - 'w.core', 'w.created_by', 'w.description', 'u.name' diff --git a/administrator/components/com_workflow/src/View/Stages/HtmlView.php b/administrator/components/com_workflow/src/View/Stages/HtmlView.php index f773f3eddb3fd..9813e9f69207e 100644 --- a/administrator/components/com_workflow/src/View/Stages/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Stages/HtmlView.php @@ -164,11 +164,12 @@ protected function addToolbar() { $canDo = ContentHelper::getActions($this->extension, 'workflow', $this->workflowID); + $user = Factory::getUser(); + $toolbar = Toolbar::getInstance('toolbar'); ToolbarHelper::title(Text::sprintf('COM_WORKFLOW_STAGES_LIST', Text::_($this->state->get('active_workflow', ''))), 'address contact'); - $isCore = $this->workflow->core; $arrow = Factory::getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'; ToolbarHelper::link( @@ -177,48 +178,45 @@ protected function addToolbar() $arrow ); - if (!$isCore) + if ($canDo->get('core.create')) { - if ($canDo->get('core.create')) - { - $toolbar->addNew('stage.add'); - } + $toolbar->addNew('stage.add'); + } + + if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) + { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('fas fa-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); - if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) + $childBar = $dropdown->getChildToolbar(); + + $childBar->publish('stages.publish', 'JTOOLBAR_ENABLE')->listCheck(true); + $childBar->unpublish('stages.unpublish', 'JTOOLBAR_DISABLE')->listCheck(true); + $childBar->makeDefault('stages.setDefault', 'COM_WORKFLOW_TOOLBAR_DEFAULT'); + + if ($canDo->get('core.admin')) { - $dropdown = $toolbar->dropdownButton('status-group') - ->text('JTOOLBAR_CHANGE_STATUS') - ->toggleSplit(false) - ->icon('fas fa-ellipsis-h') - ->buttonClass('btn btn-action') - ->listCheck(true); - - $childBar = $dropdown->getChildToolbar(); - - $childBar->publish('stages.publish', 'JTOOLBAR_ENABLE')->listCheck(true); - $childBar->unpublish('stages.unpublish', 'JTOOLBAR_DISABLE')->listCheck(true); - $childBar->makeDefault('stages.setDefault', 'COM_WORKFLOW_TOOLBAR_DEFAULT'); - - if ($canDo->get('core.admin')) - { - $childBar->checkin('stages.checkin')->listCheck(true); - } - - if ($this->state->get('filter.published') !== '-2') - { - $childBar->trash('stages.trash'); - } + $childBar->checkin('stages.checkin')->listCheck(true); } - if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete') && !$isCore) + if ($this->state->get('filter.published') !== '-2') { - $toolbar->delete('stages.delete') - ->text('JTOOLBAR_EMPTY_TRASH') - ->message('JGLOBAL_CONFIRM_DELETE') - ->listCheck(true); + $childBar->trash('stages.trash'); } } + if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) + { + $toolbar->delete('stages.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + $toolbar->help('JHELP_WORKFLOW_STAGES_LIST'); } } diff --git a/administrator/components/com_workflow/src/View/Transition/HtmlView.php b/administrator/components/com_workflow/src/View/Transition/HtmlView.php index fb707b1c8528a..1614c167fffab 100644 --- a/administrator/components/com_workflow/src/View/Transition/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Transition/HtmlView.php @@ -157,8 +157,6 @@ protected function addToolbar() $canCreate = $canDo->get('core.create'); - $workflow = $this->get('Workflow'); - if ($isNew) { // For new records, check the create permission. @@ -184,7 +182,7 @@ protected function addToolbar() $toolbarButtons[] = ['save', 'transition.save']; // We can save this record, but check the create permission to see if we can return to make a new one. - if ($canCreate && !$workflow->core) + if ($canCreate) { $toolbarButtons[] = ['save2new', 'transition.save2new']; $toolbarButtons[] = ['save2copy', 'transition.save2copy']; diff --git a/administrator/components/com_workflow/src/View/Transitions/HtmlView.php b/administrator/components/com_workflow/src/View/Transitions/HtmlView.php index 1eb0bac920736..7fb4db0430e60 100644 --- a/administrator/components/com_workflow/src/View/Transitions/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Transitions/HtmlView.php @@ -157,11 +157,12 @@ protected function addToolbar() { $canDo = ContentHelper::getActions($this->extension, 'workflow', $this->workflowID); + $user = Factory::getUser(); + $toolbar = Toolbar::getInstance('toolbar'); ToolbarHelper::title(Text::sprintf('COM_WORKFLOW_TRANSITIONS_LIST', Text::_($this->state->get('active_workflow'))), 'address contact'); - $isCore = $this->workflow->core; $arrow = Factory::getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'; ToolbarHelper::link( @@ -170,47 +171,44 @@ protected function addToolbar() $arrow ); - if (!$isCore) + if ($canDo->get('core.create')) { - if ($canDo->get('core.create')) - { - $toolbar->addNew('transition.add'); - } + $toolbar->addNew('transition.add'); + } + + if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) + { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('fas fa-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); - if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) + $childBar = $dropdown->getChildToolbar(); + + $childBar->publish('transitions.publish', 'JTOOLBAR_ENABLE'); + $childBar->unpublish('transitions.unpublish', 'JTOOLBAR_DISABLE'); + + if ($canDo->get('core.admin')) { - $dropdown = $toolbar->dropdownButton('status-group') - ->text('JTOOLBAR_CHANGE_STATUS') - ->toggleSplit(false) - ->icon('fas fa-ellipsis-h') - ->buttonClass('btn btn-action') - ->listCheck(true); - - $childBar = $dropdown->getChildToolbar(); - - $childBar->publish('transitions.publish', 'JTOOLBAR_ENABLE'); - $childBar->unpublish('transitions.unpublish', 'JTOOLBAR_DISABLE'); - - if ($canDo->get('core.admin')) - { - $childBar->checkin('transitions.checkin')->listCheck(true); - } - - if ($this->state->get('filter.published') !== '-2') - { - $childBar->trash('transitions.trash'); - } + $childBar->checkin('transitions.checkin')->listCheck(true); } - if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) + if ($this->state->get('filter.published') !== '-2') { - $toolbar->delete('transitions.delete') - ->text('JTOOLBAR_EMPTY_TRASH') - ->message('JGLOBAL_CONFIRM_DELETE') - ->listCheck(true); + $childBar->trash('transitions.trash'); } } + if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) + { + $toolbar->delete('transitions.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + $toolbar->help('JHELP_WORKFLOW_TRANSITIONS_LIST'); } } diff --git a/administrator/components/com_workflow/src/View/Workflow/HtmlView.php b/administrator/components/com_workflow/src/View/Workflow/HtmlView.php index a40ec43df818e..60df1924181f8 100644 --- a/administrator/components/com_workflow/src/View/Workflow/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Workflow/HtmlView.php @@ -150,7 +150,7 @@ protected function addToolbar() // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); - if ($itemEditable && !$this->item->core) + if ($itemEditable) { ToolbarHelper::apply('workflow.apply'); $toolbarButtons = [['save', 'workflow.save']]; diff --git a/administrator/components/com_workflow/tmpl/stages/default.php b/administrator/components/com_workflow/tmpl/stages/default.php index 6b144a4f0096b..be7d0f440a2e7 100644 --- a/administrator/components/com_workflow/tmpl/stages/default.php +++ b/administrator/components/com_workflow/tmpl/stages/default.php @@ -27,8 +27,6 @@ $saveOrder = ($listOrder == 's.ordering'); -$isCore = $this->workflow->core; - if ($saveOrder) { $saveOrderingUrl = 'index.php?option=com_workflow&task=stages.saveOrderAjax&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->extension) . '&' . Session::getFormToken() . '=1'; @@ -113,7 +111,7 @@ + + + @@ -200,48 +206,40 @@ - - + + + + + + @@ -192,6 +198,22 @@ + + + diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index eb50f8920c5a0..3406c69420855 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -654,7 +654,6 @@ JGLOBAL_WARNCOOKIES="Warning! Cookies must be enabled to access the Administrato JGLOBAL_WARNIE="Warning! Internet Explorer should not be used for proper operation of the Administrator Backend." JGLOBAL_WARNJAVASCRIPT="Warning! JavaScript must be enabled for proper operation of the Administrator Backend." JGLOBAL_WIDTH="Width" -JGLOBAL_WORKFLOW_ENABLED_LABEL="Enable Workflows" JGRID_HEADING_ACCESS="Access" JGRID_HEADING_ACCESS_ASC="Access ascending" @@ -999,6 +998,16 @@ JWARNING_DELETE_MUST_SELECT="You must select at least one item to permanently de JWARNING_REMOVE_ROOT_USER="You are logged-in using the emergency Root User setting in configuration.php.
You should remove $root_user from the configuration.php as soon as you have restored control to your site to avoid future security breaches.
Select here to try to do it automatically." JWARNING_REMOVE_ROOT_USER_ADMIN="The emergency Root User setting is enabled for the user(id): %s.
You should remove $root_user from the configuration.php as soon as you have restored control to your site to avoid future security breaches.
Select here to try to do it automatically." +; Workflow +JWORKFLOW_TITLE="Workflow" +JWORKFLOW_ENABLED_LABEL="Enable Workflow" +JWORKFLOW_FUNCTIONALITY_CORE_STATE_LABEL="Enable Workflow state functionality" +JWORKFLOW_FUNCTIONALITY_CORE_FEATURED_LABEL="Enable Workflow featured functionality" +JWORKFLOW_EXTENSION_WHITELIST_LABEL="Extension Whitelist" +JWORKFLOW_EXTENSION_WHITELIST_DESCRIPTION="Activate this plugin only for listed extensions. One extension per line (ex. com_content.article). If used all other extensions are disabled." +JWORKFLOW_EXTENSION_BLACKLIST_LABEL="Extension Blacklist" +JWORKFLOW_EXTENSION_BLACKLIST_DESCRIPTION="Disable this plugin for listed extensions. One extension per line (ex. com_content.article)." + ; Date format DATE_FORMAT_LC="l, d F Y" diff --git a/layouts/joomla/edit/global.php b/layouts/joomla/edit/global.php index f2310e954a3c0..4c83001e8b942 100644 --- a/layouts/joomla/edit/global.php +++ b/layouts/joomla/edit/global.php @@ -33,8 +33,6 @@ array('published', 'state', 'enabled'), array('category', 'catid'), 'featured', - 'featured_up', - 'featured_down', 'sticky', 'access', 'language', diff --git a/layouts/joomla/edit/publishingdata.php b/layouts/joomla/edit/publishingdata.php index a21d03de73276..6dc2304850f14 100644 --- a/layouts/joomla/edit/publishingdata.php +++ b/layouts/joomla/edit/publishingdata.php @@ -17,6 +17,8 @@ $fields = $displayData->get('fields') ?: array( 'publish_up', 'publish_down', + 'featured_up', + 'featured_down', array('created', 'created_time'), array('created_by', 'created_user_id'), 'created_by_alias', diff --git a/libraries/src/Event/View/DisplayEvent.php b/libraries/src/Event/View/DisplayEvent.php new file mode 100644 index 0000000000000..46a6f2c3e4e5f --- /dev/null +++ b/libraries/src/Event/View/DisplayEvent.php @@ -0,0 +1,61 @@ +name} is required but has not been provided or is not of type 'ViewInterface'"); + } + + if (!isset($arguments['extension']) || !is_string($arguments['extension'])) + { + throw new BadMethodCallException("Argument 'extension' of event {$this->name} is required but has not been provided or is not of type 'string'"); + } + + if (strpos($arguments['extension'], '.') === false) + { + throw new BadMethodCallException("Argument 'extension' of event {$this->name} has wrong format. Valid format: 'component.section'"); + } + + if (!\array_key_exists('extensionName', $arguments) || !\array_key_exists('section', $arguments)) + { + $parts = explode('.', $arguments['extension']); + + $arguments['extensionName'] = $arguments['extensionName'] ?? $parts[0]; + $arguments['section'] = $arguments['section'] ?? $parts[1]; + } + + parent::__construct($name, $arguments); + } +} diff --git a/libraries/src/Event/Workflow/AbstractEvent.php b/libraries/src/Event/Workflow/AbstractEvent.php new file mode 100644 index 0000000000000..b0e92c06576e8 --- /dev/null +++ b/libraries/src/Event/Workflow/AbstractEvent.php @@ -0,0 +1,61 @@ +name} is required but has not been provided"); + } + + if (!\array_key_exists('extension', $arguments)) + { + throw new BadMethodCallException("Argument 'extension' of event {$this->name} is required but has not been provided"); + } + + if (strpos($arguments['extension'], '.') === false) + { + throw new BadMethodCallException("Argument 'extension' of event {$this->name} has wrong format. Valid format: 'component.section'"); + } + + if (!\array_key_exists('extensionName', $arguments) || !\array_key_exists('section', $arguments)) + { + $parts = explode('.', $arguments['extension']); + + $arguments['extensionName'] = $arguments['extensionName'] ?? $parts[0]; + $arguments['section'] = $arguments['section'] ?? $parts[1]; + } + + parent::__construct($name, $arguments); + } +} diff --git a/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php b/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php new file mode 100644 index 0000000000000..fb0b10af1e4a3 --- /dev/null +++ b/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php @@ -0,0 +1,55 @@ +arguments['used'] = $value; + + if ($value === true) + { + $this->stopPropagation(); + } + } +} diff --git a/libraries/src/Event/Workflow/WorkflowTransitionEvent.php b/libraries/src/Event/Workflow/WorkflowTransitionEvent.php new file mode 100644 index 0000000000000..0b64831b916b9 --- /dev/null +++ b/libraries/src/Event/Workflow/WorkflowTransitionEvent.php @@ -0,0 +1,57 @@ +arguments['stopTransition'] = $value; + + if ($value === true) + { + $this->stopPropagation(); + } + } + + +} diff --git a/libraries/src/MVC/View/HtmlView.php b/libraries/src/MVC/View/HtmlView.php index 7cfeccb7482c8..6c51827c1b37d 100644 --- a/libraries/src/MVC/View/HtmlView.php +++ b/libraries/src/MVC/View/HtmlView.php @@ -11,12 +11,14 @@ \defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; +use Joomla\CMS\Event\AbstractEvent; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Uri\Uri; +use Joomla\Event\DispatcherAwareInterface; /** * Base class for a Joomla Html View @@ -203,11 +205,34 @@ public function display($tpl = null) $context = $component . '.' . $this->getName(); - $app->triggerEvent('onBeforeDisplay', [$context, $this]); + $app->getDispatcher()->dispatch( + 'onBeforeDisplay', + AbstractEvent::create( + 'onBeforeDisplay', + [ + 'eventClass' => 'Joomla\CMS\Event\View\DisplayEvent', + 'subject' => $this, + 'extension' => $context + ] + ) + ); $result = $this->loadTemplate($tpl); - $app->triggerEvent('onAfterDisplay', [$context, $this, $result]); + $eventResult = $app->getDispatcher()->dispatch( + 'onAfterDisplay', + AbstractEvent::create( + 'onAfterDisplay', + [ + 'eventClass' => 'Joomla\CMS\Event\View\DisplayEvent', + 'subject' => $this, + 'extension' => $context, + 'source' => $result + ] + ) + ); + + $eventResult->getArgument('used', false); echo $result; } diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index f2ecae8dda9bb..4aee23adbf582 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -10,6 +10,7 @@ \defined('JPATH_PLATFORM') or die; +use Joomla\CMS\Event\AbstractEvent; use Joomla\CMS\Extension\ComponentInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; @@ -177,11 +178,11 @@ public function executeTransition(array $pks, int $transition_id): bool $db->quoteName('t.workflow_id'), ] ) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) - ->where($db->quoteName('t.id') . ' = :id') - ->where($db->quoteName('t.published') . ' = 1') - ->bind(':id', $transition_id, ParameterType::INTEGER); + ->from($db->quoteName('#__workflow_transitions', 't')) + ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) + ->where($db->quoteName('t.id') . ' = :id') + ->where($db->quoteName('t.published') . ' = 1') + ->bind(':id', $transition_id, ParameterType::INTEGER); $transition = $db->setQuery($query)->loadObject(); @@ -198,7 +199,10 @@ public function executeTransition(array $pks, int $transition_id): bool $assoc = $this->getAssociation($pk); // The transition has to be in the same workflow - if (!\in_array($transition->from_stage_id, [$assoc->stage_id, -1]) || $transition->workflow_id !== $assoc->workflow_id) + if (!\in_array($transition->from_stage_id, [ + $assoc->stage_id, + -1 + ]) || $transition->workflow_id !== $assoc->workflow_id) { return false; } @@ -208,16 +212,22 @@ public function executeTransition(array $pks, int $transition_id): bool PluginHelper::importPlugin('workflow'); - $result = $app->triggerEvent( + $eventResult = $app->getDispatcher()->dispatch( 'onWorkflowBeforeTransition', - [ - 'context' => $this->extension, - 'pks' => $pks, - 'transition' => $transition, - ] + AbstractEvent::create( + 'onWorkflowBeforeTransition', + [ + 'eventClass' => 'Joomla\CMS\Event\Workflow\WorkflowTransitionEvent', + 'subject' => $this, + 'extension' => $this->extension, + 'pks' => $pks, + 'transition' => $transition, + 'stopTransition' => false, + ] + ) ); - if (\in_array(false, $result, true)) + if ($eventResult->getArgument('stopTransition')) { return false; } @@ -226,13 +236,18 @@ public function executeTransition(array $pks, int $transition_id): bool if ($success) { - $app->triggerEvent( + $app->getDispatcher()->dispatch( 'onWorkflowAfterTransition', - [ - 'context' => $this->extension, - 'pks' => $pks, - 'transition' => $transition, - ] + AbstractEvent::create( + 'onWorkflowAfterTransition', + [ + 'eventClass' => 'Joomla\CMS\Event\Workflow\WorkflowTransitionEvent', + 'subject' => $this, + 'extension' => $this->extension, + 'pks' => $pks, + 'transition' => $transition + ] + ) ); } @@ -257,17 +272,17 @@ public function createAssociation(int $pk, int $state): bool $query = $db->getQuery(true); $query->insert($db->quoteName('#__workflow_associations')) - ->columns( - [ - $db->quoteName('item_id'), - $db->quoteName('stage_id'), - $db->quoteName('extension'), - ] - ) - ->values(':pk, :state, :extension') - ->bind(':pk', $pk, ParameterType::INTEGER) - ->bind(':state', $state, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->columns( + [ + $db->quoteName('item_id'), + $db->quoteName('stage_id'), + $db->quoteName('extension'), + ] + ) + ->values(':pk, :state, :extension') + ->bind(':pk', $pk, ParameterType::INTEGER) + ->bind(':state', $state, ParameterType::INTEGER) + ->bind(':extension', $this->extension); $db->setQuery($query)->execute(); } @@ -299,11 +314,11 @@ public function updateAssociations(array $pks, int $state): bool $query = $db->getQuery(true); $query->update($db->quoteName('#__workflow_associations')) - ->set($db->quoteName('stage_id') . ' = :state') - ->whereIn($db->quoteName('item_id'), $pks) - ->where($db->quoteName('extension') . ' = :extension') - ->bind(':state', $state, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->set($db->quoteName('stage_id') . ' = :state') + ->whereIn($db->quoteName('item_id'), $pks) + ->where($db->quoteName('extension') . ' = :extension') + ->bind(':state', $state, ParameterType::INTEGER) + ->bind(':extension', $this->extension); $db->setQuery($query)->execute(); } @@ -370,19 +385,19 @@ public function getAssociation(int $item_id): ?\stdClass $db->quoteName('s.workflow_id'), ] ) - ->from($db->quoteName('#__workflow_associations', 'a')) - ->innerJoin( - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id') - ) - ->where( - [ - $db->quoteName('item_id') . ' = :id', - $db->quoteName('extension') . ' = :extension', - ] - ) - ->bind(':id', $item_id, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->from($db->quoteName('#__workflow_associations', 'a')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id') + ) + ->where( + [ + $db->quoteName('item_id') . ' = :id', + $db->quoteName('extension') . ' = :extension', + ] + ) + ->bind(':id', $item_id, ParameterType::INTEGER) + ->bind(':extension', $this->extension); return $db->setQuery($query)->loadObject(); } diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index 1f763c1524c4f..c9efe14a80d0f 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -24,8 +24,8 @@ trait WorkflowPluginTrait /** * Add different parameter options to the transition view, we need when executing the transition * - * @param Form $form The form - * @param \stdClass $data The data + * @param Form $form The form + * @param \stdClass $data The data * * @return boolean * @@ -56,7 +56,7 @@ protected function enhanceWorkflowTransitionForm(Form $form, $data) /** * Get the workflow for a given ID * - * @param int|null $workflow_id ID of the workflow + * @param int|null $workflow_id ID of the workflow * * @return CMSObject|boolean Object on success, false on failure. * @@ -72,15 +72,15 @@ protected function getWorkflow(int $workflow_id = null) } return $this->app->bootComponent('com_workflow') - ->getMVCFactory() - ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) - ->getItem($workflow_id); + ->getMVCFactory() + ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) + ->getItem($workflow_id); } /** * Check if the current plugin should execute workflow related activities * - * @param string $context Context to check + * @param string $context Context to check * * @return boolean * @@ -90,4 +90,66 @@ protected function isSupported($context) { return false; } + + /** + * Check if the context is listed in the whitelist or in the blacklist and return the result + * + * @param string $context Context to check + * + * @return bool + */ + protected function checkWhiteAndBlacklist($context) + { + $whitelist = \trim($this->params->get('whitelist', '')); + $blacklist = \trim($this->params->get('blacklist', '')); + + if (!empty($whitelist)) + { + foreach (\explode(\chr(10), $whitelist) as $allowed) + { + if ($context === \trim($allowed)) + { + return true; + } + } + + return false; + } + + if (!empty($blacklist)) + { + foreach (\explode(\chr(10), $blacklist) as $allowed) + { + if ($context === \trim($allowed)) + { + return false; + } + } + } + + return true; + } + + /** + * Check if the context is listed in the whitelist or in the blacklist and return the result + * + * @param string $context Context to check + * + * @return bool + */ + protected function checkExtensionSupport($context, $functionality) + { + $parts = explode('.', $context); + + $component = $this->app->bootComponent($parts[0]); + if (!$component instanceof WorkflowServiceInterface + || !$component->isWorkflowActive($context) + || !$component->isFunctionalityActive($functionality, $context)) + { + return false; + } + + return true; + } + } diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index 66f8dd0435a6a..dae9cb5cce884 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -9,9 +9,12 @@ namespace Joomla\CMS\Workflow; use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Event\AbstractEvent; use Joomla\CMS\Factory; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\WorkflowModelInterface; +use Joomla\Event\DispatcherAwareInterface; +use function str_repeat; \defined('JPATH_PLATFORM') or die; @@ -63,14 +66,101 @@ public function supportFunctionality($functionality, $context): bool return in_array($context, $this->supportedFunctionality[$functionality], true); } + /** + * Check if the functionality is activated in the component configuration + * + * @param string $functionality + * @param string $extension + * + * @return bool + * @throws \Exception + * + * @since 4.0.0 + */ + public function isFunctionalityActive($functionality, $context): bool + { + if (!$this->isWorkflowActive($context)) + { + return false; + } + + $parts = explode('.', $context); + $config = ComponentHelper::getParams($parts[0]); + $option = 'workflow_functionality_' . str_replace('.', '_', $functionality); + + if (!$config->get($option, 1)) + { + return false; + } + + return true; + } + + /** + * Check if the functionality is used by a plugin + * + * @param string $functionality + * @param string $extension + * + * @return bool + * @throws \Exception + * + * @since 4.0.0 + */ + public function isFunctionalityUsed($functionality, $extension): bool + { + static $used = []; + + $cacheKey = $extension . '.' . $functionality; + + if (isset($used[$cacheKey])) + { + return $used[$cacheKey]; + } + + if (!$this->isFunctionalityActive($functionality, $extension)) + { + $used[$cacheKey] = false; + + return $used[$cacheKey]; + } + + // The container to get the services from + $app = Factory::getApplication(); + + if (!($app instanceof DispatcherAwareInterface)) + { + return false; + } + + $eventResult = $app->getDispatcher()->dispatch( + 'onWorkflowFunctionalityUsed', + AbstractEvent::create( + 'onWorkflowFunctionalityUsed', + [ + 'eventClass' => 'Joomla\CMS\Event\Workflow\WorkflowFunctionalityUsedEvent', + 'subject' => $this, + 'extension' => $extension, + 'functionality' => $functionality + ] + ) + ); + + $used[$cacheKey] = $eventResult->getArgument('used', false); + + return $used[$cacheKey]; + } + /** * Returns the model name, based on the context * * @param string $context The context of the workflow * * @return boolean + * + * @since 4.0.0 */ - public function getModelName($context) : string + public function getModelName($context): string { $parts = explode('.', $context); diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php index 69cbb0b3856ee..faf8a4be436f5 100644 --- a/plugins/workflow/featuring/featuring.php +++ b/plugins/workflow/featuring/featuring.php @@ -10,15 +10,19 @@ defined('_JEXEC') or die; use Joomla\CMS\Application\CMSApplicationInterface; +use Joomla\CMS\Event\View\DisplayEvent; +use Joomla\CMS\Event\Workflow\WorkflowFunctionalityUsedEvent; +use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\DatabaseModelInterface; -use Joomla\CMS\MVC\View\ViewInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Table\TableInterface; use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\CMS\Workflow\WorkflowServiceInterface; +use Joomla\Event\EventInterface; +use Joomla\Event\SubscriberInterface; use Joomla\String\Inflector; /** @@ -26,7 +30,7 @@ * * @since __DEPLOY_VERSION__ */ -class PlgWorkflowFeaturing extends CMSPlugin +class PlgWorkflowFeaturing extends CMSPlugin implements SubscriberInterface { use WorkflowPluginTrait; @@ -54,19 +58,38 @@ class PlgWorkflowFeaturing extends CMSPlugin */ protected $supportFunctionality = 'core.featured'; + /** + * Returns an array of events this subscriber will listen to. + * + * @return array + * + * @since 4.0.0 + */ + public static function getSubscribedEvents(): array + { + return [ + 'onContentPrepareForm' => 'onContentPrepareForm', + 'onAfterDisplay' => 'onAfterDisplay', + 'onWorkflowBeforeTransition' => 'onWorkflowBeforeTransition', + 'onWorkflowAfterTransition' => 'onWorkflowAfterTransition', + 'onContentBeforeChangeFeatured' => 'onContentBeforeChangeFeatured', + 'onContentBeforeSave' => 'onContentBeforeSave', + 'onWorkflowFunctionalityUsed' => 'onWorkflowFunctionalityUsed', + ]; + } /** * The form event. * - * @param Form $form The form - * @param \stdClass $data The data - * - * @return boolean + * @param EventInterface $event The event * * @since __DEPLOY_VERSION__ */ - public function onContentPrepareForm(Form $form, $data) + public function onContentPrepareForm(EventInterface $event) { + $form = $event->getArgument('0'); + $data = $event->getArgument('1'); + $context = $form->getName(); // Extend the transition form @@ -74,20 +97,20 @@ public function onContentPrepareForm(Form $form, $data) { $this->enhanceWorkflowTransitionForm($form, $data); - return true; + return; } $this->enhanceItemForm($form, $data); - return true; + return; } /** * Disable certain fields in the item form view, when we want to take over this function in the transition * Check also for the workflow implementation and if the field exists * - * @param Form $form The form - * @param stdClass $data The data + * @param Form $form The form + * @param stdClass $data The data * * @return boolean * @@ -109,7 +132,7 @@ protected function enhanceItemForm(Form $form, $data) $modelName = $component->getModelName($context); $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) - ->getTable(); + ->getTable(); $fieldname = $table->getColumnAlias('featured'); @@ -160,35 +183,35 @@ protected function enhanceItemForm(Form $form, $data) /** * Manipulate the generic list view * - * @param string $context - * @param ViewInterface $view - * @param string $result + * @param DisplayEvent $event * * @since 4.0.0 */ - public function onAfterDisplay(string $context, ViewInterface $view, string $result) + public function onAfterDisplay(DisplayEvent $event) { - $parts = explode('.', $context); + $app = Factory::getApplication(); - if ($parts < 2) + if (!$app->isClient('administrator')) { - return true; + return; } - $app = Factory::getApplication(); + $component = $event->getArgument('extensionName'); + $section = $event->getArgument('section'); // We need the single model context for checking for workflow - $singularsection = Inflector::singularize($parts[1]); - - $newcontext = $parts[0] . '.' . $singularsection; + $singularsection = Inflector::singularize($section); - if (!$app->isClient('administrator') || !$this->isSupported($newcontext)) + if (!$this->isSupported($component . '.' . $singularsection)) { return true; } // List of releated batch functions we need to hide - $states = ['featured', 'unfeatured']; + $states = [ + 'featured', + 'unfeatured' + ]; $js = " document.addEventListener('DOMContentLoaded', function() @@ -220,16 +243,18 @@ public function onAfterDisplay(string $context, ViewInterface $view, string $res /** * Check if we can execute the transition * - * @param string $context The context - * @param array $pks IDs of the items - * @param object $transition The value to change to + * @param WorkflowTransitionEvent $event * * @return boolean * * @since 4.0.0 */ - public function onWorkflowBeforeTransition($context, $pks, $transition) + public function onWorkflowBeforeTransition(WorkflowTransitionEvent $event) { + $context = $event->getArgument('extension'); + $transition = $event->getArgument('transition'); + $pks = $event->getArgument('pks'); + if (!$this->isSupported($context) || !is_numeric($transition->options->get('featuring'))) { return true; @@ -249,7 +274,11 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) */ $this->app->set('plgWorkflowFeaturing.' . $context, $pks); - $result = $this->app->triggerEvent('onContentBeforeChangeFeatured', [$context, $pks, $value]); + $result = $this->app->triggerEvent('onContentBeforeChangeFeatured', [ + $context, + $pks, + $value + ]); // Release whitelist, the job is done $this->app->set('plgWorkflowFeaturing.' . $context, []); @@ -265,40 +294,35 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) /** * Change Feature State of an item. Used to disable feature state change * - * @param string $context The context - * @param array $pks IDs of the items - * @param object $transition The value to change to + * @param WorkflowTransitionEvent $event * * @return boolean * * @since 4.0.0 */ - public function onWorkflowAfterTransition($context, $pks, $transition) + public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) { - if (!$this->isSupported($context)) - { - return true; - } + $context = $event->getArgument('extension'); + $extensionName = $event->getArgument('extensionName'); + $transition = $event->getArgument('transition'); + $pks = $event->getArgument('pks'); - $parts = explode('.', $context); - - // We need at least the extension + view for loading the table fields - if (count($parts) < 2) + if (!$this->isSupported($context)) { - return false; + return; } - $component = $this->app->bootComponent($parts[0]); + $component = $this->app->bootComponent($extensionName); $value = $transition->options->get('featuring'); if (!is_numeric($value)) { - return true; + return; } $options = [ - 'ignore_request' => true, + 'ignore_request' => true, // We already have triggered onContentBeforeChangeFeatured, so use our own 'event_before_change_featured' => 'onWorkflowBeforeChangeFeatured' ]; @@ -307,22 +331,24 @@ public function onWorkflowAfterTransition($context, $pks, $transition) $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), $options); - return $model->featured($pks, $value); + $model->featured($pks, $value); } /** * Change Feature State of an item. Used to disable Feature state change * - * @param string $context The context - * @param array $pks IDs of the items - * @param int $value The value to change to + * @param EventInterface $event * * @return boolean * + * @throws Exception * @since 4.0.0 */ - public function onContentBeforeChangeFeatured(string $context, array $pks, int $value): bool + public function onContentBeforeChangeFeatured(EventInterface $event) { + $context = $event->getArgument('0'); + $pks = $event->getArgument('1'); + if (!$this->isSupported($context)) { return true; @@ -341,17 +367,20 @@ public function onContentBeforeChangeFeatured(string $context, array $pks, int $ /** * The save event. * - * @param string $context The context - * @param object $table The item - * @param boolean $isNew Is new item - * @param array $data The validated data + * @param EventInterface $event * * @return boolean * * @since 4.0.0 */ - public function onContentBeforeSave($context, TableInterface $table, $isNew, $data) + public function onContentBeforeSave(EventInterface $event) { + $context = $event->getArgument('0'); + /* @var TableInterface */ + $table = $event->getArgument('1'); + $isNew = $event->getArgument('2'); + $data = $event->getArgument('3'); + if (!$this->isSupported($context)) { return true; @@ -380,12 +409,18 @@ public function onContentBeforeSave($context, TableInterface $table, $isNew, $da * Check if the current plugin should execute workflow related activities * * @param string $context + * * @return boolean * * @since 4.0.0 */ protected function isSupported($context) { + if (!$this->checkWhiteAndBlacklist($context) || !$this->checkExtensionSupport($context, $this->supportFunctionality)) + { + return false; + } + $parts = explode('.', $context); // We need at least the extension + view for loading the table fields @@ -421,4 +456,23 @@ protected function isSupported($context) return true; } + + /** + * If plugin supports the functionality we set the used variable + * + * @param WorkflowFunctionalityUsedEvent $event + * + * @since 4.0.0 + */ + public function onWorkflowFunctionalityUsed(WorkflowFunctionalityUsedEvent $event) + { + $functionality = $event->getArgument('functionality'); + + if ($functionality !== 'core.featured') + { + return; + } + + $event->setUsed(); + } } diff --git a/plugins/workflow/featuring/featuring.xml b/plugins/workflow/featuring/featuring.xml index 39ab3f4e2e31f..5f652d50d7ca3 100644 --- a/plugins/workflow/featuring/featuring.xml +++ b/plugins/workflow/featuring/featuring.xml @@ -19,7 +19,18 @@
- + +
diff --git a/plugins/workflow/notification/notification.php b/plugins/workflow/notification/notification.php index dbfbd31fb032e..81b3f4aee8d36 100644 --- a/plugins/workflow/notification/notification.php +++ b/plugins/workflow/notification/notification.php @@ -9,14 +9,19 @@ defined('_JEXEC') or die; +use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; -use Joomla\CMS\Language\Language; +use Joomla\CMS\Language\LanguageFactoryInterface; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; -use Joomla\CMS\User\User; +use Joomla\CMS\User\UserFactoryInterface; use Joomla\CMS\Workflow\WorkflowPluginTrait; +use Joomla\CMS\Workflow\WorkflowServiceInterface; +use Joomla\Event\EventInterface; +use Joomla\Event\SubscriberInterface; use Joomla\Utilities\ArrayHelper; /** @@ -24,7 +29,7 @@ * * @since __DEPLOY_VERSION__ */ -class PlgWorkflowNotification extends CMSPlugin +class PlgWorkflowNotification extends CMSPlugin implements SubscriberInterface { use WorkflowPluginTrait; @@ -52,6 +57,21 @@ class PlgWorkflowNotification extends CMSPlugin */ protected $db; + /** + * Returns an array of events this subscriber will listen to. + * + * @return array + * + * @since 4.0.0 + */ + public static function getSubscribedEvents(): array + { + return [ + 'onContentPrepareForm' => 'onContentPrepareForm', + 'onWorkflowAfterTransition' => 'onWorkflowAfterTransition', + ]; + } + /** * The form event. * @@ -62,14 +82,17 @@ class PlgWorkflowNotification extends CMSPlugin * * @since __DEPLOY_VERSION__ */ - public function onContentPrepareForm(Form $form, $data) + public function onContentPrepareForm(EventInterface $event) { + $form = $event->getArgument('0'); + $data = $event->getArgument('1'); + $context = $form->getName(); // Extend the transition form if ($context === 'com_workflow.transition') { - $form->loadFile(__DIR__ . '/forms/action.xml'); + $this->enhanceWorkflowTransitionForm($form, $data); } return true; @@ -86,27 +109,24 @@ public function onContentPrepareForm(Form $form, $data) * * @since __DEPLOY_VERSION__ */ - public function onWorkflowAfterTransition($context, $pks, $data) + public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) { - $parts = explode('.', $context); + $context = $event->getArgument('extension'); + $extensionName = $event->getArgument('extensionName'); + $transition = $event->getArgument('transition'); + $pks = $event->getArgument('pks'); - // Check the extension - if (count($parts) < 2) + if (!$this->isSupported($context)) { - return false; + return; } - $component = $this->app->bootComponent($parts[0]); - - if (!$component->isWorkflowActive($context)) - { - return false; - } + $component = $this->app->bootComponent($extensionName); // Check if send-mail is active - if (empty($data->options['notification_send_mail'])) + if (empty($transition->options['notification_send_mail'])) { - return true; + return; } // ID of the items whose state has changed. @@ -114,11 +134,11 @@ public function onWorkflowAfterTransition($context, $pks, $data) if (empty($pks)) { - return true; + return; } // Get UserIds of Receivers - $userIds = $this->getUsersFromGroup($data); + $userIds = $this->getUsersFromGroup($transition); // The active user $user = $this->app->getIdentity(); @@ -147,7 +167,7 @@ public function onWorkflowAfterTransition($context, $pks, $data) // If there are no receivers, stop here if (empty($userIds)) { - return true; + return; } // Get the model for private messages @@ -158,7 +178,7 @@ public function onWorkflowAfterTransition($context, $pks, $data) $model_stage = $this->app->bootComponent('com_workflow') ->getMVCFactory()->createModel('Stage', 'Administrator'); - $toStage = $model_stage->getItem($data->to_stage_id)->title; + $toStage = $model_stage->getItem($transition->to_stage_id)->title; $hasGetItem = method_exists($model, 'getItem'); @@ -175,16 +195,16 @@ public function onWorkflowAfterTransition($context, $pks, $data) // Send Email to receivers foreach ($userIds as $user_id) { - $receiver = User::getInstance($user_id); + $receiver = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($user_id); // Load language for messaging - $lang = Language::getInstance($user->getParam('admin_language', $default_language), $debug); + $lang = Factory::getContainer()->get(LanguageFactoryInterface::class)->createLanguage($user->getParam('admin_language', $default_language), $debug); $lang->load('plg_workflow_notification'); $messageText = sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'), $title, $user->name, $lang->_($toStage)); - if (!empty($data->options['notification_text'])) + if (!empty($transition->options['notification_text'])) { - $messageText .= '
' . htmlspecialchars($lang->_($data->options['notification_text'])); + $messageText .= '
' . htmlspecialchars($lang->_($transition->options['notification_text'])); } $message = [ @@ -200,7 +220,6 @@ public function onWorkflowAfterTransition($context, $pks, $data) $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message'); - return true; } /* @@ -254,6 +273,42 @@ private function getUsersFromGroup($data): Array return array_unique(array_merge($users, $users2)); } + + /** + * Check if the current plugin should execute workflow related activities + * + * @param string $context + * + * @return boolean + * + * @since 4.0.0 + */ + protected function isSupported($context) + { + if (!$this->checkWhiteAndBlacklist($context)) + { + return false; + } + + $parts = explode('.', $context); + + // We need at least the extension + view for loading the table fields + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + if (!$component instanceof WorkflowServiceInterface + || !$component->isWorkflowActive($context)) + { + return false; + } + + return true; + } + /* * Remove receivers who have locked their message inputbox * diff --git a/plugins/workflow/notification/notification.xml b/plugins/workflow/notification/notification.xml index 84199d2433b33..0d28bf15ee802 100644 --- a/plugins/workflow/notification/notification.xml +++ b/plugins/workflow/notification/notification.xml @@ -19,7 +19,18 @@
- + +
diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index b31434fc8359e..26310a2b38b14 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -10,15 +10,19 @@ defined('_JEXEC') or die; use Joomla\CMS\Application\CMSApplicationInterface; +use Joomla\CMS\Event\View\DisplayEvent; +use Joomla\CMS\Event\Workflow\WorkflowFunctionalityUsedEvent; +use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\DatabaseModelInterface; -use Joomla\CMS\MVC\View\ViewInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Table\TableInterface; use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\CMS\Workflow\WorkflowServiceInterface; +use Joomla\Event\EventInterface; +use Joomla\Event\SubscriberInterface; use Joomla\String\Inflector; /** @@ -26,7 +30,7 @@ * * @since __DEPLOY_VERSION__ */ -class PlgWorkflowPublishing extends CMSPlugin +class PlgWorkflowPublishing extends CMSPlugin implements SubscriberInterface { use WorkflowPluginTrait; @@ -55,17 +59,37 @@ class PlgWorkflowPublishing extends CMSPlugin protected $supportFunctionality = 'core.state'; /** - * The form event. + * Returns an array of events this subscriber will listen to. * - * @param Form $form The form - * @param \stdClass $data The data + * @return array * - * @return boolean + * @since 4.0.0 + */ + public static function getSubscribedEvents(): array + { + return [ + 'onContentPrepareForm' => 'onContentPrepareForm', + 'onAfterDisplay' => 'onAfterDisplay', + 'onWorkflowBeforeTransition' => 'onWorkflowBeforeTransition', + 'onWorkflowAfterTransition' => 'onWorkflowAfterTransition', + 'onContentBeforeChangeState' => 'onContentBeforeChangeState', + 'onContentBeforeSave' => 'onContentBeforeSave', + 'onWorkflowFunctionalityUsed' => 'onWorkflowFunctionalityUsed', + ]; + } + + /** + * The form event. + * + * @param EventInterface $event The event * * @since __DEPLOY_VERSION__ */ - public function onContentPrepareForm(Form $form, $data) + public function onContentPrepareForm(EventInterface $event) { + $form = $event->getArgument('0'); + $data = $event->getArgument('1'); + $context = $form->getName(); // Extend the transition form @@ -73,19 +97,19 @@ public function onContentPrepareForm(Form $form, $data) { $this->enhanceTransitionForm($form, $data); - return true; + return; } $this->enhanceItemForm($form, $data); - return true; + return; } /** * Add different parameter options to the transition view, we need when executing the transition * - * @param Form $form The form - * @param stdClass $data The data + * @param Form $form The form + * @param stdClass $data The data * * @return boolean * @@ -109,8 +133,8 @@ protected function enhanceTransitionForm(Form $form, $data) * Disable certain fields in the item form view, when we want to take over this function in the transition * Check also for the workflow implementation and if the field exists * - * @param Form $form The form - * @param stdClass $data The data + * @param Form $form The form + * @param stdClass $data The data * * @return boolean * @@ -132,7 +156,7 @@ protected function enhanceItemForm(Form $form, $data) $modelName = $component->getModelName($context); $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) - ->getTable(); + ->getTable(); $fieldname = $table->getColumnAlias('published'); @@ -179,35 +203,38 @@ protected function enhanceItemForm(Form $form, $data) /** * Manipulate the generic list view * - * @param string $context - * @param ViewInterface $view - * @param string $result + * @param DisplayEvent $event * * @since 4.0.0 */ - public function onAfterDisplay(string $context, ViewInterface $view, string $result) + public function onAfterDisplay(DisplayEvent $event) { - $parts = explode('.', $context); + $app = Factory::getApplication(); - if ($parts < 2) + if (!$app->isClient('administrator')) { - return true; + return; } - $app = Factory::getApplication(); + $component = $event->getArgument('extensionName'); + $section = $event->getArgument('section'); // We need the single model context for checking for workflow - $singularsection = Inflector::singularize($parts[1]); - - $newcontext = $parts[0] . '.' . $singularsection; + $singularsection = Inflector::singularize($section); - if (!$app->isClient('administrator') || !$this->isSupported($newcontext)) + if (!$this->isSupported($component . '.' . $singularsection)) { return true; } // That's the hard coded list from the AdminController publish method => change, when it's make dynamic in the future - $states = ['publish', 'unpublish', 'archive', 'trash', 'report']; + $states = [ + 'publish', + 'unpublish', + 'archive', + 'trash', + 'report' + ]; $js = " document.addEventListener('DOMContentLoaded', function() @@ -239,16 +266,18 @@ public function onAfterDisplay(string $context, ViewInterface $view, string $res /** * Check if we can execute the transition * - * @param string $context The context - * @param array $pks IDs of the items - * @param object $transition The value to change to + * @param WorkflowTransitionEvent $event * * @return boolean * * @since 4.0.0 */ - public function onWorkflowBeforeTransition($context, $pks, $transition) + public function onWorkflowBeforeTransition(WorkflowTransitionEvent $event) { + $context = $event->getArgument('extension'); + $transition = $event->getArgument('transition'); + $pks = $event->getArgument('pks'); + if (!$this->isSupported($context) || !is_numeric($transition->options->get('publishing'))) { return true; @@ -268,7 +297,11 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) */ $this->app->set('plgWorkflowPublishing.' . $context, $pks); - $result = $this->app->triggerEvent('onContentBeforeChangeState', [$context, $pks, $value]); + $result = $this->app->triggerEvent('onContentBeforeChangeState', [ + $context, + $pks, + $value + ]); // Release whitelist, the job is done $this->app->set('plgWorkflowPublishing.' . $context, []); @@ -284,40 +317,35 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) /** * Change State of an item. Used to disable state change * - * @param string $context The context - * @param array $pks IDs of the items - * @param object $transition The value to change to + * @param WorkflowTransitionEvent $event * * @return boolean * * @since 4.0.0 */ - public function onWorkflowAfterTransition($context, $pks, $transition) + public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) { + $context = $event->getArgument('extension'); + $extensionName = $event->getArgument('extensionName'); + $transition = $event->getArgument('transition'); + $pks = $event->getArgument('pks'); + if (!$this->isSupported($context)) { return true; } - $parts = explode('.', $context); - - // We need at least the extension + view for loading the table fields - if (count($parts) < 2) - { - return false; - } - - $component = $this->app->bootComponent($parts[0]); + $component = $this->app->bootComponent($extensionName); $value = $transition->options->get('publishing'); if (!is_numeric($value)) { - return true; + return; } $options = [ - 'ignore_request' => true, + 'ignore_request' => true, // We already have triggered onContentBeforeChangeState, so use our own 'event_before_change_state' => 'onWorkflowBeforeChangeState' ]; @@ -326,22 +354,24 @@ public function onWorkflowAfterTransition($context, $pks, $transition) $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), $options); - return $model->publish($pks, $value); + $model->publish($pks, $value); } /** * Change State of an item. Used to disable state change * - * @param string $context The context - * @param array $pks IDs of the items - * @param int $value The value to change to + * @param EventInterface $event * * @return boolean * + * @throws Exception * @since 4.0.0 */ - public function onContentBeforeChangeState($context, $pks, $value) + public function onContentBeforeChangeState(EventInterface $event) { + $context = $event->getArgument('0'); + $pks = $event->getArgument('1'); + if (!$this->isSupported($context)) { return true; @@ -360,17 +390,20 @@ public function onContentBeforeChangeState($context, $pks, $value) /** * The save event. * - * @param string $context The context - * @param object $table The item - * @param boolean $isNew Is new item - * @param array $data The validated data + * @param EventInterface $event * * @return boolean * * @since 4.0.0 */ - public function onContentBeforeSave($context, TableInterface $table, $isNew, $data) + public function onContentBeforeSave(EventInterface $event) { + $context = $event->getArgument('0'); + /* @var TableInterface */ + $table = $event->getArgument('1'); + $isNew = $event->getArgument('2'); + $data = $event->getArgument('3'); + if (!$this->isSupported($context)) { return true; @@ -399,12 +432,18 @@ public function onContentBeforeSave($context, TableInterface $table, $isNew, $da * Check if the current plugin should execute workflow related activities * * @param string $context + * * @return boolean * * @since 4.0.0 */ protected function isSupported($context) { + if (!$this->checkWhiteAndBlacklist($context) || !$this->checkExtensionSupport($context, $this->supportFunctionality)) + { + return false; + } + $parts = explode('.', $context); // We need at least the extension + view for loading the table fields @@ -440,4 +479,23 @@ protected function isSupported($context) return true; } + + /** + * If plugin supports the functionality we set the used variable + * + * @param WorkflowFunctionalityUsedEvent $event + * + * @since 4.0.0 + */ + public function onWorkflowFunctionalityUsed(WorkflowFunctionalityUsedEvent $event) + { + $functionality = $event->getArgument('functionality'); + + if ($functionality !== 'core.state') + { + return; + } + + $event->setUsed(); + } } diff --git a/plugins/workflow/publishing/publishing.xml b/plugins/workflow/publishing/publishing.xml index 6aa683603d94d..e6741ec396768 100644 --- a/plugins/workflow/publishing/publishing.xml +++ b/plugins/workflow/publishing/publishing.xml @@ -19,7 +19,18 @@
- + +
From 831efc0c445e7bab91abbb97243c8611619eb4c6 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Tue, 26 May 2020 01:04:37 +0200 Subject: [PATCH 58/90] cs (#103) --- libraries/src/Button/TransitionButton.php | 2 - libraries/src/Event/View/DisplayEvent.php | 16 ++++- .../WorkflowFunctionalityUsedEvent.php | 6 +- .../Workflow/WorkflowTransitionEvent.php | 6 +- libraries/src/Workflow/Workflow.php | 71 ++++++++++--------- .../src/Workflow/WorkflowPluginTrait.php | 24 ++++--- .../src/Workflow/WorkflowServiceTrait.php | 18 ++--- plugins/workflow/featuring/featuring.php | 9 ++- .../workflow/notification/notification.php | 23 +++--- plugins/workflow/publishing/publishing.php | 9 ++- 10 files changed, 105 insertions(+), 79 deletions(-) diff --git a/libraries/src/Button/TransitionButton.php b/libraries/src/Button/TransitionButton.php index 719b519373243..b8279c0d3d45f 100644 --- a/libraries/src/Button/TransitionButton.php +++ b/libraries/src/Button/TransitionButton.php @@ -51,8 +51,6 @@ public function __construct(array $options = []) * @param integer|null $value Current value of this item. * @param integer|null $row The row number of this item. * @param array $options The options to override group options. - * @param string|Date $publishUp The date which item publish up. - * @param string|Date $publishDown The date which item publish down. * * @return string Rendered HTML. * diff --git a/libraries/src/Event/View/DisplayEvent.php b/libraries/src/Event/View/DisplayEvent.php index 46a6f2c3e4e5f..325db2938d924 100644 --- a/libraries/src/Event/View/DisplayEvent.php +++ b/libraries/src/Event/View/DisplayEvent.php @@ -33,14 +33,24 @@ class DisplayEvent extends AbstractImmutableEvent */ public function __construct($name, array $arguments = array()) { - if (!isset($arguments['subject']) || !($arguments['subject'] instanceof ViewInterface)) + if (!isset($arguments['subject'])) { - throw new BadMethodCallException("Argument 'subject' of event {$this->name} is required but has not been provided or is not of type 'ViewInterface'"); + throw new BadMethodCallException("Argument 'subject' of event {$this->name} is required but has not been provided"); + } + + if (!($arguments['subject'] instanceof ViewInterface)) + { + throw new BadMethodCallException("Argument 'subject' of event {$this->name} is not of type 'ViewInterface'"); + } + + if (!isset($arguments['extension'])) + { + throw new BadMethodCallException("Argument 'extension' of event {$this->name} is required but has not been provided"); } if (!isset($arguments['extension']) || !is_string($arguments['extension'])) { - throw new BadMethodCallException("Argument 'extension' of event {$this->name} is required but has not been provided or is not of type 'string'"); + throw new BadMethodCallException("Argument 'extension' of event {$this->name} is not of type 'string'"); } if (strpos($arguments['extension'], '.') === false) diff --git a/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php b/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php index fb0b10af1e4a3..afb5938681b09 100644 --- a/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php +++ b/libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php @@ -41,7 +41,11 @@ public function __construct($name, array $arguments = array()) /** * Set used parameter to true * - * @since 1.0 + * @param bool $value The value to set + * + * @return void + * + * @since 4.0.0 */ public function setUsed($value = true) { diff --git a/libraries/src/Event/Workflow/WorkflowTransitionEvent.php b/libraries/src/Event/Workflow/WorkflowTransitionEvent.php index 0b64831b916b9..58c68150abd4f 100644 --- a/libraries/src/Event/Workflow/WorkflowTransitionEvent.php +++ b/libraries/src/Event/Workflow/WorkflowTransitionEvent.php @@ -41,7 +41,11 @@ public function __construct($name, array $arguments = array()) /** * Set used parameter to true * - * @since 1.0 + * @param bool $value The value to set + * + * @return void + * + * @since 4.0.0 */ public function setStopTransition($value = true) { diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index 4aee23adbf582..5516c6d8d8ad2 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -178,11 +178,11 @@ public function executeTransition(array $pks, int $transition_id): bool $db->quoteName('t.workflow_id'), ] ) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) - ->where($db->quoteName('t.id') . ' = :id') - ->where($db->quoteName('t.published') . ' = 1') - ->bind(':id', $transition_id, ParameterType::INTEGER); + ->from($db->quoteName('#__workflow_transitions', 't')) + ->join('LEFT', $db->quoteName('#__workflow_stages', 's'), $db->quoteName('s.id') . ' = ' . $db->quoteName('t.to_stage_id')) + ->where($db->quoteName('t.id') . ' = :id') + ->where($db->quoteName('t.published') . ' = 1') + ->bind(':id', $transition_id, ParameterType::INTEGER); $transition = $db->setQuery($query)->loadObject(); @@ -202,7 +202,8 @@ public function executeTransition(array $pks, int $transition_id): bool if (!\in_array($transition->from_stage_id, [ $assoc->stage_id, -1 - ]) || $transition->workflow_id !== $assoc->workflow_id) + ] + ) || $transition->workflow_id !== $assoc->workflow_id) { return false; } @@ -272,17 +273,17 @@ public function createAssociation(int $pk, int $state): bool $query = $db->getQuery(true); $query->insert($db->quoteName('#__workflow_associations')) - ->columns( - [ - $db->quoteName('item_id'), - $db->quoteName('stage_id'), - $db->quoteName('extension'), - ] - ) - ->values(':pk, :state, :extension') - ->bind(':pk', $pk, ParameterType::INTEGER) - ->bind(':state', $state, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->columns( + [ + $db->quoteName('item_id'), + $db->quoteName('stage_id'), + $db->quoteName('extension'), + ] + ) + ->values(':pk, :state, :extension') + ->bind(':pk', $pk, ParameterType::INTEGER) + ->bind(':state', $state, ParameterType::INTEGER) + ->bind(':extension', $this->extension); $db->setQuery($query)->execute(); } @@ -314,11 +315,11 @@ public function updateAssociations(array $pks, int $state): bool $query = $db->getQuery(true); $query->update($db->quoteName('#__workflow_associations')) - ->set($db->quoteName('stage_id') . ' = :state') - ->whereIn($db->quoteName('item_id'), $pks) - ->where($db->quoteName('extension') . ' = :extension') - ->bind(':state', $state, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->set($db->quoteName('stage_id') . ' = :state') + ->whereIn($db->quoteName('item_id'), $pks) + ->where($db->quoteName('extension') . ' = :extension') + ->bind(':state', $state, ParameterType::INTEGER) + ->bind(':extension', $this->extension); $db->setQuery($query)->execute(); } @@ -385,19 +386,19 @@ public function getAssociation(int $item_id): ?\stdClass $db->quoteName('s.workflow_id'), ] ) - ->from($db->quoteName('#__workflow_associations', 'a')) - ->innerJoin( - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id') - ) - ->where( - [ - $db->quoteName('item_id') . ' = :id', - $db->quoteName('extension') . ' = :extension', - ] - ) - ->bind(':id', $item_id, ParameterType::INTEGER) - ->bind(':extension', $this->extension); + ->from($db->quoteName('#__workflow_associations', 'a')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id') + ) + ->where( + [ + $db->quoteName('item_id') . ' = :id', + $db->quoteName('extension') . ' = :extension', + ] + ) + ->bind(':id', $item_id, ParameterType::INTEGER) + ->bind(':extension', $this->extension); return $db->setQuery($query)->loadObject(); } diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index c9efe14a80d0f..ec676df7b9333 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -24,8 +24,8 @@ trait WorkflowPluginTrait /** * Add different parameter options to the transition view, we need when executing the transition * - * @param Form $form The form - * @param \stdClass $data The data + * @param Form $form The form + * @param \stdClass $data The data * * @return boolean * @@ -56,7 +56,7 @@ protected function enhanceWorkflowTransitionForm(Form $form, $data) /** * Get the workflow for a given ID * - * @param int|null $workflow_id ID of the workflow + * @param int|null $workflow_id ID of the workflow * * @return CMSObject|boolean Object on success, false on failure. * @@ -72,15 +72,15 @@ protected function getWorkflow(int $workflow_id = null) } return $this->app->bootComponent('com_workflow') - ->getMVCFactory() - ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) - ->getItem($workflow_id); + ->getMVCFactory() + ->createModel('Workflow', 'Administrator', ['ignore_request' => true]) + ->getItem($workflow_id); } /** * Check if the current plugin should execute workflow related activities * - * @param string $context Context to check + * @param string $context Context to check * * @return boolean * @@ -94,9 +94,9 @@ protected function isSupported($context) /** * Check if the context is listed in the whitelist or in the blacklist and return the result * - * @param string $context Context to check + * @param string $context Context to check * - * @return bool + * @return boolean */ protected function checkWhiteAndBlacklist($context) { @@ -133,15 +133,17 @@ protected function checkWhiteAndBlacklist($context) /** * Check if the context is listed in the whitelist or in the blacklist and return the result * - * @param string $context Context to check + * @param string $context Context to check + * @param string $functionality The funcationality * - * @return bool + * @return boolean */ protected function checkExtensionSupport($context, $functionality) { $parts = explode('.', $context); $component = $this->app->bootComponent($parts[0]); + if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context) || !$component->isFunctionalityActive($functionality, $context)) diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index dae9cb5cce884..6e8760c20faa0 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -69,22 +69,22 @@ public function supportFunctionality($functionality, $context): bool /** * Check if the functionality is activated in the component configuration * - * @param string $functionality - * @param string $extension + * @param string $functionality The functionality + * @param string $extension The extension * - * @return bool + * @return boolean * @throws \Exception * * @since 4.0.0 */ - public function isFunctionalityActive($functionality, $context): bool + public function isFunctionalityActive($functionality, $extension): bool { - if (!$this->isWorkflowActive($context)) + if (!$this->isWorkflowActive($extension)) { return false; } - $parts = explode('.', $context); + $parts = explode('.', $extension); $config = ComponentHelper::getParams($parts[0]); $option = 'workflow_functionality_' . str_replace('.', '_', $functionality); @@ -99,10 +99,10 @@ public function isFunctionalityActive($functionality, $context): bool /** * Check if the functionality is used by a plugin * - * @param string $functionality - * @param string $extension + * @param string $functionality The functionality + * @param string $extension The extension * - * @return bool + * @return boolean * @throws \Exception * * @since 4.0.0 diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php index faf8a4be436f5..88c9fd675b2ba 100644 --- a/plugins/workflow/featuring/featuring.php +++ b/plugins/workflow/featuring/featuring.php @@ -132,7 +132,7 @@ protected function enhanceItemForm(Form $form, $data) $modelName = $component->getModelName($context); $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) - ->getTable(); + ->getTable(); $fieldname = $table->getColumnAlias('featured'); @@ -278,7 +278,8 @@ public function onWorkflowBeforeTransition(WorkflowTransitionEvent $event) $context, $pks, $value - ]); + ] + ); // Release whitelist, the job is done $this->app->set('plgWorkflowFeaturing.' . $context, []); @@ -376,7 +377,9 @@ public function onContentBeforeChangeFeatured(EventInterface $event) public function onContentBeforeSave(EventInterface $event) { $context = $event->getArgument('0'); - /* @var TableInterface */ + + // @var TableInterface + $table = $event->getArgument('1'); $isNew = $event->getArgument('2'); $data = $event->getArgument('3'); diff --git a/plugins/workflow/notification/notification.php b/plugins/workflow/notification/notification.php index 81b3f4aee8d36..8a92c65ea292e 100644 --- a/plugins/workflow/notification/notification.php +++ b/plugins/workflow/notification/notification.php @@ -144,7 +144,7 @@ public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) $user = $this->app->getIdentity(); // Prepare Language for messages - $default_language = ComponentHelper::getParams('com_languages')->get('administrator'); + $defaultLanguage = ComponentHelper::getParams('com_languages')->get('administrator'); $debug = $this->app->get('debug_lang'); $modelName = $component->getModelName($context); @@ -172,20 +172,21 @@ public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) // Get the model for private messages $model_message = $this->app->bootComponent('com_messages') - ->getMVCFactory()->createModel('Message', 'Administrator'); + ->getMVCFactory()->createModel('Message', 'Administrator'); // Get the title of the stage $model_stage = $this->app->bootComponent('com_workflow') - ->getMVCFactory()->createModel('Stage', 'Administrator'); + ->getMVCFactory()->createModel('Stage', 'Administrator'); $toStage = $model_stage->getItem($transition->to_stage_id)->title; $hasGetItem = method_exists($model, 'getItem'); + $container = Factory::getContainer(); foreach ($pks as $pk) { // Get the title of the item which has changed - $title =''; + $title = ''; if ($hasGetItem) { @@ -195,10 +196,10 @@ public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) // Send Email to receivers foreach ($userIds as $user_id) { - $receiver = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($user_id); + $receiver = $container->get(UserFactoryInterface::class)->loadUserById($user_id); // Load language for messaging - $lang = Factory::getContainer()->get(LanguageFactoryInterface::class)->createLanguage($user->getParam('admin_language', $default_language), $debug); + $lang = $container->get(LanguageFactoryInterface::class)->createLanguage($user->getParam('admin_language', $defaultLanguage), $debug); $lang->load('plg_workflow_notification'); $messageText = sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'), $title, $user->name, $lang->_($toStage)); @@ -254,7 +255,7 @@ private function getUsersFromGroup($data): Array if (!empty($groups)) { // UserIds from usergroups - $model = Factory::getApplication()->bootComponent('com_users') + $model = Factory::getApplication()->bootComponent('com_users') ->getMVCFactory()->createModel('Users', 'Administrator', ['ignore_request' => true]); $model->setState('list.select', 'id'); @@ -329,10 +330,10 @@ private function removeLocked(array $userIds): Array $query = $this->db->getQuery(true); $query->select($this->db->quoteName('user_id')) - ->from($this->db->quoteName('#__messages_cfg')) - ->whereIn($this->db->quoteName('user_id'), $userIds) - ->where($this->db->quoteName('cfg_name') . ' = ' . $this->db->quote('locked')) - ->where($this->db->quoteName('cfg_value') . ' = 1'); + ->from($this->db->quoteName('#__messages_cfg')) + ->whereIn($this->db->quoteName('user_id'), $userIds) + ->where($this->db->quoteName('cfg_name') . ' = ' . $this->db->quote('locked')) + ->where($this->db->quoteName('cfg_value') . ' = 1'); $locked = $this->db->setQuery($query)->loadColumn(); diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 26310a2b38b14..6576eea577afe 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -156,7 +156,7 @@ protected function enhanceItemForm(Form $form, $data) $modelName = $component->getModelName($context); $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) - ->getTable(); + ->getTable(); $fieldname = $table->getColumnAlias('published'); @@ -301,7 +301,8 @@ public function onWorkflowBeforeTransition(WorkflowTransitionEvent $event) $context, $pks, $value - ]); + ] + ); // Release whitelist, the job is done $this->app->set('plgWorkflowPublishing.' . $context, []); @@ -399,7 +400,9 @@ public function onContentBeforeChangeState(EventInterface $event) public function onContentBeforeSave(EventInterface $event) { $context = $event->getArgument('0'); - /* @var TableInterface */ + + // @var TableInterface + $table = $event->getArgument('1'); $isNew = $event->getArgument('2'); $data = $event->getArgument('3'); From bf43a614663f99f357fa58264b015b843c56f7b8 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Tue, 26 May 2020 02:22:10 +0200 Subject: [PATCH 59/90] Add context selector for workflow (#104) --- .../src/Extension/ContentComponent.php | 18 +++++ .../com_workflow/forms/filter_workflows.xml | 10 ++- .../src/Field/WorkflowcontextsField.php | 70 +++++++++++++++++++ .../com_workflow/src/Model/WorkflowsModel.php | 22 ++++++ .../com_workflow/tmpl/workflows/default.php | 3 +- .../src/Workflow/WorkflowServiceInterface.php | 9 +++ 6 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 administrator/components/com_workflow/src/Field/WorkflowcontextsField.php diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index 8a41c6f4cde1c..dbb0729887c87 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -177,6 +177,24 @@ public function getContexts(): array return $contexts; } + /** + * Returns valid contexts + * + * @return array + * + * @since 4.0.0 + */ + public function getWorkflowContexts(): array + { + Factory::getLanguage()->load('com_content', JPATH_ADMINISTRATOR); + + $contexts = array( + 'com_content.article' => Text::_('COM_CONTENT') + ); + + return $contexts; + } + /** * Returns the table for the count items functions for the given section. * diff --git a/administrator/components/com_workflow/forms/filter_workflows.xml b/administrator/components/com_workflow/forms/filter_workflows.xml index cfd1063ba0274..e6c2915ce6efc 100644 --- a/administrator/components/com_workflow/forms/filter_workflows.xml +++ b/administrator/components/com_workflow/forms/filter_workflows.xml @@ -1,5 +1,13 @@ -
+ +
+ +
getOptions()) < 2) + { + $this->layout = 'joomla.form.field.hidden'; + } + + return parent::getInput(); + } + + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 4.0.0 + */ + protected function getOptions() + { + $parts = explode('.', $this->value); + + $component = Factory::getApplication()->bootComponent($parts[0]); + + if ($component instanceof WorkflowServiceInterface) + { + return $component->getWorkflowContexts(); + } + + return []; + } +} diff --git a/administrator/components/com_workflow/src/Model/WorkflowsModel.php b/administrator/components/com_workflow/src/Model/WorkflowsModel.php index b273b96cbd7e0..a05bb2b15ab02 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowsModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowsModel.php @@ -116,6 +116,28 @@ public function getItems() return $items; } + /** + * Get the filter form + * + * @param array $data data + * @param boolean $loadData load current data + * + * @return \JForm|false the JForm object or false + * + * @since 4.0.0 + */ + public function getFilterForm($data = array(), $loadData = true) + { + $form = parent::getFilterForm($data, $loadData); + + if ($form) + { + $form->setValue('extension', null, $this->getState('filter.extension')); + } + + return $form; + } + /** * Add the number of transitions and states to all workflow items * diff --git a/administrator/components/com_workflow/tmpl/workflows/default.php b/administrator/components/com_workflow/tmpl/workflows/default.php index 35466909617b6..18a1c08bcbd66 100644 --- a/administrator/components/com_workflow/tmpl/workflows/default.php +++ b/administrator/components/com_workflow/tmpl/workflows/default.php @@ -53,7 +53,7 @@
$this)); + echo LayoutHelper::render('joomla.searchtools.default', array('view' => $this, 'options' => array('selectorFieldName' => 'extension'))); ?> workflows)) : ?>
@@ -169,7 +169,6 @@ -
diff --git a/libraries/src/Workflow/WorkflowServiceInterface.php b/libraries/src/Workflow/WorkflowServiceInterface.php index e24713929b40b..5632fd6df7fac 100644 --- a/libraries/src/Workflow/WorkflowServiceInterface.php +++ b/libraries/src/Workflow/WorkflowServiceInterface.php @@ -80,4 +80,13 @@ public static function getConditions(string $extension): array; * @since 4.0.0 */ public function getWorkflowTableBySection(?string $section = null): string; + + /** + * Returns valid contexts. + * + * @return array + * + * @since 4.0.0 + */ + public function getWorkflowContexts(): array; } From 3bc6d86173ce94c41496946b6585e4370916c18a Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Tue, 26 May 2020 09:40:27 +0200 Subject: [PATCH 60/90] Fix update sql for extensions table (#105) Add missing column "locked", add helpful comment for the extensions table null dates. --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 13 +++++++++---- .../sql/updates/postgresql/4.0.0-2018-05-15.sql | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index e62912969180f..cebaf855873e7 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -123,11 +123,16 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` -- -- Creating extension entry -- +-- Note that the old pseudo null dates have to be used for the `checked_out_time` +-- column because the conversion to real null dates will be done with a later +-- update SQL script. +-- -INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); +INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); -- -- Creating Associations for existing content diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index f527001ebf5c8..507fb7dd7d8cf 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -119,11 +119,16 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" -- -- Creating extension entry -- +-- Note that the old pseudo null dates have to be used for the "checked_out_time" +-- column because the conversion to real null dates will be done with a later +-- update SQL script. +-- -INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); +INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); -- -- Creating Associations for existing content From 396e25efef8c0c7fefe8f4888604df80ab7118b8 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 26 May 2020 22:29:16 +0200 Subject: [PATCH 61/90] Add a11y features to the transition button --- administrator/language/en-GB/joomla.ini | 4 ++- layouts/joomla/button/transition-button.php | 37 ++++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index 3406c69420855..ed09fd99c1f34 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -139,7 +139,6 @@ JUNPROTECTED="Unprotected" JUNPUBLISHED="Unpublished" JVISIT_LINK="Visit Link" JVISIT_WEBSITE="Visit Website" -JWORKFLOW="Workflow: %s" JYEAR="Year" JVERSION="Version" JYES="Yes" @@ -999,8 +998,11 @@ JWARNING_REMOVE_ROOT_USER="You are logged-in using the emergency Root User setti JWARNING_REMOVE_ROOT_USER_ADMIN="The emergency Root User setting is enabled for the user(id): %s.
You should remove $root_user from the configuration.php as soon as you have restored control to your site to avoid future security breaches.
Select here to try to do it automatically." ; Workflow +JWORKFLOW="Workflow: %s" JWORKFLOW_TITLE="Workflow" JWORKFLOW_ENABLED_LABEL="Enable Workflow" +JWORKFLOW_EXECUTE_TRANSITION="Select the transition to execute on this item." +JWORKFLOW_SHOW_TRANSITIONS_FOR_THIS_ITEM="Show the transition selection to execute a transition on this item." JWORKFLOW_FUNCTIONALITY_CORE_STATE_LABEL="Enable Workflow state functionality" JWORKFLOW_FUNCTIONALITY_CORE_FEATURED_LABEL="Enable Workflow featured functionality" JWORKFLOW_EXTENSION_WHITELIST_LABEL="Extension Whitelist" diff --git a/layouts/joomla/button/transition-button.php b/layouts/joomla/button/transition-button.php index cb9bb9ded6be7..dabad81bcdcb0 100644 --- a/layouts/joomla/button/transition-button.php +++ b/layouts/joomla/button/transition-button.php @@ -8,6 +8,7 @@ */ use Joomla\CMS\HTML\HTMLHelper; +use Joomla\CMS\Language\Text; HTMLHelper::_('bootstrap.popover'); @@ -27,30 +28,42 @@ $tipContent = $options['tip_content']; $checkboxName = $options['checkbox_name']; ?> - - - + + > + -
- - - href="javascript://" +
+ + + - +
+ +
+
+ + + + +
+ + + escape($options['title'])), From 3cf5208b24c821549e5b1bc61843171c6d78228f Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Tue, 26 May 2020 22:33:35 +0200 Subject: [PATCH 62/90] Remove component workflow options (#107) --- .../components/com_content/config.xml | 25 ------------- administrator/language/en-GB/joomla.ini | 2 - .../src/Workflow/WorkflowPluginTrait.php | 2 +- .../src/Workflow/WorkflowServiceTrait.php | 37 ------------------- 4 files changed, 1 insertion(+), 65 deletions(-) diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml index 61b3a3c22d3dd..394da59bf83e8 100644 --- a/administrator/components/com_content/config.xml +++ b/administrator/components/com_content/config.xml @@ -1054,31 +1054,6 @@ - - - - - - - - - - -
isWorkflowActive($context) - || !$component->isFunctionalityActive($functionality, $context)) + || !$component->supportFunctionality($functionality, $context)) { return false; } diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index 6e8760c20faa0..a2a4906a23598 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -66,36 +66,6 @@ public function supportFunctionality($functionality, $context): bool return in_array($context, $this->supportedFunctionality[$functionality], true); } - /** - * Check if the functionality is activated in the component configuration - * - * @param string $functionality The functionality - * @param string $extension The extension - * - * @return boolean - * @throws \Exception - * - * @since 4.0.0 - */ - public function isFunctionalityActive($functionality, $extension): bool - { - if (!$this->isWorkflowActive($extension)) - { - return false; - } - - $parts = explode('.', $extension); - $config = ComponentHelper::getParams($parts[0]); - $option = 'workflow_functionality_' . str_replace('.', '_', $functionality); - - if (!$config->get($option, 1)) - { - return false; - } - - return true; - } - /** * Check if the functionality is used by a plugin * @@ -118,13 +88,6 @@ public function isFunctionalityUsed($functionality, $extension): bool return $used[$cacheKey]; } - if (!$this->isFunctionalityActive($functionality, $extension)) - { - $used[$cacheKey] = false; - - return $used[$cacheKey]; - } - // The container to get the services from $app = Factory::getApplication(); From 18b84a7d1cc466f51fc18180707d2ac067a13d1f Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 26 May 2020 22:44:01 +0200 Subject: [PATCH 63/90] Fix broken mobile headline in articles list --- administrator/components/com_content/tmpl/articles/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index e33f9c553af7d..9e92b78addce4 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -119,7 +119,7 @@ -
From 38c0cb251a0022ef4d094cba1a0610a12d754df1 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 26 May 2020 23:09:12 +0200 Subject: [PATCH 64/90] Improve notification description text --- administrator/language/en-GB/plg_workflow_notification.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/language/en-GB/plg_workflow_notification.ini b/administrator/language/en-GB/plg_workflow_notification.ini index 162306c97b3a5..174ca1058f40e 100644 --- a/administrator/language/en-GB/plg_workflow_notification.ini +++ b/administrator/language/en-GB/plg_workflow_notification.ini @@ -17,7 +17,7 @@ PLG_WORKFLOW_NOTIFICATION_RECEIVERS_LABEL="More Receivers" PLG_WORKFLOW_NOTIFICATION_RECEIVERS_SELECT="Select single receivers for the notification" PLG_WORKFLOW_NOTIFICATION_SENDMAIL_LABEL="Send Notification" PLG_WORKFLOW_NOTIFICATION_SENT="Notifications have been sent" -PLG_WORKFLOW_NOTIFICATION_USERGROUP_DESC="The users in this usergroup get an E-Mail if this transition has been performed" +PLG_WORKFLOW_NOTIFICATION_USERGROUP_DESC="The users in this usergroup get a notification if this transition has been performed" PLG_WORKFLOW_NOTIFICATION_USERGROUP_LABEL="Usergroups" PLG_WORKFLOW_NOTIFICATION_USERGROUP_SELECT="Select usergroups" PLG_WORKFLOW_NOTIFICATION_XML_DESCRIPTION="Send Notification if a Transition has been performed in a Workflow" From dab457ddb0c49feca0883a5168c986fc8d67633f Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Tue, 26 May 2020 23:13:54 +0200 Subject: [PATCH 65/90] Change text (#109) --- administrator/language/en-GB/com_workflow.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/language/en-GB/com_workflow.ini b/administrator/language/en-GB/com_workflow.ini index f4d685a410e9d..47c1ea6f62070 100644 --- a/administrator/language/en-GB/com_workflow.ini +++ b/administrator/language/en-GB/com_workflow.ini @@ -26,7 +26,7 @@ COM_WORKFLOW_DEFAULT_ITEM="Default option is already set for a different item." COM_WORKFLOW_BASIC_WORKFLOW="Basic Workflow" COM_WORKFLOW_DESCRIPTION="Description" COM_WORKFLOW_DESC_TAB="Description" -COM_WORKFLOW_DISABLE_DEFAULT="Cannot change default stage of this item." +COM_WORKFLOW_DISABLE_DEFAULT="The default status cannot be changed." COM_WORKFLOW_EDIT="Edit" COM_WORKFLOW_EDIT_TAB="Edit" COM_WORKFLOW_ERROR_EXTENSION_NOT_SET="Extension not set." @@ -120,7 +120,7 @@ COM_WORKFLOW_TRANSITION_NOTE="Note" COM_WORKFLOW_TRANSITION_THE_SAME_STAGE="Current stage and target stage are the same." COM_WORKFLOW_TRASHED="Trashed" COM_WORKFLOW_UNPUBLISHED="Unpublished" -COM_WORKFLOW_UNPUBLISH_DEFAULT_ERROR="You can't unpublish the default workflow." +COM_WORKFLOW_UNPUBLISH_DEFAULT_ERROR="The default workflow cannot be disabled." COM_WORKFLOW_USER_GROUPS="User Group" COM_WORKFLOW_USER_GROUPS_DESC="Select user group." COM_WORKFLOW_USE_DEFAULT_WORKFLOW="Use default (%s)" From fb859c1f3a5d427f8cac0b6878802c42e0e13e4c Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Tue, 26 May 2020 22:16:56 +0100 Subject: [PATCH 66/90] Code style (#111) really minor but best to fix it before quy picks up on it ;) --- plugins/workflow/featuring/forms/action.xml | 2 +- plugins/workflow/publishing/forms/action.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/workflow/featuring/forms/action.xml b/plugins/workflow/featuring/forms/action.xml index 02d9e95b0e676..9108b81c86bd0 100644 --- a/plugins/workflow/featuring/forms/action.xml +++ b/plugins/workflow/featuring/forms/action.xml @@ -8,7 +8,7 @@ label="PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_LABEL" description="PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_DESC" default="" - > + > diff --git a/plugins/workflow/publishing/forms/action.xml b/plugins/workflow/publishing/forms/action.xml index 2cc0f2e24156c..6c1fd15f6ff3c 100644 --- a/plugins/workflow/publishing/forms/action.xml +++ b/plugins/workflow/publishing/forms/action.xml @@ -11,7 +11,7 @@ description="PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DESC" default="" hide_all="true" - > + > From 85b392de2ac80dfea68b3602b64e9eaea4d4426e Mon Sep 17 00:00:00 2001 From: George Wilson Date: Tue, 26 May 2020 22:18:09 +0100 Subject: [PATCH 67/90] Fix missing import in access exception (#110) --- .../components/com_workflow/src/Dispatcher/Dispatcher.php | 1 + 1 file changed, 1 insertion(+) diff --git a/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php b/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php index b30e6ee24bbc5..2e4c7e8c22a8d 100644 --- a/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php +++ b/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php @@ -11,6 +11,7 @@ \defined('_JEXEC') or die; +use Joomla\CMS\Access\Exception\NotAllowed use Joomla\CMS\Dispatcher\ComponentDispatcher; /** From 309cc808b29b10e5d6d71a9996fd133d7baab87c Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 26 May 2020 23:23:09 +0200 Subject: [PATCH 68/90] Fix wrong language key --- administrator/components/com_workflow/tmpl/transition/edit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/tmpl/transition/edit.php b/administrator/components/com_workflow/tmpl/transition/edit.php index 857e8749d7b7a..0682d7600ed52 100644 --- a/administrator/components/com_workflow/tmpl/transition/edit.php +++ b/administrator/components/com_workflow/tmpl/transition/edit.php @@ -33,7 +33,7 @@ 'details')); ?> - +
From 1ca624c428da025a40ecb683e13116eee5043254 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Tue, 26 May 2020 23:26:03 +0200 Subject: [PATCH 69/90] Add Workflow Component Sections Field (#108) * Remove component workflow options * Fix pagenavigation query * Add Workflow Component Sections Field * cs --- administrator/language/en-GB/joomla.ini | 6 +- .../Field/WorkflowComponentSectionsField.php | 67 +++++++++++++++++++ .../src/Workflow/WorkflowPluginTrait.php | 16 ++--- .../content/pagenavigation/pagenavigation.php | 1 - plugins/workflow/featuring/featuring.xml | 8 ++- .../workflow/notification/notification.xml | 8 ++- plugins/workflow/publishing/publishing.xml | 8 ++- 7 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 libraries/src/Form/Field/WorkflowComponentSectionsField.php diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index c434610c1869d..6e345c18c637c 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -1004,10 +1004,10 @@ JWORKFLOW_ENABLED_LABEL="Enable Workflow" JWORKFLOW_EXECUTE_TRANSITION="Select the transition to execute on this item." JWORKFLOW_SHOW_TRANSITIONS_FOR_THIS_ITEM="Show the transition selection to execute a transition on this item." JWORKFLOW_EXTENSION_WHITELIST_LABEL="Extension Whitelist" -JWORKFLOW_EXTENSION_WHITELIST_DESCRIPTION="Activate this plugin only for listed extensions. One extension per line (ex. com_content.article). If used all other extensions are disabled." +JWORKFLOW_EXTENSION_WHITELIST_DESCRIPTION="Activate this plugin only for listed extensions. If used all other extensions are disabled." JWORKFLOW_EXTENSION_BLACKLIST_LABEL="Extension Blacklist" -JWORKFLOW_EXTENSION_BLACKLIST_DESCRIPTION="Disable this plugin for listed extensions. One extension per line (ex. com_content.article)." - +JWORKFLOW_EXTENSION_BLACKLIST_DESCRIPTION="Disable this plugin for listed extensions." +JWORKFLOW_FIELD_COMPONENT_SECTIONS_TEXT="%1$s: %2$s" ; Date format DATE_FORMAT_LC="l, d F Y" diff --git a/libraries/src/Form/Field/WorkflowComponentSectionsField.php b/libraries/src/Form/Field/WorkflowComponentSectionsField.php new file mode 100644 index 0000000000000..79e37286196fd --- /dev/null +++ b/libraries/src/Form/Field/WorkflowComponentSectionsField.php @@ -0,0 +1,67 @@ +value, 0, 4) !== 'com_') + { + continue; + } + $component = $app->bootComponent($item->value); + + if (!($component instanceof WorkflowServiceInterface)) + { + continue; + } + + foreach ($component->getWorkflowContexts() as $extension => $text) + { + $options[] = HTMLHelper::_('select.option', $extension, Text::sprintf('JWORKFLOW_FIELD_COMPONENT_SECTIONS_TEXT', $item->text, $text)); + } + } + + return $options; + } +} diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index ebf5e55c22c87..a784a9f7c42d4 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -100,14 +100,14 @@ protected function isSupported($context) */ protected function checkWhiteAndBlacklist($context) { - $whitelist = \trim($this->params->get('whitelist', '')); - $blacklist = \trim($this->params->get('blacklist', '')); + $whitelist = $this->params->get('whitelist', []); + $blacklist = $this->params->get('blacklist', []); - if (!empty($whitelist)) + if (\is_array($whitelist)) { - foreach (\explode(\chr(10), $whitelist) as $allowed) + foreach ($whitelist as $allowed) { - if ($context === \trim($allowed)) + if ($context === $allowed) { return true; } @@ -116,11 +116,11 @@ protected function checkWhiteAndBlacklist($context) return false; } - if (!empty($blacklist)) + if (\is_array($blacklist)) { - foreach (\explode(\chr(10), $blacklist) as $allowed) + foreach ($blacklist as $allowed) { - if ($context === \trim($allowed)) + if ($context === $allowed) { return false; } diff --git a/plugins/content/pagenavigation/pagenavigation.php b/plugins/content/pagenavigation/pagenavigation.php index 7641ffcc7b2f1..50e07a6be1f65 100644 --- a/plugins/content/pagenavigation/pagenavigation.php +++ b/plugins/content/pagenavigation/pagenavigation.php @@ -183,7 +183,6 @@ public function onContentBeforeDisplay($context, &$row, &$params, $page = 0) $query->where( [ - '(' . $db->quoteName('ws.condition') . ' = 1 OR ' . $db->quoteName('ws.condition') . ' = -2)', '(' . $db->quoteName('publish_up') . ' IS NULL OR ' . $db->quoteName('publish_up') . ' <= :nowDate1)', '(' . $db->quoteName('publish_down') . ' IS NULL OR ' . $db->quoteName('publish_down') . ' >= :nowDate2)', ] diff --git a/plugins/workflow/featuring/featuring.xml b/plugins/workflow/featuring/featuring.xml index 5f652d50d7ca3..ce6f529c61870 100644 --- a/plugins/workflow/featuring/featuring.xml +++ b/plugins/workflow/featuring/featuring.xml @@ -21,15 +21,19 @@
diff --git a/plugins/workflow/notification/notification.xml b/plugins/workflow/notification/notification.xml index 0d28bf15ee802..6ff63442f3f2f 100644 --- a/plugins/workflow/notification/notification.xml +++ b/plugins/workflow/notification/notification.xml @@ -21,15 +21,19 @@
diff --git a/plugins/workflow/publishing/publishing.xml b/plugins/workflow/publishing/publishing.xml index e6741ec396768..648194d180361 100644 --- a/plugins/workflow/publishing/publishing.xml +++ b/plugins/workflow/publishing/publishing.xml @@ -21,15 +21,19 @@
From 8bb999c5582c6585ab00de0560445818a2adcdb4 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Tue, 26 May 2020 23:38:51 +0200 Subject: [PATCH 70/90] Hide workflow menu item if workflow is disabled for the extension --- administrator/modules/mod_menu/src/Menu/CssMenu.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/administrator/modules/mod_menu/src/Menu/CssMenu.php b/administrator/modules/mod_menu/src/Menu/CssMenu.php index d25d717b4a690..b685831fe977b 100644 --- a/administrator/modules/mod_menu/src/Menu/CssMenu.php +++ b/administrator/modules/mod_menu/src/Menu/CssMenu.php @@ -376,7 +376,9 @@ protected function preprocess($parent) if (isset($query['extension'])) { - $workflow = ComponentHelper::getParams($query['extension'])->get('workflow_enabled', 1); + $parts = explode('.', $query['extension']); + + $workflow = ComponentHelper::getParams($parts[0])->get('workflow_enabled', 1); } if (!$workflow) From a3bf93be982f5aae630506fa9ba4414319d229e4 Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Tue, 26 May 2020 22:41:55 +0100 Subject: [PATCH 71/90] George broke it (#112) Fix missing ; from @wilsonge code --- .../components/com_workflow/src/Dispatcher/Dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php b/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php index 2e4c7e8c22a8d..792a1a263e96d 100644 --- a/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php +++ b/administrator/components/com_workflow/src/Dispatcher/Dispatcher.php @@ -11,7 +11,7 @@ \defined('_JEXEC') or die; -use Joomla\CMS\Access\Exception\NotAllowed +use Joomla\CMS\Access\Exception\NotAllowed; use Joomla\CMS\Dispatcher\ComponentDispatcher; /** From 596bc11663aa265a9c76315b3091f5e2dbb0cfa5 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Wed, 27 May 2020 00:08:35 +0200 Subject: [PATCH 72/90] Fix White/Blacklist (#113) --- .../src/Form/Field/WorkflowComponentSectionsField.php | 7 ++++--- libraries/src/Workflow/WorkflowPluginTrait.php | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/src/Form/Field/WorkflowComponentSectionsField.php b/libraries/src/Form/Field/WorkflowComponentSectionsField.php index 79e37286196fd..09270a5e336bf 100644 --- a/libraries/src/Form/Field/WorkflowComponentSectionsField.php +++ b/libraries/src/Form/Field/WorkflowComponentSectionsField.php @@ -39,9 +39,10 @@ class WorkflowComponentSectionsField extends ComponentsField */ protected function getOptions() { - $items = parent::getOptions(); - $options = []; - $app = Factory::getApplication(); + $app = Factory::getApplication(); + $items = parent::getOptions(); + $options = []; + $options[] = HTMLHelper::_('select.option', ' ', Text::_('JNONE')); foreach($items as $item) { diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index a784a9f7c42d4..3b9ac042322e6 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -103,7 +103,7 @@ protected function checkWhiteAndBlacklist($context) $whitelist = $this->params->get('whitelist', []); $blacklist = $this->params->get('blacklist', []); - if (\is_array($whitelist)) + if (!empty($whitelist) && \is_array($whitelist)) { foreach ($whitelist as $allowed) { @@ -116,11 +116,11 @@ protected function checkWhiteAndBlacklist($context) return false; } - if (\is_array($blacklist)) + if (!empty($blacklist) && \is_array($blacklist)) { - foreach ($blacklist as $allowed) + foreach ($blacklist as $forbidden) { - if ($context === $allowed) + if ($context === $forbidden) { return false; } From a70f1ad21a937e261cd0cbf015de48c0dcaaf1b1 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Wed, 27 May 2020 00:23:36 +0200 Subject: [PATCH 73/90] Fix White/Blacklist (#114) --- libraries/src/Workflow/WorkflowPluginTrait.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/src/Workflow/WorkflowPluginTrait.php b/libraries/src/Workflow/WorkflowPluginTrait.php index 3b9ac042322e6..2442042a14470 100644 --- a/libraries/src/Workflow/WorkflowPluginTrait.php +++ b/libraries/src/Workflow/WorkflowPluginTrait.php @@ -100,10 +100,10 @@ protected function isSupported($context) */ protected function checkWhiteAndBlacklist($context) { - $whitelist = $this->params->get('whitelist', []); - $blacklist = $this->params->get('blacklist', []); + $whitelist = \array_filter((array) $this->params->get('whitelist', [])); + $blacklist = \array_filter((array) $this->params->get('blacklist', [])); - if (!empty($whitelist) && \is_array($whitelist)) + if (!empty($whitelist)) { foreach ($whitelist as $allowed) { @@ -116,14 +116,11 @@ protected function checkWhiteAndBlacklist($context) return false; } - if (!empty($blacklist) && \is_array($blacklist)) + foreach ($blacklist as $forbidden) { - foreach ($blacklist as $forbidden) + if ($context === $forbidden) { - if ($context === $forbidden) - { - return false; - } + return false; } } From b53334a74449dc3345cf68e4ebd4e7cfb5d4b5a6 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 27 May 2020 00:27:53 +0200 Subject: [PATCH 74/90] Improve notification plugin languages --- .../language/en-GB/plg_workflow_notification.ini | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/administrator/language/en-GB/plg_workflow_notification.ini b/administrator/language/en-GB/plg_workflow_notification.ini index 174ca1058f40e..b73cc705d650c 100644 --- a/administrator/language/en-GB/plg_workflow_notification.ini +++ b/administrator/language/en-GB/plg_workflow_notification.ini @@ -5,16 +5,13 @@ COM_WORKFLOW_NOTIFICATION_FIELDSET_LABEL="Notification" PLG_WORKFLOW_NOTIFICATION="Workflow - Notification" -PLG_WORKFLOW_NOTIFICATION_ADDTEXT="The state has changed" -PLG_WORKFLOW_NOTIFICATION_ADDTEXT_AUTHOR_DESC="You can localise the text by using a Language key and make language overrides." -PLG_WORKFLOW_NOTIFICATION_ADDTEXT_AUTHOR_LABEL="Additional Message to Author" -PLG_WORKFLOW_NOTIFICATION_ADDTEXT_DESC="You can localise the text by using a Language key and make language overrides." -PLG_WORKFLOW_NOTIFICATION_ADDTEXT_LABEL="Additional Message Text" -PLG_WORKFLOW_NOTIFICATION_EMAIL_AUTHOR_LABEL="Email the Author" +PLG_WORKFLOW_NOTIFICATION_ADDTEXT="The stage has changed" +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_DESC="This text will be sent: Title [title], Changed by [user], New State: [state]. You can add own Text to this information. You can localise the Text by using a Language key and make language overrides." +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_LABEL="Additional Message Text." PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_SUBJECT="The status of an '%1$s' has been changed"; PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG="Title: '%1$s', Changed by '%2$s', New State: '%3$s'." -PLG_WORKFLOW_NOTIFICATION_RECEIVERS_LABEL="More Receivers" -PLG_WORKFLOW_NOTIFICATION_RECEIVERS_SELECT="Select single receivers for the notification" +PLG_WORKFLOW_NOTIFICATION_RECEIVERS_LABEL="Users" +PLG_WORKFLOW_NOTIFICATION_RECEIVERS_SELECT="Select single Users who obtain a Notification" PLG_WORKFLOW_NOTIFICATION_SENDMAIL_LABEL="Send Notification" PLG_WORKFLOW_NOTIFICATION_SENT="Notifications have been sent" PLG_WORKFLOW_NOTIFICATION_USERGROUP_DESC="The users in this usergroup get a notification if this transition has been performed" From df7a8e20714fefb50459cb34e35f8ab6350e69b7 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 27 May 2020 01:57:36 +0200 Subject: [PATCH 75/90] Fix codestyle --- libraries/src/Form/Field/WorkflowComponentSectionsField.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/src/Form/Field/WorkflowComponentSectionsField.php b/libraries/src/Form/Field/WorkflowComponentSectionsField.php index 09270a5e336bf..00c755cae805d 100644 --- a/libraries/src/Form/Field/WorkflowComponentSectionsField.php +++ b/libraries/src/Form/Field/WorkflowComponentSectionsField.php @@ -44,12 +44,13 @@ protected function getOptions() $options = []; $options[] = HTMLHelper::_('select.option', ' ', Text::_('JNONE')); - foreach($items as $item) + foreach ($items as $item) { if (substr($item->value, 0, 4) !== 'com_') { continue; } + $component = $app->bootComponent($item->value); if (!($component instanceof WorkflowServiceInterface)) From 17caeaf8b49d3f171d1804201bef8bb0f0cb4fbc Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Wed, 27 May 2020 08:34:57 +0100 Subject: [PATCH 76/90] [WF] alpha sort language strings (#115) --- administrator/language/en-GB/plg_workflow_featuring.ini | 6 +++--- administrator/language/en-GB/plg_workflow_publishing.ini | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/administrator/language/en-GB/plg_workflow_featuring.ini b/administrator/language/en-GB/plg_workflow_featuring.ini index f7c2303092ab4..21cb6e0e62527 100644 --- a/administrator/language/en-GB/plg_workflow_featuring.ini +++ b/administrator/language/en-GB/plg_workflow_featuring.ini @@ -4,8 +4,8 @@ ; Note : All ini files need to be saved as UTF-8 PLG_WORKFLOW_FEATURING="Workflow - Featuring" -PLG_WORKFLOW_FEATURING_XML_DESCRIPTION="Add featuring actions to the workflow transitions for your items" -PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_LABEL="Featuring state" -PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_DESC="Define the featured state an item should be set, when executing this transition" PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the featured state of this item. Please use a workflow transition." PLG_WORKFLOW_FEATURING_FEATURED="Featured: %s" +PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_DESC="Define the featured state an item should be set, when executing this transition" +PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_LABEL="Featuring state" +PLG_WORKFLOW_FEATURING_XML_DESCRIPTION="Add featuring actions to the workflow transitions for your items" diff --git a/administrator/language/en-GB/plg_workflow_publishing.ini b/administrator/language/en-GB/plg_workflow_publishing.ini index 8c1ed8dbcdcc9..409a97882a65f 100644 --- a/administrator/language/en-GB/plg_workflow_publishing.ini +++ b/administrator/language/en-GB/plg_workflow_publishing.ini @@ -4,9 +4,9 @@ ; Note : All ini files need to be saved as UTF-8 PLG_WORKFLOW_PUBLISHING="Workflow - Publishing" -PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing actions to the workflow transitions for your items" -PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_LABEL="Publishing state" -PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" -PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change -" PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the publishing state of this item. Please use a workflow transition." PLG_WORKFLOW_PUBLISHING_PUBLISHED="Status: %s" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change -" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_LABEL="Publishing state" +PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing actions to the workflow transitions for your items" From de6f4f9d50204174e082b63eacb2757107749a60 Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Wed, 27 May 2020 08:50:09 +0100 Subject: [PATCH 77/90] [wf] column headers on mobile (#116) * [wf] workflows list mobile columns * stages list * transitions list * Update administrator/components/com_workflow/tmpl/stages/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/stages/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/transitions/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/workflows/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/workflows/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/transitions/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/transitions/default.php Co-authored-by: Benjamin Trenkle * Update administrator/components/com_workflow/tmpl/stages/default.php Co-authored-by: Benjamin Trenkle Co-authored-by: Benjamin Trenkle --- .../components/com_workflow/tmpl/stages/default.php | 6 +++--- .../components/com_workflow/tmpl/transitions/default.php | 6 +++--- .../components/com_workflow/tmpl/workflows/default.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/administrator/components/com_workflow/tmpl/stages/default.php b/administrator/components/com_workflow/tmpl/stages/default.php index be7d0f440a2e7..0edf930c67cd8 100644 --- a/administrator/components/com_workflow/tmpl/stages/default.php +++ b/administrator/components/com_workflow/tmpl/stages/default.php @@ -66,13 +66,13 @@
- - - - - - - -
,
id); ?> @@ -221,30 +202,34 @@ ?> -
-
- +
+ $transitions, - 'stage' => Text::_($item->stage_title), - 'id' => (int) $item->id - ]; + $options = [ + 'transitions' => $transitions, + 'stage' => Text::_($item->stage_title), + 'id' => (int) $item->id + ]; - echo (new PublishedButton) - ->removeState(0) - ->removeState(1) - ->removeState(2) - ->removeState(-2) - ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) - ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) - ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) - ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) - ->setLayout('joomla.button.transition-button') - ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); - ?> -
+ echo (new PublishedButton) + ->removeState(0) + ->removeState(1) + ->removeState(2) + ->removeState(-2) + ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) + ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) + ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) + ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) + ->setLayout('joomla.button.transition-button') + ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + ?>
+ state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); + endif; + ?>
@@ -385,6 +370,10 @@ + + + + diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 6911ef9159dbd..662cff211db07 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -13,6 +13,7 @@ use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; +use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Workflow\Workflow; use Joomla\CMS\Table\Category; diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index 7004c3647fbf5..db381fbe36025 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -174,6 +174,7 @@ public function executeTransition(array $pks, int $transition_id): bool $db->quoteName('t.to_stage_id'), $db->quoteName('t.from_stage_id'), $db->quoteName('t.options'), + $db->quoteName('t.workflow_id'), ] ) ->from($db->quoteName('#__workflow_transitions', 't')) @@ -196,7 +197,8 @@ public function executeTransition(array $pks, int $transition_id): bool { $assoc = $this->getAssociation($pk); - if (!\in_array($transition->from_stage_id, [-1, $assoc->stage_id])) + // The transition has to be in the same workflow + if (!\in_array($transition->from_stage_id, [$assoc->stage_id, -1]) || $transition->workflow_id !== $assoc->workflow_id) { return false; } @@ -363,13 +365,16 @@ public function getAssociation(int $item_id): ?\stdClass $query->select( [ - $db->quoteName('item_id'), - $db->quoteName('stage_id'), + $db->quoteName('a.item_id'), + $db->quoteName('a.stage_id'), + $db->quoteName('s.workflow_id'), ] ) - ->from($db->quoteName('#__workflow_associations')) + ->from($db->quoteName('#__workflow_associations', 'a')) + ->innerJoin($db->quoteName('#__workflow_stages', 's')) ->where( [ + $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id'), $db->quoteName('item_id') . ' = :id', $db->quoteName('extension') . ' = :extension', ] From dee4961f7a11d07e9aa3c77bc21460b7ade726cf Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 29 Apr 2020 02:39:32 +0200 Subject: [PATCH 24/90] Fix wrong context when deleting a workflow --- .../com_workflow/src/Controller/WorkflowsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/src/Controller/WorkflowsController.php b/administrator/components/com_workflow/src/Controller/WorkflowsController.php index b3e776a3aa407..473c30f92ded5 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowsController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowsController.php @@ -184,7 +184,7 @@ public function delete() $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list - . '&extension=' . $this->extension, false + . $this->getRedirectToListAppend(), false ) ); } From 10b447dace10a2b3156806a7a026f5546b44a0fd Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 29 Apr 2020 02:42:15 +0200 Subject: [PATCH 25/90] Remove unnecessary delete method in workflow --- .../src/Controller/WorkflowsController.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/administrator/components/com_workflow/src/Controller/WorkflowsController.php b/administrator/components/com_workflow/src/Controller/WorkflowsController.php index 473c30f92ded5..64713e104ef95 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowsController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowsController.php @@ -171,24 +171,6 @@ public function setDefault() ); } - /** - * Deletes and returns correctly. - * - * @return void - * - * @since 4.0.0 - */ - public function delete() - { - parent::delete(); - $this->setRedirect( - Route::_( - 'index.php?option=' . $this->option . '&view=' . $this->view_list - . $this->getRedirectToListAppend(), false - ) - ); - } - /** * Gets the URL arguments to append to a list redirect. * From 914b93b5af9bcdc0de5f6566d6a494cb93e64860 Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Thu, 30 Apr 2020 02:09:41 +0200 Subject: [PATCH 26/90] Redirect after featue/unfeature workflow (#75) --- .../com_workflow/src/Controller/WorkflowsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/src/Controller/WorkflowsController.php b/administrator/components/com_workflow/src/Controller/WorkflowsController.php index 64713e104ef95..b9ab826633382 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowsController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowsController.php @@ -166,7 +166,7 @@ public function setDefault() $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list - . '&extension=' . $this->extension, false + . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''), false ) ); } From d010c6eabd8f2ce237ecd2a8a09562e921b29b45 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Thu, 30 Apr 2020 02:10:12 +0200 Subject: [PATCH 27/90] Fixing Codestyle (#77) --- .../js/admin-items-workflow-buttons.es6.js | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js index 126b2f15d1902..3fdb8bbccb399 100644 --- a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js +++ b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js @@ -45,42 +45,36 @@ Joomla.toggleAllNextElements = (element, className) => { const itemList = [].slice.call(document.querySelectorAll('table.itemList'))[0]; let itemListRows = []; - let transition_ids = []; + let transitionIds = []; if (itemList) { itemListRows = [].slice.call(itemList.querySelectorAll('tbody tr')); } function enableTransitions() { - if (transition_ids.length) - { - let availableTrans = transition_ids.shift(); + if (transitionIds.length) { + let availableTrans = transitionIds.shift(); - while(transition_ids.length) - { - const compareTrans = transition_ids.shift(); + while (transitionIds.length) { + const compareTrans = transitionIds.shift(); - availableTrans = availableTrans.filter((id) => {return compareTrans.indexOf(id) !== -1}); + availableTrans = availableTrans.filter((id) => compareTrans.indexOf(id) !== -1); } - if (availableTrans.length) - { - if (headline) - { + if (availableTrans.length) { + if (headline) { headline.classList.remove('d-none'); } - if (separator) - { + if (separator) { separator.classList.remove('d-none'); } } availableTrans.forEach((trans) => { - const elem = dropDownBtn.querySelector('.transition-' + trans); + const elem = dropDownBtn.querySelector(`.transition-${trans}`); - if (elem) - { - elem.parentNode.classList.remove('d-none') + if (elem) { + elem.parentNode.classList.remove('d-none'); } }); } @@ -89,7 +83,7 @@ Joomla.toggleAllNextElements = (element, className) => { // check for common attributes for which the conditions for a transition are possible or not // and save this information in a boolean variable. function collectTransitions(row) { - transition_ids.push(row.getAttribute('data-transitions').split(',')); + transitionIds.push(row.getAttribute('data-transitions').split(',')); } // listen to click event to get selected rows @@ -98,15 +92,13 @@ Joomla.toggleAllNextElements = (element, className) => { transitions.forEach((trans) => { trans.parentNode.classList.add('d-none'); }); - if (headline) - { + if (headline) { headline.classList.add('d-none'); } - if (separator) - { + if (separator) { separator.classList.add('d-none'); } - transition_ids = []; + transitionIds = []; itemListRows.forEach((el) => { const checkedBox = el.querySelectorAll('input[type=checkbox]')[0]; if (checkedBox.checked) { From 8876096f9ae0c7af211ebc8e4f8b55ed95135f91 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Thu, 30 Apr 2020 12:12:53 +0200 Subject: [PATCH 28/90] Add missing namespace for database parameter type --- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 662cff211db07..7b13225f52469 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -10,6 +10,7 @@ \defined('JPATH_PLATFORM') or die; +use Joomla\Database\ParameterType; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; From 471fbe2b4a39eea8afb237d414c9794126e94297 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 1 May 2020 06:47:58 +0200 Subject: [PATCH 29/90] Display publishing dropdown as text only in item form view --- .../en-GB/plg_workflow_publishing.ini | 1 + plugins/workflow/publishing/publishing.php | 38 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/administrator/language/en-GB/plg_workflow_publishing.ini b/administrator/language/en-GB/plg_workflow_publishing.ini index ba30a4cd2228f..9cdffd85611b8 100644 --- a/administrator/language/en-GB/plg_workflow_publishing.ini +++ b/administrator/language/en-GB/plg_workflow_publishing.ini @@ -10,3 +10,4 @@ PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_LABEL="Publishing state" PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change" PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the publishing state of this item. Please use a workflow transition." +PLG_WORKFLOW_PUBLISHING_PUBLISHED="Status: %s" diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 82e282b24be98..f38dea91fd3d3 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -148,7 +148,43 @@ protected function enhanceItemForm(Form $form, $data) $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) ->getTable(); - $form->setFieldAttribute($table->getColumnAlias('published'), 'disabled', 'true'); + $fieldname = $table->getColumnAlias('published'); + + $options = $form->getField($fieldname)->options; + + $value = isset($data->$fieldname) ? $data->$fieldname : $form->getValue($fieldname, null, 0); + + $text = '-'; + + $textclass = 'body'; + + switch ($value) + { + case 1: + $textclass = 'success'; + break; + + case 0: + case -2: + $textclass = 'danger'; + } + + if (!empty($options)) + { + foreach ($options as $option) + { + if ($option->value == $value) + { + $text = $option->text; + + break; + } + } + } + + $form->setFieldAttribute($fieldname, 'type', 'spacer'); + + $form->setFieldAttribute($fieldname, 'label', Text::sprintf('PLG_WORKFLOW_PUBLISHING_PUBLISHED', '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . '')); return true; } From b4a2011208d2adad5b2f5c0b987e6b18f6bc93ae Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 1 May 2020 06:48:47 +0200 Subject: [PATCH 30/90] Reset workflow if batch copy is called --- .../com_content/src/Model/ArticleModel.php | 5 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 139 ++++++++++++------ .../src/MVC/Model/WorkflowModelInterface.php | 12 ++ 3 files changed, 106 insertions(+), 50 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index 3904c7205ef46..7c76d37f80b72 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -124,10 +124,7 @@ protected function cleanupPostBatchCopy(TableInterface $table, $newId, $oldId) } } - // Copy workflow association - $assoc = $this->workflow->getAssociation((int) $oldId); - - $this->workflow->createAssociation((int) $newId, (int) $assoc->stage_id); + $this->workflowCleanupBatchMove($oldId, $newId); // Register FieldsHelper \JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php'); diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 7b13225f52469..dda4670b6c9e1 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -198,6 +198,84 @@ public function workflowAfterSave($data) } } + /** + * Batch change workflow stage or current. + * + * @param integer $value The workflow stage ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 4.0.0 + */ + public function batchWorkflowStage(int $value, array $pks, array $contexts) + { + $user = Factory::getApplication()->getIdentity(); + + $workflow = Factory::getApplication()->bootComponent('com_workflow'); + + if (!$user->authorise('core.admin', $this->option)) + { + $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); + } + + // Get workflow stage information + $stage = $workflow->getMVCFactory()->createTable('Stage', 'Administrator'); + + if (empty($value) || !$stage->load($value)) + { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + if (empty($pks)) + { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + // Update workflow associations + return $this->workflow->updateAssociations($pks, $value); + } + + /** + * Batch change workflow stage or current. + * + * @param integer $oldId The ID of the item copied from + * @param integer $newId The ID of the new item + * + * @return null + * + * @since 4.0.0 + */ + public function workflowCleanupBatchMove($oldId, $newId) + { + // Trigger workflow plugins only if enable (will be triggered from parent class) + if ($this->workflowEnabled) + { + $this->importWorkflowPlugins(); + } + + // We always need an association, so create one + $table = $this->getTable(); + + $table->load($newId); + + $catKey = $table->getColumnAlias('catid'); + + $stage_id = $this->getDefaultStageByCategoryId($table->$catKey); + + if (empty($stage_id)) + { + return; + } + + $this->workflow->createAssociation((int) $newId, (int) $stage_id); + } + /** * Runs transition for item. * @@ -282,14 +360,14 @@ protected function addTransitionField(Form $form, $data) } /** - * Try to load a workflow object for newly created items + * Try to load a workflow stage for newly created items * which does not have a workflow assinged yet. If the category is not the * carrier, overwrite it on your model and deliver your own carrier. * * @param Form $form A Form object. * @param mixed $data The data expected for the form. * - * @return boolean|object A object containing workflow information or false + * @return boolean|integer An integer, holding the stage ID or false * @since 4.0.0 */ protected function getStageForNewItem(Form $form, $data) @@ -338,6 +416,19 @@ protected function getStageForNewItem(Form $form, $data) return false; } + return $this->getDefaultStageByCategoryId($catId); + } + + /** + * Try to load a workflow default stage by category ID. + * + * @param integer $catId The category ID. + * + * @return boolean|integer An integer, holding the stage ID or false + * @since 4.0.0 + */ + protected function getDefaultStageByCategoryId($catId) + { $db = Factory::getContainer()->get('DatabaseDriver'); // Let's check if a workflow ID is assigned to a category @@ -440,48 +531,4 @@ protected function getStageForNewItem(Form $form, $data) return false; } - - /** - * Batch change workflow stage or current. - * - * @param integer $value The workflow stage ID. - * @param array $pks An array of row IDs. - * @param array $contexts An array of item contexts. - * - * @return mixed An array of new IDs on success, boolean false on failure. - * - * @since 4.0.0 - */ - public function batchWorkflowStage(int $value, array $pks, array $contexts) - { - $user = Factory::getApplication()->getIdentity(); - - $workflow = Factory::getApplication()->bootComponent('com_workflow'); - - if (!$user->authorise('core.admin', $this->option)) - { - $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); - } - - // Get workflow stage information - $stage = $workflow->getMVCFactory()->createTable('Stage', 'Administrator'); - - if (empty($value) || !$stage->load($value)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - if (empty($pks)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - // Update workflow associations - return $this->workflow->updateAssociations($pks, $value); - } - } diff --git a/libraries/src/MVC/Model/WorkflowModelInterface.php b/libraries/src/MVC/Model/WorkflowModelInterface.php index 0a8e6db72f7c6..cd03fa0a63090 100644 --- a/libraries/src/MVC/Model/WorkflowModelInterface.php +++ b/libraries/src/MVC/Model/WorkflowModelInterface.php @@ -71,6 +71,18 @@ public function workflowBeforeSave(); */ public function workflowAfterSave($data); + /** + * Batch change workflow stage or current. + * + * @param integer $oldId The ID of the item copied from + * @param integer $newId The ID of the new item + * + * @return null + * + * @since 4.0.0 + */ + public function workflowCleanupBatchMove($oldId, $newId); + /** * Runs transition for item. * From 6fafbf8ceaa15f96a7731200d2944fb2b219ee5c Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 1 May 2020 23:09:31 +0200 Subject: [PATCH 31/90] Fix notice in transition view --- .../components/com_workflow/tmpl/transitions/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index 1873e827b5796..fab6dbb7a815c 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -88,7 +88,7 @@ $edit = Route::_('index.php?option=com_workflow&task=transition.edit&id=' . $item->id . '&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->extension); $canEdit = $user->authorise('core.edit', $this->extension . '.transition.' . $item->id) && !$isCore; - $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $userId || $item->checked_out == 0; + $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $user->id || $item->checked_out == 0; $canChange = $user->authorise('core.edit.state', $this->extension . '.transition.' . $item->id) && $canCheckin && !$isCore; ?>
From 1afb6708f4da3c5818241994f3d0ab08ef43e26a Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Fri, 1 May 2020 23:55:49 +0200 Subject: [PATCH 32/90] Workflow rename transition options to actions (#79) * Add codeowners * Rename transition tab options to actions --- .github/CODEOWNERS | 15 +++++++++++++++ administrator/language/en-GB/com_workflow.ini | 1 + .../language/en-GB/plg_workflow_publishing.ini | 9 ++++----- .../publishing/forms/workflow_publishing.xml | 10 +++++----- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f6e0dcfc511fd..112744b894a2e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -54,3 +54,18 @@ plugins/system/webauthn/* @nikosdion media/plg_system_webauthn/* @nikosdion language/administrator/en-GB/en-GB.plg_system_webauthn.ini @nikosdion language/administrator/en-GB/en-GB.plg_system_webauthn.sys.ini @nikosdion + +# Workflow +administrator/components/com_workflow/* @bembelimen @hleithner +administrator/language/en-GB/com_workflow.ini @bembelimen @hleithner +administrator/language/en-GB/com_workflow.sys.ini @bembelimen @hleithner +administrator/language/en-GB/plg_workflow_publishing.ini @bembelimen @hleithner +administrator/language/en-GB/plg_workflow_publishing.sys.ini @bembelimen @hleithner +libraries/src/Form/Field/TransitionField.php @bembelimen @hleithner +libraries/src/Form/Field/Workflow* @bembelimen @hleithner +libraries/src/HTML/Helpers/Workflow* @bembelimen @hleithner +libraries/src/MVC/Model/Workflow* @bembelimen @hleithner +libraries/src/MVC/Model/Workflow* @bembelimen @hleithner +libraries/src/Workflow/* @bembelimen @hleithner +build/media_source/com_workflow/* @bembelimen @hleithner +plugins/workflow/* @bembelimen @hleithner diff --git a/administrator/language/en-GB/com_workflow.ini b/administrator/language/en-GB/com_workflow.ini index ebda98c477ad5..9e05fb30e411c 100644 --- a/administrator/language/en-GB/com_workflow.ini +++ b/administrator/language/en-GB/com_workflow.ini @@ -98,6 +98,7 @@ COM_WORKFLOW_TOO_MANY_STAGES="Only one stage can be set as the default." COM_WORKFLOW_TOO_MANY_WORKFLOWS="Only one workflow can be set as the default." COM_WORKFLOW_TO_STAGE="Target Stage" COM_WORKFLOW_TRANSITION="Transition" +COM_WORKFLOW_TRANSITION_ACTIONS_LABEL="Transition Actions" COM_WORKFLOW_TRANSITIONS="Transitions" COM_WORKFLOW_TRANSITIONS_LIST="Transitions List: %s" COM_WORKFLOW_TRANSITIONS_N_ITEMS_CHECKED_IN="%s transitions checked in." diff --git a/administrator/language/en-GB/plg_workflow_publishing.ini b/administrator/language/en-GB/plg_workflow_publishing.ini index 9cdffd85611b8..8c1ed8dbcdcc9 100644 --- a/administrator/language/en-GB/plg_workflow_publishing.ini +++ b/administrator/language/en-GB/plg_workflow_publishing.ini @@ -4,10 +4,9 @@ ; Note : All ini files need to be saved as UTF-8 PLG_WORKFLOW_PUBLISHING="Workflow - Publishing" -PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing options to the workflow transitions for your items" -PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_LABEL="Transition Options" -PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_LABEL="Publishing state" -PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" -PLG_WORKFLOW_PUBLISHING_TRANSITION_OPTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change" +PLG_WORKFLOW_PUBLISHING_XML_DESCRIPTION="Add publishing actions to the workflow transitions for your items" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_LABEL="Publishing state" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DESC="Define the state an item should be set, when executing this transition" +PLG_WORKFLOW_PUBLISHING_TRANSITION_ACTIONS_PUBLISHING_DO_NO_CHANGE="- Do not change -" PLG_WORKFLOW_PUBLISHING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the publishing state of this item. Please use a workflow transition." PLG_WORKFLOW_PUBLISHING_PUBLISHED="Status: %s" diff --git a/plugins/workflow/publishing/forms/workflow_publishing.xml b/plugins/workflow/publishing/forms/workflow_publishing.xml index 2cbc62a1dfe05..7b52b390883ca 100644 --- a/plugins/workflow/publishing/forms/workflow_publishing.xml +++ b/plugins/workflow/publishing/forms/workflow_publishing.xml @@ -1,18 +1,18 @@
-
- +
From b1bca7f3c8a1ee2b3b1399c0daaa3c03e4b4d139 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sat, 2 May 2020 03:03:07 +0200 Subject: [PATCH 33/90] Fix sample data for new workflow --- .../src/MVC/Model/WorkflowBehaviorTrait.php | 17 ++++++++++++++++- plugins/sampledata/blog/blog.php | 5 ++++- plugins/sampledata/multilang/multilang.php | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index dda4670b6c9e1..f66202b652676 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -13,6 +13,7 @@ use Joomla\Database\ParameterType; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; +use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; @@ -179,6 +180,17 @@ public function workflowAfterSave($data) // We save the first stage if ($isNew) { + // We have to add the paths, because it could be called outside of the extension context + $path = JPATH_BASE . '/components/' . $this->extension; + + $path = Path::check($path); + + Form::addFormPath($path . '/forms'); + Form::addFormPath($path . '/models/forms'); + Form::addFieldPath($path . '/models/fields'); + Form::addFormPath($path . '/model/form'); + Form::addFieldPath($path . '/model/field'); + $form = $this->getForm(); $stage_id = $this->getStageForNewItem($form, $data); @@ -346,7 +358,10 @@ protected function addTransitionField(Form $form, $data) // Transition field $assoc = $this->workflow->getAssociation($id); - $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); + if (!empty($assoc->stage_id)) + { + $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); + } } else { diff --git a/plugins/sampledata/blog/blog.php b/plugins/sampledata/blog/blog.php index 595033155d38b..b16663ee03579 100644 --- a/plugins/sampledata/blog/blog.php +++ b/plugins/sampledata/blog/blog.php @@ -217,7 +217,6 @@ public function onAjaxSampledataApplyStep1() $catIds[] = $categoryModel->getItem()->id; // Create Articles. - $articleModel = new \Joomla\Component\Content\Administrator\Model\ArticleModel; $articles = array( array( 'catid' => $catIds[1], @@ -246,8 +245,12 @@ public function onAjaxSampledataApplyStep1() ), ); + $mvcFactory = $this->app->bootComponent('com_content')->getMVCFactory(); + foreach ($articles as $i => $article) { + $articleModel = $mvcFactory->createModel('Article', 'Administrator', ['ignore_request' => true]); + // Set values from language strings. $title = Text::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_TITLE'); $alias = ApplicationHelper::stringURLSafe($title); diff --git a/plugins/sampledata/multilang/multilang.php b/plugins/sampledata/multilang/multilang.php index d152b1c848526..78eaae8029194 100644 --- a/plugins/sampledata/multilang/multilang.php +++ b/plugins/sampledata/multilang/multilang.php @@ -1159,7 +1159,7 @@ private function addArticle($itemLanguage, $categoryId) $assoc->item_id = $newId; $assoc->stage_id = 2; - $assoc->extension = 'com_content'; + $assoc->extension = 'com_content.article'; try { From b42419322b7f96c505bcbe384b97d80d4a2f6699 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sat, 2 May 2020 23:03:13 +0200 Subject: [PATCH 34/90] Fixing system tests and codestyle (#80) * Fixing system tests and codestyle * Fixing Postgres --- .../components/com_content/src/Model/ArticlesModel.php | 9 +++++---- composer.lock | 8 ++++---- libraries/src/Workflow/Workflow.php | 6 ++++-- plugins/workflow/publishing/publishing.php | 3 ++- .../_support/Step/Acceptance/Administrator/Content.php | 8 ++++---- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index cc82e2f71a861..67f7c149118ae 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -610,16 +610,17 @@ public function getTransitions() ] ) ->from($db->quoteName('#__workflow_transitions', 't')) - ->innerJoin($db->quoteName('#__workflow_stages', 's')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') + ) ->where( [ - $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), $db->quoteName('t.published') . ' = 1', $db->quoteName('s.published') . ' = 1', ] ) - ->order($db->quoteName('t.ordering')) - ->group($db->quoteName('t.id')); + ->order($db->quoteName('t.ordering')); $where = []; diff --git a/composer.lock b/composer.lock index 9aebbc588d361..7f129ef1713a3 100644 --- a/composer.lock +++ b/composer.lock @@ -5759,12 +5759,12 @@ "source": { "type": "git", "url": "https://github.com/joomla-projects/joomla-browser.git", - "reference": "45a40262a139b599193f2aee0faefb29874d200a" + "reference": "0323d0d0741b0c9096bec5a015fc39444dd28cf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-projects/joomla-browser/zipball/45a40262a139b599193f2aee0faefb29874d200a", - "reference": "45a40262a139b599193f2aee0faefb29874d200a", + "url": "https://api.github.com/repos/joomla-projects/joomla-browser/zipball/0323d0d0741b0c9096bec5a015fc39444dd28cf5", + "reference": "0323d0d0741b0c9096bec5a015fc39444dd28cf5", "shasum": "" }, "require": { @@ -5802,7 +5802,7 @@ "acceptance testing", "joomla" ], - "time": "2020-04-12T10:39:07+00:00" + "time": "2020-05-01T19:53:33+00:00" }, { "name": "joomla/cms-coding-standards", diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index db381fbe36025..f2ecae8dda9bb 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -371,10 +371,12 @@ public function getAssociation(int $item_id): ?\stdClass ] ) ->from($db->quoteName('#__workflow_associations', 'a')) - ->innerJoin($db->quoteName('#__workflow_stages', 's')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id') + ) ->where( [ - $db->quoteName('a.stage_id') . ' = ' . $db->quoteName('s.id'), $db->quoteName('item_id') . ' = :id', $db->quoteName('extension') . ' = :extension', ] diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index f38dea91fd3d3..b7c73eb46f019 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -184,7 +184,8 @@ protected function enhanceItemForm(Form $form, $data) $form->setFieldAttribute($fieldname, 'type', 'spacer'); - $form->setFieldAttribute($fieldname, 'label', Text::sprintf('PLG_WORKFLOW_PUBLISHING_PUBLISHED', '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . '')); + $label = '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . ''; + $form->setFieldAttribute($fieldname, 'label', Text::sprintf('PLG_WORKFLOW_PUBLISHING_PUBLISHED', $label)); return true; } diff --git a/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php b/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php index cad35c9d28942..a0caa7a7d67d7 100644 --- a/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php +++ b/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php @@ -121,7 +121,7 @@ public function unPublishArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('unpublish'); + $I->clickToolbarButton('transition', '1'); $I->filterByCondition($title, "Unpublished"); } @@ -144,7 +144,7 @@ public function publishArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('publish'); + $I->clickToolbarButton('transition', '2'); $I->filterByCondition($title, "Published"); } @@ -168,7 +168,7 @@ public function trashArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('trash'); + $I->clickToolbarButton('transition', '3'); $I->filterByCondition($title, "Trashed"); } @@ -210,7 +210,7 @@ public function filterByCondition($title, $condition) $I = $this; $I->click("//div[@class='js-stools-container-bar']//button[contains(text(), 'Filter')]"); $I->wait(2); - $I->selectOptionInChosenByIdUsingJs('filter_condition', $condition); + $I->selectOptionInChosenByIdUsingJs('filter_published', $condition); $I->see($title); } } From da2dd2144d62c61d91f53676a7870929a9f4d82a Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Wed, 6 May 2020 21:38:43 +0200 Subject: [PATCH 35/90] Fix redirect after warning (#83) * Fix redirect in workflow list * indent --- .../com_workflow/src/Controller/WorkflowsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_workflow/src/Controller/WorkflowsController.php b/administrator/components/com_workflow/src/Controller/WorkflowsController.php index b9ab826633382..01c9f8dd988d6 100644 --- a/administrator/components/com_workflow/src/Controller/WorkflowsController.php +++ b/administrator/components/com_workflow/src/Controller/WorkflowsController.php @@ -120,7 +120,7 @@ public function setDefault() $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list - . '&extension=' . $this->extension, false + . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''), false ) ); From bc9e5d68b8e7157438ed4167f5722df484bad7bc Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Wed, 6 May 2020 21:44:40 +0200 Subject: [PATCH 36/90] Fixing system tests (#88) * Fixing system tests and codestyle * Fixing Postgres * Adding exclusion for canDelete for API calls --- administrator/components/com_content/src/Model/ArticleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index 7c76d37f80b72..47af27fced737 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -262,7 +262,7 @@ protected function batchMove($value, $pks, $contexts) */ protected function canDelete($record) { - if (empty($record->id) || $record->state != -2) + if (empty($record->id) || ($record->state != -2 && !Factory::getApplication()->isClient('api'))) { return false; } From 0238c943b6a57ddba2a2b82733bb8a31d2657bb9 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Wed, 6 May 2020 22:42:53 +0200 Subject: [PATCH 37/90] Add featuring plugin (#84) * Initial support for featuring transition * Move $supportFunctionality from the trait to the service. * Disable list item feature button and view restriction * Comments/cs --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 3 +- .../updates/postgresql/4.0.0-2018-05-15.sql | 3 +- .../src/Extension/ContentComponent.php | 8 + .../com_content/src/Model/ArticleModel.php | 71 ++- .../com_content/tmpl/articles/default.php | 4 + .../com_content/tmpl/featured/default.php | 4 + .../language/en-GB/plg_workflow_featuring.ini | 11 + .../en-GB/plg_workflow_featuring.sys.ini | 7 + installation/sql/mysql/base.sql | 3 +- installation/sql/postgresql/base.sql | 5 +- .../src/Workflow/WorkflowServiceTrait.php | 19 +- plugins/workflow/featuring/featuring.php | 424 ++++++++++++++++++ plugins/workflow/featuring/featuring.xml | 27 ++ plugins/workflow/featuring/forms/action.xml | 18 + .../publishing/forms/workflow_publishing.xml | 2 +- plugins/workflow/publishing/publishing.xml | 4 +- 16 files changed, 594 insertions(+), 19 deletions(-) create mode 100644 administrator/language/en-GB/plg_workflow_featuring.ini create mode 100644 administrator/language/en-GB/plg_workflow_featuring.sys.ini create mode 100644 plugins/workflow/featuring/featuring.php create mode 100644 plugins/workflow/featuring/featuring.xml create mode 100644 plugins/workflow/featuring/forms/action.xml diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index ceef7055ca38e..dc847730c5a74 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -127,7 +127,8 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES (0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); -- -- Creating Associations for existing content diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 107b73c480fb2..e873e2c2c32c3 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -123,7 +123,8 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES (0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, NULL, 0, 0); -- -- Creating Associations for existing content diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index 06265cd471be8..01ad75352eb1c 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -53,6 +53,14 @@ class ContentComponent extends MVCComponent implements CategoryServiceTrait::getStateColumnForSection insteadof TagServiceTrait; } + /** @var array Supported functionality */ + protected $supportedFunctionality = [ + 'core.featured' => [ + 'com_content.articles' + ], + 'joomla.state' => true, + ]; + /** * The trashed condition * diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index 47af27fced737..bba8b0e34cead 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -73,10 +73,49 @@ class ArticleModel extends AdminModel implements WorkflowModelInterface */ protected $associationsContext = 'com_content.item'; + /** + * The event to trigger before changing featured status one or more items. + * + * @var string + * @since 4.0 + */ + protected $event_before_change_featured = null; + + /** + * The event to trigger after changing featured status one or more items. + * + * @var string + * @since 4.0 + */ + protected $event_after_change_featured = null; + + /** + * Constructor. + * + * @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request). + * @param MVCFactoryInterface $factory The factory. + * @param FormFactoryInterface $formFactory The form factory. + * + * @since 1.6 + * @throws \Exception + */ public function __construct($config = array(), MVCFactoryInterface $factory = null, FormFactoryInterface $formFactory = null) { + $config['events_map'] = $config['events_map'] ?? []; + + $config['events_map'] = array_merge( + ['featured' => 'content'], + $config['events_map'] + ); + parent::__construct($config, $factory, $formFactory); + // Set the featured status change events + $this->event_before_change_featured = $config['event_before_change_featured'] ?? $this->event_before_change_featured; + $this->event_before_change_featured = $this->event_before_change_featured ?? 'onContentBeforeChangeFeatured'; + $this->event_after_change_featured = $config['event_after_change_featured'] ?? $this->event_after_change_featured; + $this->event_after_change_featured = $this->event_after_change_featured ?? 'onContentAfterChangeFeatured'; + $this->setUpWorkflow('com_content.article'); } @@ -825,9 +864,15 @@ public function save($data) public function featured($pks, $value = 0, $featuredUp = null, $featuredDown = null) { // Sanitize the ids. - $pks = (array) $pks; - $pks = ArrayHelper::toInteger($pks); - $value = (int) $value; + $pks = (array) $pks; + $pks = ArrayHelper::toInteger($pks); + $value = (int) $value; + $context = $this->option . '.' . $this->name; + + $this->workflowBeforeStageChange(); + + // Include the plugins for the change of state event. + PluginHelper::importPlugin($this->events_map['featured']); // Convert empty strings to null for the query. if ($featuredUp === '') @@ -849,6 +894,16 @@ public function featured($pks, $value = 0, $featuredUp = null, $featuredDown = n $table = $this->getTable('Featured', 'Administrator'); + // Trigger the before change state event. + $result = Factory::getApplication()->triggerEvent($this->event_before_change_featured, array($context, $pks, $value)); + + if (\in_array(false, $result, true)) + { + $this->setError($table->getError()); + + return false; + } + try { $db = $this->getDbo(); @@ -942,6 +997,16 @@ public function featured($pks, $value = 0, $featuredUp = null, $featuredDown = n $table->reorder(); + // Trigger the change state event. + $result = Factory::getApplication()->triggerEvent($this->event_after_change_featured, array($context, $pks, $value)); + + if (\in_array(false, $result, true)) + { + $this->setError($table->getError()); + + return false; + } + $this->cleanCache(); return true; diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index fa443112a0afc..12cda5c5d8360 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -205,6 +205,10 @@ 'disabled' => !$canChange ]; + if ($workflow_enabled) : + $options['disabled'] = true; + endif; + echo (new FeaturedButton) ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); ?> diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 8e9e7b54e790f..6d993dcca50eb 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -197,6 +197,10 @@ 'disabled' => !$canChange ]; + if ($workflow_enabled) : + $options['disabled'] = true; + endif; + echo (new FeaturedButton) ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); ?> diff --git a/administrator/language/en-GB/plg_workflow_featuring.ini b/administrator/language/en-GB/plg_workflow_featuring.ini new file mode 100644 index 0000000000000..f7c2303092ab4 --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_featuring.ini @@ -0,0 +1,11 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_WORKFLOW_FEATURING="Workflow - Featuring" +PLG_WORKFLOW_FEATURING_XML_DESCRIPTION="Add featuring actions to the workflow transitions for your items" +PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_LABEL="Featuring state" +PLG_WORKFLOW_FEATURING_TRANSITION_ACTIONS_FEATURING_DESC="Define the featured state an item should be set, when executing this transition" +PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED="You're not allowed to change the featured state of this item. Please use a workflow transition." +PLG_WORKFLOW_FEATURING_FEATURED="Featured: %s" diff --git a/administrator/language/en-GB/plg_workflow_featuring.sys.ini b/administrator/language/en-GB/plg_workflow_featuring.sys.ini new file mode 100644 index 0000000000000..a80d79cb2fe80 --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_featuring.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_WORKFLOW_FEATURING="Workflow - Featuring" +PLG_WORKFLOW_FEATURING_XML_DESCRIPTION="Add featuring options to the workflow transitions for your items" diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index fe10e567000d5..86880b10e7530 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -358,7 +358,8 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, (0, 'plg_media-action_rotate', 'plugin', 'rotate', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index aaf7e5f222378..3655d76239a2b 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -364,7 +364,8 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", (0, 'plg_media-action_rotate', 'plugin', 'rotate', 'media-action', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES @@ -1181,4 +1182,4 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (3, 63, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), (4, 64, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); -SELECT setval('#__workflow_transitions_id_seq', 5, false); \ No newline at end of file +SELECT setval('#__workflow_transitions_id_seq', 5, false); diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index 20c3cc6eae4a8..66f8dd0435a6a 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -31,14 +31,17 @@ trait WorkflowServiceTrait */ abstract public function getMVCFactory(): MVCFactoryInterface; - /** @var array Supported functionality */ - protected $supportedFunctionality = [ - 'joomla.state' => true, - 'joomla.featured' => true, - ]; - /** - * Check if the functionality is supported by the context + * Check if the functionality is supported by the component + * The variable $supportFunctionality has the following structure + * [ + * 'core.featured' => [ + * 'com_content.article', + * ], + * 'core.state' => [ + * 'com_content.article', + * ], + * ] * * @param string $functionality The functionality * @param string $context The context of the functionality @@ -57,7 +60,7 @@ public function supportFunctionality($functionality, $context): bool return true; } - return in_array($context, $this->supportedFunctionality[$functionality]); + return in_array($context, $this->supportedFunctionality[$functionality], true); } /** diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php new file mode 100644 index 0000000000000..e2216352b9b3f --- /dev/null +++ b/plugins/workflow/featuring/featuring.php @@ -0,0 +1,424 @@ +getName(); + + // Extend the transition form + if ($context == 'com_workflow.transition') + { + return $this->enhanceTransitionForm($form, $data); + } + + return $this->enhanceItemForm($form, $data); + } + + /** + * Add different parameter options to the transition view, we need when executing the transition + * + * @param Form $form The form + * @param stdClass $data The data + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + protected function enhanceTransitionForm(Form $form, $data) + { + $model = $this->app->bootComponent('com_workflow') + ->getMVCFactory()->createModel('Workflow', 'Administrator', ['ignore_request' => true]); + + $workflow_id = (int) ($data->workflow_id ?? $form->getValue('workflow_id')); + + if (empty($workflow_id)) + { + $workflow_id = (int) $this->app->input->getInt('workflow_id'); + } + + $workflow = $model->getItem($workflow_id); + + if (!$this->isSupported($workflow->extension)) + { + return true; + } + + $form->loadFile(__DIR__ . '/forms/action.xml'); + + return true; + } + + /** + * Disable certain fields in the item form view, when we want to take over this function in the transition + * Check also for the workflow implementation and if the field exists + * + * @param Form $form The form + * @param stdClass $data The data + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + protected function enhanceItemForm(Form $form, $data) + { + $context = $form->getName(); + + if (!$this->isSupported($context)) + { + return true; + } + + $parts = explode('.', $context); + + $component = $this->app->bootComponent($parts[0]); + + $modelName = $component->getModelName($context); + + $table = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]) + ->getTable(); + + $fieldname = $table->getColumnAlias('featured'); + + $options = $form->getField($fieldname)->options; + + $value = isset($data->$fieldname) ? $data->$fieldname : $form->getValue($fieldname, null, 0); + + $text = '-'; + + $textclass = 'body'; + + switch ($value) + { + case 1: + $textclass = 'success'; + break; + + case 0: + case -2: + $textclass = 'danger'; + } + + if (!empty($options)) + { + foreach ($options as $option) + { + if ($option->value == $value) + { + $text = $option->text; + + break; + } + } + } + + $form->setFieldAttribute($fieldname, 'type', 'spacer'); + + $form->setFieldAttribute($fieldname, 'label', Text::sprintf('PLG_WORKFLOW_FEATURING_FEATURED', '' . htmlentities($text, ENT_COMPAT, 'UTF-8') . '')); + + return true; + } + + /** + * Manipulate the generic list view + * + * @param string $context + * @param ViewInterface $view + * @param string $result + */ + public function onAfterDisplay(string $context, ViewInterface $view, string $result) + { + $parts = explode('.', $context); + + if ($parts < 2) + { + return true; + } + + $app = Factory::getApplication(); + + // We need the single model context for checking for workflow + $singularsection = Inflector::singularize($parts[1]); + + $newcontext = $parts[0] . '.' . $singularsection; + + if (!$app->isClient('administrator') || !$this->isSupported($newcontext)) + { + return true; + } + + // List of releated batch functions we need to hide + $states = ['featured', 'unfeatured']; + + $js = " + document.addEventListener('DOMContentLoaded', function() + { + var dropdown = document.getElementById('toolbar-dropdown-status-group'); + + if (!dropdown) + { + reuturn; + } + + " . \json_encode($states) . ".forEach((action) => { + var button = document.getElementById('status-group-children-' + action); + + if (button) + { + button.classList.add('d-none'); + } + }); + + }); + "; + + $app->getDocument()->addScriptDeclaration($js); + + return true; + } + + /** + * Check if we can execute the transition + * + * @param string $context The context + * @param array $pks IDs of the items + * @param object $transition The value to change to + * + * @return boolean + */ + public function onWorkflowBeforeTransition($context, $pks, $transition) + { + if (!$this->isSupported($context) || !is_numeric($transition->options->get('featuring'))) + { + return true; + } + + $value = (int) $transition->options->get('featuring'); + + /** + * Here it becomes tricky. We would like to use the component models featured method, so we will + * Execute the normal "onContentBeforeChangeFeatured" plugins. But they could cancel the execution, + * So we have to precheck and cancel the whole transition stuff if not allowed. + */ + $this->app->set('plgWorkflowFeaturing.' . $context, $pks); + + $result = $this->app->triggerEvent('onContentBeforeChangeFeatured', [$context, $pks, $value]); + + // Release whitelist, the job is done + $this->app->set('plgWorkflowFeaturing.' . $context, []); + + if (\in_array(false, $result, true)) + { + return false; + } + + return true; + } + + /** + * Change Feature State of an item. Used to disable feature state change + * + * @param string $context The context + * @param array $pks IDs of the items + * @param object $transition The value to change to + * + * @return boolean + */ + public function onWorkflowAfterTransition($context, $pks, $transition) + { + if (!$this->isSupported($context)) + { + return true; + } + + $parts = explode('.', $context); + + // We need at least the extension + view for loading the table fields + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + $value = (int) $transition->options->get('featuring'); + + $options = [ + 'ignore_request' => true, + // We already have triggered onContentBeforeChangeFeatured, so use our own + 'event_before_change_featured' => 'onWorkflowBeforeChangeFeatured' + ]; + + $modelName = $component->getModelName($context); + + $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), $options); + + return $model->featured($pks, $value); + } + + /** + * Change Feature State of an item. Used to disable Feature state change + * + * @param string $context The context + * @param array $pks IDs of the items + * @param int $value The value to change to + * @return boolean + */ + public function onContentBeforeChangeFeatured(string $context, array $pks, int $value): bool + { + if (!$this->isSupported($context)) + { + return true; + } + + // We have whitelisted the pks, so we're the one who triggered + // With onWorkflowBeforeTransition => free pass + if ($this->app->get('plgWorkflowFeaturing.' . $context) === $pks) + { + return true; + } + + throw new Exception(Text::_('PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED')); + } + + /** + * The save event. + * + * @param string $context The context + * @param object $table The item + * @param boolean $isNew Is new item + * @param array $data The validated data + * + * @return boolean + * + * @since 4.0.0 + */ + public function onContentBeforeSave($context, TableInterface $table, $isNew, $data) + { + if (!$this->isSupported($context)) + { + return true; + } + + $keyName = $table->getColumnAlias('featured'); + + // Check for the old value + $article = clone $table; + + $article->load($table->id); + + // We don't allow the change of the feature state when we use the workflow + // As we're setting the field to disabled, no value should be there at all + if (isset($data[$keyName])) + { + $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_FEATURING_CHANGE_STATE_NOT_ALLOWED'), 'error'); + + return false; + } + + return true; + } + + /** + * Check if the current plugin should execute workflow related activities + * + * @param string $context + * @return boolean + */ + protected function isSupported($context) + { + $parts = explode('.', $context); + + // We need at least the extension + view for loading the table fields + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + if (!$component instanceof WorkflowServiceInterface + || !$component->isWorkflowActive($context) + || !$component->supportFunctionality($this->supportFunctionality, $context)) + { + return false; + } + + $modelName = $component->getModelName($context); + + $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]); + + if (!$model instanceof DatabaseModelInterface || !method_exists($model, 'featured')) + { + return false; + } + + $table = $model->getTable(); + + if (!$table instanceof TableInterface || !$table->hasField('featured')) + { + return false; + } + + return true; + } +} diff --git a/plugins/workflow/featuring/featuring.xml b/plugins/workflow/featuring/featuring.xml new file mode 100644 index 0000000000000..39ab3f4e2e31f --- /dev/null +++ b/plugins/workflow/featuring/featuring.xml @@ -0,0 +1,27 @@ + + + plg_workflow_featuring + Joomla! Project + March 2020 + Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 4.0.0 + PLG_WORKFLOW_FEATURING_XML_DESCRIPTION + + featuring.php + + + plg_workflow_featuring.ini + plg_workflow_featuring.sys.ini + + + +
+ +
+
+
+ +
diff --git a/plugins/workflow/featuring/forms/action.xml b/plugins/workflow/featuring/forms/action.xml new file mode 100644 index 0000000000000..02d9e95b0e676 --- /dev/null +++ b/plugins/workflow/featuring/forms/action.xml @@ -0,0 +1,18 @@ + + + +
+ + + + + +
+
+ diff --git a/plugins/workflow/publishing/forms/workflow_publishing.xml b/plugins/workflow/publishing/forms/workflow_publishing.xml index 7b52b390883ca..2cc0f2e24156c 100644 --- a/plugins/workflow/publishing/forms/workflow_publishing.xml +++ b/plugins/workflow/publishing/forms/workflow_publishing.xml @@ -12,7 +12,7 @@ default="" hide_all="true" > - + diff --git a/plugins/workflow/publishing/publishing.xml b/plugins/workflow/publishing/publishing.xml index d2bbfb5f0f909..6aa683603d94d 100644 --- a/plugins/workflow/publishing/publishing.xml +++ b/plugins/workflow/publishing/publishing.xml @@ -13,8 +13,8 @@ publishing.php - en-GB.plg_workflow_publishing.ini - en-GB.plg_workflow_publishing.sys.ini + plg_workflow_publishing.ini + plg_workflow_publishing.sys.ini From a52fe091c9baa24e81ef20f96dca62e4cc3aa19f Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 6 May 2020 22:48:12 +0200 Subject: [PATCH 38/90] Add check, if workflow plugins should be executed Fix isSupported call --- .../com_content/src/Extension/ContentComponent.php | 4 +--- plugins/workflow/featuring/featuring.php | 14 ++++++++++++-- plugins/workflow/publishing/publishing.php | 14 ++++++++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index 01ad75352eb1c..b529650256c11 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -55,9 +55,7 @@ class ContentComponent extends MVCComponent implements /** @var array Supported functionality */ protected $supportedFunctionality = [ - 'core.featured' => [ - 'com_content.articles' - ], + 'core.featured' => true, 'joomla.state' => true, ]; diff --git a/plugins/workflow/featuring/featuring.php b/plugins/workflow/featuring/featuring.php index e2216352b9b3f..84d8ae9c55795 100644 --- a/plugins/workflow/featuring/featuring.php +++ b/plugins/workflow/featuring/featuring.php @@ -252,7 +252,12 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) return true; } - $value = (int) $transition->options->get('featuring'); + $value = $transition->options->get('featuring'); + + if (!is_numeric($value)) + { + return true; + } /** * Here it becomes tricky. We would like to use the component models featured method, so we will @@ -300,7 +305,12 @@ public function onWorkflowAfterTransition($context, $pks, $transition) $component = $this->app->bootComponent($parts[0]); - $value = (int) $transition->options->get('featuring'); + $value = $transition->options->get('featuring'); + + if (!is_numeric($value)) + { + return true; + } $options = [ 'ignore_request' => true, diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index b7c73eb46f019..3f2b4c85ee876 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -262,7 +262,12 @@ public function onWorkflowBeforeTransition($context, $pks, $transition) return true; } - $value = (int) $transition->options->get('publishing'); + $value = $transition->options->get('publishing'); + + if (!is_numeric($value)) + { + return true; + } /** * Here it becomes tricky. We would like to use the component models publish method, so we will @@ -310,7 +315,12 @@ public function onWorkflowAfterTransition($context, $pks, $transition) $component = $this->app->bootComponent($parts[0]); - $value = (int) $transition->options->get('publishing'); + $value = $transition->options->get('publishing'); + + if (!is_numeric($value)) + { + return true; + } $options = [ 'ignore_request' => true, From 5da7511389b627ded461a4f5ec19369ef6a60898 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Thu, 7 May 2020 00:21:25 +0200 Subject: [PATCH 39/90] Rename joomla.state to core.state (#89) --- .../components/com_content/src/Extension/ContentComponent.php | 2 +- plugins/workflow/publishing/publishing.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index b529650256c11..8a41c6f4cde1c 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -56,7 +56,7 @@ class ContentComponent extends MVCComponent implements /** @var array Supported functionality */ protected $supportedFunctionality = [ 'core.featured' => true, - 'joomla.state' => true, + 'core.state' => true, ]; /** diff --git a/plugins/workflow/publishing/publishing.php b/plugins/workflow/publishing/publishing.php index 3f2b4c85ee876..263b007a8b2bc 100644 --- a/plugins/workflow/publishing/publishing.php +++ b/plugins/workflow/publishing/publishing.php @@ -49,7 +49,7 @@ class PlgWorkflowPublishing extends CMSPlugin * @var string * @since __DEPLOY_VERSION__ */ - protected $supportname = 'joomla.state'; + protected $supportname = 'core.state'; /** * The form event. From 18e4f7f08cffbbb9331490b2b258c54c5f3093e9 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Sun, 10 May 2020 05:22:42 +0200 Subject: [PATCH 40/90] Refactor stages transitions (#93) * Add feature to the default workflow Remove unnecessary stages (if s.o. wants J3 workflow => disable) * Allow edit of core transition but only permissions * Cleanup variable * Disable different edit buttons for core workflow transitions --- .../sql/updates/mysql/4.0.0-2018-05-15.sql | 15 ++--- .../updates/postgresql/4.0.0-2018-05-15.sql | 15 ++--- .../src/Controller/TransitionController.php | 5 -- .../src/Model/TransitionModel.php | 65 ++++++++++++++++--- .../com_workflow/src/Model/WorkflowModel.php | 59 +++-------------- .../src/View/Transition/HtmlView.php | 25 +++++-- .../com_workflow/tmpl/transitions/default.php | 2 +- installation/sql/mysql/base.sql | 30 ++++----- installation/sql/postgresql/base.sql | 36 +++++----- libraries/src/Form/Field/TransitionField.php | 9 ++- 10 files changed, 131 insertions(+), 130 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index dc847730c5a74..91e4013815e6b 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -80,10 +80,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), -(2, 0, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), -(3, 0, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), -(4, 0, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); -- -- Table structure for table `#__workflow_transitions` @@ -117,9 +114,11 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`, `checked_out_time`, `checked_out`) VALUES (1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), -(2, 0, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), -(3, 0, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), -(4, 0, 1, 4, 1, 'Archive', '', -1, 4, '{"publishing":"2"}', NULL, 0); +(2, 0, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}', NULL, 0), +(3, 0, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), +(4, 0, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), +(5, 0, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), +(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); -- -- Creating extension entry @@ -134,4 +133,4 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, -- Creating Associations for existing content -- INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `id`, CASE WHEN `state` = -2 THEN 3 WHEN `state` = 0 THEN 1 WHEN `state` = 2 THEN 4 ELSE 2 END, 'com_content.article' FROM `#__content`; +SELECT `id`, 1, 'com_content.article' FROM `#__content`; diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index e873e2c2c32c3..34533def3ef39 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -80,10 +80,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 1, 1, 'JUNPUBLISHED', '', 1, NULL, 0), -(2, 0, 2, 1, 1, 'JPUBLISHED', '', 0, NULL, 0), -(3, 0, 3, 1, 1, 'JTRASHED', '', 0, NULL, 0), -(4, 0, 4, 1, 1, 'JARCHIVED', '', 0, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); -- -- Table structure for table "#__workflow_transitions" @@ -113,9 +110,11 @@ CREATE INDEX "#__workflow_transitions_idx_checked_out" ON "#__workflow_transitio INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options", "checked_out_time", "checked_out") VALUES (1, 0, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}', NULL, 0), -(2, 0, 1, 2, 1, 'Publish', '', -1, 2, '{"publishing":"1"}', NULL, 0), -(3, 0, 1, 3, 1, 'Trash', '', -1, 3, '{"publishing":"-2"}', NULL, 0), -(4, 0, 1, 4, 1, 'Archive', '', -1, '{"publishing":"2"}', 4, NULL, 0); +(2, 0, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}', NULL, 0), +(3, 0, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}', NULL, 0), +(4, 0, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}', NULL, 0), +(5, 0, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}', NULL, 0), +(6, 0, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}', NULL, 0); -- -- Creating extension entry @@ -130,4 +129,4 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", -- Creating Associations for existing content -- INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") -SELECT "id", CASE WHEN "state" = -2 THEN 3 WHEN "state" = 0 THEN 1 WHEN "state" = 2 THEN 4 ELSE 2 END, 'com_content.article' FROM "#__content"; +SELECT "id", 1, 'com_content.article' FROM "#__content"; diff --git a/administrator/components/com_workflow/src/Controller/TransitionController.php b/administrator/components/com_workflow/src/Controller/TransitionController.php index 9b565d2896876..96660f10f3bb6 100644 --- a/administrator/components/com_workflow/src/Controller/TransitionController.php +++ b/administrator/components/com_workflow/src/Controller/TransitionController.php @@ -142,11 +142,6 @@ protected function allowEdit($data = array(), $key = 'id') $workflow = $model->getItem($item->workflow_id); - if ($workflow->core) - { - return false; - } - // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.transition.' . $recordId)) { diff --git a/administrator/components/com_workflow/src/Model/TransitionModel.php b/administrator/components/com_workflow/src/Model/TransitionModel.php index 0b2b2bff54cda..2681872189949 100644 --- a/administrator/components/com_workflow/src/Model/TransitionModel.php +++ b/administrator/components/com_workflow/src/Model/TransitionModel.php @@ -216,6 +216,10 @@ protected function generateNewTitle($category_id, $alias, $title) */ public function getForm($data = array(), $loadData = true) { + $app = Factory::getApplication(); + + $context = $this->option . '.' . $this->name; + // Get the form. $form = $this->loadForm( 'com_workflow.transition', @@ -233,24 +237,50 @@ public function getForm($data = array(), $loadData = true) if ($loadData) { - $data = (object) $this->loadFormData(); + $data = (array) $this->loadFormData(); } - if (!$this->canEditState((object) $data)) + if (empty($data['workflow_id'])) { - // Disable fields for display. - $form->setFieldAttribute('published', 'disabled', 'true'); + $data['workflow_id'] = (int) $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); + } + + $workflow = $this->getTable('Workflow'); + + $workflow->load($data['workflow_id']); - // Disable fields while saving. - // The controller has already verified this is a record you can edit. - $form->setFieldAttribute('published', 'filter', 'unset'); + $disableFields = []; + + // Disable all fields when we edit core, but not the permissions + if ($workflow->core) + { + $disableFields[] = 'title'; + $disableFields[] = 'from_stage_id'; + $disableFields[] = 'to_stage_id'; } - $app = Factory::getApplication(); + if (!$this->canEditState((object) $data) || $workflow->core) + { + $disableFields[] = 'published'; + } - $workflow_id = $app->input->getInt('workflow_id'); + foreach ($disableFields as $field) + { + $form->setFieldAttribute($field, 'disabled', 'true'); + $form->setFieldAttribute($field, 'required', 'false'); + $form->setFieldAttribute($field, 'filter', 'unset'); + } - $where = $this->getDbo()->quoteName('workflow_id') . ' = ' . $workflow_id . ' AND ' . $this->getDbo()->quoteName('published') . ' = 1'; + $fields = $form->getGroup('options'); + + foreach ($fields as $field) + { + $form->setFieldAttribute($field->fieldname, 'disabled', 'true', 'options'); + $form->setFieldAttribute($field->fieldname, 'required', 'false', 'options'); + $form->setFieldAttribute($field->fieldname, 'filter', 'unset', 'options'); + } + + $where = $this->getDbo()->quoteName('workflow_id') . ' = ' . (int) $data['workflow_id'] . ' AND ' . $this->getDbo()->quoteName('published') . ' = 1'; $form->setFieldAttribute('from_stage_id', 'sql_where', $where); $form->setFieldAttribute('to_stage_id', 'sql_where', $where); @@ -281,6 +311,21 @@ protected function loadFormData() return $data; } + public function getWorkflow() + { + $app = Factory::getApplication(); + + $context = $this->option . '.' . $this->name; + + $workflow_id = (int) $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); + + $workflow = $this->getTable('Workflow'); + + $workflow->load($workflow_id); + + return (object) $workflow->getProperties(); + } + /** * Trigger the form preparation for the workflow group * diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index 6f20b66ac57a4..fd588752dd27d 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -105,64 +105,21 @@ public function save($data) $result = parent::save($data); - // Create default stages/transitions + // Create default stage for new workflow if ($result && $input->getCmd('task') !== 'save2copy' && $this->getState($this->getName() . '.new')) { $workflow_id = (int) $this->getState($this->getName() . '.id'); - $stages = [ - [ - 'title' => 'JUNPUBLISHED', - 'default' => 1, - 'transition' => 'Unpublish', - 'options' => '{"publishing":"0"}' - ], - [ - 'title' => 'JPUBLISHED', - 'transition' => 'Publish', - 'options' => '{"publishing":"1"}' - ], - [ - 'title' => 'JTRASHED', - 'transition' => 'Trash', - 'options' => '{"publishing":"-2"}' - ], - [ - 'title' => 'JARCHIVED', - 'transition' => 'Archive', - 'options' => '{"publishing":"2"}' - ] - ]; - $table = $this->getTable('Stage'); - $transition = $this->getTable('Transition'); - - foreach ($stages as $stage) - { - $table->reset(); - $table->id = 0; - $table->title = $stage['title']; - $table->workflow_id = $workflow_id; - $table->published = 1; - $table->default = (int) !empty($stage['default']); - $table->description = ''; - - $table->store(); + $table->id = 0; + $table->title = 'COM_WORKFLOW_DEFAULT'; + $table->description = ''; + $table->workflow_id = $workflow_id; + $table->published = 1; + $table->default = 1; - $transition->reset(); - - $transition->id = 0; - $transition->title = $stage['transition']; - $transition->description = ''; - $transition->workflow_id = $workflow_id; - $transition->published = 1; - $transition->from_stage_id = -1; - $transition->to_stage_id = (int) $table->id; - $transition->options = $stage['options']; - - $transition->store(); - } + $table->store(); } return $result; diff --git a/administrator/components/com_workflow/src/View/Transition/HtmlView.php b/administrator/components/com_workflow/src/View/Transition/HtmlView.php index f4ce117154d7c..fb707b1c8528a 100644 --- a/administrator/components/com_workflow/src/View/Transition/HtmlView.php +++ b/administrator/components/com_workflow/src/View/Transition/HtmlView.php @@ -155,10 +155,14 @@ protected function addToolbar() $toolbarButtons = []; + $canCreate = $canDo->get('core.create'); + + $workflow = $this->get('Workflow'); + if ($isNew) { // For new records, check the create permission. - if ($canDo->get('core.edit')) + if ($canCreate) { ToolbarHelper::apply('transition.apply'); $toolbarButtons = [['save', 'transition.save'], ['save2new', 'transition.save2new']]; @@ -177,20 +181,27 @@ protected function addToolbar() if ($itemEditable) { ToolbarHelper::apply('transition.apply'); - $toolbarButtons = [['save', 'transition.save']]; + $toolbarButtons[] = ['save', 'transition.save']; // We can save this record, but check the create permission to see if we can return to make a new one. - if ($canDo->get('core.create')) + if ($canCreate && !$workflow->core) { $toolbarButtons[] = ['save2new', 'transition.save2new']; $toolbarButtons[] = ['save2copy', 'transition.save2copy']; } } - ToolbarHelper::saveGroup( - $toolbarButtons, - 'btn-success' - ); + if (count($toolbarButtons) > 1) + { + ToolbarHelper::saveGroup( + $toolbarButtons, + 'btn-success' + ); + } + else + { + ToolbarHelper::save('transition.save'); + } } ToolbarHelper::cancel('transition.cancel'); diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index fab6dbb7a815c..80b139df708ab 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -87,7 +87,7 @@ transitions as $i => $item): $edit = Route::_('index.php?option=com_workflow&task=transition.edit&id=' . $item->id . '&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->extension); - $canEdit = $user->authorise('core.edit', $this->extension . '.transition.' . $item->id) && !$isCore; + $canEdit = $user->authorise('core.edit', $this->extension . '.transition.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $user->id || $item->checked_out == 0; $canChange = $user->authorise('core.edit.state', $this->extension . '.transition.' . $item->id) && $canCheckin && !$isCore; ?>
- published, $i, 'stages.', $canChange && !$isCore); ?> + published, $i, 'stages.', $canChange); ?> default, $i, 'stages.', $canChange); ?> @@ -122,7 +120,7 @@ checked_out) : ?> editor, $item->checked_out_time, 'stages.', $canCheckin); ?> - + escape(Text::_($item->title)); ?> diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index a168ea3f06cd1..a17e05d606d3b 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -27,8 +27,6 @@ $saveOrder = ($listOrder == 't.ordering'); -$isCore = $this->workflow->core; - if ($saveOrder) { $saveOrderingUrl = 'index.php?option=com_workflow&task=transitions.saveOrderAjax&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->extension) . '&' . Session::getFormToken() . '=1'; @@ -91,7 +89,7 @@ $canEdit = $user->authorise('core.edit', $this->extension . '.transition.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $user->id || $item->checked_out == 0; - $canChange = $user->authorise('core.edit.state', $this->extension . '.transition.' . $item->id) && $canCheckin && !$isCore; ?> + $canChange = $user->authorise('core.edit.state', $this->extension . '.transition.' . $item->id) && $canCheckin; ?>
id); ?> diff --git a/administrator/components/com_workflow/tmpl/workflows/default.php b/administrator/components/com_workflow/tmpl/workflows/default.php index dc956a22b6c6b..35466909617b6 100644 --- a/administrator/components/com_workflow/tmpl/workflows/default.php +++ b/administrator/components/com_workflow/tmpl/workflows/default.php @@ -101,7 +101,6 @@ $transitions = Route::_('index.php?option=com_workflow&view=transitions&workflow_id=' . $item->id . '&extension=' . $extension); $edit = Route::_('index.php?option=com_workflow&task=workflow.edit&id=' . $item->id . '&extension=' . $extension); - $isCore = !empty($item->core); $canEdit = $user->authorise('core.edit', $extension . '.workflow.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $userId || $item->checked_out == 0; $canEditOwn = $user->authorise('core.edit.own', $extension . '.workflow.' . $item->id) && $item->created_by == $userId; @@ -131,13 +130,13 @@ - published, $i, 'workflows.', $canChange && !$isCore); ?> + published, $i, 'workflows.', $canChange); ?> checked_out) : ?> editor, $item->checked_out_time, 'workflows.', $canCheckin); ?> - + escape(Text::_($item->title)); ?> diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 62e378878e39f..989334a8c214e 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1061,7 +1061,6 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( `description` text NOT NULL, `extension` varchar(50) NOT NULL, `default` tinyint(1) NOT NULL DEFAULT 0, - `core` tinyint(1) NOT NULL DEFAULT 0, `ordering` int(11) NOT NULL DEFAULT 0, `created` datetime NOT NULL, `created_by` int(10) NOT NULL DEFAULT 0, @@ -1085,8 +1084,8 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- Dumping data for table `#__workflows` -- -INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `core`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); +INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES +(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 12c37fa0aa985..0788051ee42a2 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1071,7 +1071,6 @@ CREATE TABLE IF NOT EXISTS "#__workflows" ( "description" text NOT NULL, "extension" varchar(50) NOT NULL, "default" smallint NOT NULL DEFAULT 0, - "core" smallint NOT NULL DEFAULT 0, "ordering" bigint NOT NULL DEFAULT 0, "created" timestamp without time zone NOT NULL, "created_by" bigint DEFAULT 0 NOT NULL, @@ -1092,8 +1091,8 @@ CREATE INDEX "#__workflows_idx_modified" ON "#__workflows" ("modified"); CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); -INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "core", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); +INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES +(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); SELECT setval('#__workflows_id_seq', 2, false); From c924085cc6227d02b604ab2c479c1e7aedc0ba02 Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Fri, 22 May 2020 02:29:46 +0200 Subject: [PATCH 51/90] New Plugin workflow_notification (#92) * New Plugin workflow_notification * Remove tabs, alphaorder language keys * Doc block; get the stage name; * Fix plugin names * restore code * Update installation/sql/postgresql/base.sql ty Co-authored-by: Richard Fath * Language and form small improvement * Changes as suggested by reviewer * Re-Add check * remove tabs * add notification_ prefix to params * changes as required * add showon * move method * Remove field email_new_stage * fix unset user_id, set messag_id * fix author_id, check method getItem exists * remove unused * no message to users who are inactive or who locked their message box * display a message Co-authored-by: Richard Fath --- .../language/en-GB/plg_content_joomla.ini | 4 - .../en-GB/plg_workflow_notification.ini | 23 ++ .../en-GB/plg_workflow_notification.sys.ini | 7 + installation/sql/mysql/base.sql | 3 +- installation/sql/postgresql/base.sql | 3 +- plugins/content/joomla/joomla.php | 85 +---- plugins/content/joomla/joomla.xml | 12 - .../forms/workflow_notification.xml | 70 ++++ .../workflow/notification/notification.php | 321 ++++++++++++++++++ .../workflow/notification/notification.xml | 27 ++ 10 files changed, 453 insertions(+), 102 deletions(-) create mode 100644 administrator/language/en-GB/plg_workflow_notification.ini create mode 100644 administrator/language/en-GB/plg_workflow_notification.sys.ini create mode 100644 plugins/workflow/notification/forms/workflow_notification.xml create mode 100644 plugins/workflow/notification/notification.php create mode 100644 plugins/workflow/notification/notification.xml diff --git a/administrator/language/en-GB/plg_content_joomla.ini b/administrator/language/en-GB/plg_content_joomla.ini index 0cf5749dddb3f..c7f64edcf915a 100644 --- a/administrator/language/en-GB/plg_content_joomla.ini +++ b/administrator/language/en-GB/plg_content_joomla.ini @@ -8,8 +8,4 @@ PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_DESC="Check that categories are fully PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_LABEL="Check Category 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." -PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_STAGE_LABEL="Email on transition execution" -PLG_CONTENT_JOOMLA_ON_STAGE_CHANGE_MSG="The status of an article has been changed by '%1$s' entitled '%2$s'." -PLG_CONTENT_JOOMLA_ON_STAGE_CHANGE_SUBJECT="Status of article has changed" PLG_CONTENT_JOOMLA_XML_DESCRIPTION="This plugin does category processing for core extensions; sends an email when new article is submitted in the Frontend or a transition is executed." diff --git a/administrator/language/en-GB/plg_workflow_notification.ini b/administrator/language/en-GB/plg_workflow_notification.ini new file mode 100644 index 0000000000000..162306c97b3a5 --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_notification.ini @@ -0,0 +1,23 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +COM_WORKFLOW_NOTIFICATION_FIELDSET_LABEL="Notification" +PLG_WORKFLOW_NOTIFICATION="Workflow - Notification" +PLG_WORKFLOW_NOTIFICATION_ADDTEXT="The state has changed" +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_AUTHOR_DESC="You can localise the text by using a Language key and make language overrides." +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_AUTHOR_LABEL="Additional Message to Author" +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_DESC="You can localise the text by using a Language key and make language overrides." +PLG_WORKFLOW_NOTIFICATION_ADDTEXT_LABEL="Additional Message Text" +PLG_WORKFLOW_NOTIFICATION_EMAIL_AUTHOR_LABEL="Email the Author" +PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_SUBJECT="The status of an '%1$s' has been changed"; +PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG="Title: '%1$s', Changed by '%2$s', New State: '%3$s'." +PLG_WORKFLOW_NOTIFICATION_RECEIVERS_LABEL="More Receivers" +PLG_WORKFLOW_NOTIFICATION_RECEIVERS_SELECT="Select single receivers for the notification" +PLG_WORKFLOW_NOTIFICATION_SENDMAIL_LABEL="Send Notification" +PLG_WORKFLOW_NOTIFICATION_SENT="Notifications have been sent" +PLG_WORKFLOW_NOTIFICATION_USERGROUP_DESC="The users in this usergroup get an E-Mail if this transition has been performed" +PLG_WORKFLOW_NOTIFICATION_USERGROUP_LABEL="Usergroups" +PLG_WORKFLOW_NOTIFICATION_USERGROUP_SELECT="Select usergroups" +PLG_WORKFLOW_NOTIFICATION_XML_DESCRIPTION="Send Notification if a Transition has been performed in a Workflow" diff --git a/administrator/language/en-GB/plg_workflow_notification.sys.ini b/administrator/language/en-GB/plg_workflow_notification.sys.ini new file mode 100644 index 0000000000000..c585237338360 --- /dev/null +++ b/administrator/language/en-GB/plg_workflow_notification.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2019 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_WORKFLOW_NOTIFICATION="Workflow - Notification" +PLG_WORKFLOW_NOTIFICATION_XML_DESCRIPTION="Send Notification for Transitions in Publishing Workflow" \ No newline at end of file diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 989334a8c214e..3a9743f5ba51e 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -359,7 +359,8 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 0788051ee42a2..205030176d08b 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -365,7 +365,8 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", (0, 'plg_system_accessibility', 'plugin', 'accessibility', 'system', 0, 0, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), (0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, NULL, 0, 0); -- Templates INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES diff --git a/plugins/content/joomla/joomla.php b/plugins/content/joomla/joomla.php index 1c2ed441993b1..1c9cb000c87cf 100644 --- a/plugins/content/joomla/joomla.php +++ b/plugins/content/joomla/joomla.php @@ -616,7 +616,7 @@ public function onContentChangeState($context, $pks, $value) } // Check if this function is enabled. - if (!$this->params->def('email_new_stage', 0) || $context != 'com_content.article') + if ($context != 'com_content.article') { return true; } @@ -634,89 +634,6 @@ public function onContentChangeState($context, $pks, $value) $cctable = new CoreContent($db); $cctable->publish($ccIds, $value); - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__users')) - ->where($db->quoteName('sendEmail') . ' = 1') - ->where($db->quoteName('block') . ' = 0'); - - $users = (array) $db->setQuery($query)->loadColumn(); - - if (empty($users)) - { - return true; - } - - $user = $this->app->getIdentity(); - - // Messaging for changed items - $default_language = ComponentHelper::getParams('com_languages')->get('administrator'); - $debug = $this->app->get('debug_lang'); - - $article = new ArticleTable($db); - - $workflow = new Workflow(['extension' => 'com_content.article']); - - foreach ($pks as $pk) - { - if (!$article->load($pk)) - { - continue; - } - - $assoc = $workflow->getAssociation($pk); - $stageId = (int) $assoc->stage_id; - - // Load new transitions - $query = $db->getQuery(true) - ->select($db->quoteName('t.id')) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->from($db->quoteName('#__workflow_stages', 's')) - ->where($db->quoteName('t.from_stage_id') . ' = :stageid') - ->where($db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id')) - ->where($db->quoteName('t.published') . ' = 1') - ->where($db->quoteName('s.published') . ' = 1') - ->order($db->quoteName('t.ordering')) - ->bind(':stageid', $stageId, ParameterType::INTEGER); - - $transitions = $db->setQuery($query)->loadObjectList(); - - foreach ($users as $user_id) - { - if ($user_id != $user->id) - { - // Check if the user has available transitions - $items = array_filter( - $transitions, - function ($item) use ($user) - { - return $user->authorise('core.execute.transition', 'com_content.transition.' . $item->id); - } - ); - - if (!count($items)) - { - continue; - } - - // Load language for messaging - $receiver = User::getInstance($user_id); - $lang = Language::getInstance($receiver->getParam('admin_language', $default_language), $debug); - $lang->load('plg_content_joomla'); - - $message = array( - 'user_id_to' => $user_id, - 'subject' => $lang->_('PLG_CONTENT_JOOMLA_ON_STAGE_CHANGE_SUBJECT'), - 'message' => sprintf($lang->_('PLG_CONTENT_JOOMLA_ON_STAGE_CHANGE_MSG'), $user->name, $article->title), - ); - - $model_message = $this->app->bootComponent('com_messages') - ->getMVCFactory()->createModel('Message', 'Administrator'); - $model_message->save($message); - } - } - } - return true; } diff --git a/plugins/content/joomla/joomla.xml b/plugins/content/joomla/joomla.xml index 51572e9505904..8fbe01231966b 100644 --- a/plugins/content/joomla/joomla.xml +++ b/plugins/content/joomla/joomla.xml @@ -44,18 +44,6 @@ - - - - - diff --git a/plugins/workflow/notification/forms/workflow_notification.xml b/plugins/workflow/notification/forms/workflow_notification.xml new file mode 100644 index 0000000000000..9770512417abe --- /dev/null +++ b/plugins/workflow/notification/forms/workflow_notification.xml @@ -0,0 +1,70 @@ + +
+ +
+ + + + + + + + + + + + +
+
+
diff --git a/plugins/workflow/notification/notification.php b/plugins/workflow/notification/notification.php new file mode 100644 index 0000000000000..73ad63726b4a2 --- /dev/null +++ b/plugins/workflow/notification/notification.php @@ -0,0 +1,321 @@ +getName(); + + // Extend the transition form + if ($context !== 'com_workflow.transition') + { + return; + } + + return $this->enhanceTransitionForm($form, $data); + } + + /** + * Add different parameter options to the transition view, we need when executing the transition + * + * @param Form $form The form + * @param stdClass $data The data + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + protected function enhanceTransitionForm(Form $form, $data) + { + Form::addFormPath(__DIR__ . '/forms'); + + $form->loadFile('workflow_notification'); + + return true; + } + + /** + * Send a Notification to defined users a transion is performed + * + * @param string $context The context for the content passed to the plugin. + * @param array $pks A list of primary key ids of the content that has changed stage. + * @param object $data Object containing data about the transition + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + public function onWorkflowAfterTransition($context, $pks, $data) + { + $parts = explode('.', $context); + + // Check the extension + if (count($parts) < 2) + { + return false; + } + + $component = $this->app->bootComponent($parts[0]); + + if (!$component->isWorkflowActive($context)) + { + return false; + } + + // Check if send-mail is active + if (empty($data->options['notification_send_mail'])) + { + return true; + } + + // ID of the items whose state has changed. + $pks = ArrayHelper::toInteger($pks); + + if (empty($pks)) + { + return true; + } + + // Get UserIds of Receivers + $userIds = $this->getUsersFromGroup($data); + + // The active user + $user = $this->app->getIdentity(); + + // Prepare Language for messages + $default_language = ComponentHelper::getParams('com_languages')->get('administrator'); + $debug = $this->app->get('debug_lang'); + + $modelName = $component->getModelName($context); + $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]); + + $authorId = 0; + + // Add author of the item to the receivers array if the param email-author is set + if (!empty($data->options['notification_email_author']) && !empty($item->created_by)) + { + $author = User::getInstance($item->created_by); + + if (!empty($author) && !$author->block) + { + if (!in_array($author->id, $userIds)) + { + $userIds[] = (int) $author->id; + $authorId = $author->id; + } + } + } + + // Don't send the notification to the active user + $key = array_search($user->id, $userIds); + + if (is_integer($key)) + { + unset($userIds[$key]); + } + + // Remove users with locked input box from the list of receivers + if (!empty($userIds)) + { + $userIds = $this->removeLocked($userIds); + } + + // If there are no receivers, stop here + if (empty($userIds)) + { + return true; + } + + // Get the model for private messages + $model_message = $this->app->bootComponent('com_messages') + ->getMVCFactory()->createModel('Message', 'Administrator'); + + // Get the title of the stage + $model_stage = $this->app->bootComponent('com_workflow') + ->getMVCFactory()->createModel('Stage', 'Administrator'); + + $toStage = $model_stage->getItem($data->to_stage_id)->title; + + foreach ($pks as $pk) + { + // Get the title of the item which has changed + $title =''; + + if (method_exists($model, 'getItem')) + { + $title = $model->getItem($pk)->title; + } + + // Send Email to receivers + foreach ($userIds as $user_id) + { + $receiver = User::getInstance($user_id); + + // Load language for messaging + $lang = Language::getInstance($user->getParam('admin_language', $default_language), $debug); + $lang->load('plg_workflow_notification'); + $messageText = sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'), $title, $user->name, $lang->_($toStage)); + + if (!empty($data->options['notification_text'] && $user_id !== $authorId)) + { + $messageText .= '
' . htmlspecialchars($lang->_($data->options['notification_text'])); + } + + if (!empty($data->options['notification_author_text'] && $user_id === $authorId)) + { + $messageText .= '
' . htmlspecialchars($lang->_($data->options['notification_text_author'])); + } + + $message = [ + 'id' => 0, + 'user_id_to' => $receiver->id, + 'subject' => sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_SUBJECT'), $modelName), + 'message' => $messageText, + ]; + + $model_message->save($message); + } + + $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message'); + } + + return true; + } + + /* + * Get user_ids of receivers + * + * @param object $data Object containing data about the transition + * + * @return array $userIds The receivers + * + * @since __DEPLOY_VERSION__ + */ + private function getUsersFromGroup($data): Array + { + $users = []; + + // Single userIds + if (!empty($data->options['notification_receivers'])) + { + $users = ArrayHelper::toInteger($data->options['notification_receivers']); + } + + // Usergroups + $groups = []; + + if (!empty($data->options['notification_groups'])) + { + $groups = ArrayHelper::toInteger($data->options['notification_groups']); + } + + $users2 = []; + + if (!empty($groups)) + { + // UserIds from usergroups + $model = Factory::getApplication()->bootComponent('com_users') + ->getMVCFactory()->createModel('Users', 'Administrator', ['ignore_request' => true]); + + $model->setState('list.select', 'id'); + $model->setState('filter.groups', $groups); + $model->setState('filter.state', 0); + $model->setState('filter.active', 1); + $model->setState('filter.sendEmail', 1); + + // Ids from usergroups + $groupUsers = $model->getItems(); + $users2 = ArrayHelper::getColumn($groupUsers, 'id'); + } + + // Merge userIds from individual entries and userIDs from groups + $userIds = array_unique(array_merge($users, $users2)); + + return $userIds; + } + + /* + * Remove receivers who have locked their message inputbox + * + * @param array $uerIds The userIds which must be checked + * + * @return array users with active message input box + * + * @since __DEPLOY_VERSION__ + */ + private function removeLocked($userIds): Array + { + // Check for locked inboxes would be better to have _cdf settings in the user_object or a filter in users model + $locked = []; + + $db = $this->db; + $query = $db->getQuery(true); + $query->select($db->quoteName('user_id')) + ->from($db->quoteName('#__messages_cfg')) + ->whereIn($db->quoteName('user_id'), $userIds) + ->where($db->quoteName('cfg_name') . '=' . $db->quote('locked')) + ->where($db->quoteName('cfg_value') . '=1'); + + $locked = $db->setQuery($query)->loadColumn(); + + return array_diff($userIds, $locked); + } +} diff --git a/plugins/workflow/notification/notification.xml b/plugins/workflow/notification/notification.xml new file mode 100644 index 0000000000000..84199d2433b33 --- /dev/null +++ b/plugins/workflow/notification/notification.xml @@ -0,0 +1,27 @@ + + + plg_workflow_notification + Joomla! Project + May 2020 + Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 4.0.0 + PLG_WORKFLOW_NOTIFICATION_XML_DESCRIPTION + + notification.php + + + plg_workflow_notification.ini + plg_workflow_notification.sys.ini + + + +
+ +
+
+
+ +
From 9deef12dd9e573bb21f3f43bd46a0e0ee49a5ca6 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 22 May 2020 04:36:38 +0200 Subject: [PATCH 52/90] Remove author notification --- .../{workflow_notification.xml => action.xml} | 23 +--- .../workflow/notification/notification.php | 101 ++++++------------ 2 files changed, 34 insertions(+), 90 deletions(-) rename plugins/workflow/notification/forms/{workflow_notification.xml => action.xml} (66%) diff --git a/plugins/workflow/notification/forms/workflow_notification.xml b/plugins/workflow/notification/forms/action.xml similarity index 66% rename from plugins/workflow/notification/forms/workflow_notification.xml rename to plugins/workflow/notification/forms/action.xml index 9770512417abe..cf6b8d127a653 100644 --- a/plugins/workflow/notification/forms/workflow_notification.xml +++ b/plugins/workflow/notification/forms/action.xml @@ -1,7 +1,7 @@
-
+
- - - - -
diff --git a/plugins/workflow/notification/notification.php b/plugins/workflow/notification/notification.php index 73ad63726b4a2..cbf6b09d3b856 100644 --- a/plugins/workflow/notification/notification.php +++ b/plugins/workflow/notification/notification.php @@ -16,7 +16,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\User\User; -use Joomla\CMS\Workflow\Workflow; +use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\Utilities\ArrayHelper; /** @@ -26,6 +26,8 @@ */ class PlgWorkflowNotification extends CMSPlugin { + use WorkflowPluginTrait; + /** * Load the language file on instantiation. * @@ -49,7 +51,7 @@ class PlgWorkflowNotification extends CMSPlugin * @since 3.9.0 */ protected $db; - + /** * The form event. * @@ -65,30 +67,11 @@ public function onContentPrepareForm(Form $form, $data) $context = $form->getName(); // Extend the transition form - if ($context !== 'com_workflow.transition') + if ($context === 'com_workflow.transition') { - return; + $form->loadFile(__DIR__ . '/forms/action.xml'); } - return $this->enhanceTransitionForm($form, $data); - } - - /** - * Add different parameter options to the transition view, we need when executing the transition - * - * @param Form $form The form - * @param stdClass $data The data - * - * @return boolean - * - * @since __DEPLOY_VERSION__ - */ - protected function enhanceTransitionForm(Form $form, $data) - { - Form::addFormPath(__DIR__ . '/forms'); - - $form->loadFile('workflow_notification'); - return true; } @@ -107,7 +90,7 @@ public function onWorkflowAfterTransition($context, $pks, $data) { $parts = explode('.', $context); - // Check the extension + // Check the extension if (count($parts) < 2) { return false; @@ -126,7 +109,7 @@ public function onWorkflowAfterTransition($context, $pks, $data) return true; } - // ID of the items whose state has changed. + // ID of the items whose state has changed. $pks = ArrayHelper::toInteger($pks); if (empty($pks)) @@ -147,23 +130,6 @@ public function onWorkflowAfterTransition($context, $pks, $data) $modelName = $component->getModelName($context); $model = $component->getMVCFactory()->createModel($modelName, $this->app->getName(), ['ignore_request' => true]); - $authorId = 0; - - // Add author of the item to the receivers array if the param email-author is set - if (!empty($data->options['notification_email_author']) && !empty($item->created_by)) - { - $author = User::getInstance($item->created_by); - - if (!empty($author) && !$author->block) - { - if (!in_array($author->id, $userIds)) - { - $userIds[] = (int) $author->id; - $authorId = $author->id; - } - } - } - // Don't send the notification to the active user $key = array_search($user->id, $userIds); @@ -194,12 +160,14 @@ public function onWorkflowAfterTransition($context, $pks, $data) $toStage = $model_stage->getItem($data->to_stage_id)->title; + $hasGetItem = method_exists($model, 'getItem'); + foreach ($pks as $pk) { // Get the title of the item which has changed $title =''; - if (method_exists($model, 'getItem')) + if ($hasGetItem) { $title = $model->getItem($pk)->title; } @@ -214,16 +182,11 @@ public function onWorkflowAfterTransition($context, $pks, $data) $lang->load('plg_workflow_notification'); $messageText = sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'), $title, $user->name, $lang->_($toStage)); - if (!empty($data->options['notification_text'] && $user_id !== $authorId)) + if (!empty($data->options['notification_text'])) { $messageText .= '
' . htmlspecialchars($lang->_($data->options['notification_text'])); } - if (!empty($data->options['notification_author_text'] && $user_id === $authorId)) - { - $messageText .= '
' . htmlspecialchars($lang->_($data->options['notification_text_author'])); - } - $message = [ 'id' => 0, 'user_id_to' => $receiver->id, @@ -233,16 +196,16 @@ public function onWorkflowAfterTransition($context, $pks, $data) $model_message->save($message); } - - $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message'); } + $this->app->enqueueMessage(Text::_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message'); + return true; } /* - * Get user_ids of receivers - * + * Get user_ids of receivers + * * @param object $data Object containing data about the transition * * @return array $userIds The receivers @@ -257,7 +220,7 @@ private function getUsersFromGroup($data): Array if (!empty($data->options['notification_receivers'])) { $users = ArrayHelper::toInteger($data->options['notification_receivers']); - } + } // Usergroups $groups = []; @@ -281,40 +244,42 @@ private function getUsersFromGroup($data): Array $model->setState('filter.active', 1); $model->setState('filter.sendEmail', 1); - // Ids from usergroups - $groupUsers = $model->getItems(); + // Ids from usergroups + $groupUsers = $model->getItems(); + $users2 = ArrayHelper::getColumn($groupUsers, 'id'); } // Merge userIds from individual entries and userIDs from groups - $userIds = array_unique(array_merge($users, $users2)); - - return $userIds; + return array_unique(array_merge($users, $users2)); } /* - * Remove receivers who have locked their message inputbox - * + * Remove receivers who have locked their message inputbox + * * @param array $uerIds The userIds which must be checked * * @return array users with active message input box * * @since __DEPLOY_VERSION__ */ - private function removeLocked($userIds): Array + private function removeLocked(array $userIds): Array { + if (empty($userIds)) + { + return []; + } + // Check for locked inboxes would be better to have _cdf settings in the user_object or a filter in users model - $locked = []; + $query = $this->db->getQuery(true); - $db = $this->db; - $query = $db->getQuery(true); $query->select($db->quoteName('user_id')) ->from($db->quoteName('#__messages_cfg')) ->whereIn($db->quoteName('user_id'), $userIds) - ->where($db->quoteName('cfg_name') . '=' . $db->quote('locked')) - ->where($db->quoteName('cfg_value') . '=1'); + ->where($db->quoteName('cfg_name') . ' = ' . $db->quote('locked')) + ->where($db->quoteName('cfg_value') . ' = 1'); - $locked = $db->setQuery($query)->loadColumn(); + $locked = $this->db->setQuery($query)->loadColumn(); return array_diff($userIds, $locked); } From df6a18b16c377140cb947ab86287c420d99f303b Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Sat, 23 May 2020 09:51:17 +0200 Subject: [PATCH 53/90] Separate transition dropdown in articles list view (#102) --- .../com_content/forms/filter_articles.xml | 2 + .../com_content/forms/filter_featured.xml | 2 + .../com_content/src/Model/ArticlesModel.php | 7 +- .../com_content/src/Model/FeaturedModel.php | 2 +- .../com_content/tmpl/articles/default.php | 64 +++++++++-------- .../com_content/tmpl/featured/default.php | 54 ++++++++------- administrator/language/en-GB/joomla.ini | 5 ++ layouts/joomla/button/transition-button.php | 14 ++-- libraries/src/Button/TransitionButton.php | 69 +++++++++++++++++++ 9 files changed, 150 insertions(+), 69 deletions(-) create mode 100644 libraries/src/Button/TransitionButton.php diff --git a/administrator/components/com_content/forms/filter_articles.xml b/administrator/components/com_content/forms/filter_articles.xml index e382ff86439bc..006380099ff85 100644 --- a/administrator/components/com_content/forms/filter_articles.xml +++ b/administrator/components/com_content/forms/filter_articles.xml @@ -125,6 +125,8 @@ + + diff --git a/administrator/components/com_content/forms/filter_featured.xml b/administrator/components/com_content/forms/filter_featured.xml index 90a1e2f9be68e..bb94ca9a957af 100644 --- a/administrator/components/com_content/forms/filter_featured.xml +++ b/administrator/components/com_content/forms/filter_featured.xml @@ -111,6 +111,8 @@ + + diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 9b65a05b68349..3f145fad5b2bf 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -69,7 +69,8 @@ public function __construct($config = array()) 'level', 'tag', 'rating_count', 'rating', - 'stage', + 'stage', 'wa.stage_id', + 'ws.title' ); if (Associations::isEnabled()) @@ -276,6 +277,7 @@ protected function getListQuery() $db->quoteName('wa.stage_id', 'stage_id'), $db->quoteName('ws.title', 'stage_title'), $db->quoteName('ws.workflow_id', 'workflow_id'), + $db->quoteName('w.title', 'workflow_title'), ] ) ->from($db->quoteName('#__content', 'a')) @@ -288,7 +290,8 @@ protected function getListQuery() ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id')) ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')); + ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) + ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); if (PluginHelper::isEnabled('content', 'vote')) { diff --git a/administrator/components/com_content/src/Model/FeaturedModel.php b/administrator/components/com_content/src/Model/FeaturedModel.php index 74dd43131e7b2..9735baece3fe0 100644 --- a/administrator/components/com_content/src/Model/FeaturedModel.php +++ b/administrator/components/com_content/src/Model/FeaturedModel.php @@ -56,7 +56,7 @@ public function __construct($config = array()) 'level', 'tag', 'rating_count', 'rating', - 'stage', + 'ws.title', ); } diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index c484c4ed64901..f681604ba36ce 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -11,6 +11,7 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; +use Joomla\CMS\Button\TransitionButton; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; @@ -112,6 +113,11 @@
+ + - !$canChange - ]; - - if ($workflow_enabled) : - $options['disabled'] = true; - endif; - - echo (new FeaturedButton) - ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); - ?> - -
+
+
$transitions, - 'stage' => Text::_($item->stage_title), - 'id' => (int) $item->id + 'title' => Text::_($item->stage_title), + 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)) ]; - echo (new PublishedButton) - ->removeState(0) - ->removeState(1) - ->removeState(2) - ->removeState(-2) - ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) - ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) - ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) - ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) - ->setLayout('joomla.button.transition-button') - ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + echo (new TransitionButton($options)) + ->render(0, $i); ?>
+
state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); - endif; + $options = [ + 'disabled' => $workflow_enabled || !$canChange + ]; + + echo (new FeaturedButton) + ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); + ?> + + 'articles.', + 'disabled' => $workflow_enabled || !$canChange + ]; + + echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); ?> diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 01bfd8b5fc7e2..6eeeda05acacb 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -11,6 +11,7 @@ use Joomla\CMS\Button\FeaturedButton; use Joomla\CMS\Button\PublishedButton; +use Joomla\CMS\Button\TransitionButton; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; @@ -106,6 +107,11 @@ + + +
+ $transitions, + 'title' => Text::_($item->stage_title), + 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)) + ]; + + echo (new TransitionButton($options)) + ->render(0, $i); + ?> +
+
- -
- $transitions, - 'stage' => Text::_($item->stage_title), - 'id' => (int) $item->id - ]; - - echo (new PublishedButton) - ->removeState(0) - ->removeState(1) - ->removeState(2) - ->removeState(-2) - ->addState(ContentComponent::CONDITION_PUBLISHED, '', 'publish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JPUBLISHED')]) - ->addState(ContentComponent::CONDITION_UNPUBLISHED, '', 'unpublish', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JUNPUBLISHED')]) - ->addState(ContentComponent::CONDITION_ARCHIVED, '', 'archive', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JARCHIVED')]) - ->addState(ContentComponent::CONDITION_TRASHED, '', 'trash', Text::_('COM_CONTENT_CHANGE_STAGE'), ['tip_title' => Text::_('JTRASHED')]) - ->setLayout('joomla.button.transition-button') - ->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); - ?> -
state, $i, 'articles.', $canChange, 'cb', $item->publish_up, $item->publish_down); - endif; + $options = [ + 'task_prefix' => 'articles.', + 'disabled' => $workflow_enabled || !$canChange + ]; + + echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); ?>
diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini index d7e833de27900..eb50f8920c5a0 100644 --- a/administrator/language/en-GB/joomla.ini +++ b/administrator/language/en-GB/joomla.ini @@ -115,6 +115,10 @@ JREGISTER="Register" JORDERINGDISABLED="Please sort by order to enable reordering" JSAVE="Save & Close" JSELECT="Select" +JSTAGE="Stage" +JSTATUS="Status" +JSTAGE_ASC="Stage ascending" +JSTAGE_DESC="Stage descending" JSTATUS="Status" JSTATUS_ASC="Status ascending" JSTATUS_DESC="Status descending" @@ -135,6 +139,7 @@ JUNPROTECTED="Unprotected" JUNPUBLISHED="Unpublished" JVISIT_LINK="Visit Link" JVISIT_WEBSITE="Visit Website" +JWORKFLOW="Workflow: %s" JYEAR="Year" JVERSION="Version" JYES="Yes" diff --git a/layouts/joomla/button/transition-button.php b/layouts/joomla/button/transition-button.php index be757b261d158..cb9bb9ded6be7 100644 --- a/layouts/joomla/button/transition-button.php +++ b/layouts/joomla/button/transition-button.php @@ -23,19 +23,19 @@ $only_icon = empty($options['transitions']); $disabled = !empty($options['disabled']); $tip = !empty($options['tip']); -$id = (int) $options['id']; $tipTitle = $options['tip_title']; +$tipContent = $options['tip_content']; $checkboxName = $options['checkbox_name']; ?> -
escape($options['stage']); ?>
+
@@ -43,24 +43,24 @@ title="" - data-content="" + data-content="" data-placement="top" onclick="Joomla.toggleAllNextElements(this, 'd-none')" > -
escape($options['stage']); ?>
+
escape($options['stage'])), + HTMLHelper::_('select.option', '', $this->escape($options['title'])), HTMLHelper::_('select.option', '-1', '--------', ['disable' => true]) ]; $transitions = array_merge($default, $options['transitions']); $attribs = [ - 'id' => 'transition-select_' . (int) $id, + 'id' => 'transition-select_' . (int) $row ?? '', 'list.attr' => [ 'class' => 'custom-select custom-select-sm w-auto', 'onchange' => "this.form.transition_id.value=this.value;Joomla.listItemTask('" . $checkboxName . $this->escape($row ?? '') . "', 'articles.runTransition')"] diff --git a/libraries/src/Button/TransitionButton.php b/libraries/src/Button/TransitionButton.php new file mode 100644 index 0000000000000..719b519373243 --- /dev/null +++ b/libraries/src/Button/TransitionButton.php @@ -0,0 +1,69 @@ +unknownState['icon'] = 'shuffle'; + $this->unknownState['title'] = $options['title'] ?? Text::_('JLIB_HTML_UNKNOWN_STATE'); + $this->unknownState['tip_content'] = $options['tip_content'] ?? $this->unknownState['title']; + } + + /** + * Render action button by item value. + * + * @param integer|null $value Current value of this item. + * @param integer|null $row The row number of this item. + * @param array $options The options to override group options. + * @param string|Date $publishUp The date which item publish up. + * @param string|Date $publishDown The date which item publish down. + * + * @return string Rendered HTML. + * + * @since 4.0.0 + */ + public function render(?int $value = null, ?int $row = null, array $options = []): string + { + $default = $this->unknownState; + + $options['tip_title'] = $options['tip_title'] ?? ($options['title'] ?? $default['title']); + + return parent::render($value, $row, $options); + } +} From 87e2bcf2c9027cee6cefd86467e44541cbdaaffa Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sat, 23 May 2020 17:56:29 +0200 Subject: [PATCH 54/90] Fix broken DB calls --- plugins/workflow/notification/notification.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/workflow/notification/notification.php b/plugins/workflow/notification/notification.php index cbf6b09d3b856..dbfbd31fb032e 100644 --- a/plugins/workflow/notification/notification.php +++ b/plugins/workflow/notification/notification.php @@ -273,11 +273,11 @@ private function removeLocked(array $userIds): Array // Check for locked inboxes would be better to have _cdf settings in the user_object or a filter in users model $query = $this->db->getQuery(true); - $query->select($db->quoteName('user_id')) - ->from($db->quoteName('#__messages_cfg')) - ->whereIn($db->quoteName('user_id'), $userIds) - ->where($db->quoteName('cfg_name') . ' = ' . $db->quote('locked')) - ->where($db->quoteName('cfg_value') . ' = 1'); + $query->select($this->db->quoteName('user_id')) + ->from($this->db->quoteName('#__messages_cfg')) + ->whereIn($this->db->quoteName('user_id'), $userIds) + ->where($this->db->quoteName('cfg_name') . ' = ' . $this->db->quote('locked')) + ->where($this->db->quoteName('cfg_value') . ' = 1'); $locked = $this->db->setQuery($query)->loadColumn(); From 5a18ed191dfe068655c5f251c50e35a95db82b72 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Sat, 23 May 2020 18:03:30 +0200 Subject: [PATCH 55/90] Rename default workflow/stage to "basic" --- .../com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql | 4 ++-- .../com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql | 4 ++-- .../components/com_workflow/src/Model/WorkflowModel.php | 2 +- administrator/language/en-GB/com_workflow.ini | 3 ++- administrator/language/en-GB/com_workflow.sys.ini | 2 +- installation/sql/mysql/base.sql | 8 ++++---- installation/sql/postgresql/base.sql | 8 ++++---- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index c559a7478f43d..e62912969180f 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -34,7 +34,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); +(1, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- -- Table structure for table `#__workflow_associations` @@ -79,7 +79,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0); -- -- Table structure for table `#__workflow_transitions` diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 86d842eb022e5..f527001ebf5c8 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -31,7 +31,7 @@ CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); +(1, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0); -- -- Table structure for table "#__workflow_associations" @@ -79,7 +79,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES -(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0); -- -- Table structure for table "#__workflow_transitions" diff --git a/administrator/components/com_workflow/src/Model/WorkflowModel.php b/administrator/components/com_workflow/src/Model/WorkflowModel.php index 7c472af3ac84d..5cf20b0ac9bc8 100644 --- a/administrator/components/com_workflow/src/Model/WorkflowModel.php +++ b/administrator/components/com_workflow/src/Model/WorkflowModel.php @@ -113,7 +113,7 @@ public function save($data) $table = $this->getTable('Stage'); $table->id = 0; - $table->title = 'COM_WORKFLOW_DEFAULT'; + $table->title = 'COM_WORKFLOW_BASIC_STAGE'; $table->description = ''; $table->workflow_id = $workflow_id; $table->published = 1; diff --git a/administrator/language/en-GB/com_workflow.ini b/administrator/language/en-GB/com_workflow.ini index 9e05fb30e411c..f4d685a410e9d 100644 --- a/administrator/language/en-GB/com_workflow.ini +++ b/administrator/language/en-GB/com_workflow.ini @@ -6,6 +6,7 @@ COM_WORKFLOW_ARE_YOU_SURE="Are you sure?" COM_WORKFLOW_AUTHOR="Author" COM_WORKFLOW_BASIC_TAB="Basic" +COM_WORKFLOW_BASIC_STAGE="Basic Stage" COM_WORKFLOW_CHOOSE_CONTEXT_LABEL="Context" COM_WORKFLOW_CONDITION="Condition of items in this stage: " COM_WORKFLOW_CONDITION_DESC="Defines item behaviour." @@ -22,7 +23,7 @@ COM_WORKFLOW_DATE_CREATED="Date Created" COM_WORKFLOW_DATE_MODIFIED="Date Modified" COM_WORKFLOW_DEFAULT="Default" COM_WORKFLOW_DEFAULT_ITEM="Default option is already set for a different item." -COM_WORKFLOW_DEFAULT_WORKFLOW="Joomla! Default" +COM_WORKFLOW_BASIC_WORKFLOW="Basic Workflow" COM_WORKFLOW_DESCRIPTION="Description" COM_WORKFLOW_DESC_TAB="Description" COM_WORKFLOW_DISABLE_DEFAULT="Cannot change default stage of this item." diff --git a/administrator/language/en-GB/com_workflow.sys.ini b/administrator/language/en-GB/com_workflow.sys.ini index 53b54f1ecc162..5baa202207a65 100644 --- a/administrator/language/en-GB/com_workflow.sys.ini +++ b/administrator/language/en-GB/com_workflow.sys.ini @@ -4,7 +4,7 @@ ; Note : All ini files need to be saved as UTF-8 COM_WORKFLOW="Workflows" -COM_WORKFLOW_DEFAULT_WORKFLOW="Joomla! Default" +COM_WORKFLOW_BASIC_WORKFLOW="Basic Workflow" COM_WORKFLOW_MESSAGES_VIEW_DEFAULT_DESC="Customised workflow support for Joomla! site" COM_WORKFLOW_MESSAGES_VIEW_DEFAULT_TITLE="Workflows" COM_WORKFLOW_XML_DESCRIPTION="Customised workflow support for Joomla! site" diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 3a9743f5ba51e..d03e2c8df3833 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -75,8 +75,8 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (53, 18, 90, 91, 2, 'com_modules.module.86', 'Joomla Version', '{}'), (54, 16, 54, 55, 2, 'com_menus.menu.1', 'Main Menu', '{}'), (55, 18, 92, 93, 2, 'com_modules.module.87', 'Sample Data', '{}'), -(56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_DEFAULT_WORKFLOW', '{}'), -(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_DEFAULT', '{}'), +(56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), +(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), (58, 56, 23, 24, 3, 'com_content.transition.1', 'Publish', '{}'), (59, 56, 25, 26, 3, 'com_content.transition.2', 'Unpublish', '{}'), (60, 56, 27, 28, 3, 'com_content.transition.3', 'Archive', '{}'), @@ -1086,7 +1086,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); +(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42, NULL, 0); -- -------------------------------------------------------- @@ -1135,7 +1135,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) VALUES -(1, 0, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 205030176d08b..ef425dcf2ea5a 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -81,8 +81,8 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (53, 18, 90, 91, 2, 'com_modules.module.86', 'Joomla Version', '{}'), (54, 16, 54, 55, 2, 'com_menus.menu.1', 'Main Menu', '{}'), (55, 18, 92, 93, 2, 'com_modules.module.87', 'Sample Data', '{}'), -(56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_DEFAULT_WORKFLOW', '{}'), -(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_DEFAULT', '{}'), +(56, 8, 20, 37, 2, 'com_content.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), +(57, 56, 21, 22, 3, 'com_content.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), (58, 56, 23, 24, 3, 'com_content.transition.1', 'Publish', '{}'), (59, 56, 25, 26, 3, 'com_content.transition.2', 'Unpublish', '{}'), (60, 56, 27, 28, 3, 'com_content.transition.3', 'Archive', '{}'), @@ -1093,7 +1093,7 @@ CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES -(1, 56, 1, 'COM_WORKFLOW_DEFAULT_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); +(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42, NULL, 0); SELECT setval('#__workflows_id_seq', 2, false); @@ -1143,7 +1143,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") VALUES -(1, 57, 1, 1, 1, 'COM_WORKFLOW_DEFAULT', '', 1, NULL, 0); +(1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0); SELECT setval('#__workflow_stages_id_seq', 2, false); From 28e7aa79b074101797d6ebb6ca8c768d0ea4032f Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Sat, 23 May 2020 18:05:22 +0200 Subject: [PATCH 56/90] fix ordering workflows (#101) * fix ordering workflows * fix ordering for stages and transitions --- .../com_workflow/src/Table/StageTable.php | 5 ----- .../src/Table/TransitionTable.php | 20 ------------------- .../com_workflow/src/Table/WorkflowTable.php | 5 ----- 3 files changed, 30 deletions(-) diff --git a/administrator/components/com_workflow/src/Table/StageTable.php b/administrator/components/com_workflow/src/Table/StageTable.php index e59f1a3847616..31589d6180e0f 100644 --- a/administrator/components/com_workflow/src/Table/StageTable.php +++ b/administrator/components/com_workflow/src/Table/StageTable.php @@ -177,11 +177,6 @@ public function check() */ public function store($updateNulls = true) { - if (!(int) $this->ordering) - { - $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); - } - $table = new StageTable($this->getDbo()); if ($this->default == '1') diff --git a/administrator/components/com_workflow/src/Table/TransitionTable.php b/administrator/components/com_workflow/src/Table/TransitionTable.php index 30447ecddc61d..9da1e1a2bbca0 100644 --- a/administrator/components/com_workflow/src/Table/TransitionTable.php +++ b/administrator/components/com_workflow/src/Table/TransitionTable.php @@ -54,26 +54,6 @@ public function __construct(DatabaseDriver $db) $this->access = (int) Factory::getApplication()->get('access'); } - /** - * Overloaded store function - * - * @param boolean $updateNulls True to update fields even if they are null. - * - * @return mixed False on failure, positive integer on success. - * - * @see Table::store() - * @since 4.0.0 - */ - public function store($updateNulls = true) - { - if (!(int) $this->ordering) - { - $this->ordering = $this->getNextOrder($this->_db->quoteName('workflow_id') . ' = ' . (int) $this->workflow_id); - } - - return parent::store($updateNulls); - } - /** * Method to compute the default name of the asset. * The default name is in the form table_name.id diff --git a/administrator/components/com_workflow/src/Table/WorkflowTable.php b/administrator/components/com_workflow/src/Table/WorkflowTable.php index 236913cc52360..04797b014fc51 100644 --- a/administrator/components/com_workflow/src/Table/WorkflowTable.php +++ b/administrator/components/com_workflow/src/Table/WorkflowTable.php @@ -197,11 +197,6 @@ public function store($updateNulls = true) $this->modified_by = 0; } - if (!(int) $this->ordering) - { - $this->ordering = $this->getNextOrder(); - } - if (!(int) $this->created) { $this->created = $date->toSql(); From c72060ba18f896a764f0bbe61f51921b8e3d755e Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Tue, 26 May 2020 00:24:13 +0200 Subject: [PATCH 57/90] [WIP] Add options per section and functionality and use new event system (#99) * Add section options and new event system * CS * Support plugin whitelist and blacklist and component config options * Updated notification plugin * Cache if functionality is not active in service trait * Move featured up/down out of global layout --- .../components/com_content/config.xml | 33 +++- .../components/com_content/forms/article.xml | 42 ++--- .../com_content/tmpl/articles/default.php | 24 ++- administrator/language/en-GB/joomla.ini | 11 +- layouts/joomla/edit/global.php | 2 - layouts/joomla/edit/publishingdata.php | 2 + libraries/src/Event/View/DisplayEvent.php | 61 +++++++ .../src/Event/Workflow/AbstractEvent.php | 61 +++++++ .../WorkflowFunctionalityUsedEvent.php | 55 ++++++ .../Workflow/WorkflowTransitionEvent.php | 57 ++++++ libraries/src/MVC/View/HtmlView.php | 29 ++- libraries/src/Workflow/Workflow.php | 111 ++++++----- .../src/Workflow/WorkflowPluginTrait.php | 76 +++++++- .../src/Workflow/WorkflowServiceTrait.php | 92 +++++++++- plugins/workflow/featuring/featuring.php | 166 +++++++++++------ plugins/workflow/featuring/featuring.xml | 13 +- .../workflow/notification/notification.php | 109 ++++++++--- .../workflow/notification/notification.xml | 13 +- plugins/workflow/publishing/publishing.php | 172 ++++++++++++------ plugins/workflow/publishing/publishing.xml | 13 +- 20 files changed, 909 insertions(+), 233 deletions(-) create mode 100644 libraries/src/Event/View/DisplayEvent.php create mode 100644 libraries/src/Event/Workflow/AbstractEvent.php create mode 100644 libraries/src/Event/Workflow/WorkflowFunctionalityUsedEvent.php create mode 100644 libraries/src/Event/Workflow/WorkflowTransitionEvent.php diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml index d7c412d0ab738..61b3a3c22d3dd 100644 --- a/administrator/components/com_content/config.xml +++ b/administrator/components/com_content/config.xml @@ -1039,17 +1039,46 @@ - + +
+ + + + + + + + + + +
+ + + + JYES - - - - get('workflow_enabled', 1); +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled', 1); +$workflow_state = false; +$workflow_featured = false; if ($workflow_enabled) : @@ -80,6 +82,9 @@ HTMLHelper::_('script', 'com_workflow/admin-items-workflow-buttons.js', ['relative' => true, 'version' => 'auto']); + $workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_content.article'); + $workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article'); + endif; $assoc = Associations::isEnabled(); @@ -223,10 +228,15 @@
- $workflow_enabled || !$canChange - ]; + !$canChange + ]; + + if ($workflow_featured) : + $options['disabled'] = true; + endif; echo (new FeaturedButton) ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); @@ -239,6 +249,10 @@ 'disabled' => $workflow_enabled || !$canChange ]; + if ($workflow_state) : + $options['disabled'] = true; + endif; + echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); ?> + + + + diff --git a/administrator/components/com_workflow/tmpl/transitions/default.php b/administrator/components/com_workflow/tmpl/transitions/default.php index 6d9d0b9d6ef98..d9a6235f73965 100644 --- a/administrator/components/com_workflow/tmpl/transitions/default.php +++ b/administrator/components/com_workflow/tmpl/transitions/default.php @@ -66,16 +66,16 @@ + + + diff --git a/administrator/components/com_workflow/tmpl/workflows/default.php b/administrator/components/com_workflow/tmpl/workflows/default.php index 18a1c08bcbd66..eae067e20fe37 100644 --- a/administrator/components/com_workflow/tmpl/workflows/default.php +++ b/administrator/components/com_workflow/tmpl/workflows/default.php @@ -75,10 +75,10 @@ + + From 2241a3ef08d1362822d4d1d4e9984e80c4303413 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Wed, 27 May 2020 16:56:10 +0200 Subject: [PATCH 78/90] Use direct queryselector for workflow JS --- .../com_workflow/js/admin-items-workflow-buttons.es6.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js index 3fdb8bbccb399..b6434abc14cc8 100644 --- a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js +++ b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js @@ -40,9 +40,9 @@ Joomla.toggleAllNextElements = (element, className) => { document.addEventListener('DOMContentLoaded', () => { const dropDownBtn = document.getElementById('toolbar-dropdown-status-group'); const transitions = [].slice.call(dropDownBtn.querySelectorAll('.button-transition')); - const headline = dropDownBtn.getElementsByClassName('button-transition-headline')[0]; - const separator = dropDownBtn.getElementsByClassName('button-transition-separator')[0]; - const itemList = [].slice.call(document.querySelectorAll('table.itemList'))[0]; + const headline = dropDownBtn.querySelector('.button-transition-headline'); + const separator = dropDownBtn.querySelector('.button-transition-separator'); + const itemList = document.querySelector('table.itemList'); let itemListRows = []; let transitionIds = []; @@ -100,7 +100,7 @@ Joomla.toggleAllNextElements = (element, className) => { } transitionIds = []; itemListRows.forEach((el) => { - const checkedBox = el.querySelectorAll('input[type=checkbox]')[0]; + const checkedBox = el.querySelector('input[type=checkbox]'); if (checkedBox.checked) { const parentTr = checkedBox.closest('tr'); collectTransitions(parentTr); From d10177fb62190b64abda5c130e72f70a0333f2d3 Mon Sep 17 00:00:00 2001 From: Richard Fath Date: Wed, 27 May 2020 19:21:12 +0200 Subject: [PATCH 79/90] Remove locked column of extensions table from update sql - sorry was my mistake (#117) --- .../com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql | 10 +++++----- .../sql/updates/postgresql/4.0.0-2018-05-15.sql | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql index cebaf855873e7..b0c2b3115e08c 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2018-05-15.sql @@ -128,11 +128,11 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` -- update SQL script. -- -INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), -(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); +INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, '', '{}', 0, '0000-00-00 00:00:00', 0, 0); -- -- Creating Associations for existing content diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql index 507fb7dd7d8cf..ec7f6c3508ae3 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2018-05-15.sql @@ -124,11 +124,11 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" -- update SQL script. -- -INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES -(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), -(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); +INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "checked_out", "checked_out_time", "ordering", "state") VALUES +(0, 'com_workflow', 'component', 'com_workflow', '', 1, 1, 0, 1, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_publishing', 'plugin', 'publishing', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_featuring', 'plugin', 'featuring', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0), +(0, 'plg_workflow_notification', 'plugin', 'notification', 'workflow', 0, 1, 1, 0, '', '{}', 0, '1970-01-01 00:00:00', 0, 0); -- -- Creating Associations for existing content From edf2af83f37ff8e632462f1cb6b0aeff9db15b4d Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Wed, 27 May 2020 20:50:51 +0200 Subject: [PATCH 80/90] Fix filter stages fpr atricles (#118) --- administrator/components/com_content/forms/filter_articles.xml | 2 +- administrator/components/com_content/forms/filter_featured.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_content/forms/filter_articles.xml b/administrator/components/com_content/forms/filter_articles.xml index 006380099ff85..f1c01cd9eb621 100644 --- a/administrator/components/com_content/forms/filter_articles.xml +++ b/administrator/components/com_content/forms/filter_articles.xml @@ -29,7 +29,7 @@ label="JOPTION_SELECT_STAGE" onchange="this.form.submit();" activeonly="true" - extension="com_content" + extension="com_content.article" > diff --git a/administrator/components/com_content/forms/filter_featured.xml b/administrator/components/com_content/forms/filter_featured.xml index bb94ca9a957af..6d05c14f2ed22 100644 --- a/administrator/components/com_content/forms/filter_featured.xml +++ b/administrator/components/com_content/forms/filter_featured.xml @@ -26,7 +26,7 @@ type="status" label="JOPTION_SELECT_PUBLISHED" onchange="this.form.submit();" - extension="com_content" + extension="com_content.article" > From d15a27f0db005cda276a185c94074e73d42cef6b Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Thu, 28 May 2020 01:53:24 +0200 Subject: [PATCH 81/90] Change workflow enable parameter (#119) --- administrator/components/com_content/config.xml | 2 +- .../components/com_content/src/Model/ArticlesModel.php | 4 ++-- .../components/com_content/src/View/Articles/HtmlView.php | 2 +- .../components/com_content/src/View/Featured/HtmlView.php | 2 +- .../components/com_content/tmpl/articles/default.php | 2 +- .../com_content/tmpl/articles/default_batch_body.php | 2 +- .../components/com_content/tmpl/featured/default.php | 2 +- administrator/modules/mod_menu/src/Menu/CssMenu.php | 2 +- administrator/modules/mod_submenu/src/Menu/Menu.php | 4 +++- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 2 +- libraries/src/Workflow/WorkflowServiceTrait.php | 2 +- 11 files changed, 14 insertions(+), 12 deletions(-) diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml index 394da59bf83e8..62b34237ba614 100644 --- a/administrator/components/com_content/config.xml +++ b/administrator/components/com_content/config.xml @@ -1049,7 +1049,7 @@ type="radio" label="JWORKFLOW_ENABLED_LABEL" layout="joomla.form.field.radio.switcher" - default="1" + default="0" > diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 3f145fad5b2bf..2328df7d43560 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -98,7 +98,7 @@ public function getFilterForm($data = array(), $loadData = true) $params = ComponentHelper::getParams('com_content'); - if (!$params->get('workflow_enabled', 1)) + if (!$params->get('workflow_enabled')) { $form->removeField('stage', 'filter'); } @@ -358,7 +358,7 @@ protected function getListQuery() // Filter by published state $workflowStage = (string) $this->getState('filter.stage'); - if ($params->get('workflow_enabled', 1) && is_numeric($workflowStage)) + if ($params->get('workflow_enabled') && is_numeric($workflowStage)) { $workflowStage = (int) $workflowStage; $query->where($db->quoteName('wa.stage_id') . ' = :stage') diff --git a/administrator/components/com_content/src/View/Articles/HtmlView.php b/administrator/components/com_content/src/View/Articles/HtmlView.php index 6bc32c85e617b..a66139ec85c9a 100644 --- a/administrator/components/com_content/src/View/Articles/HtmlView.php +++ b/administrator/components/com_content/src/View/Articles/HtmlView.php @@ -88,7 +88,7 @@ public function display($tpl = null) $this->activeFilters = $this->get('ActiveFilters'); $this->vote = PluginHelper::isEnabled('content', 'vote'); - if (ComponentHelper::getParams('com_content')->get('workflow_enabled', 1)) + if (ComponentHelper::getParams('com_content')->get('workflow_enabled')) { PluginHelper::importPlugin('workflow'); diff --git a/administrator/components/com_content/src/View/Featured/HtmlView.php b/administrator/components/com_content/src/View/Featured/HtmlView.php index 351a55ff16b25..b2601d44c1b13 100644 --- a/administrator/components/com_content/src/View/Featured/HtmlView.php +++ b/administrator/components/com_content/src/View/Featured/HtmlView.php @@ -89,7 +89,7 @@ public function display($tpl = null) $this->transitions = $this->get('Transitions'); $this->vote = PluginHelper::isEnabled('content', 'vote'); - if (ComponentHelper::getParams('com_content')->get('workflow_enabled', 1)) + if (ComponentHelper::getParams('com_content')->get('workflow_enabled')) { PluginHelper::importPlugin('workflow'); diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php index 9e92b78addce4..40406132836b1 100644 --- a/administrator/components/com_content/tmpl/articles/default.php +++ b/administrator/components/com_content/tmpl/articles/default.php @@ -57,7 +57,7 @@ HTMLHelper::_('draggablelist.draggable'); } -$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled', 1); +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled'); $workflow_state = false; $workflow_featured = false; diff --git a/administrator/components/com_content/tmpl/articles/default_batch_body.php b/administrator/components/com_content/tmpl/articles/default_batch_body.php index 8f5a7b5bb0c1f..9f88c07f16963 100644 --- a/administrator/components/com_content/tmpl/articles/default_batch_body.php +++ b/administrator/components/com_content/tmpl/articles/default_batch_body.php @@ -45,7 +45,7 @@ - authorise('core.admin', 'com_content') && $params->get('workflow_enabled', 1)) : ?> + authorise('core.admin', 'com_content') && $params->get('workflow_enabled')) : ?>
'com_content']); ?> diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 01bad28efe90f..e97dbe709d73c 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -52,7 +52,7 @@ HTMLHelper::_('draggablelist.draggable'); } -$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled', 1); +$workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled'); if ($workflow_enabled) : diff --git a/administrator/modules/mod_menu/src/Menu/CssMenu.php b/administrator/modules/mod_menu/src/Menu/CssMenu.php index b685831fe977b..3b86b9ed11208 100644 --- a/administrator/modules/mod_menu/src/Menu/CssMenu.php +++ b/administrator/modules/mod_menu/src/Menu/CssMenu.php @@ -378,7 +378,7 @@ protected function preprocess($parent) { $parts = explode('.', $query['extension']); - $workflow = ComponentHelper::getParams($parts[0])->get('workflow_enabled', 1); + $workflow = ComponentHelper::getParams($parts[0])->get('workflow_enabled'); } if (!$workflow) diff --git a/administrator/modules/mod_submenu/src/Menu/Menu.php b/administrator/modules/mod_submenu/src/Menu/Menu.php index 7f8168f9521cc..a0af252bdcb86 100644 --- a/administrator/modules/mod_submenu/src/Menu/Menu.php +++ b/administrator/modules/mod_submenu/src/Menu/Menu.php @@ -129,7 +129,9 @@ public static function preprocess($parent) if (isset($query['extension'])) { - $workflow = ComponentHelper::getParams($query['extension'])->get('workflow_enabled', 1); + $parts = explode('.', $query['extension']); + + $workflow = ComponentHelper::getParams($parts[0])->get('workflow_enabled'); } if (!$workflow) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index f66202b652676..15345c9aaec70 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -84,7 +84,7 @@ public function setUpWorkflow($extension) $params = ComponentHelper::getParams($this->extension); - $this->workflowEnabled = $params->get('workflow_enabled', 1); + $this->workflowEnabled = $params->get('workflow_enabled'); $this->enableWorkflowBatch(); } diff --git a/libraries/src/Workflow/WorkflowServiceTrait.php b/libraries/src/Workflow/WorkflowServiceTrait.php index a2a4906a23598..6637135e88eef 100644 --- a/libraries/src/Workflow/WorkflowServiceTrait.php +++ b/libraries/src/Workflow/WorkflowServiceTrait.php @@ -163,7 +163,7 @@ public function isWorkflowActive($context): bool $parts = explode('.', $context); $config = ComponentHelper::getParams($parts[0]); - if (!$config->get('workflow_enabled', 1)) + if (!$config->get('workflow_enabled')) { return false; } From 89712e1684faca5170f95b91fa311e9a8cd5372b Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Thu, 28 May 2020 10:53:43 +0200 Subject: [PATCH 82/90] Only save feature flag if not managed by workflow --- .../components/com_content/src/Model/ArticleModel.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index bba8b0e34cead..16518edc11ffd 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -830,7 +830,8 @@ public function save($data) if (parent::save($data)) { - if (isset($data['featured'])) + // check if featured is set and if not managed by workflow + if (isset($data['featured']) && !$this->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article')) { if (!$this->featured( $this->getState($this->getName() . '.id'), From 9cbade794434f0f40a8973d0fc8f95bcdd0eb7e9 Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Thu, 28 May 2020 12:07:45 +0200 Subject: [PATCH 83/90] Fix doc block - return (#120) --- .../components/com_content/src/Extension/ContentComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Extension/ContentComponent.php b/administrator/components/com_content/src/Extension/ContentComponent.php index dbb0729887c87..3d2dd23ba030d 100644 --- a/administrator/components/com_content/src/Extension/ContentComponent.php +++ b/administrator/components/com_content/src/Extension/ContentComponent.php @@ -228,7 +228,7 @@ public function getWorkflowTableBySection(?string $section = null): string * * @param string $context The context of the workflow * - * @return bool + * @return string */ public function getModelName($context): string { From c749e566371abd2c784f56579c1776f7a5486857 Mon Sep 17 00:00:00 2001 From: Harald Leithner Date: Thu, 28 May 2020 12:59:15 +0200 Subject: [PATCH 84/90] cs (#121) --- administrator/components/com_content/src/Model/ArticleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticleModel.php b/administrator/components/com_content/src/Model/ArticleModel.php index 16518edc11ffd..042f121847689 100644 --- a/administrator/components/com_content/src/Model/ArticleModel.php +++ b/administrator/components/com_content/src/Model/ArticleModel.php @@ -830,7 +830,7 @@ public function save($data) if (parent::save($data)) { - // check if featured is set and if not managed by workflow + // Check if featured is set and if not managed by workflow if (isset($data['featured']) && !$this->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article')) { if (!$this->featured( From 5b4fc0e11240751fcb2e5c63f2ed830d8c497e95 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 29 May 2020 19:44:02 +0200 Subject: [PATCH 85/90] Fix sample data --- libraries/src/MVC/Model/AdminModel.php | 2 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 120 +----------------- libraries/src/Workflow/Workflow.php | 118 +++++++++++++++++ plugins/sampledata/blog/blog.php | 12 +- plugins/sampledata/multilang/multilang.php | 19 ++- plugins/sampledata/testing/testing.php | 10 +- 6 files changed, 144 insertions(+), 137 deletions(-) diff --git a/libraries/src/MVC/Model/AdminModel.php b/libraries/src/MVC/Model/AdminModel.php index 8e5db2b2e3f12..69800571938a0 100644 --- a/libraries/src/MVC/Model/AdminModel.php +++ b/libraries/src/MVC/Model/AdminModel.php @@ -1269,7 +1269,7 @@ public function save($data) } $key = $table->getKeyName(); - $pk = (!empty($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); + $pk = (isset($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); $isNew = true; // Include the plugins for the save events. diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 15345c9aaec70..f8cca5c09a6c5 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -10,7 +10,6 @@ \defined('JPATH_PLATFORM') or die; -use Joomla\Database\ParameterType; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; @@ -18,8 +17,6 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Workflow\Workflow; -use Joomla\CMS\Table\Category; -use Joomla\Registry\Registry; /** * Trait which supports state behavior @@ -278,7 +275,7 @@ public function workflowCleanupBatchMove($oldId, $newId) $catKey = $table->getColumnAlias('catid'); - $stage_id = $this->getDefaultStageByCategoryId($table->$catKey); + $stage_id = $this->workflow->getDefaultStageByCategory($table->$catKey); if (empty($stage_id)) { @@ -431,119 +428,6 @@ protected function getStageForNewItem(Form $form, $data) return false; } - return $this->getDefaultStageByCategoryId($catId); - } - - /** - * Try to load a workflow default stage by category ID. - * - * @param integer $catId The category ID. - * - * @return boolean|integer An integer, holding the stage ID or false - * @since 4.0.0 - */ - protected function getDefaultStageByCategoryId($catId) - { - $db = Factory::getContainer()->get('DatabaseDriver'); - - // Let's check if a workflow ID is assigned to a category - $category = new Category($db); - - $categories = array_reverse($category->getPath($catId)); - - $workflow_id = 0; - - foreach ($categories as $cat) - { - $cat->params = new Registry($cat->params); - - $workflow_id = $cat->params->get('workflow_id'); - - if ($workflow_id == 'inherit') - { - $workflow_id = 0; - - continue; - } - elseif ($workflow_id == 'use_default') - { - $workflow_id = 0; - - break; - } - elseif ($workflow_id > 0) - { - break; - } - } - - // Check if the workflow exists - if ($workflow_id = (int) $workflow_id) - { - $query = $db->getQuery(true); - - $query->select( - [ - $db->quoteName('ws.id') - ] - ) - ->from( - [ - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflows', 'w'), - ] - ) - ->where( - [ - $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), - $db->quoteName('ws.default') . ' = 1', - $db->quoteName('w.published') . ' = 1', - $db->quoteName('ws.published') . ' = 1', - $db->quoteName('w.id') . ' = :workflowId', - ] - ) - ->bind(':workflowId', $workflow_id, ParameterType::INTEGER); - - $stage_id = (int) $db->setQuery($query)->loadResult(); - - if (!empty($stage_id)) - { - return $stage_id; - } - } - - // Use default workflow - $query = $db->getQuery(true); - - $query->select( - [ - $db->quoteName('ws.id') - ] - ) - ->from( - [ - $db->quoteName('#__workflow_stages', 'ws'), - $db->quoteName('#__workflows', 'w'), - ] - ) - ->where( - [ - $db->quoteName('ws.default') . ' = 1', - $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), - $db->quoteName('w.published') . ' = 1', - $db->quoteName('ws.published') . ' = 1', - $db->quoteName('w.default') . ' = 1', - ] - ); - - $stage_id = (int) $db->setQuery($query)->loadResult(); - - // Last check if we have a workflow ID - if (!empty($stage_id)) - { - return $stage_id; - } - - return false; + return $this->workflow->getDefaultStageByCategory($catId); } } diff --git a/libraries/src/Workflow/Workflow.php b/libraries/src/Workflow/Workflow.php index 5516c6d8d8ad2..1842ad393538a 100644 --- a/libraries/src/Workflow/Workflow.php +++ b/libraries/src/Workflow/Workflow.php @@ -14,6 +14,7 @@ use Joomla\CMS\Extension\ComponentInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; +use Joomla\CMS\Table\Category; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; @@ -148,6 +149,123 @@ protected function getComponent() return $this->component; } + /** + * Try to load a workflow default stage by category ID. + * + * @param integer $catId The category ID. + * + * @return boolean|integer An integer, holding the stage ID or false + * @since 4.0.0 + */ + public function getDefaultStageByCategory($catId = 0) + { + $db = Factory::getContainer()->get('DatabaseDriver'); + + // Let's check if a workflow ID is assigned to a category + $category = new Category($db); + + $categories = array_reverse($category->getPath($catId)); + + $workflow_id = 0; + + foreach ($categories as $cat) + { + $cat->params = new Registry($cat->params); + + $workflow_id = $cat->params->get('workflow_id'); + + if ($workflow_id == 'inherit') + { + $workflow_id = 0; + + continue; + } + elseif ($workflow_id == 'use_default') + { + $workflow_id = 0; + + break; + } + elseif ($workflow_id > 0) + { + break; + } + } + + // Check if the workflow exists + if ($workflow_id = (int) $workflow_id) + { + $query = $db->getQuery(true); + + $query->select( + [ + $db->quoteName('ws.id') + ] + ) + ->from( + [ + $db->quoteName('#__workflow_stages', 'ws'), + $db->quoteName('#__workflows', 'w'), + ] + ) + ->where( + [ + $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), + $db->quoteName('ws.default') . ' = 1', + $db->quoteName('w.published') . ' = 1', + $db->quoteName('ws.published') . ' = 1', + $db->quoteName('w.id') . ' = :workflowId', + $db->quoteName('w.extension') . ' = :extension', + ] + ) + ->bind(':workflowId', $workflow_id, ParameterType::INTEGER) + ->bind(':extension', $this->extension); + + $stage_id = (int) $db->setQuery($query)->loadResult(); + + if (!empty($stage_id)) + { + return $stage_id; + } + } + + // Use default workflow + $query = $db->getQuery(true); + + $query->select( + [ + $db->quoteName('ws.id') + ] + ) + ->from( + [ + $db->quoteName('#__workflow_stages', 'ws'), + $db->quoteName('#__workflows', 'w'), + ] + ) + ->where( + [ + $db->quoteName('ws.default') . ' = 1', + $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), + $db->quoteName('w.published') . ' = 1', + $db->quoteName('ws.published') . ' = 1', + $db->quoteName('w.default') . ' = 1', + $db->quoteName('w.extension') . ' = :extension' + ] + ) + ->bind(':extension', $this->extension); + + $stage_id = (int) $db->setQuery($query)->loadResult(); + + // Last check if we have a workflow ID + if (!empty($stage_id)) + { + return $stage_id; + } + + return false; + } + /** * Executes a transition to change the current state in the association table * diff --git a/plugins/sampledata/blog/blog.php b/plugins/sampledata/blog/blog.php index b16663ee03579..bf14dfa79a5b3 100644 --- a/plugins/sampledata/blog/blog.php +++ b/plugins/sampledata/blog/blog.php @@ -117,8 +117,6 @@ public function onAjaxSampledataApplyStep1() $language = Multilanguage::isEnabled() ? Factory::getLanguage()->getTag() : '*'; $langSuffix = ($language !== '*') ? ' (' . $language . ')' : ''; - $workflow_id = 1; - // Create "blog" category. $categoryModel = $this->app->bootComponent('com_categories') ->getMVCFactory()->createModel('Category', 'Administrator'); @@ -147,7 +145,7 @@ public function onAjaxSampledataApplyStep1() 'associations' => array(), 'description' => '', 'language' => $language, - 'params' => '{"workflow_id": "' . $workflow_id . '"}', + 'params' => '{}', ); try @@ -194,7 +192,7 @@ public function onAjaxSampledataApplyStep1() 'associations' => array(), 'description' => '', 'language' => $language, - 'params' => '{"workflow_id": "' . $workflow_id . '"}', + 'params' => '{}', ); try @@ -247,6 +245,8 @@ public function onAjaxSampledataApplyStep1() $mvcFactory = $this->app->bootComponent('com_content')->getMVCFactory(); + ComponentHelper::getParams('com_content')->set('workflow_enabled', 0); + foreach ($articles as $i => $article) { $articleModel = $mvcFactory->createModel('Article', 'Administrator', ['ignore_request' => true]); @@ -273,6 +273,7 @@ public function onAjaxSampledataApplyStep1() $article['language'] = $language; $article['associations'] = array(); + $article['published'] = 1; $article['featured'] = 0; $article['images'] = ''; $article['metakey'] = ''; @@ -283,9 +284,6 @@ public function onAjaxSampledataApplyStep1() $article['access'] = $access; } - // Publish - $article['transition'] = 2; - if (!$articleModel->save($article)) { Factory::getLanguage()->load('com_content'); diff --git a/plugins/sampledata/multilang/multilang.php b/plugins/sampledata/multilang/multilang.php index 78eaae8029194..2e3da61d97df4 100644 --- a/plugins/sampledata/multilang/multilang.php +++ b/plugins/sampledata/multilang/multilang.php @@ -20,6 +20,7 @@ use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Session\Session; use Joomla\CMS\Table\Table; +use Joomla\CMS\Workflow\Workflow; use Joomla\Database\Exception\ExecutionFailureException; use Joomla\Database\ParameterType; @@ -375,6 +376,8 @@ public function onAjaxSampledataApplyStep6() $siteLanguages = $this->getInstalledlangsFrontend(); + ComponentHelper::getParams('com_content')->set('workflow_enabled', 0); + foreach ($siteLanguages as $siteLang) { if (!$tableCategory = $this->addCategory($siteLang)) @@ -1020,7 +1023,7 @@ public function addCategory($itemLanguage) 'description' => '', 'published' => 1, 'access' => 1, - 'params' => '{"target":"","image":"", "workflow_id":"1"}', + 'params' => '{"target":"","image":""}', 'metadesc' => '', 'metakey' => '', 'metadata' => '{"page_title":"","author":"","robots":""}', @@ -1114,6 +1117,7 @@ private function addArticle($itemLanguage, $categoryId) 'metadesc' => '', 'language' => $itemLanguage->language, 'state' => 1, + 'published' => 1, 'featured' => 1, 'attribs' => array(), 'rules' => array(), @@ -1155,15 +1159,16 @@ private function addArticle($itemLanguage, $categoryId) return false; } - $assoc = new stdClass; - - $assoc->item_id = $newId; - $assoc->stage_id = 2; - $assoc->extension = 'com_content.article'; + $workflow = new Workflow(['extension' => 'com_content.article']); try { - $db->insertObject('#__workflow_associations', $assoc); + $stage_id = $workflow->getDefaultStageByCategory($categoryId); + + if ($stage_id) + { + $workflow->createAssociation($newId, $stage_id); + } } catch (ExecutionFailureException $e) { diff --git a/plugins/sampledata/testing/testing.php b/plugins/sampledata/testing/testing.php index 527e1b9c8df20..85269dae8dd3b 100644 --- a/plugins/sampledata/testing/testing.php +++ b/plugins/sampledata/testing/testing.php @@ -639,6 +639,8 @@ public function onAjaxSampledataApplyStep4() return $response; } + ComponentHelper::getParams('com_content')->set('workflow_enabled', 0); + $catIdsLevel1 = $this->app->getUserState('sampledata.testing.articles.catids1'); $catIdsLevel2 = $this->app->getUserState('sampledata.testing.articles.catids2'); $catIdsLevel3 = $this->app->getUserState('sampledata.testing.articles.catids3'); @@ -979,7 +981,7 @@ public function onAjaxSampledataApplyStep4() ), array( 'catid' => $catIdsLevel2[0], - 'transition' => 4, + 'published' => 2, 'ordering' => 0, ), array( @@ -4648,10 +4650,10 @@ private function addArticles(array $articles) $article['metadesc'] = ''; $article['xreference'] = ''; - // Set transition to published if not set. - if (!isset($article['transition'])) + // Set article to published if not set. + if (!isset($article['published'])) { - $article['transition'] = 2; + $article['published'] = 1; } // Set article to not featured if not set. From 3712f19b0afc5aab095d8dfcceec63384ab853dc Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 29 May 2020 20:43:29 +0200 Subject: [PATCH 86/90] Fix wrong state in sample data --- plugins/sampledata/blog/blog.php | 2 +- plugins/sampledata/multilang/multilang.php | 1 - plugins/sampledata/testing/testing.php | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/sampledata/blog/blog.php b/plugins/sampledata/blog/blog.php index bf14dfa79a5b3..a11fcf3efe4e6 100644 --- a/plugins/sampledata/blog/blog.php +++ b/plugins/sampledata/blog/blog.php @@ -273,7 +273,7 @@ public function onAjaxSampledataApplyStep1() $article['language'] = $language; $article['associations'] = array(); - $article['published'] = 1; + $article['state'] = 1; $article['featured'] = 0; $article['images'] = ''; $article['metakey'] = ''; diff --git a/plugins/sampledata/multilang/multilang.php b/plugins/sampledata/multilang/multilang.php index 2e3da61d97df4..832896c50f78a 100644 --- a/plugins/sampledata/multilang/multilang.php +++ b/plugins/sampledata/multilang/multilang.php @@ -1117,7 +1117,6 @@ private function addArticle($itemLanguage, $categoryId) 'metadesc' => '', 'language' => $itemLanguage->language, 'state' => 1, - 'published' => 1, 'featured' => 1, 'attribs' => array(), 'rules' => array(), diff --git a/plugins/sampledata/testing/testing.php b/plugins/sampledata/testing/testing.php index 85269dae8dd3b..e01f28dcf64b2 100644 --- a/plugins/sampledata/testing/testing.php +++ b/plugins/sampledata/testing/testing.php @@ -981,7 +981,7 @@ public function onAjaxSampledataApplyStep4() ), array( 'catid' => $catIdsLevel2[0], - 'published' => 2, + 'state' => 2, 'ordering' => 0, ), array( @@ -4651,9 +4651,9 @@ private function addArticles(array $articles) $article['xreference'] = ''; // Set article to published if not set. - if (!isset($article['published'])) + if (!isset($article['state'])) { - $article['published'] = 1; + $article['state'] = 1; } // Set article to not featured if not set. From bc6c53c7ca4a55c696070050566dc7356abe84e7 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 29 May 2020 20:57:13 +0200 Subject: [PATCH 87/90] Make Stage in filter translatable --- .../components/com_workflow/forms/filter_transitions.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/administrator/components/com_workflow/forms/filter_transitions.xml b/administrator/components/com_workflow/forms/filter_transitions.xml index 334b712b13c63..0b2b2d39f3186 100644 --- a/administrator/components/com_workflow/forms/filter_transitions.xml +++ b/administrator/components/com_workflow/forms/filter_transitions.xml @@ -24,6 +24,7 @@ onchange="this.form.submit();" sql_select="id as value, title as from_stage" sql_from="#__workflow_stages" + translate="true" > @@ -34,6 +35,7 @@ onchange="this.form.submit();" sql_select="id as value, title as to_stage" sql_from="#__workflow_stages" + translate="true" > From 781fab17d263d1f6cfd8ba4a7cc4f37791dee233 Mon Sep 17 00:00:00 2001 From: bembelimen Date: Fri, 29 May 2020 21:34:46 +0200 Subject: [PATCH 88/90] Remove stages filter in articles when workflow is disabled --- .../components/com_content/forms/filter_articles.xml | 2 -- .../components/com_content/forms/filter_featured.xml | 2 -- .../components/com_content/src/Model/ArticlesModel.php | 7 +++++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/administrator/components/com_content/forms/filter_articles.xml b/administrator/components/com_content/forms/filter_articles.xml index f1c01cd9eb621..1d11a45b734c9 100644 --- a/administrator/components/com_content/forms/filter_articles.xml +++ b/administrator/components/com_content/forms/filter_articles.xml @@ -125,8 +125,6 @@ - - diff --git a/administrator/components/com_content/forms/filter_featured.xml b/administrator/components/com_content/forms/filter_featured.xml index 6d05c14f2ed22..9d5d1585857d2 100644 --- a/administrator/components/com_content/forms/filter_featured.xml +++ b/administrator/components/com_content/forms/filter_featured.xml @@ -111,8 +111,6 @@ - - diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 2328df7d43560..f18a1182b513d 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -102,6 +102,13 @@ public function getFilterForm($data = array(), $loadData = true) { $form->removeField('stage', 'filter'); } + else + { + $ordering = $form->getField('fullordering', 'list'); + + $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); + $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title DESC']); + } return $form; } From fbf3c1273a8c9d095eba70bfa5a61e45b822eda9 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Fri, 29 May 2020 21:44:35 +0200 Subject: [PATCH 89/90] Update administrator/components/com_content/src/Model/ArticlesModel.php Fix wrong language Co-authored-by: Quy --- .../components/com_content/src/Model/ArticlesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index f18a1182b513d..9b26569f5db0a 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -107,7 +107,7 @@ public function getFilterForm($data = array(), $loadData = true) $ordering = $form->getField('fullordering', 'list'); $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); - $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title DESC']); + $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); } return $form; From bd5e23778139e5ff654ab293c645bd20784b3f87 Mon Sep 17 00:00:00 2001 From: wilsonge Date: Fri, 29 May 2020 22:56:38 +0100 Subject: [PATCH 90/90] Try and fix tests --- .../Step/Acceptance/Administrator/Content.php | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php b/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php index a0caa7a7d67d7..7620ac3ab84de 100644 --- a/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php +++ b/tests/Codeception/_support/Step/Acceptance/Administrator/Content.php @@ -20,11 +20,17 @@ */ class Content extends Admin { + /** + * Flag if workflows are enabled by default + * + * @var bool + */ + private $workflowsEnabled = false; /** * Method to create an article. * - * @param Array articleDetails Array with Article Details like Title, Alias, Content etc + * @param array articleDetails Array with Article Details like Title, Alias, Content etc * * @return void * @@ -121,7 +127,16 @@ public function unPublishArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('transition', '1'); + + if ($this->workflowsEnabled) + { + $I->clickToolbarButton('transition', '1'); + } + else + { + $I->clickToolbarButton('unpublish'); + } + $I->filterByCondition($title, "Unpublished"); } @@ -144,7 +159,16 @@ public function publishArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('transition', '2'); + + if ($this->workflowsEnabled) + { + $I->clickToolbarButton('transition', '2'); + } + else + { + $I->clickToolbarButton('publish'); + } + $I->filterByCondition($title, "Published"); } @@ -168,7 +192,16 @@ public function trashArticle($title) $I->checkAllResults(); $I->clickToolbarButton('Action'); $I->wait(2); - $I->clickToolbarButton('transition', '3'); + + if ($this->workflowsEnabled) + { + $I->clickToolbarButton('transition', '3'); + } + else + { + $I->clickToolbarButton('trash'); + } + $I->filterByCondition($title, "Trashed"); }