""" Notification System Email, SMS, Push notifications for IOM platform """ from typing import Dict, List, Optional from dataclasses import dataclass from enum import Enum from datetime import datetime class NotificationChannel(str, Enum): """Notification channels""" EMAIL = "email" SMS = "sms" PUSH = "push" WEBHOOK = "webhook" SLACK = "slack" class NotificationPriority(str, Enum): """Notification priorities""" LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" @dataclass class Notification: """Notification message""" id: str channel: NotificationChannel recipient: str subject: str body: str priority: NotificationPriority timestamp: str metadata: Optional[Dict] = None class NotificationEngine: """ Multi-channel notification engine Supports: - Email (SMTP) - SMS (Twilio/simulated) - Push (Firebase/APNs) - Webhook (HTTP callbacks) - Slack (webhooks) """ def __init__(self): self.providers: Dict[NotificationChannel, callable] = { NotificationChannel.EMAIL: self._send_email, NotificationChannel.SMS: self._send_sms, NotificationChannel.PUSH: self._send_push, NotificationChannel.WEBHOOK: self._send_webhook, NotificationChannel.SLACK: self._send_slack } self.history: List[Notification] = [] def send( self, channel: NotificationChannel, recipient: str, subject: str, body: str, priority: NotificationPriority = NotificationPriority.MEDIUM, metadata: Optional[Dict] = None ) -> Dict: """Send notification""" notification = Notification( id=f"NOT-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}", channel=channel, recipient=recipient, subject=subject, body=body, priority=priority, timestamp=datetime.utcnow().isoformat(), metadata=metadata ) # Send via provider provider = self.providers.get(channel) if provider: result = provider(notification) else: result = {"status": "failed", "error": "Unknown channel"} # Store in history self.history.append(notification) return { "notification_id": notification.id, "channel": channel.value, "recipient": recipient, "status": result.get("status", "unknown"), "timestamp": notification.timestamp } def send_bulk( self, notifications: List[Dict] ) -> List[Dict]: """Send multiple notifications""" results = [] for notif in notifications: result = self.send( channel=NotificationChannel(notif["channel"]), recipient=notif["recipient"], subject=notif["subject"], body=notif["body"], priority=NotificationPriority(notif.get("priority", "medium")) ) results.append(result) return results def notify_stakeholder( self, stakeholder_type: str, event_type: str, data: Dict ) -> List[Dict]: """Notify stakeholder about event""" notifications = [] if stakeholder_type == "municipality": if event_type == "critical_defect": notifications.append({ "channel": "email", "recipient": "municipality@example.com", "subject": f"Critical defect detected: {data.get('location', 'Unknown')}", "body": f"A critical defect has been detected. Location: {data.get('location')}. Condition: {data.get('condition')}", "priority": "critical" }) elif stakeholder_type == "property_owner": if event_type == "maintenance_required": notifications.append({ "channel": "email", "recipient": "owner@example.com", "subject": "Maintenance required", "body": f"Your property requires maintenance. Estimated cost: ${data.get('cost', 0)}", "priority": "high" }) return self.send_bulk(notifications) def _send_email(self, notification: Notification) -> Dict: """Send email notification""" # In production, use SMTP print(f"[EMAIL] To: {notification.recipient}") print(f"[EMAIL] Subject: {notification.subject}") print(f"[EMAIL] Body: {notification.body[:100]}...") return {"status": "sent"} def _send_sms(self, notification: Notification) -> Dict: """Send SMS notification""" # In production, use Twilio print(f"[SMS] To: {notification.recipient}") print(f"[SMS] Body: {notification.body[:160]}") return {"status": "sent"} def _send_push(self, notification: Notification) -> Dict: """Send push notification""" # In production, use Firebase/APNs print(f"[PUSH] To: {notification.recipient}") print(f"[PUSH] Title: {notification.subject}") return {"status": "sent"} def _send_webhook(self, notification: Notification) -> Dict: """Send webhook notification""" # In production, use HTTP client print(f"[WEBHOOK] URL: {notification.recipient}") print(f"[WEBHOOK] Payload: {notification.body[:100]}...") return {"status": "sent"} def _send_slack(self, notification: Notification) -> Dict: """Send Slack notification""" # In production, use Slack webhook print(f"[SLACK] Channel: {notification.recipient}") print(f"[SLACK] Message: {notification.body[:100]}...") return {"status": "sent"} def get_history(self, limit: int = 100) -> List[Dict]: """Get notification history""" return [ { "id": n.id, "channel": n.channel.value, "recipient": n.recipient, "subject": n.subject, "priority": n.priority.value, "timestamp": n.timestamp } for n in self.history[-limit:] ] # Example usage def example_notifications(): """Example: Notification system""" print("=== Notification Engine Demo ===\n") engine = NotificationEngine() # Send email print("Sending email...") result = engine.send( channel=NotificationChannel.EMAIL, recipient="admin@landvex.com", subject="Critical alert: Bridge condition", body="The bridge on Main Street has degraded to condition 4. Immediate action required.", priority=NotificationPriority.CRITICAL ) print(f"Status: {result['status']}\n") # Send SMS print("Sending SMS...") result = engine.send( channel=NotificationChannel.SMS, recipient="+46701234567", subject="Alert", body="Critical defect detected near your location. Please check the app.", priority=NotificationPriority.HIGH ) print(f"Status: {result['status']}\n") # Notify stakeholder print("Notifying municipality...") results = engine.notify_stakeholder( stakeholder_type="municipality", event_type="critical_defect", data={"location": "Main Street Bridge", "condition": 4} ) print(f"Sent: {len(results)} notifications\n") # History print("Notification history:") history = engine.get_history() for h in history: print(f" [{h['channel']}] {h['subject']} ({h['priority']})") return engine if __name__ == '__main__': example_notifications()