This commit is contained in:
Iliyan Angelov
2025-12-05 00:01:15 +02:00
parent 9f1aeb32da
commit 99da0afecd
24 changed files with 3701 additions and 569 deletions

View File

@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, Numeric, Boolean, Text, DateTime
from sqlalchemy import Column, Integer, String, Numeric, Boolean, Text, DateTime, Index
from sqlalchemy.orm import relationship
from datetime import datetime
from ...shared.config.database import Base
@@ -10,6 +10,13 @@ class Service(Base):
description = Column(Text, nullable=True)
price = Column(Numeric(10, 2), nullable=False)
category = Column(String(50), nullable=True)
slug = Column(String(200), nullable=True, unique=True, index=True)
image = Column(String(1000), nullable=True)
content = Column(Text, nullable=True)
sections = Column(Text, nullable=True) # JSON string for advanced content blocks
meta_title = Column(String(500), nullable=True)
meta_description = Column(Text, nullable=True)
meta_keywords = Column(String(1000), nullable=True)
is_active = Column(Boolean, nullable=False, default=True)
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)

View File

@@ -24,7 +24,24 @@ async def get_services(search: Optional[str]=Query(None), status_filter: Optiona
services = query.order_by(Service.created_at.desc()).offset(offset).limit(limit).all()
result = []
for service in services:
service_dict = {'id': service.id, 'name': service.name, 'description': service.description, 'price': float(service.price) if service.price else 0.0, 'category': service.category, 'is_active': service.is_active, 'created_at': service.created_at.isoformat() if service.created_at else None}
service_dict = {
'id': service.id,
'name': service.name,
'description': service.description,
'price': float(service.price) if service.price else 0.0,
'category': service.category,
'slug': service.slug,
'image': service.image,
'content': service.content,
'sections': service.sections,
'meta_title': service.meta_title,
'meta_description': service.meta_description,
'meta_keywords': service.meta_keywords,
'is_active': service.is_active,
'status': 'active' if service.is_active else 'inactive',
'unit': service.category, # For backward compatibility
'created_at': service.created_at.isoformat() if service.created_at else None
}
result.append(service_dict)
return {'status': 'success', 'data': {'services': result, 'pagination': {'total': total, 'page': page, 'limit': limit, 'totalPages': (total + limit - 1) // limit}}}
except Exception as e:
@@ -36,7 +53,54 @@ async def get_service_by_id(id: int, db: Session=Depends(get_db)):
service = db.query(Service).filter(Service.id == id).first()
if not service:
raise HTTPException(status_code=404, detail='Service not found')
service_dict = {'id': service.id, 'name': service.name, 'description': service.description, 'price': float(service.price) if service.price else 0.0, 'category': service.category, 'is_active': service.is_active, 'created_at': service.created_at.isoformat() if service.created_at else None}
service_dict = {
'id': service.id,
'name': service.name,
'description': service.description,
'price': float(service.price) if service.price else 0.0,
'category': service.category,
'slug': service.slug,
'image': service.image,
'content': service.content,
'sections': service.sections,
'meta_title': service.meta_title,
'meta_description': service.meta_description,
'meta_keywords': service.meta_keywords,
'is_active': service.is_active,
'status': 'active' if service.is_active else 'inactive',
'unit': service.category, # For backward compatibility
'created_at': service.created_at.isoformat() if service.created_at else None
}
return {'status': 'success', 'data': {'service': service_dict}}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get('/slug/{slug}')
async def get_service_by_slug(slug: str, db: Session=Depends(get_db)):
try:
service = db.query(Service).filter(Service.slug == slug, Service.is_active == True).first()
if not service:
raise HTTPException(status_code=404, detail='Service not found')
service_dict = {
'id': service.id,
'name': service.name,
'description': service.description,
'price': float(service.price) if service.price else 0.0,
'category': service.category,
'slug': service.slug,
'image': service.image,
'content': service.content,
'sections': service.sections,
'meta_title': service.meta_title,
'meta_description': service.meta_description,
'meta_keywords': service.meta_keywords,
'is_active': service.is_active,
'status': 'active' if service.is_active else 'inactive',
'unit': service.category, # For backward compatibility
'created_at': service.created_at.isoformat() if service.created_at else None
}
return {'status': 'success', 'data': {'service': service_dict}}
except HTTPException:
raise
@@ -50,7 +114,39 @@ async def create_service(service_data: dict, current_user: User=Depends(authoriz
existing = db.query(Service).filter(Service.name == name).first()
if existing:
raise HTTPException(status_code=400, detail='Service name already exists')
service = Service(name=name, description=service_data.get('description'), price=float(service_data.get('price', 0)), category=service_data.get('category'), is_active=service_data.get('status') == 'active' if service_data.get('status') else True)
# Generate slug from name if not provided
slug = service_data.get('slug')
if not slug and name:
import re
slug = re.sub(r'[^a-z0-9-]', '', name.lower().replace(' ', '-'))
# Ensure slug is unique
counter = 1
original_slug = slug
while db.query(Service).filter(Service.slug == slug).first():
slug = f"{original_slug}-{counter}"
counter += 1
# Handle sections as JSON string
sections = service_data.get('sections')
if sections and isinstance(sections, (list, dict)):
import json
sections = json.dumps(sections)
service = Service(
name=name,
description=service_data.get('description'),
price=float(service_data.get('price', 0)),
category=service_data.get('category'),
slug=slug,
image=service_data.get('image'),
content=service_data.get('content'),
sections=sections,
meta_title=service_data.get('meta_title'),
meta_description=service_data.get('meta_description'),
meta_keywords=service_data.get('meta_keywords'),
is_active=service_data.get('status') == 'active' if service_data.get('status') else True
)
db.add(service)
db.commit()
db.refresh(service)
@@ -72,6 +168,14 @@ async def update_service(id: int, service_data: dict, current_user: User=Depends
existing = db.query(Service).filter(Service.name == name, Service.id != id).first()
if existing:
raise HTTPException(status_code=400, detail='Service name already exists')
# Check slug uniqueness if provided
slug = service_data.get('slug')
if slug and slug != service.slug:
existing = db.query(Service).filter(Service.slug == slug, Service.id != id).first()
if existing:
raise HTTPException(status_code=400, detail='Service slug already exists')
if 'name' in service_data:
service.name = service_data['name']
if 'description' in service_data:
@@ -80,6 +184,25 @@ async def update_service(id: int, service_data: dict, current_user: User=Depends
service.price = float(service_data['price'])
if 'category' in service_data:
service.category = service_data['category']
if 'slug' in service_data:
service.slug = service_data['slug']
if 'image' in service_data:
service.image = service_data['image']
if 'content' in service_data:
service.content = service_data['content']
if 'sections' in service_data:
sections = service_data['sections']
if sections and isinstance(sections, (list, dict)):
import json
service.sections = json.dumps(sections)
else:
service.sections = sections
if 'meta_title' in service_data:
service.meta_title = service_data['meta_title']
if 'meta_description' in service_data:
service.meta_description = service_data['meta_description']
if 'meta_keywords' in service_data:
service.meta_keywords = service_data['meta_keywords']
if 'status' in service_data:
service.is_active = service_data['status'] == 'active'
db.commit()