updates
This commit is contained in:
@@ -7,300 +7,144 @@ from pathlib import Path
|
||||
import os
|
||||
import aiofiles
|
||||
import uuid
|
||||
|
||||
from ..config.database import get_db
|
||||
from ..middleware.auth import get_current_user, authorize_roles
|
||||
from ..models.user import User
|
||||
from ..models.banner import Banner
|
||||
|
||||
router = APIRouter(prefix="/banners", tags=["banners"])
|
||||
|
||||
router = APIRouter(prefix='/banners', tags=['banners'])
|
||||
|
||||
def normalize_image_url(image_url: str, base_url: str) -> str:
|
||||
"""Normalize image URL to absolute URL"""
|
||||
if not image_url:
|
||||
return image_url
|
||||
if image_url.startswith('http://') or image_url.startswith('https://'):
|
||||
return image_url
|
||||
if image_url.startswith('/'):
|
||||
return f"{base_url}{image_url}"
|
||||
return f"{base_url}/{image_url}"
|
||||
|
||||
return f'{base_url}{image_url}'
|
||||
return f'{base_url}/{image_url}'
|
||||
|
||||
def get_base_url(request: Request) -> str:
|
||||
"""Get base URL for image normalization"""
|
||||
return os.getenv("SERVER_URL") or f"http://{request.headers.get('host', 'localhost:3000')}"
|
||||
return os.getenv('SERVER_URL') or f'http://{request.headers.get('host', 'localhost:3000')}'
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_banners(
|
||||
request: Request,
|
||||
position: Optional[str] = Query(None),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all active banners"""
|
||||
@router.get('/')
|
||||
async def get_banners(request: Request, position: Optional[str]=Query(None), db: Session=Depends(get_db)):
|
||||
try:
|
||||
query = db.query(Banner).filter(Banner.is_active == True)
|
||||
|
||||
# Filter by position
|
||||
if position:
|
||||
query = query.filter(Banner.position == position)
|
||||
|
||||
# Filter by date range
|
||||
now = datetime.utcnow()
|
||||
query = query.filter(
|
||||
or_(
|
||||
Banner.start_date == None,
|
||||
Banner.start_date <= now
|
||||
)
|
||||
).filter(
|
||||
or_(
|
||||
Banner.end_date == None,
|
||||
Banner.end_date >= now
|
||||
)
|
||||
)
|
||||
|
||||
query = query.filter(or_(Banner.start_date == None, Banner.start_date <= now)).filter(or_(Banner.end_date == None, Banner.end_date >= now))
|
||||
banners = query.order_by(Banner.display_order.asc(), Banner.created_at.desc()).all()
|
||||
|
||||
base_url = get_base_url(request)
|
||||
result = []
|
||||
for banner in banners:
|
||||
banner_dict = {
|
||||
"id": banner.id,
|
||||
"title": banner.title,
|
||||
"description": banner.description,
|
||||
"image_url": normalize_image_url(banner.image_url, base_url),
|
||||
"link_url": banner.link_url,
|
||||
"position": banner.position,
|
||||
"display_order": banner.display_order,
|
||||
"is_active": banner.is_active,
|
||||
"start_date": banner.start_date.isoformat() if banner.start_date else None,
|
||||
"end_date": banner.end_date.isoformat() if banner.end_date else None,
|
||||
"created_at": banner.created_at.isoformat() if banner.created_at else None,
|
||||
}
|
||||
banner_dict = {'id': banner.id, 'title': banner.title, 'description': banner.description, 'image_url': normalize_image_url(banner.image_url, base_url), 'link_url': banner.link_url, 'position': banner.position, 'display_order': banner.display_order, 'is_active': banner.is_active, 'start_date': banner.start_date.isoformat() if banner.start_date else None, 'end_date': banner.end_date.isoformat() if banner.end_date else None, 'created_at': banner.created_at.isoformat() if banner.created_at else None}
|
||||
result.append(banner_dict)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"data": {"banners": result}
|
||||
}
|
||||
return {'status': 'success', 'data': {'banners': result}}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{id}")
|
||||
async def get_banner_by_id(
|
||||
id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get banner by ID"""
|
||||
@router.get('/{id}')
|
||||
async def get_banner_by_id(id: int, request: Request, db: Session=Depends(get_db)):
|
||||
try:
|
||||
banner = db.query(Banner).filter(Banner.id == id).first()
|
||||
if not banner:
|
||||
raise HTTPException(status_code=404, detail="Banner not found")
|
||||
|
||||
raise HTTPException(status_code=404, detail='Banner not found')
|
||||
base_url = get_base_url(request)
|
||||
banner_dict = {
|
||||
"id": banner.id,
|
||||
"title": banner.title,
|
||||
"description": banner.description,
|
||||
"image_url": normalize_image_url(banner.image_url, base_url),
|
||||
"link_url": banner.link_url,
|
||||
"position": banner.position,
|
||||
"display_order": banner.display_order,
|
||||
"is_active": banner.is_active,
|
||||
"start_date": banner.start_date.isoformat() if banner.start_date else None,
|
||||
"end_date": banner.end_date.isoformat() if banner.end_date else None,
|
||||
"created_at": banner.created_at.isoformat() if banner.created_at else None,
|
||||
}
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"data": {"banner": banner_dict}
|
||||
}
|
||||
banner_dict = {'id': banner.id, 'title': banner.title, 'description': banner.description, 'image_url': normalize_image_url(banner.image_url, base_url), 'link_url': banner.link_url, 'position': banner.position, 'display_order': banner.display_order, 'is_active': banner.is_active, 'start_date': banner.start_date.isoformat() if banner.start_date else None, 'end_date': banner.end_date.isoformat() if banner.end_date else None, 'created_at': banner.created_at.isoformat() if banner.created_at else None}
|
||||
return {'status': 'success', 'data': {'banner': banner_dict}}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/", dependencies=[Depends(authorize_roles("admin"))])
|
||||
async def create_banner(
|
||||
banner_data: dict,
|
||||
current_user: User = Depends(authorize_roles("admin")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create new banner (Admin only)"""
|
||||
@router.post('/', dependencies=[Depends(authorize_roles('admin'))])
|
||||
async def create_banner(banner_data: dict, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
||||
try:
|
||||
banner = Banner(
|
||||
title=banner_data.get("title"),
|
||||
description=banner_data.get("description"),
|
||||
image_url=banner_data.get("image_url"),
|
||||
link_url=banner_data.get("link"),
|
||||
position=banner_data.get("position", "home"),
|
||||
display_order=banner_data.get("display_order", 0),
|
||||
is_active=True,
|
||||
start_date=datetime.fromisoformat(banner_data["start_date"].replace('Z', '+00:00')) if banner_data.get("start_date") else None,
|
||||
end_date=datetime.fromisoformat(banner_data["end_date"].replace('Z', '+00:00')) if banner_data.get("end_date") else None,
|
||||
)
|
||||
|
||||
banner = Banner(title=banner_data.get('title'), description=banner_data.get('description'), image_url=banner_data.get('image_url'), link_url=banner_data.get('link'), position=banner_data.get('position', 'home'), display_order=banner_data.get('display_order', 0), is_active=True, start_date=datetime.fromisoformat(banner_data['start_date'].replace('Z', '+00:00')) if banner_data.get('start_date') else None, end_date=datetime.fromisoformat(banner_data['end_date'].replace('Z', '+00:00')) if banner_data.get('end_date') else None)
|
||||
db.add(banner)
|
||||
db.commit()
|
||||
db.refresh(banner)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "Banner created successfully",
|
||||
"data": {"banner": banner}
|
||||
}
|
||||
return {'status': 'success', 'message': 'Banner created successfully', 'data': {'banner': banner}}
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.put("/{id}", dependencies=[Depends(authorize_roles("admin"))])
|
||||
async def update_banner(
|
||||
id: int,
|
||||
banner_data: dict,
|
||||
current_user: User = Depends(authorize_roles("admin")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update banner (Admin only)"""
|
||||
@router.put('/{id}', dependencies=[Depends(authorize_roles('admin'))])
|
||||
async def update_banner(id: int, banner_data: dict, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
||||
try:
|
||||
banner = db.query(Banner).filter(Banner.id == id).first()
|
||||
if not banner:
|
||||
raise HTTPException(status_code=404, detail="Banner not found")
|
||||
|
||||
if "title" in banner_data:
|
||||
banner.title = banner_data["title"]
|
||||
if "description" in banner_data:
|
||||
banner.description = banner_data["description"]
|
||||
if "image_url" in banner_data:
|
||||
banner.image_url = banner_data["image_url"]
|
||||
if "link" in banner_data:
|
||||
banner.link_url = banner_data["link"]
|
||||
if "position" in banner_data:
|
||||
banner.position = banner_data["position"]
|
||||
if "display_order" in banner_data:
|
||||
banner.display_order = banner_data["display_order"]
|
||||
if "is_active" in banner_data:
|
||||
banner.is_active = banner_data["is_active"]
|
||||
if "start_date" in banner_data:
|
||||
banner.start_date = datetime.fromisoformat(banner_data["start_date"].replace('Z', '+00:00')) if banner_data["start_date"] else None
|
||||
if "end_date" in banner_data:
|
||||
banner.end_date = datetime.fromisoformat(banner_data["end_date"].replace('Z', '+00:00')) if banner_data["end_date"] else None
|
||||
|
||||
raise HTTPException(status_code=404, detail='Banner not found')
|
||||
if 'title' in banner_data:
|
||||
banner.title = banner_data['title']
|
||||
if 'description' in banner_data:
|
||||
banner.description = banner_data['description']
|
||||
if 'image_url' in banner_data:
|
||||
banner.image_url = banner_data['image_url']
|
||||
if 'link' in banner_data:
|
||||
banner.link_url = banner_data['link']
|
||||
if 'position' in banner_data:
|
||||
banner.position = banner_data['position']
|
||||
if 'display_order' in banner_data:
|
||||
banner.display_order = banner_data['display_order']
|
||||
if 'is_active' in banner_data:
|
||||
banner.is_active = banner_data['is_active']
|
||||
if 'start_date' in banner_data:
|
||||
banner.start_date = datetime.fromisoformat(banner_data['start_date'].replace('Z', '+00:00')) if banner_data['start_date'] else None
|
||||
if 'end_date' in banner_data:
|
||||
banner.end_date = datetime.fromisoformat(banner_data['end_date'].replace('Z', '+00:00')) if banner_data['end_date'] else None
|
||||
db.commit()
|
||||
db.refresh(banner)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "Banner updated successfully",
|
||||
"data": {"banner": banner}
|
||||
}
|
||||
return {'status': 'success', 'message': 'Banner updated successfully', 'data': {'banner': banner}}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{id}", dependencies=[Depends(authorize_roles("admin"))])
|
||||
async def delete_banner(
|
||||
id: int,
|
||||
current_user: User = Depends(authorize_roles("admin")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Delete banner (Admin only)"""
|
||||
@router.delete('/{id}', dependencies=[Depends(authorize_roles('admin'))])
|
||||
async def delete_banner(id: int, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
||||
try:
|
||||
banner = db.query(Banner).filter(Banner.id == id).first()
|
||||
if not banner:
|
||||
raise HTTPException(status_code=404, detail="Banner not found")
|
||||
|
||||
# Delete image file if it exists and is a local upload
|
||||
raise HTTPException(status_code=404, detail='Banner not found')
|
||||
if banner.image_url and banner.image_url.startswith('/uploads/banners/'):
|
||||
file_path = Path(__file__).parent.parent.parent / "uploads" / "banners" / Path(banner.image_url).name
|
||||
file_path = Path(__file__).parent.parent.parent / 'uploads' / 'banners' / Path(banner.image_url).name
|
||||
if file_path.exists():
|
||||
file_path.unlink()
|
||||
|
||||
db.delete(banner)
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "Banner deleted successfully"
|
||||
}
|
||||
return {'status': 'success', 'message': 'Banner deleted successfully'}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/upload", dependencies=[Depends(authorize_roles("admin"))])
|
||||
async def upload_banner_image(
|
||||
request: Request,
|
||||
image: UploadFile = File(...),
|
||||
current_user: User = Depends(authorize_roles("admin")),
|
||||
):
|
||||
"""Upload banner image (Admin only)"""
|
||||
@router.post('/upload', dependencies=[Depends(authorize_roles('admin'))])
|
||||
async def upload_banner_image(request: Request, image: UploadFile=File(...), current_user: User=Depends(authorize_roles('admin'))):
|
||||
try:
|
||||
# Validate file exists
|
||||
if not image:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="No file provided"
|
||||
)
|
||||
|
||||
# Validate file type
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='No file provided')
|
||||
if not image.content_type or not image.content_type.startswith('image/'):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"File must be an image. Received: {image.content_type}"
|
||||
)
|
||||
|
||||
# Validate filename
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f'File must be an image. Received: {image.content_type}')
|
||||
if not image.filename:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Filename is required"
|
||||
)
|
||||
|
||||
# Create uploads directory
|
||||
upload_dir = Path(__file__).parent.parent.parent / "uploads" / "banners"
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Filename is required')
|
||||
upload_dir = Path(__file__).parent.parent.parent / 'uploads' / 'banners'
|
||||
upload_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Generate filename
|
||||
ext = Path(image.filename).suffix or '.jpg'
|
||||
filename = f"banner-{uuid.uuid4()}{ext}"
|
||||
filename = f'banner-{uuid.uuid4()}{ext}'
|
||||
file_path = upload_dir / filename
|
||||
|
||||
# Save file
|
||||
async with aiofiles.open(file_path, 'wb') as f:
|
||||
content = await image.read()
|
||||
if not content:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="File is empty"
|
||||
)
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='File is empty')
|
||||
await f.write(content)
|
||||
|
||||
# Return the image URL
|
||||
image_url = f"/uploads/banners/{filename}"
|
||||
image_url = f'/uploads/banners/{filename}'
|
||||
base_url = get_base_url(request)
|
||||
full_url = normalize_image_url(image_url, base_url)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"status": "success",
|
||||
"message": "Image uploaded successfully",
|
||||
"data": {
|
||||
"image_url": image_url,
|
||||
"full_url": full_url
|
||||
}
|
||||
}
|
||||
return {'success': True, 'status': 'success', 'message': 'Image uploaded successfully', 'data': {'image_url': image_url, 'full_url': full_url}}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user