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/components/com_admin/script.php b/administrator/components/com_admin/script.php
index e1dc20147133c..f02edfed1efb8 100644
--- a/administrator/components/com_admin/script.php
+++ b/administrator/components/com_admin/script.php
@@ -6560,7 +6560,7 @@ private function contactItems(Table $tableItem): array
}
$parentId = $tableItem->id;
- $componentId = ExtensionHelper::getExtensionRecord('com_fields')->extension_id;
+ $componentId = ExtensionHelper::getExtensionRecord('com_fields', 'component')->extension_id;
// Add Contact Fields Menu Items.
$menuItems = [
@@ -6576,7 +6576,7 @@ private function contactItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6601,7 +6601,7 @@ private function contactItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6626,7 +6626,7 @@ private function contactItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6670,7 +6670,7 @@ private function finderItems(Table $tableItem): array
}
$parentId = $tableItem->id;
- $componentId = ExtensionHelper::getExtensionRecord('com_finder')->extension_id;
+ $componentId = ExtensionHelper::getExtensionRecord('com_finder', 'component')->extension_id;
// Add Finder Fields Menu Items.
$menuItems = [
@@ -6686,7 +6686,7 @@ private function finderItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6711,7 +6711,7 @@ private function finderItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6736,7 +6736,7 @@ private function finderItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6761,7 +6761,7 @@ private function finderItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
@@ -6786,7 +6786,7 @@ private function finderItems(Table $tableItem): array
'parent_id' => $parentId,
'level' => 2,
'component_id' => $componentId,
- 'checked_out' => 0,
+ 'checked_out' => null,
'checked_out_time' => null,
'browserNav' => 0,
'access' => 0,
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..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
@@ -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', 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_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0);
--
-- Table structure for table `#__workflow_associations`
@@ -64,7 +63,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 +78,8 @@ 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, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0);
--
-- Table structure for table `#__workflow_transitions`
@@ -100,6 +95,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`),
@@ -115,21 +111,31 @@ 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, 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),
+(7, 0, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0);
--
-- 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, '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
--
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`, 1, 'com_content.article' FROM `#__content`;
diff --git a/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-05-29.sql b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-05-29.sql
new file mode 100644
index 0000000000000..51ab88b3a6ae4
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/mysql/4.0.0-2020-05-29.sql
@@ -0,0 +1,39 @@
+ALTER TABLE `#__extensions` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__menu` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__modules` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__tags` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__update_sites` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__user_notes` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__workflows` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__workflow_stages` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__workflow_transitions` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__banners` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__banner_clients` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__contact_details` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__content` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__finder_filters` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__newsfeeds` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__categories` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__fields` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__fields_groups` MODIFY `checked_out` INT(10) UNSIGNED;
+ALTER TABLE `#__ucm_content` MODIFY `core_checked_out_user_id` INT(10) UNSIGNED;
+
+UPDATE `#__extensions` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__menu` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__modules` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__tags` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__update_sites` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__user_notes` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__workflows` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__workflow_stages` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__workflow_transitions` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__banners` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__banner_clients` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__contact_details` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__content` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__finder_filters` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__newsfeeds` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__categories` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__fields` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__fields_groups` SET `checked_out` = null WHERE `checked_out` = 0;
+UPDATE `#__ucm_content` SET `core_checked_out_user_id` = null WHERE `checked_out` = 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 a41ff39e4f764..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
@@ -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', 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_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 0, CURRENT_TIMESTAMP, 0, NULL, 0);
--
-- Table structure for table "#__workflow_associations"
@@ -64,7 +63,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 +78,8 @@ 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, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0);
--
-- Table structure for table "#__workflow_transitions"
@@ -100,6 +95,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")
@@ -111,21 +107,31 @@ 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, 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),
+(7, 0, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}', NULL, 0);
--
-- 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, '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
--
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", 1, 'com_content.article' FROM "#__content";
diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-05-29.sql b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-05-29.sql
new file mode 100644
index 0000000000000..de1f5e820246a
--- /dev/null
+++ b/administrator/components/com_admin/sql/updates/postgresql/4.0.0-2020-05-29.sql
@@ -0,0 +1,58 @@
+ALTER TABLE "#__extensions" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__extensions" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__menu" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__menu" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__modules" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__modules" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__tags" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__tags" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__update_sites" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__update_sites" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__user_notes" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__user_notes" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__workflows" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__workflows" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__workflow_stages" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__workflow_stages" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__workflow_transitions" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__workflow_transitions" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__banners" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__banners" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__banner_clients" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__banner_clients" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__contact_details" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__contact_details" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__content" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__content" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__finder_filters" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__finder_filters" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__newsfeeds" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__newsfeeds" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__categories" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__categories" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__fields" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__fields" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__fields_groups" ALTER COLUMN "checked_out" DROP DEFAULT;
+ALTER TABLE "#__fields_groups" ALTER COLUMN "checked_out" DROP NOT NULL;
+ALTER TABLE "#__ucm_content" ALTER COLUMN "core_checked_out_user_id" DROP DEFAULT;
+ALTER TABLE "#__ucm_content" ALTER COLUMN "core_checked_out_user_id" DROP NOT NULL;
+
+UPDATE "#__extensions" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__menu" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__modules" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__tags" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__update_sites" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__user_notes" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__workflows" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__workflow_stages" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__workflow_transitions" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__banners" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__banner_clients" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__contact_details" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__content" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__finder_filters" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__newsfeeds" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__categories" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__fields" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__fields_groups" SET "checked_out" = null WHERE "checked_out" = 0;
+UPDATE "#__ucm_content" SET "core_checked_out_user_id" = null WHERE "checked_out" = 0;
diff --git a/administrator/components/com_banners/src/Helper/BannersHelper.php b/administrator/components/com_banners/src/Helper/BannersHelper.php
index c0fa92d8925fa..fbf19892f3fe3 100644
--- a/administrator/components/com_banners/src/Helper/BannersHelper.php
+++ b/administrator/components/com_banners/src/Helper/BannersHelper.php
@@ -53,7 +53,7 @@ public static function updateReset()
->extendWhere(
'AND',
[
- $db->quoteName('checked_out') . ' = 0',
+ $db->quoteName('checked_out') . ' IS NULL',
$db->quoteName('checked_out') . ' = :userId',
],
'OR'
diff --git a/administrator/components/com_banners/src/Table/BannerTable.php b/administrator/components/com_banners/src/Table/BannerTable.php
index 0437d5275ef0e..5a4f0c3c672c7 100644
--- a/administrator/components/com_banners/src/Table/BannerTable.php
+++ b/administrator/components/com_banners/src/Table/BannerTable.php
@@ -352,11 +352,11 @@ public function stick($pks = null, $state = 1, $userId = 0)
}
// Verify checkout
- if ($table->checked_out == 0 || $table->checked_out == $userId)
+ if (is_null($table->checked_out) || $table->checked_out == $userId)
{
// Change the state
$table->sticky = $state;
- $table->checked_out = 0;
+ $table->checked_out = null;
$table->checked_out_time = null;
// Check the row
diff --git a/administrator/components/com_banners/src/Table/ClientTable.php b/administrator/components/com_banners/src/Table/ClientTable.php
index 9cc783f6f83e0..81e9cdcec9278 100644
--- a/administrator/components/com_banners/src/Table/ClientTable.php
+++ b/administrator/components/com_banners/src/Table/ClientTable.php
@@ -100,7 +100,7 @@ public function publish($pks = null, $state = 1, $userId = 0)
$query->extendWhere(
'AND',
[
- $this->_db->quoteName('checked_out') . ' = 0',
+ $this->_db->quoteName('checked_out') . ' IS NULL',
$this->_db->quoteName('checked_out') . ' = :userId',
],
'OR'
diff --git a/administrator/components/com_banners/src/View/Banner/HtmlView.php b/administrator/components/com_banners/src/View/Banner/HtmlView.php
index ffb8f44a51c41..4d887601f9a7b 100644
--- a/administrator/components/com_banners/src/View/Banner/HtmlView.php
+++ b/administrator/components/com_banners/src/View/Banner/HtmlView.php
@@ -98,7 +98,7 @@ protected function addToolbar(): void
$user = Factory::getUser();
$userId = $user->id;
$isNew = ($this->item->id == 0);
- $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId);
+ $checkedOut = !(is_null($this->item->checked_out) || $this->item->checked_out == $userId);
// Since we don't track these assets at the item level, use the category id.
$canDo = ContentHelper::getActions('com_banners', 'category', $this->item->catid);
diff --git a/administrator/components/com_banners/src/View/Client/HtmlView.php b/administrator/components/com_banners/src/View/Client/HtmlView.php
index 4612a379f588e..e7ab4f74e8f28 100644
--- a/administrator/components/com_banners/src/View/Client/HtmlView.php
+++ b/administrator/components/com_banners/src/View/Client/HtmlView.php
@@ -108,7 +108,7 @@ protected function addToolbar(): void
$user = Factory::getUser();
$isNew = ($this->item->id == 0);
- $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->id);
+ $checkedOut = !(is_null($this->item->checked_out) || $this->item->checked_out == $user->id);
$canDo = $this->canDo;
ToolbarHelper::title(
diff --git a/administrator/components/com_banners/tmpl/banners/default.php b/administrator/components/com_banners/tmpl/banners/default.php
index 02cdcb03eb530..3793664f1cd79 100644
--- a/administrator/components/com_banners/tmpl/banners/default.php
+++ b/administrator/components/com_banners/tmpl/banners/default.php
@@ -95,7 +95,7 @@
$item->cat_link = Route::_('index.php?option=com_categories&extension=com_banners&task=edit&type=other&cid[]=' . $item->catid);
$canCreate = $user->authorise('core.create', 'com_banners.category.' . $item->catid);
$canEdit = $user->authorise('core.edit', 'com_banners.category.' . $item->catid);
- $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0;
+ $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || is_null($item->checked_out);
$canChange = $user->authorise('core.edit.state', 'com_banners.category.' . $item->catid) && $canCheckin;
?>
diff --git a/administrator/components/com_banners/tmpl/clients/default.php b/administrator/components/com_banners/tmpl/clients/default.php
index ddc481883c228..021b6a47fbdc1 100644
--- a/administrator/components/com_banners/tmpl/clients/default.php
+++ b/administrator/components/com_banners/tmpl/clients/default.php
@@ -96,7 +96,7 @@
items as $i => $item) :
$canCreate = $user->authorise('core.create', 'com_banners');
$canEdit = $user->authorise('core.edit', 'com_banners');
- $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || $item->checked_out == 0;
+ $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || is_null($item->checked_out);
$canChange = $user->authorise('core.edit.state', 'com_banners') && $canCheckin;
?>
diff --git a/administrator/components/com_categories/src/View/Category/HtmlView.php b/administrator/components/com_categories/src/View/Category/HtmlView.php
index f6a938cf8a045..e792d3d367bba 100644
--- a/administrator/components/com_categories/src/View/Category/HtmlView.php
+++ b/administrator/components/com_categories/src/View/Category/HtmlView.php
@@ -135,7 +135,7 @@ protected function addToolbar()
$userId = $user->id;
$isNew = ($this->item->id == 0);
- $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId);
+ $checkedOut = !(is_null($this->item->checked_out) || $this->item->checked_out == $userId);
// Avoid nonsense situation.
if ($extension == 'com_categories')
diff --git a/administrator/components/com_categories/tmpl/categories/default.php b/administrator/components/com_categories/tmpl/categories/default.php
index 97da8347a6ebf..2dc49311a1e27 100644
--- a/administrator/components/com_categories/tmpl/categories/default.php
+++ b/administrator/components/com_categories/tmpl/categories/default.php
@@ -129,7 +129,7 @@
items as $i => $item) : ?>
authorise('core.edit', $extension . '.category.' . $item->id);
- $canCheckin = $user->authorise('core.admin', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0;
+ $canCheckin = $user->authorise('core.admin', 'com_checkin') || $item->checked_out == $userId || is_null($item->checked_out);
$canEditOwn = $user->authorise('core.edit.own', $extension . '.category.' . $item->id) && $item->created_user_id == $userId;
$canChange = $user->authorise('core.edit.state', $extension . '.category.' . $item->id) && $canCheckin;
diff --git a/administrator/components/com_contact/src/Service/HTML/Icon.php b/administrator/components/com_contact/src/Service/HTML/Icon.php
index da96487953847..943a6dca166c2 100644
--- a/administrator/components/com_contact/src/Service/HTML/Icon.php
+++ b/administrator/components/com_contact/src/Service/HTML/Icon.php
@@ -123,7 +123,7 @@ public static function edit($contact, $params, $attribs = array(), $legacy = fal
// Show checked_out icon if the contact is checked out by a different user
if (property_exists($contact, 'checked_out')
&& property_exists($contact, 'checked_out_time')
- && $contact->checked_out > 0
+ && !is_null($contact->checked_out)
&& $contact->checked_out !== $user->get('id'))
{
$checkoutUser = Factory::getUser($contact->checked_out);
diff --git a/administrator/components/com_contact/src/View/Contact/HtmlView.php b/administrator/components/com_contact/src/View/Contact/HtmlView.php
index 49a99dea63583..60b89ea1966fe 100644
--- a/administrator/components/com_contact/src/View/Contact/HtmlView.php
+++ b/administrator/components/com_contact/src/View/Contact/HtmlView.php
@@ -101,7 +101,7 @@ protected function addToolbar()
$user = Factory::getUser();
$userId = $user->id;
$isNew = ($this->item->id == 0);
- $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $userId);
+ $checkedOut = !(is_null($this->item->checked_out) || $this->item->checked_out == $userId);
// Since we don't track these assets at the item level, use the category id.
$canDo = ContentHelper::getActions('com_contact', 'category', $this->item->catid);
diff --git a/administrator/components/com_contact/tmpl/contacts/default.php b/administrator/components/com_contact/tmpl/contacts/default.php
index f012c909480b7..c7d88168e8eba 100644
--- a/administrator/components/com_contact/tmpl/contacts/default.php
+++ b/administrator/components/com_contact/tmpl/contacts/default.php
@@ -94,7 +94,7 @@
foreach ($this->items as $i => $item) :
$canCreate = $user->authorise('core.create', 'com_contact.category.' . $item->catid);
$canEdit = $user->authorise('core.edit', 'com_contact.category.' . $item->catid);
- $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || $item->checked_out == 0;
+ $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || is_null($item->checked_out);
$canEditOwn = $user->authorise('core.edit.own', 'com_contact.category.' . $item->catid) && $item->created_by == $userId;
$canChange = $user->authorise('core.edit.state', 'com_contact.category.' . $item->catid) && $canCheckin;
diff --git a/administrator/components/com_content/config.xml b/administrator/components/com_content/config.xml
index 67901887c1ead..62b34237ba614 100644
--- a/administrator/components/com_content/config.xml
+++ b/administrator/components/com_content/config.xml
@@ -1039,13 +1039,17 @@
-
+
+