243 lines
6.5 KiB
Python
243 lines
6.5 KiB
Python
from pydantic import BaseModel, Field
|
|
from typing import Optional, List, Dict
|
|
from datetime import datetime
|
|
from uuid import UUID
|
|
|
|
|
|
# ============================================
|
|
# User Schemas
|
|
# ============================================
|
|
class UserBase(BaseModel):
|
|
email: str
|
|
|
|
|
|
class UserCreate(UserBase):
|
|
pass
|
|
|
|
|
|
class User(UserBase):
|
|
id: UUID
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================
|
|
# Event Schemas
|
|
# ============================================
|
|
class EventBase(BaseModel):
|
|
name: str
|
|
date: Optional[datetime] = None
|
|
location: Optional[str] = None
|
|
partner1_name: Optional[str] = None
|
|
partner2_name: Optional[str] = None
|
|
venue: Optional[str] = None
|
|
event_time: Optional[str] = None
|
|
guest_link: Optional[str] = None
|
|
|
|
|
|
class EventCreate(EventBase):
|
|
pass
|
|
|
|
|
|
class EventUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
date: Optional[datetime] = None
|
|
location: Optional[str] = None
|
|
partner1_name: Optional[str] = None
|
|
partner2_name: Optional[str] = None
|
|
venue: Optional[str] = None
|
|
event_time: Optional[str] = None
|
|
guest_link: Optional[str] = None
|
|
|
|
|
|
class Event(EventBase):
|
|
id: UUID
|
|
created_at: datetime
|
|
updated_at: Optional[datetime] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class EventWithMembers(Event):
|
|
members: List["EventMember"] = []
|
|
|
|
|
|
# ============================================
|
|
# Event Member Schemas
|
|
# ============================================
|
|
class EventMemberBase(BaseModel):
|
|
role: str = "admin" # admin, editor, viewer
|
|
display_name: Optional[str] = None
|
|
|
|
|
|
class EventMemberCreate(BaseModel):
|
|
user_email: str = Field(..., description="Email address of the user to invite")
|
|
role: str = "admin"
|
|
display_name: Optional[str] = None
|
|
|
|
|
|
class EventMember(EventMemberBase):
|
|
id: UUID
|
|
event_id: UUID
|
|
user_id: UUID
|
|
created_at: datetime
|
|
user: Optional[User] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================
|
|
# Guest Schemas
|
|
# ============================================
|
|
class GuestBase(BaseModel):
|
|
first_name: str
|
|
last_name: str
|
|
email: Optional[str] = None
|
|
phone_number: Optional[str] = None
|
|
rsvp_status: str = "invited" # invited, confirmed, declined
|
|
meal_preference: Optional[str] = None
|
|
has_plus_one: bool = False
|
|
plus_one_name: Optional[str] = None
|
|
table_number: Optional[str] = None
|
|
side: Optional[str] = None # e.g., "groom side", "bride side"
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class GuestCreate(GuestBase):
|
|
pass
|
|
|
|
|
|
class GuestUpdate(BaseModel):
|
|
first_name: Optional[str] = None
|
|
last_name: Optional[str] = None
|
|
email: Optional[str] = None
|
|
phone_number: Optional[str] = None
|
|
rsvp_status: Optional[str] = None
|
|
meal_preference: Optional[str] = None
|
|
has_plus_one: Optional[bool] = None
|
|
plus_one_name: Optional[str] = None
|
|
table_number: Optional[str] = None
|
|
side: Optional[str] = None
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class Guest(GuestBase):
|
|
id: UUID
|
|
event_id: UUID
|
|
added_by_user_id: UUID
|
|
owner_email: Optional[str] = None
|
|
source: str = "manual"
|
|
created_at: datetime
|
|
updated_at: Optional[datetime] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================
|
|
# Bulk Import Schemas
|
|
# ============================================
|
|
class GuestImportItem(BaseModel):
|
|
first_name: str
|
|
last_name: str
|
|
email: Optional[str] = None
|
|
phone_number: Optional[str] = None
|
|
side: Optional[str] = None
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class GuestBulkImport(BaseModel):
|
|
guests: List[GuestImportItem]
|
|
|
|
|
|
# ============================================
|
|
# Filter/Search Schemas
|
|
# ============================================
|
|
class GuestFilter(BaseModel):
|
|
search: Optional[str] = None
|
|
side: Optional[str] = None
|
|
status: Optional[str] = None
|
|
added_by: Optional[str] = None # "me" for current user
|
|
|
|
|
|
# ============================================
|
|
# WhatsApp Schemas
|
|
# ============================================
|
|
class WhatsAppMessage(BaseModel):
|
|
message: str
|
|
phone: Optional[str] = None # Optional: override guest's phone
|
|
|
|
|
|
class WhatsAppStatus(BaseModel):
|
|
message_id: str
|
|
status: str
|
|
timestamp: datetime
|
|
|
|
|
|
class WhatsAppWeddingInviteRequest(BaseModel):
|
|
"""Request to send wedding invitation template to guest(s)"""
|
|
guest_ids: Optional[List[str]] = None # For bulk sending
|
|
phone_override: Optional[str] = None # Optional: override phone number
|
|
template_key: Optional[str] = "wedding_invitation" # Registry key for template selection
|
|
# Optional form data overrides (frontend form values take priority over DB)
|
|
partner1_name: Optional[str] = None # First partner / groom name
|
|
partner2_name: Optional[str] = None # Second partner / bride name
|
|
venue: Optional[str] = None # Hall / venue name
|
|
event_date: Optional[str] = None # YYYY-MM-DD or DD/MM
|
|
event_time: Optional[str] = None # HH:mm
|
|
guest_link: Optional[str] = None # RSVP link
|
|
extra_params: Optional[Dict[str, str]] = None # Custom/extra param values keyed by param name
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class WhatsAppSendResult(BaseModel):
|
|
"""Result of sending WhatsApp message to a guest"""
|
|
guest_id: str
|
|
guest_name: Optional[str] = None
|
|
phone: str
|
|
status: str # "sent", "failed"
|
|
message_id: Optional[str] = None
|
|
error: Optional[str] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class WhatsAppBulkResult(BaseModel):
|
|
"""Result of bulk WhatsApp sending"""
|
|
total: int
|
|
succeeded: int
|
|
failed: int
|
|
results: List[WhatsAppSendResult]
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================
|
|
# Google Contacts Import Schema
|
|
# ============================================
|
|
class GoogleContactsImport(BaseModel):
|
|
access_token: str
|
|
owner: Optional[str] = "Google Import"
|
|
|
|
|
|
# ============================================
|
|
# Public Guest Self-Service Schema
|
|
# ============================================
|
|
class GuestPublicUpdate(BaseModel):
|
|
"""Schema for public guest self-service updates (phone-based lookup)"""
|
|
first_name: Optional[str] = None
|
|
last_name: Optional[str] = None
|
|
rsvp_status: Optional[str] = None
|
|
meal_preference: Optional[str] = None
|
|
has_plus_one: Optional[bool] = None
|
|
plus_one_name: Optional[str] = None
|
|
|