from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import Optional from datetime import datetime import json from ..config.database import get_db from ..middleware.auth import get_current_user, authorize_roles from ..models.user import User from ..models.page_content import PageContent, PageType router = APIRouter(prefix="/page-content", tags=["page-content"]) @router.get("/") async def get_all_page_contents( db: Session = Depends(get_db) ): """Get all page contents""" try: contents = db.query(PageContent).all() result = [] for content in contents: content_dict = { "id": content.id, "page_type": content.page_type.value, "title": content.title, "subtitle": content.subtitle, "description": content.description, "content": content.content, "meta_title": content.meta_title, "meta_description": content.meta_description, "meta_keywords": content.meta_keywords, "og_title": content.og_title, "og_description": content.og_description, "og_image": content.og_image, "canonical_url": content.canonical_url, "contact_info": json.loads(content.contact_info) if content.contact_info else None, "map_url": content.map_url, "social_links": json.loads(content.social_links) if content.social_links else None, "footer_links": json.loads(content.footer_links) if content.footer_links else None, "hero_title": content.hero_title, "hero_subtitle": content.hero_subtitle, "hero_image": content.hero_image, "story_content": content.story_content, "values": json.loads(content.values) if content.values else None, "features": json.loads(content.features) if content.features else None, "is_active": content.is_active, "created_at": content.created_at.isoformat() if content.created_at else None, "updated_at": content.updated_at.isoformat() if content.updated_at else None, } result.append(content_dict) return { "status": "success", "data": { "page_contents": result } } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error fetching page contents: {str(e)}" ) @router.get("/{page_type}") async def get_page_content( page_type: PageType, db: Session = Depends(get_db) ): """Get content for a specific page""" try: content = db.query(PageContent).filter(PageContent.page_type == page_type).first() if not content: # Return default structure if not found return { "status": "success", "data": { "page_content": None } } content_dict = { "id": content.id, "page_type": content.page_type.value, "title": content.title, "subtitle": content.subtitle, "description": content.description, "content": content.content, "meta_title": content.meta_title, "meta_description": content.meta_description, "meta_keywords": content.meta_keywords, "og_title": content.og_title, "og_description": content.og_description, "og_image": content.og_image, "canonical_url": content.canonical_url, "contact_info": json.loads(content.contact_info) if content.contact_info else None, "social_links": json.loads(content.social_links) if content.social_links else None, "footer_links": json.loads(content.footer_links) if content.footer_links else None, "hero_title": content.hero_title, "hero_subtitle": content.hero_subtitle, "hero_image": content.hero_image, "story_content": content.story_content, "values": json.loads(content.values) if content.values else None, "features": json.loads(content.features) if content.features else None, "is_active": content.is_active, "created_at": content.created_at.isoformat() if content.created_at else None, "updated_at": content.updated_at.isoformat() if content.updated_at else None, } return { "status": "success", "data": { "page_content": content_dict } } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error fetching page content: {str(e)}" ) @router.post("/{page_type}") async def create_or_update_page_content( page_type: PageType, title: Optional[str] = None, subtitle: Optional[str] = None, description: Optional[str] = None, content: Optional[str] = None, meta_title: Optional[str] = None, meta_description: Optional[str] = None, meta_keywords: Optional[str] = None, og_title: Optional[str] = None, og_description: Optional[str] = None, og_image: Optional[str] = None, canonical_url: Optional[str] = None, contact_info: Optional[str] = None, map_url: Optional[str] = None, social_links: Optional[str] = None, footer_links: Optional[str] = None, hero_title: Optional[str] = None, hero_subtitle: Optional[str] = None, hero_image: Optional[str] = None, story_content: Optional[str] = None, values: Optional[str] = None, features: Optional[str] = None, is_active: bool = True, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """Create or update page content (admin only)""" try: authorize_roles(current_user, ["admin"]) # Validate JSON fields if provided if contact_info: try: json.loads(contact_info) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON in contact_info" ) if social_links: try: json.loads(social_links) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON in social_links" ) if footer_links: try: json.loads(footer_links) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON in footer_links" ) if values: try: json.loads(values) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON in values" ) if features: try: json.loads(features) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid JSON in features" ) # Check if content exists existing_content = db.query(PageContent).filter(PageContent.page_type == page_type).first() if existing_content: # Update existing if title is not None: existing_content.title = title if subtitle is not None: existing_content.subtitle = subtitle if description is not None: existing_content.description = description if content is not None: existing_content.content = content if meta_title is not None: existing_content.meta_title = meta_title if meta_description is not None: existing_content.meta_description = meta_description if meta_keywords is not None: existing_content.meta_keywords = meta_keywords if og_title is not None: existing_content.og_title = og_title if og_description is not None: existing_content.og_description = og_description if og_image is not None: existing_content.og_image = og_image if canonical_url is not None: existing_content.canonical_url = canonical_url if contact_info is not None: existing_content.contact_info = contact_info if map_url is not None: existing_content.map_url = map_url if social_links is not None: existing_content.social_links = social_links if footer_links is not None: existing_content.footer_links = footer_links if hero_title is not None: existing_content.hero_title = hero_title if hero_subtitle is not None: existing_content.hero_subtitle = hero_subtitle if hero_image is not None: existing_content.hero_image = hero_image if story_content is not None: existing_content.story_content = story_content if values is not None: existing_content.values = values if features is not None: existing_content.features = features if is_active is not None: existing_content.is_active = is_active existing_content.updated_at = datetime.utcnow() db.commit() db.refresh(existing_content) return { "status": "success", "message": "Page content updated successfully", "data": { "page_content": { "id": existing_content.id, "page_type": existing_content.page_type.value, "title": existing_content.title, "updated_at": existing_content.updated_at.isoformat() if existing_content.updated_at else None, } } } else: # Create new new_content = PageContent( page_type=page_type, title=title, subtitle=subtitle, description=description, content=content, meta_title=meta_title, meta_description=meta_description, meta_keywords=meta_keywords, og_title=og_title, og_description=og_description, og_image=og_image, canonical_url=canonical_url, contact_info=contact_info, map_url=map_url, social_links=social_links, footer_links=footer_links, hero_title=hero_title, hero_subtitle=hero_subtitle, hero_image=hero_image, story_content=story_content, values=values, features=features, is_active=is_active, ) db.add(new_content) db.commit() db.refresh(new_content) return { "status": "success", "message": "Page content created successfully", "data": { "page_content": { "id": new_content.id, "page_type": new_content.page_type.value, "title": new_content.title, "created_at": new_content.created_at.isoformat() if new_content.created_at else None, } } } except HTTPException: raise except Exception as e: db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error saving page content: {str(e)}" ) @router.put("/{page_type}") async def update_page_content( page_type: PageType, page_data: dict, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """Create or update page content using JSON body (admin only)""" try: authorize_roles(current_user, ["admin"]) existing_content = db.query(PageContent).filter(PageContent.page_type == page_type).first() if not existing_content: # Create new content if it doesn't exist existing_content = PageContent( page_type=page_type, is_active=True, ) db.add(existing_content) # Update fields from request body for key, value in page_data.items(): if hasattr(existing_content, key): # Handle JSON fields - convert dict/list to JSON string if key in ["contact_info", "social_links", "footer_links", "values", "features"] and value is not None: if isinstance(value, str): # Already a string, validate it's valid JSON try: json.loads(value) except json.JSONDecodeError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invalid JSON in {key}" ) elif isinstance(value, (dict, list)): # Convert dict/list to JSON string for storage value = json.dumps(value) # Skip None values to allow partial updates if value is not None: setattr(existing_content, key, value) existing_content.updated_at = datetime.utcnow() db.commit() db.refresh(existing_content) content_dict = { "id": existing_content.id, "page_type": existing_content.page_type.value, "title": existing_content.title, "subtitle": existing_content.subtitle, "description": existing_content.description, "content": existing_content.content, "meta_title": existing_content.meta_title, "meta_description": existing_content.meta_description, "meta_keywords": existing_content.meta_keywords, "og_title": existing_content.og_title, "og_description": existing_content.og_description, "og_image": existing_content.og_image, "canonical_url": existing_content.canonical_url, "contact_info": json.loads(existing_content.contact_info) if existing_content.contact_info else None, "social_links": json.loads(existing_content.social_links) if existing_content.social_links else None, "footer_links": json.loads(existing_content.footer_links) if existing_content.footer_links else None, "hero_title": existing_content.hero_title, "hero_subtitle": existing_content.hero_subtitle, "hero_image": existing_content.hero_image, "story_content": existing_content.story_content, "values": json.loads(existing_content.values) if existing_content.values else None, "features": json.loads(existing_content.features) if existing_content.features else None, "is_active": existing_content.is_active, "updated_at": existing_content.updated_at.isoformat() if existing_content.updated_at else None, } return { "status": "success", "message": "Page content updated successfully", "data": { "page_content": content_dict } } except HTTPException: raise except Exception as e: db.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error updating page content: {str(e)}" )