diff --git a/backend/news/+hide-addons.feature b/backend/news/+hide-addons.feature
new file mode 100644
index 00000000..6cf23276
--- /dev/null
+++ b/backend/news/+hide-addons.feature
@@ -0,0 +1 @@
+Hid all add-ons managed by our package. @ericof
diff --git a/backend/news/+missing-upgrade.bugfix b/backend/news/+missing-upgrade.bugfix
new file mode 100644
index 00000000..95bc7224
--- /dev/null
+++ b/backend/news/+missing-upgrade.bugfix
@@ -0,0 +1 @@
+Added missing upgrade step from 20260620001 to 20260701001 and added upgrade tests. @ericof
diff --git a/backend/news/452.internal b/backend/news/452.internal
new file mode 100644
index 00000000..305a7442
--- /dev/null
+++ b/backend/news/452.internal
@@ -0,0 +1 @@
+Bumped `plone.formblock` to `>=1.0.0a3`. @ericof
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
index 2093bafd..782de805 100644
--- a/backend/pyproject.toml
+++ b/backend/pyproject.toml
@@ -30,7 +30,7 @@ dependencies = [
"plone.volto",
"kitconcept.voltolighttheme>=8.0.0a30",
"collective.volto.formsupport==3.2.3",
- "plone.formblock>=1.0.0a2",
+ "plone.formblock>=1.0.0a3",
"collective.honeypot",
"collective.person==1.0.0b6",
"pas.plugins.authomatic==2.0.0",
diff --git a/backend/src/kitconcept/core/factory.py b/backend/src/kitconcept/core/factory.py
index 69c005fc..0cd572c5 100644
--- a/backend/src/kitconcept/core/factory.py
+++ b/backend/src/kitconcept/core/factory.py
@@ -12,40 +12,28 @@
_PLONE_PACKAGES = [
+ "borg.localrole",
"CMFDefault",
- "Products.CMFDefault",
+ "CMFDiffTool",
+ "CMFEditions",
"CMFPlone",
- "Products.CMFPlone",
- "Products.CMFPlone.migrations",
"CMFTopic",
- "Products.CMFTopic",
"CMFUid",
- "Products.CMFUid",
"DCWorkflow",
- "Products.DCWorkflow",
- "PasswordResetTool",
- "Products.PasswordResetTool",
- "PlonePAS",
- "Products.PlonePAS",
- "PloneLanguageTool",
- "Products.PloneLanguageTool",
"MimetypesRegistry",
- "Products.MimetypesRegistry",
- "PortalTransforms",
- "Products.PortalTransforms",
- "CMFDiffTool",
- "Products.CMFDiffTool",
- "CMFEditions",
- "Products.CMFEditions",
- "Products.NuPlone",
- "borg.localrole",
+ "PasswordResetTool",
+ "plone.app.caching",
"plone.app.dexterity",
+ "plone.app.discussion",
"plone.app.event",
"plone.app.intid",
+ "plone.app.iterate",
+ "plone.app.layout",
"plone.app.linkintegrity",
"plone.app.querystring",
- "plone.app.registry",
+ "plone.app.multilingual",
"plone.app.referenceablebehavior",
+ "plone.app.registry",
"plone.app.relationfield",
"plone.app.theming",
"plone.app.users",
@@ -53,18 +41,48 @@
"plone.formwidget.recurrence",
"plone.keyring",
"plone.outputfilters",
- "plone.portlet.static",
"plone.portlet.collection",
+ "plone.portlet.static",
"plone.protect",
"plone.resource",
- "plonetheme.barceloneta",
"plone.restapi",
+ "plone.session",
"plone.volto",
- "kitconcept.voltolighttheme",
+ "PloneLanguageTool",
+ "PlonePAS",
+ "plonetheme.barceloneta",
+ "PortalTransforms",
+ "Products.CMFDefault",
+ "Products.CMFDiffTool",
+ "Products.CMFEditions",
+ "Products.CMFPlacefulWorkflow",
+ "Products.CMFPlone.migrations",
+ "Products.CMFPlone",
+ "Products.CMFTopic",
+ "Products.CMFUid",
+ "Products.DCWorkflow",
+ "Products.MimetypesRegistry",
+ "Products.NuPlone",
+ "Products.PasswordResetTool",
+ "Products.PloneLanguageTool",
+ "Products.PlonePAS",
+ "Products.PortalTransforms",
+]
+
+_CORE_DEPENDENCIES = [
"collective.volto.formsupport",
+ "collective.contact_behaviors",
+ "collective.person",
+ "kitconcept.voltolighttheme",
"plone.formblock",
"plonegovbr.socialmedia",
+ "souper.plone",
+ "collective.volto.otp",
+ "pas.plugins.authomatic",
+ "pas.plugins.oidc",
+ "pas.plugins.keycloakgroups",
]
+
_PLONE_PROFILES = [
"Products.CMFDiffTool:CMFDiffTool",
"Products.CMFEditions:CMFEditions",
@@ -109,7 +127,7 @@
@implementer(INonInstallable)
class HiddenProfiles:
def getNonInstallableProducts(self):
- return [PACKAGE_NAME, *_PLONE_PACKAGES]
+ return [PACKAGE_NAME, *_CORE_DEPENDENCIES, *_PLONE_PACKAGES]
def getNonInstallableProfiles(self):
"""Hide uninstall profile from site-creation and quickinstaller."""
diff --git a/backend/src/kitconcept/core/upgrades/configure.zcml b/backend/src/kitconcept/core/upgrades/configure.zcml
index 60b9c20c..0bdaa530 100644
--- a/backend/src/kitconcept/core/upgrades/configure.zcml
+++ b/backend/src/kitconcept/core/upgrades/configure.zcml
@@ -14,5 +14,6 @@
+
diff --git a/backend/src/kitconcept/core/upgrades/v20260701001/__init__.py b/backend/src/kitconcept/core/upgrades/v20260701001/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/src/kitconcept/core/upgrades/v20260701001/configure.zcml b/backend/src/kitconcept/core/upgrades/v20260701001/configure.zcml
new file mode 100644
index 00000000..bf751c23
--- /dev/null
+++ b/backend/src/kitconcept/core/upgrades/v20260701001/configure.zcml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/backend/tests/setup/__init__.py b/backend/tests/setup/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/tests/setup/test_setup_addons.py b/backend/tests/setup/test_setup_addons.py
new file mode 100644
index 00000000..7e147c75
--- /dev/null
+++ b/backend/tests/setup/test_setup_addons.py
@@ -0,0 +1,15 @@
+from plone import api
+
+import pytest
+
+
+class TestAddonsList:
+ @pytest.fixture(autouse=True)
+ def _setup(self, portal_class) -> None:
+ self.portal = portal_class
+
+ def test_addons_list_should_be_empty(self) -> None:
+ """Test that the addons list should be empty."""
+ with api.env.adopt_roles(["Manager"]):
+ addons = api.addon.get_addons()
+ assert addons == [], "Expected no addons to be installed, but found some."
diff --git a/backend/tests/setup/test_setup_install.py b/backend/tests/setup/test_setup_install.py
index fb566e54..6fea76f9 100644
--- a/backend/tests/setup/test_setup_install.py
+++ b/backend/tests/setup/test_setup_install.py
@@ -35,7 +35,7 @@ def test_dependencies_version(self, profile_last_version):
class TestSetupDependencies:
@pytest.fixture(autouse=True)
- def _setup(self, portal_class):
+ def _setup(self, portal_class) -> None:
self.portal = portal_class
self.setup_tool: SetupTool = portal_class.portal_setup
self.types_tool: TypesTool = portal_class.portal_types
diff --git a/backend/tests/setup/test_upgrades.py b/backend/tests/setup/test_upgrades.py
new file mode 100644
index 00000000..d9945ebe
--- /dev/null
+++ b/backend/tests/setup/test_upgrades.py
@@ -0,0 +1,55 @@
+from kitconcept.core import PACKAGE_NAME
+from Products.GenericSetup.tool import SetupTool
+
+import pytest
+
+
+@pytest.fixture(scope="module")
+def base_profile_id() -> str:
+ """Fixture to provide the profile ID for the package."""
+ return f"{PACKAGE_NAME}:base"
+
+
+@pytest.fixture(scope="module")
+def list_upgrades(base_profile_id):
+ """Fixture to list available upgrades for the package."""
+ from Products.GenericSetup.upgrade import listUpgradeSteps
+
+ def _list_upgrades(setup_tool: SetupTool, source: str, dest: str) -> list:
+ return listUpgradeSteps(setup_tool, base_profile_id, source, dest)
+
+ return _list_upgrades
+
+
+class TestUpgrades:
+ @pytest.fixture(autouse=True)
+ def _setup(self, portal_class, current_versions) -> None:
+ self.portal = portal_class
+ self.setup_tool: SetupTool = portal_class.portal_setup
+ self.version = current_versions.base
+
+ @pytest.mark.parametrize(
+ "src_version",
+ [
+ "20250523001",
+ "20250612001",
+ "20250902001",
+ "20250903001",
+ "20250915001",
+ "20250916001",
+ "20250917001",
+ "20251209001",
+ "20260122001",
+ "20260504001",
+ "20260505001",
+ "20260619001",
+ "20260620001",
+ ],
+ )
+ def test_upgrade_to_latest(self, list_upgrades, src_version: str) -> None:
+ """Test that the upgrade step to the latest version is available."""
+
+ upgrades = list_upgrades(self.setup_tool, src_version, self.version)
+ assert len(upgrades) > 0, (
+ f"No upgrade path found from {src_version} to {self.version}"
+ )
diff --git a/backend/uv.lock b/backend/uv.lock
index b341fbf5..391e9ad8 100644
--- a/backend/uv.lock
+++ b/backend/uv.lock
@@ -1398,7 +1398,7 @@ requires-dist = [
{ name = "plone-api" },
{ name = "plone-app-testing", marker = "extra == 'test'" },
{ name = "plone-distribution" },
- { name = "plone-formblock", specifier = ">=1.0.0a2" },
+ { name = "plone-formblock", specifier = ">=1.0.0a3" },
{ name = "plone-restapi", extras = ["test"], marker = "extra == 'test'" },
{ name = "plone-volto" },
{ name = "products-cmfplone", specifier = "==6.2.1" },
@@ -3207,7 +3207,7 @@ wheels = [
[[package]]
name = "plone-formblock"
-version = "1.0.0a2"
+version = "1.0.0a3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "beautifulsoup4" },
@@ -3219,9 +3219,9 @@ dependencies = [
{ name = "pyotp" },
{ name = "souper-plone" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0c/2c/f184add43539b0b53ceb7857a70cd532af520b9eef28b8fa60b9da3d4e47/plone_formblock-1.0.0a2.tar.gz", hash = "sha256:059ff2452349d79a0e007c80527758d02d771baf9d22f8ab75c7bbff534a2612", size = 133651, upload-time = "2026-06-18T15:23:09.514Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/df/fc/890be2b7e96232a507345cf9caaefaf6495abb24411383ab469aa923bc94/plone_formblock-1.0.0a3.tar.gz", hash = "sha256:00efa055eb83bb424570e5c19c393941df548bb3f5894f2a5ead6783419f454f", size = 138494, upload-time = "2026-07-07T17:48:30.263Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/66/86/c310b2d0202affd415eceee62308fa3b4b3774df5a34b4b641d27d946d47/plone_formblock-1.0.0a2-py3-none-any.whl", hash = "sha256:c91288c9e1821bb556638bfb29630c2cdeb93aba309d0c3c2f59f6e2c6670c66", size = 89528, upload-time = "2026-06-18T15:23:07.894Z" },
+ { url = "https://files.pythonhosted.org/packages/73/32/c8b1d61849c77402b8ad427f292dd4a93e701c387d1f9c64ea3ef7b2704c/plone_formblock-1.0.0a3-py3-none-any.whl", hash = "sha256:74dbba615b221b80ea51dbfd3ba69706fea062a3b49e019fac4a6c68918f6ce9", size = 92976, upload-time = "2026-07-07T17:48:28.585Z" },
]
[[package]]