""" @service StorefrontService (Backend/app/services/StorefrontService.py) @purpose Domain service handling business logic, layout assembly, review moderation workflows, and cache invalidation. """ from sqlalchemy.orm import Session from typing import List, Dict, Any, Optional import ulid from app.repositories.StorefrontRepository import StorefrontRepository from app.models.StorefrontContentModel import StorefrontContent, ContentStatusEnum from app.models.ProductReviewModel import ProductReview # In-Memory Cache Store for high performance _IN_MEMORY_CACHE: Dict[str, Any] = {} class StorefrontService: def __init__(self, db: Session): self.repo = StorefrontRepository(db) def get_layout(self, page: str, region: Optional[str] = None) -> List[Dict[str, Any]]: # No in-memory cache here — layout changes via admin must reflect immediately contents = self.repo.get_active_content(page, region) result = [ { "content_id": c.content_id, "page": c.page, "region": c.region, "type": c.type, "title": c.title, "subtitle": c.subtitle, "image_url": c.image_url, "button_text": c.button_text, "button_url": c.button_url, "display_order": c.display_order, # Expose under both keys so frontend works regardless of which it checks "metadata": c.metadata_json or {}, "metadata_json": c.metadata_json or {} } for c in contents ] return result def invalidate_cache(self, pattern: Optional[str] = None): global _IN_MEMORY_CACHE if pattern: _IN_MEMORY_CACHE = {k: v for k, v in _IN_MEMORY_CACHE.items() if not k.startswith(pattern)} else: _IN_MEMORY_CACHE.clear() def get_reviews(self, product_id: str) -> List[Dict[str, Any]]: cache_key = f"reviews:{product_id}" if cache_key in _IN_MEMORY_CACHE: return _IN_MEMORY_CACHE[cache_key] reviews = self.repo.get_approved_reviews(product_id) result = [ { "review_id": r.review_id, "product_id": r.product_id, "author_name": r.author_name, "rating": r.rating, "title": r.title, "comment": r.comment, "verified_buyer": r.verified_purchase, "helpful_count": r.helpful_count, "admin_reply": r.admin_reply, "review_date": r.created_at.strftime("%Y-%m-%d") if r.created_at else "2026-07-25", "images": [img.image_url for img in r.images if img.is_approved] if r.images else [] } for r in reviews ] _IN_MEMORY_CACHE[cache_key] = result return result def get_public_settings(self, group: Optional[str] = None) -> Dict[str, Any]: cache_key = f"settings:public:{group or 'all'}" if cache_key in _IN_MEMORY_CACHE: return _IN_MEMORY_CACHE[cache_key] settings = self.repo.get_public_settings(group) result = {s.setting_key: s.setting_value for s in settings} _IN_MEMORY_CACHE[cache_key] = result return result