diff --git a/civicfix/core/__pycache__/models.cpython-313.pyc b/civicfix/core/__pycache__/models.cpython-313.pyc index 10f13c8..7f5d826 100644 Binary files a/civicfix/core/__pycache__/models.cpython-313.pyc and b/civicfix/core/__pycache__/models.cpython-313.pyc differ diff --git a/civicfix/core/__pycache__/urls.cpython-313.pyc b/civicfix/core/__pycache__/urls.cpython-313.pyc index e85e993..9d16970 100644 Binary files a/civicfix/core/__pycache__/urls.cpython-313.pyc and b/civicfix/core/__pycache__/urls.cpython-313.pyc differ diff --git a/civicfix/core/__pycache__/views.cpython-313.pyc b/civicfix/core/__pycache__/views.cpython-313.pyc index bbaf288..110248d 100644 Binary files a/civicfix/core/__pycache__/views.cpython-313.pyc and b/civicfix/core/__pycache__/views.cpython-313.pyc differ diff --git a/civicfix/core/models.py b/civicfix/core/models.py index de722af..2e9f04a 100644 --- a/civicfix/core/models.py +++ b/civicfix/core/models.py @@ -34,37 +34,72 @@ class IssueCategory(models.Model): def __str__(self): return self.name +# issues/models.py class Issue(models.Model): + STATUS_REPORTED = 'reported' + STATUS_ACKNOWLEDGED = 'acknowledged' + STATUS_IN_PROGRESS = 'in_progress' + STATUS_RESOLVED = 'resolved' + STATUS_CHOICES = [ - ('reported', 'Reported'), - ('acknowledged', 'Acknowledged'), - ('in_progress', 'In Progress'), - ('resolved', 'Resolved'), + (STATUS_REPORTED, 'Reported'), + (STATUS_ACKNOWLEDGED, 'Acknowledged'), + (STATUS_IN_PROGRESS, 'In Progress'), + (STATUS_RESOLVED, 'Resolved'), ] - + title = models.CharField(max_length=200) description = models.TextField() - category = models.ForeignKey(IssueCategory, on_delete=models.SET_NULL, null=True, blank=True) - reporter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reported_issues') - location = models.CharField(max_length=200) - latitude = models.FloatField() - longitude = models.FloatField() - photo = models.ImageField(upload_to='issue_photos/', blank=True, null=True, - validators=[FileExtensionValidator(['jpg', 'jpeg', 'png', 'gif'])]) - status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='reported') + + category = models.ForeignKey( + "IssueCategory", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="issues" + ) + + reporter = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name="reported_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="issue_photos/", + blank=True, + null=True, + validators=[FileExtensionValidator(['jpg', 'jpeg', 'png', 'gif'])] + ) + + 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"] # 🔹 latest issues first by default + def __str__(self): - return self.title - + return f"{self.title} ({self.get_status_display()})" + + # 🔹 Helpers def vote_count(self): - return self.votes.count() - + return self.votes.count() if hasattr(self, "votes") else 0 + def has_user_voted(self, user): - if user.is_authenticated: + if user.is_authenticated and hasattr(self, "votes"): return self.votes.filter(user=user).exists() return False + class Vote(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) diff --git a/civicfix/core/templates/dashboard/superadmin_dashboard.html b/civicfix/core/templates/dashboard/superadmin_dashboard.html index ef052f1..0ab3c71 100644 --- a/civicfix/core/templates/dashboard/superadmin_dashboard.html +++ b/civicfix/core/templates/dashboard/superadmin_dashboard.html @@ -19,6 +19,9 @@ Manage Departments +
  • + Manage Issues +
  • Manage Roles & Permissions
  • diff --git a/civicfix/core/templates/issues/manage_issues.html b/civicfix/core/templates/issues/manage_issues.html new file mode 100644 index 0000000..7597f0e --- /dev/null +++ b/civicfix/core/templates/issues/manage_issues.html @@ -0,0 +1,53 @@ +{% extends "core/base.html" %} + +{% block content %} +
    +
    +
    +

    Manage Issues

    +
    +
    + {% if issues %} + + + + + + + + + + + + + {% for issue in issues %} + + + + + + + + + {% endfor %} + +
    #TitleCategoryReported ByStatusCreated At
    {{ forloop.counter }}{{ issue.title }}{{ issue.category.name|default:"—" }}{{ issue.reporter.username }} + {% if issue.status == "reported" %} + Reported + {% elif issue.status == "acknowledged" %} + Acknowledged + {% elif issue.status == "in_progress" %} + In Progress + {% elif issue.status == "resolved" %} + Resolved + {% else %} + Unknown + {% endif %} + {{ issue.created_at|date:"M d, Y H:i" }}
    + {% else %} +

    No issues reported yet.

    + {% endif %} +
    +
    +
    +{% endblock %} diff --git a/civicfix/core/urls.py b/civicfix/core/urls.py index af20d7b..5ecf5f9 100644 --- a/civicfix/core/urls.py +++ b/civicfix/core/urls.py @@ -7,6 +7,8 @@ urlpatterns = [ path("superadmin/", views.superadmin_dashboard, name="superadmin_dashboard"), path("superadmin/departments/", views.manage_departments, name="manage_departments"), path("superadmin/departments//", views.department_detail, name="department_detail"), + path("superadmin/manage/", views.manage_issues, name="manage_issues"), + path('register/', views.register, name='register'), path('login/', views.custom_login, name='login'), path('logout/', auth_views.LogoutView.as_view(), name='logout'), diff --git a/civicfix/core/views.py b/civicfix/core/views.py index 6a8ecac..934ab4d 100644 --- a/civicfix/core/views.py +++ b/civicfix/core/views.py @@ -266,4 +266,10 @@ def department_detail(request, pk): return render(request, "department/department_detail.html", { "department": department, "users": users, - }) \ No newline at end of file + }) + +@login_required +@user_passes_test(superadmin_check) +def manage_issues(request): + issues = Issue.objects.all().order_by("-created_at") + return render(request, "issues/manage_issues.html", {"issues": issues}) \ No newline at end of file