""" Notification Models for IGNY8 This module provides a notification system for tracking AI operations, workflow events, and system alerts. """ from django.db import models from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from igny8_core.auth.models import AccountBaseModel class NotificationType(models.TextChoices): """Notification type choices""" # AI Operations AI_CLUSTER_COMPLETE = 'ai_cluster_complete', 'Clustering Complete' AI_CLUSTER_FAILED = 'ai_cluster_failed', 'Clustering Failed' AI_IDEAS_COMPLETE = 'ai_ideas_complete', 'Ideas Generated' AI_IDEAS_FAILED = 'ai_ideas_failed', 'Idea Generation Failed' AI_CONTENT_COMPLETE = 'ai_content_complete', 'Content Generated' AI_CONTENT_FAILED = 'ai_content_failed', 'Content Generation Failed' AI_IMAGES_COMPLETE = 'ai_images_complete', 'Images Generated' AI_IMAGES_FAILED = 'ai_images_failed', 'Image Generation Failed' AI_PROMPTS_COMPLETE = 'ai_prompts_complete', 'Image Prompts Created' AI_PROMPTS_FAILED = 'ai_prompts_failed', 'Image Prompts Failed' # Workflow CONTENT_READY_REVIEW = 'content_ready_review', 'Content Ready for Review' CONTENT_PUBLISHED = 'content_published', 'Content Published' CONTENT_PUBLISH_FAILED = 'content_publish_failed', 'Publishing Failed' # WordPress Sync WORDPRESS_SYNC_SUCCESS = 'wordpress_sync_success', 'WordPress Sync Complete' WORDPRESS_SYNC_FAILED = 'wordpress_sync_failed', 'WordPress Sync Failed' # Credits/Billing CREDITS_LOW = 'credits_low', 'Credits Running Low' CREDITS_DEPLETED = 'credits_depleted', 'Credits Depleted' # Setup SITE_SETUP_COMPLETE = 'site_setup_complete', 'Site Setup Complete' KEYWORDS_IMPORTED = 'keywords_imported', 'Keywords Imported' # System SYSTEM_INFO = 'system_info', 'System Information' class NotificationSeverity(models.TextChoices): """Notification severity choices""" INFO = 'info', 'Info' SUCCESS = 'success', 'Success' WARNING = 'warning', 'Warning' ERROR = 'error', 'Error' class Notification(AccountBaseModel): """ Notification model for tracking events and alerts Notifications are account-scoped (via AccountBaseModel) and can optionally target specific users. They support generic relations to link to any related object. """ user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, related_name='notifications', help_text='If null, notification is visible to all account users' ) # Notification content notification_type = models.CharField( max_length=50, choices=NotificationType.choices, default=NotificationType.SYSTEM_INFO ) title = models.CharField(max_length=200) message = models.TextField() severity = models.CharField( max_length=20, choices=NotificationSeverity.choices, default=NotificationSeverity.INFO ) # Related site (optional) site = models.ForeignKey( 'igny8_core_auth.Site', on_delete=models.CASCADE, null=True, blank=True, related_name='notifications' ) # Generic relation to any object content_type = models.ForeignKey( ContentType, on_delete=models.CASCADE, null=True, blank=True ) object_id = models.PositiveIntegerField(null=True, blank=True) content_object = GenericForeignKey('content_type', 'object_id') # Action action_url = models.CharField(max_length=500, null=True, blank=True) action_label = models.CharField(max_length=50, null=True, blank=True) # Status is_read = models.BooleanField(default=False) read_at = models.DateTimeField(null=True, blank=True) # Metadata for counts/details metadata = models.JSONField(default=dict, blank=True) class Meta: ordering = ['-created_at'] indexes = [ models.Index(fields=['account', '-created_at']), models.Index(fields=['account', 'is_read', '-created_at']), models.Index(fields=['user', '-created_at']), ] def __str__(self): return f"{self.title} ({self.notification_type})" def mark_as_read(self): """Mark notification as read""" if not self.is_read: from django.utils import timezone self.is_read = True self.read_at = timezone.now() self.save(update_fields=['is_read', 'read_at', 'updated_at']) @classmethod def create_notification( cls, account, notification_type: str, title: str, message: str, severity: str = NotificationSeverity.INFO, user=None, site=None, content_object=None, action_url: str = None, action_label: str = None, metadata: dict = None ): """ Factory method to create notifications Args: account: The account this notification belongs to notification_type: Type from NotificationType choices title: Notification title message: Notification message body severity: Severity level from NotificationSeverity choices user: Optional specific user (if None, visible to all account users) site: Optional related site content_object: Optional related object (using GenericForeignKey) action_url: Optional URL for action button action_label: Optional label for action button metadata: Optional dict with additional data (counts, etc.) Returns: Created Notification instance """ notification = cls( account=account, user=user, notification_type=notification_type, title=title, message=message, severity=severity, site=site, action_url=action_url, action_label=action_label, metadata=metadata or {} ) if content_object: notification.content_type = ContentType.objects.get_for_model(content_object) notification.object_id = content_object.pk notification.save() return notification