Rename metadata fields for clarity and fix imports. Updated metadata-related field names across models to improve clarity and consistency (e.g., `metadata` to `media_metadata` and `notification_metadata`). Fixed an error in `guest_gifts` metadata reference and added a proper imports initialization in `__init__.py` for all models. ```
88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
from datetime import datetime, timezone
|
|
from enum import Enum
|
|
|
|
from sqlalchemy import Column, String, ForeignKey, Enum as SQLEnum, Text, DateTime, Integer
|
|
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
|
from sqlalchemy.orm import relationship
|
|
|
|
from .base import Base, TimestampMixin, UUIDMixin
|
|
|
|
|
|
class NotificationType(str, Enum):
|
|
EMAIL = "email"
|
|
SMS = "sms"
|
|
PUSH = "push"
|
|
IN_APP = "in_app"
|
|
|
|
|
|
class NotificationStatus(str, Enum):
|
|
QUEUED = "queued"
|
|
SENT = "sent"
|
|
DELIVERED = "delivered"
|
|
FAILED = "failed"
|
|
OPENED = "opened"
|
|
CLICKED = "clicked"
|
|
|
|
|
|
class NotificationLog(Base, UUIDMixin, TimestampMixin):
|
|
__tablename__ = 'notification_logs'
|
|
|
|
# Notification Details
|
|
notification_type = Column(SQLEnum(NotificationType), nullable=False)
|
|
status = Column(SQLEnum(NotificationStatus), nullable=False, default=NotificationStatus.QUEUED)
|
|
|
|
# Content
|
|
subject = Column(String)
|
|
content_preview = Column(String(255)) # Short preview of content
|
|
template_id = Column(UUID(as_uuid=True), ForeignKey('email_templates.id'))
|
|
|
|
# Recipient Information
|
|
event_id = Column(UUID(as_uuid=True), ForeignKey('events.id'), nullable=False)
|
|
guest_id = Column(UUID(as_uuid=True), ForeignKey('guests.id')) # Optional, if sent to a specific guest
|
|
recipient = Column(String, nullable=False) # Email address or phone number
|
|
|
|
# Tracking
|
|
sent_at = Column(DateTime(timezone=True))
|
|
delivered_at = Column(DateTime(timezone=True))
|
|
opened_at = Column(DateTime(timezone=True))
|
|
error_message = Column(Text)
|
|
retry_count = Column(Integer, default=0)
|
|
external_id = Column(String) # ID from external provider (SendGrid, Twilio, etc.)
|
|
|
|
# Additional Data
|
|
notification_metadata = Column(JSONB, default=dict)
|
|
|
|
# Relationships
|
|
event = relationship("Event")
|
|
guest = relationship("Guest")
|
|
template = relationship("EmailTemplate")
|
|
|
|
def __repr__(self):
|
|
return f"<NotificationLog {self.notification_type.value} to {self.recipient} status={self.status.value}>"
|
|
|
|
def mark_sent(self):
|
|
"""Mark notification as sent"""
|
|
self.status = NotificationStatus.SENT
|
|
self.sent_at = datetime.now(timezone.utc)
|
|
|
|
def mark_delivered(self):
|
|
"""Mark notification as delivered"""
|
|
self.status = NotificationStatus.DELIVERED
|
|
self.delivered_at = datetime.now(timezone.utc)
|
|
|
|
def mark_opened(self):
|
|
"""Mark notification as opened"""
|
|
self.status = NotificationStatus.OPENED
|
|
self.opened_at = datetime.now(timezone.utc)
|
|
|
|
def mark_failed(self, error: str):
|
|
"""Mark notification as failed with error message"""
|
|
self.status = NotificationStatus.FAILED
|
|
self.error_message = error
|
|
self.retry_count += 1
|
|
|
|
@property
|
|
def can_retry(self):
|
|
"""Check if notification can be retried (fewer than 3 attempts)"""
|
|
return self.status == NotificationStatus.FAILED and self.retry_count < 3
|