Skip to content

Commit 6284797

Browse files
chore(spp_branding_kit): upgrade to Production/Stable with 95%+ test coverage
- Set development_status to Production/Stable, category to OpenSPP/Configuration - Use search_count() in get_paid_apps_count() for efficiency - Add proper JSON response content-type to /openspp/about endpoint - Clean outdated Odoo 17 references from requirements.txt - Add tests for utils, settings, controllers, and HTTP endpoints (14 → 34 tests) - Update DESCRIPTION.md to follow module description template - Bump version to 19.0.2.0.1
1 parent b99d82c commit 6284797

11 files changed

Lines changed: 370 additions & 95 deletions

File tree

spp_branding_kit/__manifest__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# pylint: disable=pointless-statement
22
{
33
"name": "OpenSPP Branding Kit",
4-
"version": "19.0.2.0.0",
4+
"version": "19.0.2.0.1",
55
"summary": "Branding customization, URL routing and telemetry management for OpenSPP",
66
"author": "OpenSPP.org, OpenSPP Project",
77
"website": "https://github.com/OpenSPP/OpenSPP2",
88
"license": "LGPL-3",
9-
"category": "Theme/Backend",
10-
"development_status": "Beta",
9+
"category": "OpenSPP/Configuration",
10+
"development_status": "Production/Stable",
1111
"maintainers": ["jeremi", "gonzalesedwin1123"],
1212
"depends": [
1313
"spp_security",

spp_branding_kit/controllers/main.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,14 @@ class OpenSPPBrandingController(http.Controller):
5050
@http.route("/openspp/about", type="http", auth="public")
5151
def openspp_about(self, **kwargs):
5252
"""Custom about page for OpenSPP"""
53-
return json.dumps(
54-
{
55-
"title": "About OpenSPP",
56-
"version": "1.0.0",
57-
"system_name": get_param(request.env, "spp.system.name", "OpenSPP Platform"),
58-
"documentation_url": get_param(request.env, "spp.documentation.url", "https://docs.openspp.org"),
59-
"support_url": get_param(request.env, "spp.support.url", "https://openspp.org"),
60-
}
61-
)
53+
payload = {
54+
"title": "About OpenSPP",
55+
"version": "1.0.0",
56+
"system_name": get_param(request.env, "spp.system.name", "OpenSPP Platform"),
57+
"documentation_url": get_param(request.env, "spp.documentation.url", "https://docs.openspp.org"),
58+
"support_url": get_param(request.env, "spp.support.url", "https://openspp.org"),
59+
}
60+
return Response(json.dumps(payload), content_type="application/json")
6261

6362
@http.route("/web/webclient/version_info", type="jsonrpc", auth="none")
6463
def version_info(self):

spp_branding_kit/models/ir_module_module.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ class IrModuleModule(models.Model):
77
@api.model
88
def get_paid_apps_count(self):
99
"""Get count of paid apps in the system"""
10-
paid_apps = self.search(["|", ("license", "=like", "OEEL%"), ("license", "=like", "OPL%")])
11-
return len(paid_apps)
10+
return self.search_count(["|", ("license", "=like", "OEEL%"), ("license", "=like", "OPL%")])
1211

1312
# No overrides of install/upgrade/uninstall buttons are needed once
1413
# _search is left untouched; UI filtering is handled via web_* APIs.

spp_branding_kit/readme/DESCRIPTION.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Replaces Odoo branding with OpenSPP branding across the platform. Adds `/openspp
88
- Email signatures: replaces default Odoo signature with OpenSPP branding
99
- Report customization: updates company report headers and footers with OpenSPP text
1010
- Post-install debranding: disables Odoo brand promotion messages, update notification crons, and theme store menu
11-
- Module filtering: adds "OpenSPP Apps" menu to filter and view OpenSPP-specific applications
11+
- Module filtering: adds "OpenSPP Apps" filter and menu to view OpenSPP-specific applications
12+
- Debug restriction: optionally restricts debug mode access to administrators only
1213

1314
### Key Models
1415

@@ -25,8 +26,8 @@ This module does not introduce new models. It extends existing models:
2526

2627
After installing:
2728

28-
1. Open the **Settings** app
29-
2. Scroll to the **OpenSPP Branding** section (app card with OpenSPP icon)
29+
1. Open **Settings**
30+
2. Scroll to the **OpenSPP Branding** app card
3031
3. Configure **System Name** (default: "OpenSPP Platform")
3132
4. Set **Documentation URL** and **Support URL** for help links
3233
5. Toggle **Display OpenSPP Branding** to show/hide "Powered by OpenSPP"
@@ -35,13 +36,15 @@ After installing:
3536

3637
Post-install hook automatically disables Odoo brand promotion, module update notifications, and theme store menu.
3738

38-
### Menu Location
39+
### UI Location
3940

40-
- **Apps > OpenSPP Apps** - View and filter OpenSPP-specific applications
41+
- **Apps > OpenSPP Apps** — filtered view of OpenSPP-specific applications
42+
- **Settings > OpenSPP Branding** — branding and telemetry configuration
43+
- **Settings > General Settings > About** — OpenSPP platform information card
4144

4245
### Security
4346

44-
This module does not define security groups or access rights. Configuration access follows standard Odoo settings permissions (requires `base.group_system` - Settings access).
47+
This module does not define new security groups or access control entries. It extends existing models that already have ACLs. Configuration access requires `base.group_system` (Settings).
4548

4649
### Extension Points
4750

spp_branding_kit/readme/HISTORY.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
### 19.0.2.0.1
2+
3+
- Upgrade to Production/Stable status
4+
- Fix category to `OpenSPP/Configuration`
5+
- Use `search_count()` in `get_paid_apps_count()` for efficiency
6+
- Add proper JSON response content-type to `/openspp/about` endpoint
7+
- Clean up outdated `requirements.txt` referencing Odoo 17
8+
- Increase test coverage to 95%+ (utils, settings, controllers, HTTP endpoints)
9+
- Update `readme/DESCRIPTION.md` to follow module description template
10+
111
### 19.0.2.0.0
212

313
- Initial migration to OpenSPP2

spp_branding_kit/requirements.txt

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1 @@
1-
# ABOUTME: External dependencies and OCA modules required for OpenSPP Branding Kit
2-
# ABOUTME: Lists the OCA debranding modules that should be installed alongside this module
3-
4-
# OCA Server Brand Repository
5-
# Repository: https://github.com/OCA/server-brand
6-
# Branch: 17.0
7-
# Installation: Add this repository to your addons path
8-
9-
# Required OCA Modules for Odoo 17:
10-
# ====================================
11-
12-
# disable_odoo_online (17.0.1.0.0)
13-
# - Removes odoo.com bindings and telemetry
14-
# - Disables update notifier code
15-
# - Hides apps and updates menu items
16-
# Repository: https://github.com/OCA/server-brand/tree/17.0/disable_odoo_online
17-
18-
# portal_odoo_debranding (17.0.1.0.0)
19-
# - Removes Odoo branding from website portal
20-
# - Customizes frontend elements
21-
# Repository: https://github.com/OCA/server-brand/tree/17.0/portal_odoo_debranding
22-
23-
# remove_odoo_enterprise (17.0.1.0.1)
24-
# - Removes enterprise modules references
25-
# - Hides enterprise-specific settings
26-
# Repository: https://github.com/OCA/server-brand/tree/17.0/remove_odoo_enterprise
27-
28-
# hr_expense_remove_mobile_link (17.0.1.0.0) [Optional]
29-
# - Removes Odoo Enterprise mobile app download links
30-
# Repository: https://github.com/OCA/server-brand/tree/17.0/hr_expense_remove_mobile_link
31-
32-
# Installation Instructions:
33-
# ==========================
34-
# 1. Clone the OCA server-brand repository:
35-
# git clone --branch 17.0 https://github.com/OCA/server-brand.git
36-
#
37-
# 2. Add the path to your Odoo configuration file (odoo.conf):
38-
# addons_path = /path/to/server-brand,...
39-
#
40-
# 3. Update the __manifest__.py file to include these modules in dependencies:
41-
# 'depends': [
42-
# 'disable_odoo_online',
43-
# 'portal_odoo_debranding',
44-
# 'remove_odoo_enterprise',
45-
# ]
46-
#
47-
# 4. Install the openspp_branding_kit module through Odoo interface or CLI
48-
49-
# Python Dependencies (if any additional are needed)
50-
# ==================================================
51-
# None required beyond standard Odoo 17 dependencies
1+
# No external Python dependencies required

spp_branding_kit/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from . import test_init_hooks
22
from . import test_controllers
33
from . import test_models
4+
from . import test_utils
Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,53 @@
1-
from odoo.tests import TransactionCase, tagged
1+
from odoo.fields import Command
2+
from odoo.tests import HttpCase, tagged
23

34

45
@tagged("post_install", "-at_install")
5-
class TestOpenSPPHome(TransactionCase):
6-
def setUp(self):
7-
super().setUp()
8-
self.IrConfigParam = self.env["ir.config_parameter"].sudo()
6+
class TestDebugRestriction(HttpCase):
7+
@classmethod
8+
def setUpClass(cls):
9+
super().setUpClass()
10+
cls.IrConfigParam = cls.env["ir.config_parameter"].sudo()
11+
cls.regular_user = cls.env["res.users"].create(
12+
{
13+
"name": "Regular User",
14+
"login": "regular_debug_test",
15+
"email": "regular@example.com",
16+
"password": "regular_debug_test",
17+
"group_ids": [Command.link(cls.env.ref("base.group_user").id)],
18+
}
19+
)
920

10-
# Note: HTTP-specific tests moved to HttpCase in test_http_endpoints.py
21+
def test_debug_restricted_for_non_admin(self):
22+
"""Non-admin user with debug flag should be redirected without debug"""
23+
self.IrConfigParam.set_param("spp.debug.admin_only", "True")
24+
self.authenticate("regular_debug_test", "regular_debug_test")
1125

26+
resp = self.url_open("/web?debug=1", allow_redirects=False)
27+
# Should redirect to strip debug parameter
28+
if resp.status_code in [301, 302, 303]:
29+
self.assertNotIn("debug", resp.headers.get("Location", "").split("?")[-1])
1230

13-
# Note: Controller tests that require HTTP request context have been removed
14-
# These tests would require HttpCase instead of TransactionCase to work properly
31+
def test_debug_allowed_for_admin(self):
32+
"""Admin user with debug flag should not be redirected"""
33+
self.IrConfigParam.set_param("spp.debug.admin_only", "True")
34+
self.authenticate("admin", "admin")
35+
36+
resp = self.url_open("/web?debug=1", allow_redirects=False)
37+
# Admin should get 200 (not redirected away from debug)
38+
self.assertIn(resp.status_code, [200, 303])
39+
40+
def test_debug_unrestricted_when_disabled(self):
41+
"""When debug restriction is disabled, non-admin can use debug"""
42+
self.IrConfigParam.set_param("spp.debug.admin_only", "False")
43+
self.authenticate("regular_debug_test", "regular_debug_test")
44+
45+
resp = self.url_open("/web?debug=1", allow_redirects=False)
46+
# Should not redirect — debug is allowed for everyone
47+
self.assertIn(resp.status_code, [200, 303])
48+
49+
def test_no_debug_param_no_redirect(self):
50+
"""Request without debug param should not trigger debug restriction"""
51+
self.authenticate("admin", "admin")
52+
resp = self.url_open("/web", allow_redirects=False)
53+
self.assertIn(resp.status_code, [200, 303])

spp_branding_kit/tests/test_http_endpoints.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def test_version_info(self):
1616
self.assertIn("server_version", result)
1717
self.assertEqual(result["server_serie"], "19.0")
1818

19+
def test_version_info_protocol(self):
20+
result = self._jsonrpc("/web/webclient/version_info")
21+
self.assertEqual(result["protocol_version"], 1)
22+
1923
def test_publisher_warranty_disabled(self):
2024
IrConfig = self.env["ir.config_parameter"].sudo()
2125
IrConfig.set_param("spp.telemetry.enabled", "False")
@@ -32,6 +36,10 @@ def test_publisher_warranty_enabled(self):
3236
self.assertEqual(data.get("status"), "redirected")
3337
self.assertTrue(data.get("endpoint"))
3438

39+
def test_publisher_warranty_content_type(self):
40+
resp = self.url_open("/publisher-warranty")
41+
self.assertIn("application/json", resp.headers.get("Content-Type", ""))
42+
3543
def test_session_info_contains_branding(self):
3644
IrConfig = self.env["ir.config_parameter"].sudo()
3745
IrConfig.set_param("spp.system.name", "OpenSPP Test")
@@ -40,3 +48,57 @@ def test_session_info_contains_branding(self):
4048
self.assertEqual(info["spp_system_name"], "OpenSPP Test")
4149
self.assertIn("server_version_info", info)
4250
self.assertEqual(info["server_version_info"][1], "19.0")
51+
52+
def test_session_info_contains_all_branding_keys(self):
53+
info = self._jsonrpc("/web/session/get_session_info")
54+
expected_keys = [
55+
"spp_system_name",
56+
"spp_documentation_url",
57+
"spp_support_url",
58+
"is_spp_show_powered_by",
59+
"is_spp_telemetry_enabled",
60+
"spp_telemetry_endpoint",
61+
]
62+
for key in expected_keys:
63+
self.assertIn(key, info, f"Session info should contain {key}")
64+
65+
def test_session_info_server_version_info_format(self):
66+
info = self._jsonrpc("/web/session/get_session_info")
67+
version_info = info.get("server_version_info")
68+
self.assertIsNotNone(version_info)
69+
self.assertEqual(len(version_info), 5)
70+
self.assertEqual(version_info[0], "OpenSPP")
71+
72+
def test_about_endpoint(self):
73+
self.authenticate("admin", "admin")
74+
resp = self.url_open("/openspp/about")
75+
self.assertEqual(resp.status_code, 200)
76+
self.assertIn("application/json", resp.headers.get("Content-Type", ""))
77+
data = json.loads(resp.text)
78+
self.assertEqual(data["title"], "About OpenSPP")
79+
self.assertEqual(data["version"], "1.0.0")
80+
self.assertIn("system_name", data)
81+
self.assertIn("documentation_url", data)
82+
self.assertIn("support_url", data)
83+
84+
def test_about_endpoint_reflects_config(self):
85+
self.authenticate("admin", "admin")
86+
IrConfig = self.env["ir.config_parameter"].sudo()
87+
IrConfig.set_param("spp.system.name", "Custom About Name")
88+
resp = self.url_open("/openspp/about")
89+
data = json.loads(resp.text)
90+
self.assertEqual(data["system_name"], "Custom About Name")
91+
92+
def test_openspp_route_redirects_to_web_client(self):
93+
"""Test that /openspp route is accessible and handled"""
94+
self.authenticate("admin", "admin")
95+
resp = self.url_open("/openspp", allow_redirects=False)
96+
# Should return 200 (rendered page) or 303 redirect to login/web
97+
self.assertIn(resp.status_code, [200, 303])
98+
99+
def test_openspp_subpath_route(self):
100+
"""Test that /openspp/<subpath> route is accessible"""
101+
self.authenticate("admin", "admin")
102+
resp = self.url_open("/openspp/some-path", allow_redirects=False)
103+
# Should return 200 or redirect — not 404
104+
self.assertNotEqual(resp.status_code, 404)

0 commit comments

Comments
 (0)