diff --git a/backend/app/crud/event_theme.py b/backend/app/crud/event_theme.py new file mode 100644 index 0000000..bd9dc78 --- /dev/null +++ b/backend/app/crud/event_theme.py @@ -0,0 +1,25 @@ +from typing import List, Optional +from sqlalchemy.orm import Session + +from app.crud.base import CRUDBase +from app.models.event_theme import EventTheme +from app.schemas.event_theme import EventThemeCreate, EventThemeUpdate + + +class CRUDEventTheme(CRUDBase[EventTheme, EventThemeCreate, EventThemeUpdate]): + def get_by_name(self, db: Session, *, name: str) -> Optional[EventTheme]: + return db.query(EventTheme).filter(EventTheme.name == name).first() + + def get_active_themes( + self, db: Session, *, skip: int = 0, limit: int = 100 + ) -> List[EventTheme]: + return ( + db.query(self.model) + .filter(self.model.events.any()) + .offset(skip) + .limit(limit) + .all() + ) + + +event_theme = CRUDEventTheme(EventTheme) \ No newline at end of file diff --git a/backend/app/schemas/event_theme.py b/backend/app/schemas/event_theme.py new file mode 100644 index 0000000..6d6a310 --- /dev/null +++ b/backend/app/schemas/event_theme.py @@ -0,0 +1,31 @@ +from typing import Dict, Optional +from pydantic import BaseModel + + +class EventThemeBase(BaseModel): + name: str + description: Optional[str] = None + preview_image_url: Optional[str] = None + color_palette: Dict[str, str] + fonts: Dict[str, str] + + +class EventThemeCreate(EventThemeBase): + pass + + +class EventThemeUpdate(EventThemeBase): + name: Optional[str] = None + color_palette: Optional[Dict[str, str]] = None + fonts: Optional[Dict[str, str]] = None + + +class EventThemeInDBBase(EventThemeBase): + id: str + + class Config: + from_attributes = True + + +class EventTheme(EventThemeInDBBase): + pass \ No newline at end of file diff --git a/backend/tests/crud/test_event_theme.py b/backend/tests/crud/test_event_theme.py new file mode 100644 index 0000000..508c7b6 --- /dev/null +++ b/backend/tests/crud/test_event_theme.py @@ -0,0 +1,124 @@ +from uuid import UUID + +import pytest +from sqlalchemy.orm import Session + +from app.crud.event_theme import event_theme +from app.schemas.event_theme import EventThemeCreate, EventThemeUpdate + + +def test_create_event_theme(db_session: Session) -> None: + theme_in = EventThemeCreate( + name="Animal Theme", + description="A cute animal-themed celebration", + preview_image_url="https://example.com/preview/animal_theme.jpg", + color_palette={ + "primary": "#4CAF50", + "secondary": "#FFC107", + "background": "#FFFFFF", + "text": "#333333" + }, + fonts={ + "header": "Roboto", + "body": "Open Sans" + } + ) + theme = event_theme.create(db=db_session, obj_in=theme_in) + assert theme.name == theme_in.name + assert theme.color_palette == theme_in.color_palette + assert theme.fonts == theme_in.fonts + + +def test_get_event_theme(db_session: Session, event_theme_fixture) -> None: + stored_theme = event_theme.get(db=db_session, id=event_theme_fixture.id) + assert stored_theme + assert stored_theme.id == event_theme_fixture.id + assert stored_theme.name == event_theme_fixture.name + assert stored_theme.color_palette == event_theme_fixture.color_palette + assert stored_theme.fonts == event_theme_fixture.fonts + + +def test_get_event_theme_by_name(db_session: Session, event_theme_fixture) -> None: + stored_theme = event_theme.get_by_name(db=db_session, name=event_theme_fixture.name) + assert stored_theme + assert stored_theme.id == event_theme_fixture.id + assert stored_theme.name == event_theme_fixture.name + + +def test_update_event_theme(db_session: Session, event_theme_fixture) -> None: + theme_update = EventThemeUpdate( + name="Updated Animal Theme", + color_palette={ + "primary": "#FF5722", + "secondary": "#FFC107", + "background": "#FAFAFA", + "text": "#212121" + } + ) + updated_theme = event_theme.update( + db=db_session, + db_obj=event_theme_fixture, + obj_in=theme_update + ) + assert updated_theme.id == event_theme_fixture.id + assert updated_theme.name == "Updated Animal Theme" + assert updated_theme.color_palette == theme_update.color_palette + # Original fonts should remain unchanged as they weren't included in the update + assert updated_theme.fonts == event_theme_fixture.fonts + + +def test_delete_event_theme(db_session: Session, event_theme_fixture) -> None: + theme_id = event_theme_fixture.id + deleted_theme = event_theme.remove(db=db_session, id=theme_id) + assert deleted_theme.id == theme_id + + # Verify theme no longer exists + theme = event_theme.get(db=db_session, id=theme_id) + assert theme is None + + +def test_get_active_themes(db_session: Session, event_theme_fixture, event_fixture) -> None: + # First, ensure the theme is associated with an event + event_fixture.theme_id = event_theme_fixture.id + db_session.commit() + + # Get active themes + active_themes = event_theme.get_active_themes(db=db_session) + + assert len(active_themes) > 0 + assert any(theme.id == event_theme_fixture.id for theme in active_themes) + + +def test_get_multi_themes(db_session: Session, event_theme_fixture) -> None: + # Create another theme to test pagination + another_theme = EventThemeCreate( + name="Birthday Theme", + color_palette={ + "primary": "#2196F3", + "secondary": "#FF4081", + "background": "#FFFFFF", + "text": "#000000" + }, + fonts={ + "header": "Montserrat", + "body": "Lato" + } + ) + event_theme.create(db=db_session, obj_in=another_theme) + + # Test pagination + themes = event_theme.get_multi(db=db_session, skip=0, limit=10) + assert len(themes) >= 2 # Should have at least the fixture and the new theme + + +def test_get_non_existent_theme(db_session: Session) -> None: + non_existent_id = UUID('00000000-0000-0000-0000-000000000000') + theme = event_theme.get(db=db_session, id=non_existent_id) + assert theme is None + + + +def test_get_non_existent_theme_by_name(db_session: Session) -> None: + non_existent_name = "Non-existent Theme" + theme = event_theme.get_by_name(db=db_session, name=non_existent_name) + assert theme is None \ No newline at end of file