diff --git a/alembic/versions/z4e5f6a7b8c9_add_multi_platform_support.py b/alembic/versions/z4e5f6a7b8c9_add_multi_platform_support.py index 46920729..185ed0cf 100644 --- a/alembic/versions/z4e5f6a7b8c9_add_multi_platform_support.py +++ b/alembic/versions/z4e5f6a7b8c9_add_multi_platform_support.py @@ -178,9 +178,7 @@ def upgrade() -> None: """) ) - # Get the OMS platform ID - result = conn.execute(sa.text("SELECT id FROM platforms WHERE code = 'oms'")) - oms_platform_id = result.fetchone()[0] +I dn # ========================================================================= # 6. Backfill content_pages with platform_id diff --git a/alembic/versions/z7h8i9j0k1l2_fix_content_page_nullable_columns.py b/alembic/versions/z7h8i9j0k1l2_fix_content_page_nullable_columns.py new file mode 100644 index 00000000..12a0fe1f --- /dev/null +++ b/alembic/versions/z7h8i9j0k1l2_fix_content_page_nullable_columns.py @@ -0,0 +1,115 @@ +"""Fix content_page nullable boolean columns + +Revision ID: z7h8i9j0k1l2 +Revises: z6g7h8i9j0k1 +Create Date: 2026-01-20 + +This migration: +1. Sets NULL values to defaults for boolean and integer columns +2. Alters columns to be NOT NULL +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "z7h8i9j0k1l2" +down_revision = "z6g7h8i9j0k1" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # First, update any NULL values to defaults + op.execute(""" + UPDATE content_pages + SET display_order = 0 + WHERE display_order IS NULL + """) + + op.execute(""" + UPDATE content_pages + SET show_in_footer = true + WHERE show_in_footer IS NULL + """) + + op.execute(""" + UPDATE content_pages + SET show_in_header = false + WHERE show_in_header IS NULL + """) + + op.execute(""" + UPDATE content_pages + SET show_in_legal = false + WHERE show_in_legal IS NULL + """) + + # Now alter columns to be NOT NULL + op.alter_column( + "content_pages", + "display_order", + existing_type=sa.Integer(), + nullable=False, + server_default="0", + ) + + op.alter_column( + "content_pages", + "show_in_footer", + existing_type=sa.Boolean(), + nullable=False, + server_default="true", + ) + + op.alter_column( + "content_pages", + "show_in_header", + existing_type=sa.Boolean(), + nullable=False, + server_default="false", + ) + + op.alter_column( + "content_pages", + "show_in_legal", + existing_type=sa.Boolean(), + nullable=False, + server_default="false", + ) + + +def downgrade() -> None: + # Revert columns to nullable (no server default) + op.alter_column( + "content_pages", + "display_order", + existing_type=sa.Integer(), + nullable=True, + server_default=None, + ) + + op.alter_column( + "content_pages", + "show_in_footer", + existing_type=sa.Boolean(), + nullable=True, + server_default=None, + ) + + op.alter_column( + "content_pages", + "show_in_header", + existing_type=sa.Boolean(), + nullable=True, + server_default=None, + ) + + op.alter_column( + "content_pages", + "show_in_legal", + existing_type=sa.Boolean(), + nullable=True, + server_default=None, + ) diff --git a/app/platforms/shared/base_platform.py b/app/platforms/shared/base_platform.py index b3d5d1f3..f8d20c2b 100644 --- a/app/platforms/shared/base_platform.py +++ b/app/platforms/shared/base_platform.py @@ -69,7 +69,6 @@ class BasePlatformConfig(ABC): """ return [ "home", - "platform_homepage", "pricing", "about", "contact", diff --git a/app/routes/admin_pages.py b/app/routes/admin_pages.py index 89b1cd6e..b03d5dda 100644 --- a/app/routes/admin_pages.py +++ b/app/routes/admin_pages.py @@ -1116,23 +1116,21 @@ async def admin_platform_edit( # ============================================================================ -@router.get("/platform-homepage", response_class=HTMLResponse, include_in_schema=False) +@router.get("/platform-homepage", include_in_schema=False) async def admin_platform_homepage_manager( request: Request, current_user: User = Depends(get_current_admin_from_cookie_or_header), db: Session = Depends(get_db), ): """ - Render platform homepage manager. - Allows editing the main platform homepage with template selection. + Deprecated: Redirects to platforms page. + + Platform homepages are now managed via: + - /admin/platforms → Select platform → Homepage button + - Or directly: /admin/content-pages?platform_code={code}&slug=home """ - return templates.TemplateResponse( - "admin/platform-homepage.html", - { - "request": request, - "user": current_user, - }, - ) + from starlette.responses import RedirectResponse + return RedirectResponse(url="/admin/platforms", status_code=302) @router.get("/content-pages", response_class=HTMLResponse, include_in_schema=False) diff --git a/app/routes/platform_pages.py b/app/routes/platform_pages.py index 1b7fea18..1fc045f8 100644 --- a/app/routes/platform_pages.py +++ b/app/routes/platform_pages.py @@ -158,18 +158,13 @@ async def homepage( return RedirectResponse(url="/shop/", status_code=302) # Scenario 2: Platform marketing site (no vendor) - # Try to load platform homepage from CMS + # Load platform homepage from CMS (slug='home') platform_id = platform.id if platform else 1 cms_homepage = content_page_service.get_platform_page( db, platform_id=platform_id, slug="home", include_unpublished=False ) - if not cms_homepage: - cms_homepage = content_page_service.get_platform_page( - db, platform_id=platform_id, slug="platform_homepage", include_unpublished=False - ) - if cms_homepage: # Use CMS-based homepage with template selection context = get_platform_context(request, db) diff --git a/app/services/content_page_service.py b/app/services/content_page_service.py index 816be7b0..c94edbb4 100644 --- a/app/services/content_page_service.py +++ b/app/services/content_page_service.py @@ -305,6 +305,66 @@ class ContentPageService: .all() ) + @staticmethod + def list_all_platform_pages( + db: Session, + include_unpublished: bool = False, + ) -> list[ContentPage]: + """ + List all platform marketing pages across all platforms (for admin use). + + Args: + db: Database session + include_unpublished: Include draft pages + + Returns: + List of all platform marketing ContentPage objects + """ + filters = [ + ContentPage.vendor_id.is_(None), + ContentPage.is_platform_page.is_(True), + ] + + if not include_unpublished: + filters.append(ContentPage.is_published.is_(True)) + + return ( + db.query(ContentPage) + .filter(and_(*filters)) + .order_by(ContentPage.platform_id, ContentPage.display_order, ContentPage.title) + .all() + ) + + @staticmethod + def list_all_vendor_defaults( + db: Session, + include_unpublished: bool = False, + ) -> list[ContentPage]: + """ + List all vendor default pages across all platforms (for admin use). + + Args: + db: Database session + include_unpublished: Include draft pages + + Returns: + List of all vendor default ContentPage objects + """ + filters = [ + ContentPage.vendor_id.is_(None), + ContentPage.is_platform_page.is_(False), + ] + + if not include_unpublished: + filters.append(ContentPage.is_published.is_(True)) + + return ( + db.query(ContentPage) + .filter(and_(*filters)) + .order_by(ContentPage.platform_id, ContentPage.display_order, ContentPage.title) + .all() + ) + # ========================================================================= # CRUD Methods # ========================================================================= diff --git a/app/templates/admin/content-pages.html b/app/templates/admin/content-pages.html index 09e44c5d..a38d1f44 100644 --- a/app/templates/admin/content-pages.html +++ b/app/templates/admin/content-pages.html @@ -32,7 +32,8 @@