Files
civic-fix/core/models.py
T
2026-02-02 17:34:09 +05:30

212 lines
6.0 KiB
Python

from datetime import timedelta
from django.contrib.auth.models import AbstractUser
from django.core.validators import FileExtensionValidator
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)
is_resolver = models.BooleanField(default=False)
phone = models.CharField(max_length=15, blank=True, null=True)
groups = models.ManyToManyField(
'auth.Group',
verbose_name='groups',
blank=True,
help_text='The groups this user belongs to.',
related_name='core_user_groups',
related_query_name='core_user',
)
user_permissions = models.ManyToManyField(
'auth.Permission',
verbose_name='user permissions',
blank=True,
help_text='Specific permissions for this user.',
related_name='core_user_permissions',
related_query_name='core_user',
)
# Ban-related fields
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
self.banned_until = timezone.now() + timedelta(days=days)
self.save()
def unban(self):
"""Unban user immediately."""
self.is_banned = False
self.banned_until = None
self.save()
@property
def currently_banned(self):
if self.is_banned and self.banned_until:
if timezone.now() >= self.banned_until:
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)
created_at = models.DateTimeField(auto_now_add=True)
# Each department can have many users
users = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name="departments",
blank=True
)
# One admin per department
admin = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
related_name="admin_of_department",
null=True,
blank=True
)
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'
STATUS_IN_PROGRESS = 'in_progress'
STATUS_RESOLVED = 'resolved'
STATUS_CHOICES = [
(STATUS_REPORTED, 'Reported'),
(STATUS_ACKNOWLEDGED, 'Acknowledged'),
(STATUS_IN_PROGRESS, 'In Progress'),
(STATUS_RESOLVED, 'Resolved'),
]
title = models.CharField(max_length=200)
description = models.TextField()
reporter = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="reported_issues"
)
# 🔹 Add relation to department
department = models.ForeignKey(
Department,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="issues"
)
location = models.CharField(max_length=200, blank=True)
latitude = models.FloatField(null=True, blank=True)
longitude = models.FloatField(null=True, blank=True)
photo = models.ImageField(
upload_to="issues/",
blank=True,
null=True,
validators=[FileExtensionValidator(["jpg", "jpeg", "png", "webp"])]
)
status = models.CharField(
max_length=20,
choices=STATUS_CHOICES,
default=STATUS_REPORTED
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
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()
def has_user_voted(self, user):
if user.is_authenticated:
return self.votes.filter(user=user).exists()
return False
def assign_to_department(self, department):
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:
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)
content = models.TextField()
parent = models.ForeignKey("self", null=True, blank=True, related_name="replies", on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["created_at"]
def __str__(self):
return f"Comment by {self.user} on {self.issue}"
@property
def is_reply(self):
return self.parent is not None