Add event schema models and corresponding test cases
Introduce Pydantic models for event creation, updates, and responses, including validation for fields such as timezone, event date, and RSVP deadline. Add comprehensive pytest test cases to ensure correct behavior and data validation. This provides a robust foundation for event-related functionalities.
This commit is contained in:
81
backend/app/schemas/events.py
Normal file
81
backend/app/schemas/events.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from datetime import datetime, time
|
||||
from typing import Dict, Optional, List, Union
|
||||
from uuid import UUID
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
class EventBase(BaseModel):
|
||||
title: str = Field(..., min_length=1, max_length=200)
|
||||
description: Optional[str] = None
|
||||
location_name: Optional[str] = None
|
||||
location_address: Optional[str] = None
|
||||
location_url: Optional[str] = None
|
||||
event_date: datetime
|
||||
event_start_time: Optional[time] = None
|
||||
event_end_time: Optional[time] = None
|
||||
timezone: str
|
||||
rsvp_deadline: Optional[datetime] = None
|
||||
is_public: bool = False
|
||||
access_code: Optional[str] = None
|
||||
theme_id: Optional[UUID] = None
|
||||
custom_theme_settings: Optional[Dict] = None
|
||||
additional_info: Optional[Dict] = None
|
||||
is_active: bool = True
|
||||
rsvp_enabled: bool = True
|
||||
gift_registry_enabled: bool = True
|
||||
updates_enabled: bool = True
|
||||
max_guests_per_invitation: Optional[int] = Field(None, ge=1)
|
||||
contact_email: Optional[str] = None
|
||||
contact_phone: Optional[str] = None
|
||||
|
||||
@field_validator('timezone')
|
||||
def validate_timezone(cls, v):
|
||||
try:
|
||||
ZoneInfo(v)
|
||||
return v
|
||||
except Exception:
|
||||
raise ValueError("Invalid timezone")
|
||||
|
||||
@field_validator('event_date')
|
||||
def validate_event_date(cls, v):
|
||||
if v < datetime.now(ZoneInfo('UTC')):
|
||||
raise ValueError("Event date cannot be in the past")
|
||||
return v
|
||||
|
||||
@field_validator('rsvp_deadline')
|
||||
def validate_rsvp_deadline(cls, v, values):
|
||||
if v and 'event_date' in values.data:
|
||||
if v > values.data['event_date']:
|
||||
raise ValueError("RSVP deadline must be before event date")
|
||||
return v
|
||||
|
||||
|
||||
class EventCreate(EventBase):
|
||||
slug: str = Field(..., min_length=1, pattern="^[a-z0-9-]+$")
|
||||
|
||||
|
||||
class EventUpdate(EventBase):
|
||||
title: Optional[str] = None
|
||||
event_date: Optional[datetime] = None
|
||||
timezone: Optional[str] = None
|
||||
slug: Optional[str] = Field(None, min_length=1, pattern="^[a-z0-9-]+$")
|
||||
|
||||
|
||||
class EventInDBBase(EventBase):
|
||||
id: UUID
|
||||
created_by: UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
slug: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class EventResponse(EventInDBBase):
|
||||
pass
|
||||
|
||||
|
||||
class Event(EventInDBBase):
|
||||
pass
|
||||
97
backend/tests/schemas/test_events.py
Normal file
97
backend/tests/schemas/test_events.py
Normal file
@@ -0,0 +1,97 @@
|
||||
import pytest
|
||||
from datetime import datetime, time, timedelta
|
||||
from uuid import uuid4, UUID
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from app.schemas.events import EventCreate, EventUpdate, EventResponse
|
||||
|
||||
|
||||
def test_valid_event_create():
|
||||
event_date = datetime.now(ZoneInfo('UTC')) + timedelta(days=1)
|
||||
event_data = {
|
||||
"title": "Emma's First Birthday",
|
||||
"slug": "emmas-first-birthday",
|
||||
"description": "Join us for Emma's first birthday celebration!",
|
||||
"event_date": event_date,
|
||||
"timezone": "America/New_York",
|
||||
"location_name": "Central Park",
|
||||
"is_public": False,
|
||||
"access_code": "EMMA2024"
|
||||
}
|
||||
event = EventCreate(**event_data)
|
||||
assert event.title == "Emma's First Birthday"
|
||||
assert event.slug == "emmas-first-birthday"
|
||||
assert event.timezone == "America/New_York"
|
||||
|
||||
|
||||
def test_invalid_event_create():
|
||||
event_date = datetime.now(ZoneInfo('UTC')) - timedelta(days=1)
|
||||
with pytest.raises(ValueError):
|
||||
EventCreate(
|
||||
title="Past Event",
|
||||
slug="past-event",
|
||||
event_date=event_date,
|
||||
timezone="America/New_York"
|
||||
)
|
||||
|
||||
|
||||
def test_invalid_timezone():
|
||||
with pytest.raises(ValueError):
|
||||
EventCreate(
|
||||
title="Test Event",
|
||||
slug="test-event",
|
||||
event_date=datetime.now(ZoneInfo('UTC')) + timedelta(days=1),
|
||||
timezone="Invalid/Timezone"
|
||||
)
|
||||
|
||||
|
||||
def test_event_update_partial():
|
||||
update_data = {
|
||||
"title": "Updated Title",
|
||||
"description": "Updated description"
|
||||
}
|
||||
event_update = EventUpdate(**update_data)
|
||||
assert event_update.title == "Updated Title"
|
||||
assert event_update.description == "Updated description"
|
||||
|
||||
|
||||
def test_event_response():
|
||||
event_date = datetime.now(ZoneInfo('UTC')) + timedelta(days=1)
|
||||
event_data = {
|
||||
"id": uuid4(),
|
||||
"title": "Test Event",
|
||||
"slug": "test-event",
|
||||
"event_date": event_date,
|
||||
"timezone": "UTC",
|
||||
"created_by": uuid4(),
|
||||
"created_at": datetime.now(ZoneInfo('UTC')),
|
||||
"updated_at": datetime.now(ZoneInfo('UTC'))
|
||||
}
|
||||
event_response = EventResponse(**event_data)
|
||||
assert event_response.title == "Test Event"
|
||||
assert isinstance(event_response.id, UUID)
|
||||
|
||||
|
||||
def test_invalid_slug_format():
|
||||
event_date = datetime.now(ZoneInfo('UTC')) + timedelta(days=1)
|
||||
with pytest.raises(ValueError):
|
||||
EventCreate(
|
||||
title="Test Event",
|
||||
slug="Invalid Slug!", # Invalid slug format
|
||||
event_date=event_date,
|
||||
timezone="UTC"
|
||||
)
|
||||
|
||||
|
||||
def test_rsvp_deadline_validation():
|
||||
event_date = datetime.now(ZoneInfo('UTC')) + timedelta(days=10)
|
||||
invalid_deadline = event_date + timedelta(days=1)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
EventCreate(
|
||||
title="Test Event",
|
||||
slug="test-event",
|
||||
event_date=event_date,
|
||||
timezone="UTC",
|
||||
rsvp_deadline=invalid_deadline
|
||||
)
|
||||
Reference in New Issue
Block a user