good stuff

This commit is contained in:
pacnpal
2024-10-29 21:29:16 -04:00
parent 4e970400ef
commit 6880f36b99
42 changed files with 2835 additions and 262 deletions

262
moderation/models.py Normal file
View File

@@ -0,0 +1,262 @@
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()