From bd447ae7f23d489f88f5b2e1636797a6ef4a1390 Mon Sep 17 00:00:00 2001
From: Samir Boulahtit
Date: Sun, 28 Dec 2025 20:03:34 +0100
Subject: [PATCH] feat: add show_in_legal category for bottom bar CMS pages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add third placement category for content pages that appear in the
bottom bar alongside the copyright notice (Privacy Policy, Terms, etc.):
Model changes:
- Add show_in_legal boolean field to ContentPage model
- Add to to_dict() serialization
Service changes:
- Add legal_only filter to list_pages_for_vendor()
Platform changes:
- Fetch legal_pages in get_platform_context()
- Update base.html to render legal_pages dynamically
- Fallback to hardcoded links if no CMS pages configured
Migration:
- Add column with default=False
- Auto-set show_in_legal=True for privacy and terms pages
Categories:
- show_in_header: Top navigation
- show_in_footer: Quick Links column
- show_in_legal: Bottom bar with copyright (NEW)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5
---
...8396_add_show_in_legal_to_content_pages.py | 41 +++++++++++++++++++
app/routes/platform_pages.py | 9 +++-
app/services/content_page_service.py | 5 +++
app/templates/platform/base.html | 21 +++++++---
models/database/content_page.py | 2 +
5 files changed, 70 insertions(+), 8 deletions(-)
create mode 100644 alembic/versions/ba2c0ce78396_add_show_in_legal_to_content_pages.py
diff --git a/alembic/versions/ba2c0ce78396_add_show_in_legal_to_content_pages.py b/alembic/versions/ba2c0ce78396_add_show_in_legal_to_content_pages.py
new file mode 100644
index 00000000..1ff03b77
--- /dev/null
+++ b/alembic/versions/ba2c0ce78396_add_show_in_legal_to_content_pages.py
@@ -0,0 +1,41 @@
+"""add show_in_legal to content_pages
+
+Revision ID: ba2c0ce78396
+Revises: m1b2c3d4e5f6
+Create Date: 2025-12-28 20:00:24.263518
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = 'ba2c0ce78396'
+down_revision: Union[str, None] = 'm1b2c3d4e5f6'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ """Add show_in_legal column to content_pages table.
+
+ This column controls whether a page appears in the bottom bar
+ alongside the copyright notice (e.g., Privacy Policy, Terms of Service).
+ """
+ op.add_column(
+ 'content_pages',
+ sa.Column('show_in_legal', sa.Boolean(), nullable=True, default=False)
+ )
+
+ # Set default value for existing rows
+ op.execute("UPDATE content_pages SET show_in_legal = 0 WHERE show_in_legal IS NULL")
+
+ # Set privacy and terms pages to show in legal by default
+ op.execute("UPDATE content_pages SET show_in_legal = 1 WHERE slug IN ('privacy', 'terms')")
+
+
+def downgrade() -> None:
+ """Remove show_in_legal column from content_pages table."""
+ op.drop_column('content_pages', 'show_in_legal')
diff --git a/app/routes/platform_pages.py b/app/routes/platform_pages.py
index bca83740..587969b4 100644
--- a/app/routes/platform_pages.py
+++ b/app/routes/platform_pages.py
@@ -47,9 +47,10 @@ def get_platform_context(request: Request, db: Session) -> dict:
# Add i18n globals (_, t, current_language, SUPPORTED_LANGUAGES, etc.)
context.update(i18n_globals)
- # Load CMS pages for header and footer navigation
+ # Load CMS pages for header, footer, and legal navigation
header_pages = []
footer_pages = []
+ legal_pages = []
try:
# Platform pages have vendor_id=None
header_pages = content_page_service.list_pages_for_vendor(
@@ -58,14 +59,18 @@ def get_platform_context(request: Request, db: Session) -> dict:
footer_pages = content_page_service.list_pages_for_vendor(
db, vendor_id=None, footer_only=True, include_unpublished=False
)
+ legal_pages = content_page_service.list_pages_for_vendor(
+ db, vendor_id=None, legal_only=True, include_unpublished=False
+ )
logger.debug(
- f"Loaded CMS pages: {len(header_pages)} header, {len(footer_pages)} footer"
+ f"Loaded CMS pages: {len(header_pages)} header, {len(footer_pages)} footer, {len(legal_pages)} legal"
)
except Exception as e:
logger.error(f"Failed to load CMS navigation pages: {e}")
context["header_pages"] = header_pages
context["footer_pages"] = footer_pages
+ context["legal_pages"] = legal_pages
return context
diff --git a/app/services/content_page_service.py b/app/services/content_page_service.py
index cbacc6b5..69211cd9 100644
--- a/app/services/content_page_service.py
+++ b/app/services/content_page_service.py
@@ -97,6 +97,7 @@ class ContentPageService:
include_unpublished: bool = False,
footer_only: bool = False,
header_only: bool = False,
+ legal_only: bool = False,
) -> list[ContentPage]:
"""
List all available pages for a vendor (includes vendor overrides + platform defaults).
@@ -109,6 +110,7 @@ class ContentPageService:
include_unpublished: Include draft pages
footer_only: Only pages marked for footer display
header_only: Only pages marked for header display
+ legal_only: Only pages marked for legal/bottom bar display
Returns:
List of ContentPage objects
@@ -124,6 +126,9 @@ class ContentPageService:
if header_only:
filters.append(ContentPage.show_in_header == True)
+ if legal_only:
+ filters.append(ContentPage.show_in_legal == True)
+
# Get vendor-specific pages
vendor_pages = []
if vendor_id:
diff --git a/app/templates/platform/base.html b/app/templates/platform/base.html
index f7adc854..e9b01e54 100644
--- a/app/templates/platform/base.html
+++ b/app/templates/platform/base.html
@@ -251,12 +251,21 @@
{{ _("platform.footer.copyright", year=2025) }}
diff --git a/models/database/content_page.py b/models/database/content_page.py
index 321f058e..3d38fdee 100644
--- a/models/database/content_page.py
+++ b/models/database/content_page.py
@@ -82,6 +82,7 @@ class ContentPage(Base):
display_order = Column(Integer, default=0)
show_in_footer = Column(Boolean, default=True)
show_in_header = Column(Boolean, default=False)
+ show_in_legal = Column(Boolean, default=False) # Bottom bar with copyright
# Timestamps
created_at = Column(
@@ -153,6 +154,7 @@ class ContentPage(Base):
"display_order": self.display_order,
"show_in_footer": self.show_in_footer,
"show_in_header": self.show_in_header,
+ "show_in_legal": self.show_in_legal,
"is_platform_default": self.is_platform_default,
"is_vendor_override": self.is_vendor_override,
"created_at": self.created_at.isoformat() if self.created_at else None,