""" Version control models for acknowledgement content. Tracks changes to content and checklist items for audit purposes. """ from django.db import models from django.conf import settings from apps.core.models import TimeStampedModel, UUIDModel class ContentVersion(UUIDModel, TimeStampedModel): """ Version history for AcknowledgementContent. Tracks all changes made to content sections. """ content = models.ForeignKey( 'AcknowledgementContent', on_delete=models.CASCADE, related_name='versions', help_text='The content this version belongs to' ) # Version number (auto-incrementing per content) version_number = models.PositiveIntegerField( help_text='Version number (1, 2, 3, ...)' ) # Snapshots of the content at this version title_en = models.CharField(max_length=200) title_ar = models.CharField(max_length=200, blank=True) description_en = models.TextField() description_ar = models.TextField(blank=True) content_en = models.TextField(blank=True) content_ar = models.TextField(blank=True) # Metadata role = models.CharField(max_length=50, null=True, blank=True) order = models.IntegerField(default=0) is_active = models.BooleanField(default=True) # Change tracking changed_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='content_versions_created' ) change_reason = models.TextField( blank=True, help_text='Reason for this change' ) class Meta: ordering = ['-version_number'] unique_together = [['content', 'version_number']] verbose_name = 'Content Version' verbose_name_plural = 'Content Versions' def __str__(self): return f"{self.content.code} v{self.version_number}" @property def change_summary(self): """Get a summary of changes from previous version""" previous = ContentVersion.objects.filter( content=self.content, version_number__lt=self.version_number ).first() if not previous: return "Initial version" changes = [] if self.title_en != previous.title_en: changes.append("Title (EN) changed") if self.title_ar != previous.title_ar: changes.append("Title (AR) changed") if self.content_en != previous.content_en: changes.append("Content (EN) changed") if self.content_ar != previous.content_ar: changes.append("Content (AR) changed") if self.is_active != previous.is_active: changes.append("Active status changed") return ", ".join(changes) if changes else "Minor changes" class ChecklistItemVersion(UUIDModel, TimeStampedModel): """ Version history for AcknowledgementChecklistItem. Tracks all changes made to checklist items. """ checklist_item = models.ForeignKey( 'AcknowledgementChecklistItem', on_delete=models.CASCADE, related_name='versions', help_text='The checklist item this version belongs to' ) # Version number version_number = models.PositiveIntegerField( help_text='Version number (1, 2, 3, ...)' ) # Snapshots of the item at this version text_en = models.CharField(max_length=500) text_ar = models.CharField(max_length=500, blank=True) description_en = models.TextField(blank=True) description_ar = models.TextField(blank=True) # Configuration is_required = models.BooleanField(default=True) is_active = models.BooleanField(default=True) order = models.IntegerField(default=0) # Relationships content = models.ForeignKey( 'AcknowledgementContent', on_delete=models.SET_NULL, null=True, blank=True, related_name='checklist_versions' ) role = models.CharField(max_length=50, null=True, blank=True) # Change tracking changed_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='checklist_versions_created' ) change_reason = models.TextField( blank=True, help_text='Reason for this change' ) class Meta: ordering = ['-version_number'] unique_together = [['checklist_item', 'version_number']] verbose_name = 'Checklist Item Version' verbose_name_plural = 'Checklist Item Versions' def __str__(self): return f"{self.checklist_item.code} v{self.version_number}" class ContentChangeLog(UUIDModel, TimeStampedModel): """ Comprehensive change log for all content-related activities. Captures create, update, and delete operations. """ ACTION_CHOICES = [ ('create', 'Created'), ('update', 'Updated'), ('delete', 'Deleted'), ('activate', 'Activated'), ('deactivate', 'Deactivated'), ('reorder', 'Reordered'), ] CONTENT_TYPE_CHOICES = [ ('content', 'Acknowledgement Content'), ('checklist_item', 'Checklist Item'), ] user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='content_change_logs' ) action = models.CharField( max_length=20, choices=ACTION_CHOICES ) content_type = models.CharField( max_length=20, choices=CONTENT_TYPE_CHOICES ) object_id = models.CharField( max_length=50, help_text='UUID of the content/checklist item' ) object_code = models.CharField( max_length=100, help_text='Human-readable code of the object' ) # Snapshot of the object after the change snapshot = models.JSONField( default=dict, help_text='JSON snapshot of the object after change' ) # Change details changes_summary = models.TextField( blank=True, help_text='Human-readable summary of changes' ) # IP and user agent for audit ip_address = models.GenericIPAddressField( null=True, blank=True ) user_agent = models.TextField( blank=True ) class Meta: ordering = ['-created_at'] verbose_name = 'Content Change Log' verbose_name_plural = 'Content Change Logs' def __str__(self): return f"{self.get_action_display()} {self.object_code} by {self.user}"