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) }}

- - {{ _("platform.footer.privacy") }} - - - {{ _("platform.footer.terms") }} - + {% if legal_pages %} + {% for page in legal_pages %} + + {{ page.title }} + + {% endfor %} + {% else %} + {# Fallback to hardcoded links if no CMS pages #} + + {{ _("platform.footer.privacy") }} + + + {{ _("platform.footer.terms") }} + + {% endif %}
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,