diff --git a/core/models.py b/core/models.py index 34795a5..3d6543e 100644 --- a/core/models.py +++ b/core/models.py @@ -1,4 +1,3 @@ -from cloudinary.models import CloudinaryField from datetime import timedelta from django.contrib.auth.models import AbstractUser from django.core.validators import FileExtensionValidator @@ -6,6 +5,7 @@ from django.conf import settings from django.db import models from django.utils import timezone +#User Model class User(AbstractUser): is_citizen = models.BooleanField(default=False) is_moderator = models.BooleanField(default=False) @@ -33,6 +33,9 @@ class User(AbstractUser): is_banned = models.BooleanField(default=False) banned_until = models.DateTimeField(null=True, blank=True) + def __str__(self): + return self.username + def ban(self, days=7): """Ban user for given number of days (default = 7).""" self.is_banned = True @@ -45,16 +48,16 @@ class User(AbstractUser): self.banned_until = None self.save() - def is_currently_banned(self): - """Check if user is still banned (auto-unban if expired).""" + @property + def currently_banned(self): if self.is_banned and self.banned_until: if timezone.now() >= self.banned_until: - # Auto unban if ban expired self.unban() return False return True return False - + +#Department Model class Department(models.Model): name = models.CharField(max_length=100, unique=True) description = models.TextField(blank=True, null=True) @@ -78,10 +81,17 @@ class Department(models.Model): class Meta: ordering = ["name"] + constraints = [ + models.UniqueConstraint( + fields=["admin"], + name="unique_department_admin" + ) + ] def __str__(self): return self.name +#Issue Model class Issue(models.Model): STATUS_REPORTED = 'reported' STATUS_ACKNOWLEDGED = 'acknowledged' @@ -117,10 +127,11 @@ class Issue(models.Model): latitude = models.FloatField(null=True, blank=True) longitude = models.FloatField(null=True, blank=True) - photo = CloudinaryField( - 'images', + photo = models.ImageField( + upload_to="issues/", blank=True, null=True, + validators=[FileExtensionValidator(["jpg", "jpeg", "png", "webp"])] ) status = models.CharField( @@ -133,39 +144,56 @@ class Issue(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: - ordering = ["-created_at"] # 🔹 latest issues first by default + ordering = ["-created_at"] + indexes = [ + models.Index(fields=["status"]), + models.Index(fields=["created_at"]), + models.Index(fields=["department"]), + models.Index(fields=["reporter"]), + ] + + + # 🔹 latest issues first by default def __str__(self): return f"{self.title} ({self.get_status_display()})" # 🔹 Helpers def vote_count(self): - return self.votes.count() if hasattr(self, "votes") else 0 + return self.votes.count() + def has_user_voted(self, user): - if user.is_authenticated and hasattr(self, "votes"): + if user.is_authenticated: return self.votes.filter(user=user).exists() - return + return False + def assign_to_department(self, department): - """Assign issue to a department and auto-update status to acknowledged""" + if self.department_id == department.id: + return self.department = department self.status = self.STATUS_ACKNOWLEDGED self.save() - - +#Vote Model class Vote(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name='votes') created_at = models.DateTimeField(auto_now_add=True) class Meta: - unique_together = ('user', 'issue') # Prevent duplicate votes per user + constraints = [ + models.UniqueConstraint( + fields=["user", "issue"], + name="unique_vote_per_user_issue" + ) + ] def __str__(self): return f"{self.user.username} voted on {self.issue.title}" +#Comment Model class Comment(models.Model): issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="comments") user = models.ForeignKey(User, on_delete=models.CASCADE)