From 7272f1726f626209cc427bc76ffcee6b0d44a980 Mon Sep 17 00:00:00 2001 From: Gokuldevx Date: Mon, 25 Aug 2025 14:26:58 +0530 Subject: [PATCH] minor update --- .../core/__pycache__/forms.cpython-313.pyc | Bin 2852 -> 3388 bytes .../core/__pycache__/models.cpython-313.pyc | Bin 8036 -> 8494 bytes .../core/__pycache__/urls.cpython-313.pyc | Bin 1680 -> 1804 bytes .../core/__pycache__/views.cpython-313.pyc | Bin 14218 -> 15635 bytes civicfix/core/forms.py | 8 ++ ...e_options_alter_issue_category_and_more.py | 38 +++++++++ .../core/migrations/0009_issue_department.py | 19 +++++ ...er_issue_category_and_more.cpython-313.pyc | Bin 0 -> 1578 bytes .../0009_issue_department.cpython-313.pyc | Bin 0 -> 1055 bytes civicfix/core/models.py | 74 +++++++++++------- .../core/templates/issues/manage_issues.html | 19 +++++ civicfix/core/urls.py | 3 +- civicfix/core/views.py | 35 ++++++++- 13 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 civicfix/core/migrations/0008_alter_issue_options_alter_issue_category_and_more.py create mode 100644 civicfix/core/migrations/0009_issue_department.py create mode 100644 civicfix/core/migrations/__pycache__/0008_alter_issue_options_alter_issue_category_and_more.cpython-313.pyc create mode 100644 civicfix/core/migrations/__pycache__/0009_issue_department.cpython-313.pyc diff --git a/civicfix/core/__pycache__/forms.cpython-313.pyc b/civicfix/core/__pycache__/forms.cpython-313.pyc index 18dc82c4ca2a8ecf3a36632581a1e51c269f2aeb..23e47e2a548257b64b199153f38eb412cba2c88d 100644 GIT binary patch delta 342 zcmZ1?wnvKZGcPX}0}z~6T$7=}Hjz()@yJB=*<2C~N({l=QVhX76D#CddD3|``8FP_ z;AH$f*`7;k@YOguE}vr1Wk*cZ)!>6OD&+jTU;rr1&Ku^xv6<2w^);N5{rwgq|$(<>K3Qw zq$ZarAhC6eb0^nwDoyTS7hz`$21`%g&MB`S3^WI1Rx!vSZ45UAL_1h-2+2*5>tK7p zBQZmDzRoP273mkugD>cYT$Bo(%*v%B9{^NZ1R_9siu^!?JWR+>lXr3qS3G0DMiU}J=+1OT~477_pe diff --git a/civicfix/core/__pycache__/models.cpython-313.pyc b/civicfix/core/__pycache__/models.cpython-313.pyc index 7f5d826ba841edb754e9c730018c3e721c738b9f..145a2a62e833302b67051a6c127d6ecb8ca672f4 100644 GIT binary patch delta 2151 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 diff --git a/civicfix/core/__pycache__/urls.cpython-313.pyc b/civicfix/core/__pycache__/urls.cpython-313.pyc index 9d1697098a9d1fdab67cee47a2268889eee4a006..136a0af6da75d6612ab0d60b58ea788f18369df8 100644 GIT binary patch delta 352 zcmbQh+ry{+nU|M~0SJyNuF0@vWng#=;=q6?l<_%Zqq-cUC3BDzOa?&*iv+V-GRH6~ zF$9aoums5i54$^|@LeRm=ARYPw zMPlhHnyQnFn65bJ6qgpH7A2ab$S6KJjU}3?h;Q;f7Ii5>poK+3AVL^Kh=2%?|BJ*X|7Y>! zQUo#?fwGg%EE>ZcB!`e^m^_hj-eg`TIYx!aeoW%LiXesh{6(VaN}9@(r!ZaFypma- zkx^{&NtWoznye};0zkc!eOM(YXR*3*DF8W)KwNA#c^7NpWP7$l+=_zyOpV+{AS(dQ C(IG?t diff --git a/civicfix/core/__pycache__/views.cpython-313.pyc b/civicfix/core/__pycache__/views.cpython-313.pyc index 110248d484466b3ca03ae532db8d72827a8e0c4b..a4513e6305d693d045e9cefe6f1d3bf43e3aa59b 100644 GIT binary patch delta 3716 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 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 0000000000000000000000000000000000000000..637896402c62ba8860190232f2260e40314149bc GIT binary patch literal 1578 zcma)6O>Epm6dv1a$99u;*GV8PO#{gyu}ImZ2L!3AN~ql&lC+?m1QE&V$ZJm=7sn1` zZ`JgGkSg`uOC`jq$0GI6BS$#Fv75`T=E8wfPTgqX&YN+zP$g-x1W$Nlo0w;2*XD|+69x65cKnS;LDz|r{ka>BOCK)$&(tyU9UpN-)*pV>!Q4!f)nVG3rVH#E! z6jpNe=IDO|ioK`>m$1H|EGpPoQo-x&DPAM4*>p~{nb>sg<~zr2&GHGlsS|V;j_a_6 zZG2`)$D>Qy8>$+EsxBUnhI2tx`0SGUmiTiJf9aI?GOoNe-uXZI7j#y}OMc2IpIlsA{FDTA*JJq(O>)xCD9gAWWm%hYGi3o~Q4-!iGw(C%)KL$n3r&;OkNt8f!Y&Td|jX1L5sB=2n_O=9uP`k1`rd zbcw6xX-$LS69Y$thKV8K`c_2afSceM9!CjHQelQx(IlXW zAJL47Tf-}#$2ny;MX_HT^~08`Wl=7J8;iKT4Bd#rWR>o5Be>%wVanB@#Z7sBsG6I& zu}*GntgV4>oO-zo=GOIXj}==x-KE33I7vvB!)bkBBWF>oozsjECPs1qFXAo#it9&r zBmYa5-l2Y82wTxTSJ2}Ad#zpI|1;u=6A(!jIpXv+-H<`zB>}Vwh~3>|1|*V;7^v(e zEDurNK-R~7O`R~lU+de*8tQPY&XqTK&F(w1PbYq!>p0g=^t$+3S+B5a=N;q03Y#Bxpl0y%1*`R-RWE*& z^&z$FLvZ8PE4!Q;ITl3=1#1OVT{xOoi&?zJE`tdFRg}%Z($^G485l_U;1BfCU&f4L RJhHpxYNuTN8-XAJ{sHegibDVZ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8468f2fcdc7e0ff543fb6250c0b010d3cac454e5 GIT binary patch literal 1055 zcmZuwyKmD#7(YL2oAg22LZNDTG!kS9U3e5Bq)MbiQz{fUl`2_1Iri1KICeNY6=gt3 zNX#t#A3$PYK+G_)k}j!kVPNW(DzNjNozSAz(%pTp`}y>(4GLIqI)PO%~`OH^8xseBbpq3g($E+bR6q-u&b0LaeUQg%|s6N<_q zcUFrcGa9}}?Zl75n5m7(B|+?Dh1s6#JH5|f>>(?CGZjsNN~U;Apt7Y@2Q??|@m`>l zq3YO)VBdtCVk(wioj9GVj+_y@a7JwEbj(!EAyZpWOnpIu&W25cj(F#aIi^1zeBbX0bsj0v>SwpNmP_T4lY3!k<+-c z<&(hu0Ah_Y4W}85nSr4dw-peua~MBw*#WNxZxrJ#pTZauCW9?`(9WfyG(Vr?a+&u=+>E*HVUJ`G_$;hS8FRP%!ry~FfWrB#|g}i zgY6`te!Z2D7-KpKm_1mCEjsrt$KUatCp6k7PLerW{tJti z;G`Q@F1BHNi@GY(D?(QiC)C#~T?6Uk9c_AFn?ATWdvJc{AV1Z~&+X^u-WNWteO>>) z@ol41uC>dxPI%}^Qw!`Be5nPAvC@&9u3L5(UsJ^`evEV4c=K)*`H#Tq2FjTJFP~DI5}Gy5X~>`oyij|P3HFfQ09Sw&UxBSF34+j5k#OxN Wy7^np3Fi`8x_L< literal 0 HcmV?d00001 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