414 lines
16 KiB
Python
414 lines
16 KiB
Python
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)}"
|
|
)
|
|
|