from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.conf import settings from django.utils import timezone from django.apps import apps class EditSubmission(models.Model): STATUS_CHOICES = [ ('PENDING', 'Pending'), ('APPROVED', 'Approved'), ('REJECTED', 'Rejected'), ('AUTO_APPROVED', 'Auto Approved'), ] SUBMISSION_TYPE_CHOICES = [ ('EDIT', 'Edit Existing'), ('CREATE', 'Create New'), ] # Who submitted the edit user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='edit_submissions' ) # What is being edited (Park or Ride) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField(null=True, blank=True) # Null for new objects content_object = GenericForeignKey('content_type', 'object_id') # Type of submission submission_type = models.CharField( max_length=10, choices=SUBMISSION_TYPE_CHOICES, default='EDIT' ) # The actual changes/data changes = models.JSONField( help_text='JSON representation of the changes or new object data' ) # Metadata reason = models.TextField( help_text='Why this edit/addition is needed' ) source = models.TextField( blank=True, help_text='Source of information (if applicable)' ) status = models.CharField( max_length=20, choices=STATUS_CHOICES, default='PENDING' ) submitted_at = models.DateTimeField(auto_now_add=True) # Review details reviewed_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_submissions' ) reviewed_at = models.DateTimeField(null=True, blank=True) review_notes = models.TextField( blank=True, help_text='Notes from the moderator about this submission' ) class Meta: ordering = ['-submitted_at'] indexes = [ models.Index(fields=['content_type', 'object_id']), models.Index(fields=['status']), ] def __str__(self): action = "creation" if self.submission_type == 'CREATE' else "edit" target = self.content_object or self.content_type.model_class().__name__ return f"{action} by {self.user.username} on {target}" def _resolve_foreign_keys(self, data): """Convert foreign key IDs to model instances""" model_class = self.content_type.model_class() resolved_data = data.copy() for field_name, value in data.items(): field = model_class._meta.get_field(field_name) if isinstance(field, models.ForeignKey) and value is not None: related_model = field.related_model resolved_data[field_name] = related_model.objects.get(id=value) return resolved_data def approve(self, moderator, notes=''): """Approve the submission and apply the changes""" self.status = 'APPROVED' self.reviewed_by = moderator self.reviewed_at = timezone.now() self.review_notes = notes model_class = self.content_type.model_class() resolved_data = self._resolve_foreign_keys(self.changes) if self.submission_type == 'CREATE': # Create new object obj = model_class(**resolved_data) obj.save() # Update object_id after creation self.object_id = obj.id else: # Apply changes to existing object obj = self.content_object for field, value in resolved_data.items(): setattr(obj, field, value) obj.save() self.save() return obj def reject(self, moderator, notes): """Reject the submission""" self.status = 'REJECTED' self.reviewed_by = moderator self.reviewed_at = timezone.now() self.review_notes = notes self.save() def auto_approve(self): """Auto-approve the submission (for moderators/admins)""" self.status = 'AUTO_APPROVED' self.reviewed_by = self.user self.reviewed_at = timezone.now() model_class = self.content_type.model_class() resolved_data = self._resolve_foreign_keys(self.changes) if self.submission_type == 'CREATE': # Create new object obj = model_class(**resolved_data) obj.save() # Update object_id after creation self.object_id = obj.id else: # Apply changes to existing object obj = self.content_object for field, value in resolved_data.items(): setattr(obj, field, value) obj.save() self.save() return obj class PhotoSubmission(models.Model): STATUS_CHOICES = [ ('PENDING', 'Pending'), ('APPROVED', 'Approved'), ('REJECTED', 'Rejected'), ('AUTO_APPROVED', 'Auto Approved'), ] # Who submitted the photo user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='photo_submissions' ) # What the photo is for (Park or Ride) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') # The photo itself photo = models.ImageField(upload_to='submissions/photos/') caption = models.CharField(max_length=255, blank=True) date_taken = models.DateField(null=True, blank=True) # Metadata status = models.CharField( max_length=20, choices=STATUS_CHOICES, default='PENDING' ) submitted_at = models.DateTimeField(auto_now_add=True) # Review details reviewed_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_photos' ) reviewed_at = models.DateTimeField(null=True, blank=True) review_notes = models.TextField( blank=True, help_text='Notes from the moderator about this photo submission' ) class Meta: ordering = ['-submitted_at'] indexes = [ models.Index(fields=['content_type', 'object_id']), models.Index(fields=['status']), ] def __str__(self): return f"Photo submission by {self.user.username} for {self.content_object}" def approve(self, moderator, notes=''): """Approve the photo submission""" from media.models import Photo self.status = 'APPROVED' self.reviewed_by = moderator self.reviewed_at = timezone.now() self.review_notes = notes # Create the approved photo Photo.objects.create( user=self.user, content_type=self.content_type, object_id=self.object_id, image=self.photo, caption=self.caption, date_taken=self.date_taken ) self.save() def reject(self, moderator, notes): """Reject the photo submission""" self.status = 'REJECTED' self.reviewed_by = moderator self.reviewed_at = timezone.now() self.review_notes = notes self.save() def auto_approve(self): """Auto-approve the photo submission (for moderators/admins)""" from media.models import Photo self.status = 'AUTO_APPROVED' self.reviewed_by = self.user self.reviewed_at = timezone.now() # Create the approved photo Photo.objects.create( user=self.user, content_type=self.content_type, object_id=self.object_id, image=self.photo, caption=self.caption, date_taken=self.date_taken ) self.save()