Fixed mod models

This commit is contained in:
pacnpal
2024-11-13 14:53:31 +00:00
parent 08e97f21b7
commit 7f4de7c2ec

View File

@@ -11,83 +11,78 @@ from django.contrib.auth.models import AnonymousUser
UserType = Union[AbstractBaseUser, AnonymousUser] UserType = Union[AbstractBaseUser, AnonymousUser]
class EditSubmission(models.Model): class EditSubmission(models.Model):
STATUS_CHOICES = [ STATUS_CHOICES = [
('NEW', 'New'), ("NEW", "New"),
('APPROVED', 'Approved'), ("APPROVED", "Approved"),
('REJECTED', 'Rejected'), ("REJECTED", "Rejected"),
('ESCALATED', 'Escalated'), ("ESCALATED", "Escalated"),
] ]
SUBMISSION_TYPE_CHOICES = [ SUBMISSION_TYPE_CHOICES = [
('EDIT', 'Edit Existing'), ("EDIT", "Edit Existing"),
('CREATE', 'Create New'), ("CREATE", "Create New"),
] ]
# Who submitted the edit # Who submitted the edit
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='edit_submissions' related_name="edit_submissions",
) )
# What is being edited (Park or Ride) # What is being edited (Park or Ride)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(null=True, blank=True) # Null for new objects object_id = models.PositiveIntegerField(
content_object = GenericForeignKey('content_type', 'object_id') null=True, blank=True
) # Null for new objects
content_object = GenericForeignKey("content_type", "object_id")
# Type of submission # Type of submission
submission_type = models.CharField( submission_type = models.CharField(
max_length=10, max_length=10, choices=SUBMISSION_TYPE_CHOICES, default="EDIT"
choices=SUBMISSION_TYPE_CHOICES,
default='EDIT'
) )
# The actual changes/data # The actual changes/data
changes = models.JSONField( changes = models.JSONField(
help_text='JSON representation of the changes or new object data' help_text="JSON representation of the changes or new object data"
) )
# Metadata # Metadata
reason = models.TextField( reason = models.TextField(help_text="Why this edit/addition is needed")
help_text='Why this edit/addition is needed'
)
source = models.TextField( source = models.TextField(
blank=True, blank=True, help_text="Source of information (if applicable)"
help_text='Source of information (if applicable)'
)
status = models.CharField(
max_length=20,
choices=STATUS_CHOICES,
default='NEW'
) )
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="NEW")
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
# Review details # Review details
handled_by = models.ForeignKey( handled_by = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True, null=True,
blank=True, blank=True,
related_name='handled_submissions' related_name="handled_submissions",
) )
handled_at = models.DateTimeField(null=True, blank=True) handled_at = models.DateTimeField(null=True, blank=True)
notes = models.TextField( notes = models.TextField(
blank=True, blank=True, help_text="Notes from the moderator about this submission"
help_text='Notes from the moderator about this submission'
) )
class Meta: class Meta:
ordering = ['-created_at'] ordering = ["-created_at"]
indexes = [ indexes = [
models.Index(fields=['content_type', 'object_id']), models.Index(fields=["content_type", "object_id"]),
models.Index(fields=['status']), models.Index(fields=["status"]),
] ]
def __str__(self) -> str: def __str__(self) -> str:
action = "creation" if self.submission_type == 'CREATE' else "edit" action = "creation" if self.submission_type == "CREATE" else "edit"
model_class = self.content_type.model_class() model_class = self.content_type.model_class()
target = self.content_object or (model_class.__name__ if model_class else 'Unknown') target = self.content_object or (
model_class.__name__ if model_class else "Unknown"
)
return f"{action} by {self.user.username} on {target}" return f"{action} by {self.user.username} on {target}"
def _resolve_foreign_keys(self, data: Dict[str, Any]) -> Dict[str, Any]: def _resolve_foreign_keys(self, data: Dict[str, Any]) -> Dict[str, Any]:
@@ -112,10 +107,10 @@ class EditSubmission(models.Model):
def approve(self, user: UserType) -> Optional[models.Model]: def approve(self, user: UserType) -> Optional[models.Model]:
"""Approve the submission and apply the changes""" """Approve the submission and apply the changes"""
self.status = 'APPROVED' self.status = "APPROVED"
self.handled_by = user # type: ignore self.handled_by = user # type: ignore
self.handled_at = timezone.now() self.handled_at = timezone.now()
model_class = self.content_type.model_class() model_class = self.content_type.model_class()
if not model_class: if not model_class:
raise ValueError("Could not resolve model class") raise ValueError("Could not resolve model class")
@@ -123,12 +118,12 @@ class EditSubmission(models.Model):
try: try:
resolved_data = self._resolve_foreign_keys(self.changes) resolved_data = self._resolve_foreign_keys(self.changes)
if self.submission_type == 'CREATE': if self.submission_type == "CREATE":
# Create new object # Create new object
obj = model_class(**resolved_data) obj = model_class(**resolved_data)
obj.save() obj.save()
# Update object_id after creation # Update object_id after creation
self.object_id = getattr(obj, 'id', None) self.object_id = getattr(obj, "id", None)
else: else:
# Apply changes to existing object # Apply changes to existing object
obj = self.content_object obj = self.content_object
@@ -137,7 +132,7 @@ class EditSubmission(models.Model):
for field, value in resolved_data.items(): for field, value in resolved_data.items():
setattr(obj, field, value) setattr(obj, field, value)
obj.save() obj.save()
self.save() self.save()
return obj return obj
except Exception as e: except Exception as e:
@@ -145,84 +140,80 @@ class EditSubmission(models.Model):
def reject(self, user: UserType) -> None: def reject(self, user: UserType) -> None:
"""Reject the submission""" """Reject the submission"""
self.status = 'REJECTED' self.status = "REJECTED"
self.handled_by = user # type: ignore self.handled_by = user # type: ignore
self.handled_at = timezone.now() self.handled_at = timezone.now()
self.save() self.save()
def escalate(self, user: UserType) -> None: def escalate(self, user: UserType) -> None:
"""Escalate the submission to admin""" """Escalate the submission to admin"""
self.status = 'ESCALATED' self.status = "ESCALATED"
self.handled_by = user # type: ignore self.handled_by = user # type: ignore
self.handled_at = timezone.now() self.handled_at = timezone.now()
self.save() self.save()
class PhotoSubmission(models.Model): class PhotoSubmission(models.Model):
STATUS_CHOICES = [ STATUS_CHOICES = [
('NEW', 'New'), ("NEW", "New"),
('APPROVED', 'Approved'), ("APPROVED", "Approved"),
('REJECTED', 'Rejected'), ("REJECTED", "Rejected"),
('AUTO_APPROVED', 'Auto Approved'), ("AUTO_APPROVED", "Auto Approved"),
] ]
# Who submitted the photo # Who submitted the photo
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='photo_submissions' related_name="photo_submissions",
) )
# What the photo is for (Park or Ride) # What the photo is for (Park or Ride)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField() object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id') content_object = GenericForeignKey("content_type", "object_id")
# The photo itself # The photo itself
photo = models.ImageField(upload_to='submissions/photos/') photo = models.ImageField(upload_to="submissions/photos/")
caption = models.CharField(max_length=255, blank=True) caption = models.CharField(max_length=255, blank=True)
date_taken = models.DateField(null=True, blank=True) date_taken = models.DateField(null=True, blank=True)
# Metadata # Metadata
status = models.CharField( status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="NEW")
max_length=20,
choices=STATUS_CHOICES,
default='NEW'
)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
# Review details # Review details
handled_by = models.ForeignKey( handled_by = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True, null=True,
blank=True, blank=True,
related_name='handled_photos' related_name="handled_photos",
) )
handled_at = models.DateTimeField(null=True, blank=True) handled_at = models.DateTimeField(null=True, blank=True)
notes = models.TextField( notes = models.TextField(
blank=True, blank=True, help_text="Notes from the moderator about this photo submission"
help_text='Notes from the moderator about this photo submission'
) )
class Meta: class Meta:
ordering = ['-created_at'] ordering = ["-created_at"]
indexes = [ indexes = [
models.Index(fields=['content_type', 'object_id']), models.Index(fields=["content_type", "object_id"]),
models.Index(fields=['status']), models.Index(fields=["status"]),
] ]
def __str__(self) -> str: def __str__(self) -> str:
return f"Photo submission by {self.user.username} for {self.content_object}" return f"Photo submission by {self.user.username} for {self.content_object}"
def approve(self, moderator: UserType, notes: str = '') -> None: def approve(self, moderator: UserType, notes: str = "") -> None:
"""Approve the photo submission""" """Approve the photo submission"""
from media.models import Photo from media.models import Photo
self.status = 'APPROVED' self.status = "APPROVED"
self.handled_by = moderator # type: ignore self.handled_by = moderator # type: ignore
self.handled_at = timezone.now() self.handled_at = timezone.now()
self.notes = notes self.notes = notes
# Create the approved photo # Create the approved photo
Photo.objects.create( Photo.objects.create(
uploaded_by=self.user, uploaded_by=self.user,
@@ -230,14 +221,14 @@ class PhotoSubmission(models.Model):
object_id=self.object_id, object_id=self.object_id,
image=self.photo, image=self.photo,
caption=self.caption, caption=self.caption,
is_approved=True is_approved=True,
) )
self.save() self.save()
def reject(self, moderator: UserType, notes: str) -> None: def reject(self, moderator: UserType, notes: str) -> None:
"""Reject the photo submission""" """Reject the photo submission"""
self.status = 'REJECTED' self.status = "REJECTED"
self.handled_by = moderator # type: ignore self.handled_by = moderator # type: ignore
self.handled_at = timezone.now() self.handled_at = timezone.now()
self.notes = notes self.notes = notes
@@ -246,11 +237,11 @@ class PhotoSubmission(models.Model):
def auto_approve(self) -> None: def auto_approve(self) -> None:
"""Auto-approve the photo submission (for moderators/admins)""" """Auto-approve the photo submission (for moderators/admins)"""
from media.models import Photo from media.models import Photo
self.status = 'AUTO_APPROVED' self.status = "AUTO_APPROVED"
self.handled_by = self.user self.handled_by = self.user
self.handled_at = timezone.now() self.handled_at = timezone.now()
# Create the approved photo # Create the approved photo
Photo.objects.create( Photo.objects.create(
uploaded_by=self.user, uploaded_by=self.user,
@@ -258,7 +249,7 @@ class PhotoSubmission(models.Model):
object_id=self.object_id, object_id=self.object_id,
image=self.photo, image=self.photo,
caption=self.caption, caption=self.caption,
is_approved=True is_approved=True,
) )
self.save() self.save()