diff --git a/commera/api/admin/plugins.py b/commera/api/admin/plugins.py
index 07448ebf..474a0cdb 100644
--- a/commera/api/admin/plugins.py
+++ b/commera/api/admin/plugins.py
@@ -7,6 +7,7 @@
from frappe.query_builder.functions import Count
from frappe.utils.data import cint
+from commera import storefront_plugins
from commera.api.admin.docfields import build_field_groups, get_editable_docfields, get_missing_fields
from commera.api.admin.integrations import write_settings
from commera.plugin_events import get_plugin_apps
@@ -33,6 +34,7 @@ def get_plugins() -> list[dict]:
registry = get_registry()
failed_deliveries = get_failed_delivery_counts()
+ storefront_switches = storefront_plugins.get_storefront_switches()
return [
{
"app": app,
@@ -46,11 +48,19 @@ def get_plugins() -> list[dict]:
],
"problems": [problem["message"] for problem in registry["problems"] if problem["app"] == app],
"failed_deliveries": failed_deliveries.get(app, 0),
+ # None for an app with no storefront hook; else whether its scripts and blocks load on store pages.
+ "storefront": storefront_switches.get(app),
}
for app in dict.fromkeys([*get_plugin_apps(), *registry["apps"]])
]
+@frappe.whitelist(methods=["POST"])
+def set_storefront_enabled(app: str, enabled: bool) -> None:
+ frappe.only_for("System Manager")
+ storefront_plugins.set_storefront_enabled(app, enabled)
+
+
@frappe.whitelist()
def get_plugin_deliveries(app: str, status: str | None = None, start: int = 0, page_length: int = 20) -> dict:
frappe.only_for("System Manager")
diff --git a/commera/storefront_plugins.py b/commera/storefront_plugins.py
index 9312bd90..65aed9a9 100644
--- a/commera/storefront_plugins.py
+++ b/commera/storefront_plugins.py
@@ -4,6 +4,7 @@
import os
import frappe
+from frappe import _
from markupsafe import Markup
from commera.guest import is_guest
@@ -123,6 +124,22 @@ def sync_storefront_apps(app_name: str | None = None):
clear_storefront_plugin_cache()
+def get_storefront_switches() -> dict[str, bool]:
+ """Each app that declares a storefront hook, and whether the merchant has it switched on."""
+ settings = frappe.get_cached_doc(SETTINGS)
+ return {row.app: bool(row.enabled) for row in settings.storefront_apps}
+
+
+def set_storefront_enabled(app: str, enabled: bool):
+ settings = frappe.get_single(SETTINGS)
+ row = next((row for row in settings.storefront_apps if row.app == app), None)
+ if not row:
+ frappe.throw(_("{0} adds nothing to the storefront.").format(app))
+ row.enabled = int(enabled)
+ settings.save()
+ clear_storefront_plugin_cache()
+
+
def clear_storefront_plugin_cache():
frappe.cache.delete_value(CACHE_KEY)
diff --git a/commera/tests/test_storefront_plugins.py b/commera/tests/test_storefront_plugins.py
index 241a4959..e6acd8de 100644
--- a/commera/tests/test_storefront_plugins.py
+++ b/commera/tests/test_storefront_plugins.py
@@ -6,6 +6,7 @@
from frappe.utils import get_html_for_route, set_request
from commera import storefront_plugins
+from commera.api.admin.plugins import set_storefront_enabled
BANNER = "commera/tests/storefront_plugin_templates/banner.html"
BROKEN = "commera/tests/storefront_plugin_templates/broken.html"
@@ -77,6 +78,27 @@ def test_switching_on_renders_tags_and_blocks(self):
currency = frappe.db.get_single_value("Global Defaults", "default_currency")
self.assertIn(f"{store_name}|{currency}|{frappe.local.lang}|False", banner)
+ def test_the_switch_turns_a_plugin_on_and_off_the_storefront(self):
+ self.declare_full_plugin()
+
+ set_storefront_enabled(app="commera", enabled=True)
+ self.assertEqual(storefront_plugins.get_storefront_switches()["commera"], True)
+ self.assertIn(SCRIPT, storefront_plugins.format_plugin_includes("js"))
+
+ set_storefront_enabled(app="commera", enabled=False)
+ self.assertEqual(storefront_plugins.format_plugin_includes("js"), "")
+
+ def test_the_switch_refuses_an_app_without_storefront_hooks(self):
+ with self.assertRaises(frappe.ValidationError):
+ set_storefront_enabled(app="frappe", enabled=True)
+
+ def test_only_a_system_manager_turns_the_switch(self):
+ self.declare_full_plugin()
+ frappe.set_user("Guest")
+ self.addCleanup(frappe.set_user, "Administrator")
+ with self.assertRaises(frappe.PermissionError):
+ set_storefront_enabled(app="commera", enabled=True)
+
def test_asset_outside_the_app_is_refused(self):
self.declare_hooks(
{
diff --git a/dashboard/src/components/settings/PluginsSettings.vue b/dashboard/src/components/settings/PluginsSettings.vue
index 9f866e49..e7178666 100644
--- a/dashboard/src/components/settings/PluginsSettings.vue
+++ b/dashboard/src/components/settings/PluginsSettings.vue
@@ -1,13 +1,13 @@
@@ -146,6 +160,20 @@ function retry(row) {
+
+
+
+