Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4b2fe42
feat: add spp_branding_kit module for custom branding
jeremi Aug 21, 2025
9980f8f
fix the build
jeremi Aug 21, 2025
27e9550
Try to fix again the build
jeremi Aug 21, 2025
364aca4
fix(spp_branding_kit): resolve XPath conflicts with g2p_theme module
jeremi Aug 21, 2025
91ecfd3
fix(spp_branding_kit): address all code review feedback from Gemini
jeremi Aug 22, 2025
b9e4829
test(spp_branding_kit): add comprehensive test coverage
jeremi Aug 22, 2025
6ea41ec
refactor(spp_branding_kit): reorganize documentation structure
jeremi Aug 22, 2025
72f87eb
fix(spp_branding_kit): fix test failures in build
jeremi Aug 22, 2025
1b9f08e
fix(spp_branding_kit): remove tests that require HTTP request context
jeremi Aug 22, 2025
c950e77
fix(spp_branding_kit): fix failing tests and update license filtering…
jeremi Aug 22, 2025
ebfc88f
fix(spp_branding_kit): remove debug mode restriction to fix singleton…
jeremi Aug 22, 2025
02a4ed8
spp_branding_kit: drop server-side Apps filtering; UI-only default to…
jeremi Sep 15, 2025
05b8607
spp_branding_kit: refine controllers and hooks; correct JSON response…
jeremi Sep 15, 2025
811903c
spp_branding_kit: adopt dotted keys; add HttpCase tests; cleanup tests
jeremi Sep 15, 2025
26ce9f4
spp_branding_kit: remove obsolete settings fields and tests; update r…
jeremi Sep 15, 2025
341edcb
spp_branding_kit: format controllers after import reorder
jeremi Sep 15, 2025
c9128e6
spp_branding_kit: remove stale comments; format CSS/XML after cleanup
jeremi Sep 15, 2025
8b78e20
spp_branding_kit: format utils and controllers after refactor
jeremi Sep 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ jobs:
rm -rf openg2p-program/g2p_payment_files
rm -rf openg2p-program/g2p_payment_g2p_connect
rm -rf openg2p-program/g2p_program_documents
rm -rf openg2p-program/g2p_theme
rm -rf openg2p_registry/g2p_service_provider_portal_base
rm -rf mukit-modules/muk_web_enterprise_theme
cp -r openg2p-registry/* ${ADDONS_DIR}/
cat test-requirements.txt >> spp-test-requirements.txt
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,6 @@ docs/_build/
#ruff
.ruff_cache
.aider*

# Local release planning files (ignored)
.release/
95 changes: 95 additions & 0 deletions spp_branding_kit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from . import models
from . import controllers

import logging

_logger = logging.getLogger(__name__)


def post_init_hook(env):
"""
Post-installation hook to perform initial branding setup
"""
_logger.info("OpenSPP Branding Kit: Running post-installation setup...")

# No default parameters for app filtering; UI handles Apps filters now

# Disable Odoo branding elements
try:
# Deactivate brand promotion view
brand_promotion = env.ref("web.brand_promotion_message", raise_if_not_found=False)
if brand_promotion:
brand_promotion.active = False
_logger.info("Disabled Odoo brand promotion message")

# Disable specific Odoo update notification cron (if present)
crons_to_disable = [
"mail.ir_cron_module_update_notification", # Module update notification
]

for cron_xml_id in crons_to_disable:
try:
cron = env.ref(cron_xml_id, raise_if_not_found=False)
if cron and cron.active:
cron.active = False
_logger.info(f"Disabled cron job: {cron.name} ({cron_xml_id})")
except Exception as e:
_logger.debug(f"Could not disable cron {cron_xml_id}: {e}")

# Disable theme store menu if it exists
theme_menu = env["ir.ui.menu"].sudo().search([("name", "ilike", "Theme Store")], limit=1)
if theme_menu and theme_menu.active:
theme_menu.active = False
_logger.info("Disabled Theme Store menu")

except Exception as e:
_logger.warning(f"Error during branding setup: {e}")

# Update company information for all companies
try:
Company = env["res.company"].sudo()
companies = Company.search([])
for company in companies:
company.write(
{
"report_header": "OpenSPP Platform",
"report_footer": "OpenSPP - Open Source Social Protection Platform",
"website": "https://openspp.org",
}
)
_logger.info(f"Updated branding for {len(companies)} companies")
except Exception as e:
_logger.warning(f"Error updating company data: {e}")

_logger.info("OpenSPP Branding Kit: Post-installation setup completed")


def uninstall_hook(env):
"""
Uninstall hook to clean up configuration parameters
"""
_logger.info("OpenSPP Branding Kit: Running uninstall cleanup...")

# Remove all openspp.* configuration parameters
try:
IrConfigParam = env["ir.config_parameter"].sudo()
params = IrConfigParam.search([("key", "=like", "openspp.%")])
if params:
param_count = len(params)
params.unlink()
_logger.info(f"Removed {param_count} OpenSPP configuration parameters")
except Exception as e:
_logger.warning(f"Error removing configuration parameters: {e}")

# Optionally re-enable Odoo branding elements
# This is commented out by default to maintain debranding even after uninstall
# Uncomment if you want to restore Odoo branding on module removal

# try:
# brand_promotion = env.ref('web.brand_promotion_message', raise_if_not_found=False)
# if brand_promotion:
# brand_promotion.active = True
# except Exception as e:
# _logger.warning(f"Error during uninstall cleanup: {e}")

_logger.info("OpenSPP Branding Kit: Uninstall cleanup completed")
65 changes: 65 additions & 0 deletions spp_branding_kit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "OpenSPP Branding Kit",
"version": "17.0.1.0.0",
"summary": "Branding customization and telemetry management for OpenSPP",
"description": """
OpenSPP Branding Kit
====================

This module provides comprehensive branding customization for OpenSPP:

Features:
- Customizes system branding across all interfaces
- Redirects telemetry to OpenSPP servers (configurable)
- Option to completely disable telemetry
- Removes enterprise promotion elements
- Customizes system messages with OpenSPP branding

Technical Features:
- Works with theme_openspp_muk for visual styling
- Configurable telemetry endpoint
- Privacy-focused with opt-out options
""",
"author": "OpenSPP Project",
"website": "https://github.com/OpenSPP/openspp-modules",
"license": "LGPL-3",
"category": "Theme/Backend",
"depends": [
"base",
"web",
"base_setup",
"theme_openspp_muk", # Required for OpenSPP styling
],
"data": [
# Default configuration data (order matters)
"data/res_company_data.xml",
"data/ir_config_parameter.xml",
"data/debranding_data.xml",
# Views - UI customizations
"views/webclient_templates.xml",
"views/login_templates.xml",
"views/report_templates.xml",
"views/backend_customization.xml",
"views/res_config_settings_views.xml",
"views/about_settings.xml",
"views/ir_module_module_views.xml",
],
"assets": {
"web.assets_backend": [
"spp_branding_kit/static/src/js/webclient.js",
"spp_branding_kit/static/src/js/user_menu.js",
],
"web.assets_frontend": [
"spp_branding_kit/static/src/css/login_branding.css",
],
},
"images": [
"static/description/icon.png",
"static/description/banner.png",
],
"installable": True,
"application": False,
"auto_install": False,
"post_init_hook": "post_init_hook",
"uninstall_hook": "uninstall_hook",
}
1 change: 1 addition & 0 deletions spp_branding_kit/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
61 changes: 61 additions & 0 deletions spp_branding_kit/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import json

from werkzeug.urls import url_encode
from werkzeug.wrappers import Response

from odoo import http
from odoo.http import request

from odoo.addons.portal.controllers.web import Home

from ..utils import get_param, telemetry_payload, version_info_payload


class OpenSPPHome(Home):
"""Restrict debug mode to administrators when enabled via parameter."""

@http.route()
def web_client(self, s_action=None, **kw):
# Enforce optional debug restriction before rendering
debug_admin_only = get_param(request.env, "openspp.debug.admin_only", "True") == "True"

# Detect debug flag from kwargs or query string
has_debug = bool(kw.get("debug")) or ("debug" in (request.httprequest.args or {}))
if debug_admin_only and has_debug:
uid = request.session.uid
# If not logged in or not admin, strip debug and redirect
if not uid or not request.env.user._is_admin():
kw.pop("debug", None)
args = {k: v for k, v in request.httprequest.args.items() if k != "debug"}
query = url_encode(args)
return request.redirect("/web" + (f"?{query}" if query else ""))

return super().web_client(s_action, **kw)


class OpenSPPBrandingController(http.Controller):
"""Custom routes for OpenSPP branding"""

@http.route("/openspp/about", type="http", auth="public")
def openspp_about(self, **kwargs):
"""Custom about page for OpenSPP"""
return json.dumps(
{
"title": "About OpenSPP",
"version": "1.0.0",
"system_name": get_param(request.env, "openspp.system.name", "OpenSPP Platform"),
"documentation_url": get_param(request.env, "openspp.documentation.url", "https://docs.openspp.org"),
"support_url": get_param(request.env, "openspp.support.url", "https://openspp.org"),
}
)

@http.route("/web/webclient/version_info", type="json", auth="none")
def version_info(self):
"""Override version info to show OpenSPP branding"""
return version_info_payload(request.env)

@http.route("/publisher-warranty", type="http", auth="none", csrf=False)
def publisher_warranty(self, **kwargs):
"""Handle telemetry based on configuration"""
payload = telemetry_payload(request.env)
return Response(json.dumps(payload), content_type="application/json")
34 changes: 34 additions & 0 deletions spp_branding_kit/data/debranding_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">

<!-- Note: Some cron jobs and views may not exist in all Odoo versions -->
<!-- They will be handled safely in the post_init_hook -->

<!-- Remove Odoo Links from Menus -->

<!-- Rename Apps Store Menu to Local Apps -->
<record id="base.menu_module_tree" model="ir.ui.menu">
<field name="name">Local Apps</field>
</record>

<!-- Configuration Parameters -->

<!-- Disable Odoo IAP (In-App Purchase) -->
<record id="param_iap_endpoint" model="ir.config_parameter">
<field name="key">iap.endpoint</field>
<field name="value">False</field>
</record>

<!-- Disable Update Notifications -->
<record id="param_module_update_notification" model="ir.config_parameter">
<field name="key">module.update.notification</field>
<field name="value">False</field>
</record>

<!-- Custom Module Categories -->
<record id="module_category_openspp" model="ir.module.category">
<field name="name">OpenSPP</field>
<field name="sequence">1</field>
</record>

</odoo>
122 changes: 122 additions & 0 deletions spp_branding_kit/data/ir_config_parameter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">

<!-- System Information Parameters -->
<record id="param_system_name" model="ir.config_parameter">
<field name="key">openspp.system.name</field>
<field name="value">OpenSPP Platform</field>
</record>

<record id="param_system_version" model="ir.config_parameter">
<field name="key">openspp.system.version</field>
<field name="value">1.0.0</field>
</record>

<!-- Support and Documentation URLs -->
<record id="param_support_url" model="ir.config_parameter">
<field name="key">openspp.support.url</field>
<field name="value">https://openspp.org/</field>
</record>

<record id="param_documentation_url" model="ir.config_parameter">
<field name="key">openspp.documentation.url</field>
<field name="value">https://docs.openspp.org/</field>
</record>

<record id="param_community_url" model="ir.config_parameter">
<field name="key">openspp.community.url</field>
<field name="value">https://openspp.org/</field>
</record>

<!-- Telemetry Configuration -->
<record id="param_openspp_telemetry_enabled" model="ir.config_parameter">
<field name="key">openspp.telemetry.enabled</field>
<field name="value">True</field>
</record>

<record id="param_openspp_telemetry_endpoint" model="ir.config_parameter">
<field name="key">openspp.telemetry.endpoint</field>
<field name="value">https://telemetry.openspp.org</field>
</record>

<!-- Disable External Services -->
<record id="param_disable_external_links" model="ir.config_parameter">
<field name="key">openspp.disable.external_links</field>
<field name="value">True</field>
</record>

<!-- Custom Footer Text -->
<record id="param_footer_copyright" model="ir.config_parameter">
<field name="key">openspp.footer.copyright</field>
<field name="value">© OpenSPP Project - Open Source Social Protection Platform</field>
</record>

<!-- Email Configuration -->
<record id="param_email_from_name" model="ir.config_parameter">
<field name="key">openspp.email.from_name</field>
<field name="value">OpenSPP Platform</field>
</record>

<!-- Report Configuration -->
<record id="param_report_footer_text" model="ir.config_parameter">
<field name="key">openspp.report.footer_text</field>
<field name="value">Generated by OpenSPP Platform</field>
</record>

<!-- Login Page Configuration -->
<record id="param_login_page_title" model="ir.config_parameter">
<field name="key">openspp.login.page.title</field>
<field name="value">OpenSPP - Social Protection Platform</field>
</record>

<record id="param_login_page_subtitle" model="ir.config_parameter">
<field name="key">openspp.login.page.subtitle</field>
<field name="value">Secure Access Portal</field>
</record>

<!-- Database Manager Configuration -->
<record id="param_database_manager_disabled" model="ir.config_parameter">
<field name="key">openspp.database.manager.disabled</field>
<field name="value">True</field>
</record>

<!-- Custom Favicon Path -->
<record id="param_favicon_path" model="ir.config_parameter">
<field name="key">openspp.favicon.path</field>
<field name="value">/spp_branding_kit/static/description/icon.png</field>
</record>

<!-- Theme Configuration -->
<record id="param_theme_primary_color" model="ir.config_parameter">
<field name="key">openspp.theme.primary_color</field>
<field name="value">#2c3e50</field>
</record>

<record id="param_theme_secondary_color" model="ir.config_parameter">
<field name="key">openspp.theme.secondary_color</field>
<field name="value">#34495e</field>
</record>

<!-- Analytics and Tracking -->
<record id="param_google_analytics_disabled" model="ir.config_parameter">
<field name="key">openspp.google_analytics.disabled</field>
<field name="value">True</field>
</record>

<!-- Custom Error Messages -->
<record id="param_error_message_404" model="ir.config_parameter">
<field name="key">openspp.error.message.404</field>
<field name="value">Page not found in OpenSPP Platform</field>
</record>

<record id="param_error_message_403" model="ir.config_parameter">
<field name="key">openspp.error.message.403</field>
<field name="value">Access denied. Please contact your OpenSPP administrator.</field>
</record>

<record id="param_error_message_500" model="ir.config_parameter">
<field name="key">openspp.error.message.500</field>
<field name="value">An error occurred in OpenSPP Platform. Please try again later.</field>
</record>

</odoo>
Loading
Loading