diff --git a/civicfix/core/__pycache__/forms.cpython-313.pyc b/civicfix/core/__pycache__/forms.cpython-313.pyc index 18dc82c..23e47e2 100644 Binary files a/civicfix/core/__pycache__/forms.cpython-313.pyc and b/civicfix/core/__pycache__/forms.cpython-313.pyc differ diff --git a/civicfix/core/__pycache__/models.cpython-313.pyc b/civicfix/core/__pycache__/models.cpython-313.pyc index 7f5d826..145a2a6 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 9d16970..136a0af 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 110248d..a4513e6 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/forms.py b/civicfix/core/forms.py index ced7d24..7785e7d 100644 --- a/civicfix/core/forms.py +++ b/civicfix/core/forms.py @@ -37,3 +37,11 @@ class CommentForm(forms.ModelForm): widgets = { "content": forms.Textarea(attrs={"rows": 2, "placeholder": "Add a comment..."}) } + +class IssueAssignForm(forms.ModelForm): + class Meta: + model = Issue + fields = ['department'] + widgets = { + 'department': forms.Select(attrs={'class': 'form-select form-select-sm'}), + } \ No newline at end of file diff --git a/civicfix/core/migrations/0008_alter_issue_options_alter_issue_category_and_more.py b/civicfix/core/migrations/0008_alter_issue_options_alter_issue_category_and_more.py new file mode 100644 index 0000000..3a08f75 --- /dev/null +++ b/civicfix/core/migrations/0008_alter_issue_options_alter_issue_category_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2.5 on 2025-08-25 08:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0007_department_users'), + ] + + operations = [ + migrations.AlterModelOptions( + name='issue', + options={'ordering': ['-created_at']}, + ), + migrations.AlterField( + model_name='issue', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issues', to='core.issuecategory'), + ), + migrations.AlterField( + model_name='issue', + name='latitude', + field=models.FloatField(blank=True, null=True), + ), + migrations.AlterField( + model_name='issue', + name='location', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AlterField( + model_name='issue', + name='longitude', + field=models.FloatField(blank=True, null=True), + ), + ] diff --git a/civicfix/core/migrations/0009_issue_department.py b/civicfix/core/migrations/0009_issue_department.py new file mode 100644 index 0000000..c74cace --- /dev/null +++ b/civicfix/core/migrations/0009_issue_department.py @@ -0,0 +1,19 @@ +# Generated by Django 5.2.5 on 2025-08-25 08:28 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_alter_issue_options_alter_issue_category_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='issue', + name='department', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issues', to='core.department'), + ), + ] diff --git a/civicfix/core/migrations/__pycache__/0008_alter_issue_options_alter_issue_category_and_more.cpython-313.pyc b/civicfix/core/migrations/__pycache__/0008_alter_issue_options_alter_issue_category_and_more.cpython-313.pyc new file mode 100644 index 0000000..6378964 Binary files /dev/null and b/civicfix/core/migrations/__pycache__/0008_alter_issue_options_alter_issue_category_and_more.cpython-313.pyc differ diff --git a/civicfix/core/migrations/__pycache__/0009_issue_department.cpython-313.pyc b/civicfix/core/migrations/__pycache__/0009_issue_department.cpython-313.pyc new file mode 100644 index 0000000..8468f2f Binary files /dev/null and b/civicfix/core/migrations/__pycache__/0009_issue_department.cpython-313.pyc differ diff --git a/civicfix/core/models.py b/civicfix/core/models.py index 2e9f04a..c3b25cf 100644 --- a/civicfix/core/models.py +++ b/civicfix/core/models.py @@ -26,6 +26,33 @@ class User(AbstractUser): related_query_name='core_user', ) +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"] + + def __str__(self): + return self.name + class IssueCategory(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) @@ -65,6 +92,15 @@ class Issue(models.Model): 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) @@ -98,7 +134,14 @@ class Issue(models.Model): def has_user_voted(self, user): if user.is_authenticated and hasattr(self, "votes"): return self.votes.filter(user=user).exists() - return False + return + + def assign_to_department(self, department): + """Assign issue to a department and auto-update status to acknowledged""" + self.department = department + self.status = self.STATUS_ACKNOWLEDGED + self.save() + class Vote(models.Model): @@ -127,31 +170,4 @@ class Comment(models.Model): @property def is_reply(self): - return self.parent is not None - -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"] - - def __str__(self): - return self.name \ No newline at end of file + return self.parent is not None \ No newline at end of file diff --git a/civicfix/core/templates/issues/manage_issues.html b/civicfix/core/templates/issues/manage_issues.html index 7597f0e..b764f45 100644 --- a/civicfix/core/templates/issues/manage_issues.html +++ b/civicfix/core/templates/issues/manage_issues.html @@ -17,6 +17,7 @@ Reported By Status Created At + Assign Department @@ -40,6 +41,24 @@ {% endif %} {{ issue.created_at|date:"M d, Y H:i" }} + + {% if issue.department %} + {{ issue.department.name }} + {% else %} +
+ {% csrf_token %} + + + +
+ {% endif %} + + {% endfor %} diff --git a/civicfix/core/urls.py b/civicfix/core/urls.py index 5ecf5f9..1565a84 100644 --- a/civicfix/core/urls.py +++ b/civicfix/core/urls.py @@ -8,7 +8,8 @@ urlpatterns = [ 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("superadmin/assign-department//", views.assign_department, name="assign_department"), + 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 934ab4d..760396e 100644 --- a/civicfix/core/views.py +++ b/civicfix/core/views.py @@ -9,7 +9,7 @@ from django.http import JsonResponse from django.shortcuts import render, redirect, get_object_or_404 from django.views.decorators.http import require_POST from .models import Issue, IssueCategory, User, Vote, Comment, Department -from .forms import CitizenRegistrationForm, IssueForm, CommentForm +from .forms import CitizenRegistrationForm, IssueForm, CommentForm, IssueAssignForm def home(request): total_issues = Issue.objects.count() @@ -271,5 +271,34 @@ def department_detail(request, pk): @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 + issues = Issue.objects.all().order_by('-created_at') + + if request.method == "POST": + issue_id = request.POST.get("issue_id") + dept_id = request.POST.get("department") + + issue = get_object_or_404(Issue, id=issue_id) + if dept_id: # Only assign if a department is selected + department = get_object_or_404(Department, id=dept_id) + issue.assign_to_department(department) # 🔹 uses helper + return redirect("manage_issues") # refresh page after save + + return render(request, "issues/manage_issues.html", { + "issues": issues, + "departments": Department.objects.all() +}) + +@user_passes_test(superadmin_check) +def assign_department(request, issue_id): + if request.method == "POST": + issue = get_object_or_404(Issue, id=issue_id) + dept_id = request.POST.get("department_id") + + if dept_id: + department = get_object_or_404(Department, id=dept_id) + issue.assign_to_department(department) + messages.success(request, f"Issue '{issue.title}' assigned to {department.name}.") + else: + messages.error(request, "Please select a department.") + + return redirect("manage_issues") # redirect back to the issues page \ No newline at end of file