diff --git a/mandelstudio/launch_validation.py b/mandelstudio/launch_validation.py new file mode 100644 index 0000000..2a87435 --- /dev/null +++ b/mandelstudio/launch_validation.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import json +import os +from pathlib import Path + +from django.conf import settings +from django.core.management.base import CommandError + + +def _is_demo_data(value: str) -> bool: + normalized = "".join(ch for ch in str(value).lower() if ch.isalnum()) + return "demodata" in normalized + + +def validate_payment_provider_config() -> None: + installed_apps = list(settings.INSTALLED_APPS) + payment_apps = [app for app in installed_apps if "payment" in app.lower()] + checkout_apps = [app for app in installed_apps if "checkout" in app.lower()] + + if not payment_apps: + raise CommandError("No payment app found in INSTALLED_APPS.") + if not checkout_apps: + raise CommandError("No checkout app found in INSTALLED_APPS.") + if not any("oscar_checkout" in app.lower() for app in checkout_apps): + raise CommandError("Oscar checkout app is not active.") + if any(_is_demo_data(app) for app in installed_apps): + raise CommandError( + "Demo data plugin detected in INSTALLED_APPS. Remove all demodata plugins before launch." + ) + if any("dummy" in app.lower() for app in payment_apps): + raise CommandError( + "Dummy payment app detected in INSTALLED_APPS. Use a real provider plugin before production launch." + ) + + if any("mollie" in app.lower() for app in payment_apps): + mollie_settings = ( + getattr(settings, "PAYMENT_MOLLIE", None) + or getattr(settings, "payment_mollie", None) + or {} + ) + config_key = str(mollie_settings.get("api_key", "")).strip() + env_key = str(os.environ.get("MOLLIE_API_KEY", "")).strip() + effective_key = env_key or config_key + if not effective_key or effective_key.upper() == "CHANGE_ME": + raise CommandError( + "Mollie payment provider is enabled but no valid API key is configured. " + "Set MOLLIE_API_KEY or settings.payment_mollie.api_key to a real key." + ) + if not effective_key.startswith("live_"): + raise CommandError( + "Mollie key must be a live key for production launch (expected prefix 'live_')." + ) + + config_path = Path(__file__).resolve().parent / "ocyan.json" + if config_path.exists(): + with config_path.open("r", encoding="utf-8") as handle: + config_payload = json.load(handle) + config_plugins = [str(plugin) for plugin in config_payload.get("ocyan_plugins", [])] + if any(_is_demo_data(plugin) for plugin in config_plugins): + raise CommandError( + "Demo data plugin detected in ocyan.json. Remove it before launch." + ) diff --git a/mandelstudio/management/commands/validate_idea_marketplace_launch.py b/mandelstudio/management/commands/validate_idea_marketplace_launch.py index 20c38af..494be1d 100644 --- a/mandelstudio/management/commands/validate_idea_marketplace_launch.py +++ b/mandelstudio/management/commands/validate_idea_marketplace_launch.py @@ -1,7 +1,6 @@ from __future__ import annotations import json -import os from pathlib import Path from django.conf import settings @@ -17,6 +16,7 @@ from mandelstudio.idea_marketplace import ( IDEA_PRODUCTS, SHORT_DESCRIPTION_ATTRIBUTE_CODE, ) +from mandelstudio.launch_validation import validate_payment_provider_config class Command(BaseCommand): @@ -32,53 +32,14 @@ class Command(BaseCommand): StockRecord = get_model("partner", "StockRecord") Page = get_model("wagtailcore", "Page") - installed_apps = list(settings.INSTALLED_APPS) - payment_apps = [app for app in installed_apps if "payment" in app.lower()] - checkout_apps = [app for app in installed_apps if "checkout" in app.lower()] - if not payment_apps: - raise CommandError("No payment app found in INSTALLED_APPS.") - if not checkout_apps: - raise CommandError("No checkout app found in INSTALLED_APPS.") - if not any("oscar_checkout" in app.lower() for app in checkout_apps): - raise CommandError("Oscar checkout app is not active.") - def _is_demo_data(value: str) -> bool: - normalized = "".join(ch for ch in str(value).lower() if ch.isalnum()) - return "demodata" in normalized - - if any(_is_demo_data(app) for app in installed_apps): - raise CommandError( - "Demo data plugin detected in INSTALLED_APPS. Remove all demodata plugins before launch." - ) - - if any("dummy" in app.lower() for app in payment_apps): - raise CommandError( - "Dummy payment app detected in INSTALLED_APPS. Use a real provider plugin before production launch." - ) - if any("mollie" in app.lower() for app in payment_apps): - mollie_settings = ( - getattr(settings, "PAYMENT_MOLLIE", None) - or getattr(settings, "payment_mollie", None) - or {} - ) - config_key = str(mollie_settings.get("api_key", "")).strip() - env_key = str(os.environ.get("MOLLIE_API_KEY", "")).strip() - effective_key = env_key or config_key - if not effective_key or effective_key.upper() == "CHANGE_ME": - raise CommandError( - "Mollie payment provider is enabled but no valid API key is configured. " - "Set MOLLIE_API_KEY or settings.payment_mollie.api_key to a real key." - ) - if not effective_key.startswith("live_"): - raise CommandError( - "Mollie key must be a live key for production launch (expected prefix 'live_')." - ) + validate_payment_provider_config() config_path = Path(__file__).resolve().parents[2] / "ocyan.json" if config_path.exists(): with config_path.open("r", encoding="utf-8") as handle: config_payload = json.load(handle) config_plugins = [str(plugin) for plugin in config_payload.get("ocyan_plugins", [])] - if any(_is_demo_data(plugin) for plugin in config_plugins): + if any("demodata" in "".join(ch for ch in str(plugin).lower() if ch.isalnum()) for plugin in config_plugins): raise CommandError( "Demo data plugin detected in ocyan.json. Remove it before launch." ) diff --git a/scripts/validate_payment_provider_config.py b/scripts/validate_payment_provider_config.py new file mode 100644 index 0000000..d77413e --- /dev/null +++ b/scripts/validate_payment_provider_config.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import os +import sys +from pathlib import Path + + +def main() -> int: + project_root = Path(__file__).resolve().parents[1] + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mandelstudio.settings.base") + os.chdir(project_root) + + import django + + django.setup() + + from mandelstudio.launch_validation import validate_payment_provider_config + + validate_payment_provider_config() + print("Payment provider configuration validation passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())