From 27d013e853c7e37da5626224d3e6942569376563 Mon Sep 17 00:00:00 2001 From: Gokuldevx Date: Wed, 20 Aug 2025 11:35:11 +0530 Subject: [PATCH] major updation --- .../__pycache__/settings.cpython-313.pyc | Bin 2461 -> 2513 bytes civicfix/civicfix/settings.py | 12 +- .../core/__pycache__/forms.cpython-313.pyc | Bin 1502 -> 2960 bytes .../core/__pycache__/models.cpython-313.pyc | Bin 1002 -> 3504 bytes .../core/__pycache__/urls.cpython-313.pyc | Bin 718 -> 820 bytes .../core/__pycache__/views.cpython-313.pyc | Bin 1015 -> 5091 bytes civicfix/core/forms.py | 32 ++- civicfix/core/migrations/0001_initial.py | 35 ++- .../__pycache__/0001_initial.cpython-313.pyc | Bin 3820 -> 6040 bytes ...lter_user_user_permissions.cpython-313.pyc | Bin 0 -> 1269 bytes ...lter_user_user_permissions.cpython-313.pyc | Bin 0 -> 1070 bytes ...lter_user_user_permissions.cpython-313.pyc | Bin 0 -> 1053 bytes civicfix/core/models.py | 51 +++- civicfix/core/templates/core/base.html | 74 ++++-- .../templates/core/citizen_dashboard.html | 240 ++++++++++++++++++ civicfix/core/templates/core/login.html | 54 ++++ civicfix/core/templates/core/register.html | 49 ++-- civicfix/core/urls.py | 4 +- civicfix/core/views.py | 87 ++++++- 19 files changed, 578 insertions(+), 60 deletions(-) create mode 100644 civicfix/core/migrations/__pycache__/0002_alter_user_groups_alter_user_user_permissions.cpython-313.pyc create mode 100644 civicfix/core/migrations/__pycache__/0003_alter_user_user_permissions.cpython-313.pyc create mode 100644 civicfix/core/migrations/__pycache__/0004_alter_user_user_permissions.cpython-313.pyc create mode 100644 civicfix/core/templates/core/citizen_dashboard.html create mode 100644 civicfix/core/templates/core/login.html diff --git a/civicfix/civicfix/__pycache__/settings.cpython-313.pyc b/civicfix/civicfix/__pycache__/settings.cpython-313.pyc index 9100e234d3b8f91ec3feb9b2766f46f58e2ee598..17153dbd0b4ad43d02d748252242571747cd0abe 100644 GIT binary patch delta 206 zcmbO$d{LP9GcPX}0}#w8T$=G_BCjN)#YS}_MsCF->0qTInRG@?<;e+*uf?iFlJkpF z^%4sTiuIgioLQ1tm6{iyl31LPl%H6Xa*H)5KOLx&B_lsKRa18JNj7IjHclUZcTc~`>>N>C zmOvLV0&%h7{2%b#BYemPnP5?miWNNAf|bNLFfjLa0BNJF`0`D!bRplr2wlp BKYIWG delta 158 zcmca8JXe_aGcPX}0}wR3EY4Uukynz@WTUzfBfCP8bULG^;^Y*@*KD^~lJkpFH>WZk zV^Zf%&MeEUNXx8mh^!elqjV!;QZ(ia$nZivZTWDqVg0jdE2 D2_!D- diff --git a/civicfix/civicfix/settings.py b/civicfix/civicfix/settings.py index b8c4d3f..8a2325a 100644 --- a/civicfix/civicfix/settings.py +++ b/civicfix/civicfix/settings.py @@ -26,7 +26,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'core', + 'core.apps.CoreConfig', ] AUTH_USER_MODEL = 'core.User' @@ -67,9 +67,9 @@ WSGI_APPLICATION = 'civicfix.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'civixfix_db', - 'USER': 'civicfix_user', - 'PASSWORD': 'Gokul@2001', + 'NAME': 'civicfix', + 'USER': 'admin', + 'PASSWORD': 'qwerty123', 'HOST': 'localhost', 'PORT': '5432', } @@ -116,5 +116,7 @@ STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -LOGIN_REDIRECT_URL = 'home' +# Add these settings +LOGIN_REDIRECT_URL = 'citizen_dashboard' +LOGIN_URL = 'login' LOGOUT_REDIRECT_URL = 'home' diff --git a/civicfix/core/__pycache__/forms.cpython-313.pyc b/civicfix/core/__pycache__/forms.cpython-313.pyc index 630c814198b32384ff02ae392a54b0638cec2513..f9aea4a9ac6021ae37c3bdc50fee8e5ecff4535a 100644 GIT binary patch literal 2960 zcmdrOO>f*pbnLagpXnwvp-GyiO9_Q-(Uz75k%~s3G=U^)3UMMKv0%C0$;QEJr_bJ| zt%?+JK?lPU}(lncrK*|v=Ps>v=h#?-+m1$*41$9aT zEysG<5vHsCOxKFB;aDUC;vqHOmYP6nvM9}VHqLwI*W8~hr}F7-TFFa7UGSjdBhoqV za~K0|2Dax;AaPqF4p}I)Ak<0UuX5`dd8|dJFHox@14(Bf>k`C@%4}$jXE!j?M%H5^ z5@@)-uXT-PxUT4`u8qi$Xlj`lmLpC`>gjoQTGEsKY$>rMK}t^nQqD?{8Dja2I51`h z_BHO#^0Ms*@KhDL>Re3{3E-EiHt^DR7AX@oS)?lF6~p0fIaq`Y(pofZoXhGtT-mE1 zs3%aHPf!;<2Jy0zSH-|{&M%zjfw`STAvIMbs%THwtZXxGK`8>syc*c4C7MObQ&vJ!&tDv4;-aHobnHygvM<}#$KWk-D~Kiw_LZXL0WXHZ zQdqt!6w(N~a0_WwC(C`qwmQ4lRM9ngOM@dwfFT6dt_=}q3VsyD^`8-pN_W|3_>ab1 zY@U6NZqg-P9+6ymp3M^Xo}tIclk>9E$OXjP^C=C!rVL%hT|^AWy!1u`Gci-<<=LjZ z1{r_D4K#=AL#(FFOkkF1mRG6R0rcP^yo_M3rU})rE@O%)zImC8jOB3CJXvMG zWxH>z+_=6zymtLwHovB9_4IA_9Np+Sy1uf}b7D=oooYkrAH;?1U+J!`Oy`}+8Hfqvbtpg4s1_J~R5f~&ub`z;_isK0iu~1==99uLYnv;#fKnN9qSBSr( zp{vCm$1rLVoJ6Wm<>viJXNoBxKn|;qAb5h&mFe2d4BXEQtd}-2$5+R3e&@o?3+wR9 z_(tZ;>iAI6`Y zY`OSuI=x^?3R84D^xS@uO5U7-{#`V(P8erHM5BZbnO~#X|1OE)by6!&pn#xFrokzs zA0~#k34|6Po55)UR1$!~v2C!D^WY2t+ScN=-7-|CjBjluVVje&ZO58zPSF)m%W7T| z$*}8&-I#9OA~TKz8ugn9T4fe-|88?C#@jsxjx@{L3#`8sp3?%bQR7oZR|_&WYe|n6 zV%UrmkS-_lDY374>!|S^!>#$aPy;(~xJZ|{Z-Ko`?+lT!%z&3YxGEBkhj>VH@E=r5 z*b*JjEk`Id$-vttLtZ<4E|hSQ=YmC^v*}@yv)xP0!EAU<#$cG=UEZgh`Rlv@LLCWe5WzM_3GjNPlFPO5B}vm#cwD%<(H&=(#E4 zD|V^O13xTsq0qhQbq;rvG5oU#s9*L_zqHo0KY9;s_U7;R<{$JP-|8FO>^pY9@7ROB zH@6PvejNQ_^w+L?)6T|Qm5qb$qqwp^bu0cfHygLt+TK1)YO1+=uk!)X2vAu0QTu)@ z$JNvhLl8-){j~3*oZ>$Tva@9~^%8`hd`QRC`78 zJiS9Gki%2=Tt_6{i(WOO@F{Xj`1$W5_&X*^(nHq!kiGLeJG`TGO5OJc3p)(|J3}p# Sgp~SL{XY9$7K^?V-Tz;gbx4>1 delta 499 zcmX|-PfHs?7{+Hdvzug_#6KiWYSnBFZ8Dc4g7#oZ3qn8wUJ|83VM&wGENm2K5-2?s z@gRa1!`vm%dp|+HK`%Xqfq3_(tp$(1?^-&rzh$21nR#C3B7gNH^Cz8l39R4sZ{3kK z%oJ#KST4_dq(GKP!=57z=VNR&h7m%fvmfV);rB|M8n&&3)Fb;+pU~nGrzRoA(IAkb zb3Fyo8n=wwYkl@Zaj@U-N>}eV@3du=DA%v772vM*iRSbV>y4Lzd=fsD0-TcZboR_P zGn?m*TmV59_1O72$DOSjv^edCX>06d- zV53QHbX&3(h_Dk4Ba7&l5c6oK|CO~x82Ub^vI452fcKB335+6aH1w`rO-0=(ZSlAs zyX*BRgTp*N2M%izZ+nNGK`5$n8Mb(#dJedWQA#JIFd=KeJ2p+TzZPHrCGd|9KLD}z BaI*ja diff --git a/civicfix/core/__pycache__/models.cpython-313.pyc b/civicfix/core/__pycache__/models.cpython-313.pyc index 8c0e36e7ef18bcb00e1c32f110206bb1bbdfcc4e..fc1ad279bafe9b41c9814e2c709c2cb34cbd3497 100644 GIT binary patch literal 3504 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 aILrXR4{~{*Ozo4|Un)R-q-S9f($s&1S%>QY diff --git a/civicfix/core/forms.py b/civicfix/core/forms.py index f41ee0a..77787de 100644 --- a/civicfix/core/forms.py +++ b/civicfix/core/forms.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.auth.forms import UserCreationForm -from .models import User +from .models import User, Issue class CitizenRegistrationForm(UserCreationForm): email = forms.EmailField(required=True) @@ -18,4 +18,32 @@ class CitizenRegistrationForm(UserCreationForm): if commit: user.save() - return user \ No newline at end of file + return user + +class CitizenRegistrationForm(UserCreationForm): + email = forms.EmailField(required=True) + phone = forms.CharField(max_length=15, required=False) + + class Meta: + model = User + fields = ['username', 'email', 'phone', 'password1', 'password2'] + + def save(self, commit=True): + user = super().save(commit=False) + user.email = self.cleaned_data['email'] + user.phone = self.cleaned_data['phone'] + user.is_citizen = True + + if commit: + user.save() + return user + +class IssueForm(forms.ModelForm): + class Meta: + model = Issue + fields = ['title', 'description', 'category', 'location', 'latitude', 'longitude', 'photo'] + widgets = { + 'latitude': forms.HiddenInput(), + 'longitude': forms.HiddenInput(), + 'description': forms.Textarea(attrs={'rows': 4, 'placeholder': 'Describe the issue in detail...'}), + } \ No newline at end of file diff --git a/civicfix/core/migrations/0001_initial.py b/civicfix/core/migrations/0001_initial.py index 7d6412f..1478ea0 100644 --- a/civicfix/core/migrations/0001_initial.py +++ b/civicfix/core/migrations/0001_initial.py @@ -1,8 +1,11 @@ -# Generated by Django 5.2.5 on 2025-08-18 15:07 +# Generated by Django 5.2.5 on 2025-08-20 06:30 import django.contrib.auth.models import django.contrib.auth.validators +import django.core.validators +import django.db.models.deletion import django.utils.timezone +from django.conf import settings from django.db import migrations, models @@ -15,6 +18,15 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='IssueCategory', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('description', models.TextField(blank=True)), + ('icon', models.CharField(default='fas fa-exclamation-circle', max_length=50)), + ], + ), migrations.CreateModel( name='User', fields=[ @@ -33,8 +45,8 @@ class Migration(migrations.Migration): ('is_moderator', models.BooleanField(default=False)), ('is_resolver', models.BooleanField(default=False)), ('phone', models.CharField(blank=True, max_length=15, null=True)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to.', related_name='core_user_groups', related_query_name='core_user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='core_user_permissions', related_query_name='core_user', to='auth.permission', verbose_name='user permissions')), ], options={ 'verbose_name': 'user', @@ -45,4 +57,21 @@ class Migration(migrations.Migration): ('objects', django.contrib.auth.models.UserManager()), ], ), + migrations.CreateModel( + name='Issue', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('description', models.TextField()), + ('location', models.CharField(max_length=200)), + ('latitude', models.FloatField()), + ('longitude', models.FloatField()), + ('photo', models.ImageField(blank=True, null=True, upload_to='issue_photos/', validators=[django.core.validators.FileExtensionValidator(['jpg', 'jpeg', 'png', 'gif'])])), + ('status', models.CharField(choices=[('reported', 'Reported'), ('acknowledged', 'Acknowledged'), ('in_progress', 'In Progress'), ('resolved', 'Resolved')], default='reported', max_length=20)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('reporter', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reported_issues', to=settings.AUTH_USER_MODEL)), + ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.issuecategory')), + ], + ), ] diff --git a/civicfix/core/migrations/__pycache__/0001_initial.cpython-313.pyc b/civicfix/core/migrations/__pycache__/0001_initial.cpython-313.pyc index 4682d1cf79bd294983f03154d877069238c8498c..4854e70c94703a81eca98b4f70236c35f8462b43 100644 GIT binary patch delta 3070 zcmZuzOH3Qv8J-!B-w$j81OqmP@QB03CIoV8LQ)6;LU_dS0d7J`CKG!wLyX5gGY$l) z^_A{jc2P8ovZ}J_qPs}9s?trHzydN5z~2RC+b20 z$_tWH?rszsVNnn2Mck%G|1BGC?XBZEvn2ZUO}@hwWl<1ah*`j39~|y<_M(0?K#dI& zx~UgktkYp|H~{#YE}@}1>$3)irePGRV~7$Ss5wW_+Cx#d}8M-Y0ko;Ef$t{a>I>PvYvw$w_>wda;l7q6}KS$Bwf#2^4lM#sjEz z0M*_M!Y}Tz=stRYHfW}PKpM)#3_9Sk7f-h2^Pl(;aYC8{sQoAdkvOD*Q^GTE^pUjB6bjF91GEQcslTl)cGps3TOU!39+(K#G42xme zlBG;aHTX4E!iFs;s%rC|f>S47)|7}Y_URFGz>Uc}$KbR1Oa?d`=DlX@Cmj2>l*tL2 zw66jCJM)X#9&&~ryg=lRXJST9iJF2{?4yh=8LOH=qC9ZWeTeMCChDPf()Z0DEJ4;! z9MliVs*sd5`9Oluv0pdYhT93CntC^}Ye{1zpHmM)`fXci)bJ)1ED3ptOQ;D9`zhzZ zA?CI12<3+@HNQRjA8nUdpZ;&##CfCjR8`1Hcvn_c^3v3=*!#RZF=?2|Qw7XEU9=Au zXf|;Nfnil>fmFk`D`v$sXc=Z&WW%h<8r0)kqGih{Nm?b?!K&p`l3~v%*>r7d&TT82 za^MEXc}bvz8V&P?X(yL9_??`THcYuJJks)3n8yX03YrCbK9^C%lmPi2pjlBhQOm1g z9$LVLrJRB_DP`Ca^&N0sV)AKL*~>_&G)P?2XDE<5<*bmyN*YV5df;5hhT?UiW=~Zz z&!kj=7_4n^9K4>;9y1x%e0OkOsI4YEr|>Y$mFGD6iGJjmE-!m!Xd z^Gmod2lQXrm&bWx!8t>LE|Y5#n+eBtQ%+9<-Z?TehJ9vR#P#hebiY327_-=ku>oCj z2!%N)gI1F}7IvW#YI~l*G1}(jj5NEiNmx~I99CIL*)7eGoxxuBL7&aOhs2J9n zX*4r^YZjAh-e{U$TfHr;q1lA6eD~Jul3_!$tHR3K(vsm&pkqZ%|GlG&74`2NGhQnJ zMIJ8rs}{39;p}BY`a@@6{`^r}#UC#F!!J?EA1it%j(x!wmP%-(92$A4l|qw6@AYHf zsaA1xxwx@e@;@wkA64z<7SB7g&F-i+e{;{-#TAOTcd86?z%FsHh+Kv&KjeNymL=1w z=^ev#t(k!Et(%U07hbGa`mdGyuf6UoCiZ|k&pjfVD)(cu%)kLylBPU4H}H&}+cQ-! zG`D!F7nz>H7W8aW+}*19OK$r&}G$#AbISqZMohNbLQZEEbNHZU1+I@NSAut-P( zD1pC*r(v4}C;5zY1OEg_@{yvBz@utnS@yk!VSC>){coATTPF0D>G~5B`ZII!AC_sB Twfxjk@%ELxeg9+#MNR$}NEc7? delta 1268 zcmZuuPi)&%827UsH+GW7X`3|v>!#@+51Mq)0a?e^ZXj5vPFfxyG*t_3^XeEJJAHQ6 zQ6x5r3lc&idKZq9cH)M#GiV1SPDpS<@+1()N=O?j?81fjoD?<*OYi&hd%y4ZzVGvw z_1{b5$BBf((eIm$d!5hXgYhhQXRxRh_$%UO1V=U{ENNVpt8h@rb5PulG{*-Y7h+>3 z&?85z?&{#{xmbxs^gI4h82s{KM24{jPp*TR7!MP0ydkXeFiBKCmyn~fA?598 zvr1H9IyM8f5jH#Op#tYdJx~T;h|R-=QNBoSfNX{~vhZ{Z!J6UuaEfWk z5`3-!X!iUw+43`4ZPZ&G@^B^W_B8E{RtVGS7vPI<6`p~o;Y;CUFQ43;c_qAQz_Y`f zdW!Papajp=1o-OzZ>m`)@yH^m(_Q6fSNS@C=Nn=j;4Hj=bLP6f5y)GXi4EU!og^Z(=h5|Yv}btUfs5Nmcj&k}A1GbpR?9|?>36V7Zpfu%5ZSQ}=Yv3W`nFB6 zPvwJ5FxEzUM&I@Wxr6Lp%SX3-dX-Y{7IRbwPcl=WCQxn~w$(O#7kiZOgHn#A|0SsR zpD1OJ%Q8R>$(GmJwS4OkIXWGHEXS8`|3}X-iezH9-}4TQw>n50#+u);JgrYh(sq#T zI;N-jZcW=5LI;*@YbNqFgZduAUCZ<6COlefI6i7qu7-@=j^^%BA!Ol^YAuK|$(fdi z{6J*kp#tVvO}p)#3MTjX!G z0@g@5bxD;N$c#*n_Zv_4QH>(L`a`O+l;;-D&pVA_bzEFNvt3RpLzc`vu8J^?* E0d#dbP5=M^ diff --git a/civicfix/core/migrations/__pycache__/0002_alter_user_groups_alter_user_user_permissions.cpython-313.pyc b/civicfix/core/migrations/__pycache__/0002_alter_user_groups_alter_user_user_permissions.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b64a15325b18a0a0b0f302d0bb20508f5f1e68c1 GIT binary patch literal 1269 zcmaJ>y>HV%6hD8&jopN#X%Xe4l0{ooFQFhYv_b_`iJ@PhUI&JVljB^HD~_F>FIAff z35l7d{{cv_^-qB=jc#S?mMS0y7Vhl2Nf~;Q-}n3Zy?f6dnIx4qXq(NOq z!XV;CE39EZ@}w(0H!g(1u@H_x1yBV7szQZoP=(q^UCM;2_G3iWkb2IJlOx}s;Sa&$drA3a8{&oD)uNRT?A5krC7!l>mQARh+})|BC1NHNbXig-i8HM&6*^#rQ5DzKMWd?&B8J-N|59|NgOvXEnQ0%RF3VA!829g4c>9HiTyTW z_<->o#lFjMEiR6iQf;q;>0x41S;%wym{!9G#}-EugO$Tf{JLz5XX*s|HC~L{ZDZOZ zQ6%TyorP`ekvj405vyGf>9CtJpSmm<4Wqh+xb_i4j6RC<4Qx5%Jd5H=5aJd>qOy*U zg`7iZujBghr6XQI$q;-J;2@Ol8gApDh69h_h|2Zl)(bhYm$DJ6OG9DP4GwogNnb^sY!8hzIbutIHLS>=W-b4R^7}5~WTKDze+k@Y|?} z`CnO=WQ?N=^#8S%+lN%HTuh`8eHP>+=o`RX?q%(MMw>F;Z}fA(oIK6WoMdNuw`O`1 zw|k}O)6&98Y2hpT{><$Iu&1o5g1u2a$(kyYY*ky=&HgJTa9s&dGGhWX5ZHiibV^EbHDqs{Xqrbn-qp8cLfIP z0-OQ}pz;iCDn!{-iCP6S;5LBjEP$G$>>9(M5r3d%m}o8C&Rs~sR=L#)TEt~R98qp` zVjqXp8^r)nyb=a&0ZxGfhynpop+YpMLTy2jE7`cB%{NeGqGF#r_F#9Fb_>= z!AV$HHDGa7TULk(uMw+Nvdi4u9_Do+YZ001Zo=Apv0lHsg4~c{f)Xl7Ga!_q$n9X% zagR`lqZVsRcP}QGuhi@HKipd+PP%mbf%KIwCY^xNv<H zwHcEtYX`I{18RI)em6^P#{#Q*9>sze+E1DB+sMNf)KY55}rwj z1uh_Tkho#mO~gwm>uwlCIEtm&$6XxxIPwBaiQFe{J&~i>kPj1GDoWdKbi5Z!nrgWf zi~6oM>;^)V3G5-4F%mQqhABd1Rs;^j1$^u2n&SnBf%k&M``BZd&{{&^Lg&*2{17bK11=W~*NS=G1w9?kqpoyE)gpKHsa%oL834 zDodZ(mq&gd04Dw~!H~KyS*$+R1bePI+9d!}FSW}F-L(3eQ8C_bl7-<1cWj-T{=OTv z;+o$`Ta~saOG(z7`7R2?^AEEDtdl!JRK%sX1nFyvqWm;~Vt+S^it*k$FE4y8FZ=*P HNTYuNU;{Wd literal 0 HcmV?d00001 diff --git a/civicfix/core/migrations/__pycache__/0004_alter_user_user_permissions.cpython-313.pyc b/civicfix/core/migrations/__pycache__/0004_alter_user_user_permissions.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce54275febdee37ea5b3ec815a10934d9f6b41a0 GIT binary patch literal 1053 zcmaJ<%TE(Q7@vJ~=`O9UMIs@RGy;LWl&W}u7z{D-z$=8|xH4>ar|rOYx6Dona56FR z;K>Vrf{Fe&%7tdGp174%3W=)t$^$+BX#1HN8HQxh?ZHC z#AO*!;gj;0G?5W6ZvIhU6lB_!p^=XdacmnrQw!Yin43);v=PH+jOQp0T!#ImC|(*! zCml@BQ=Q5po;$^~7R5Nx*qRum9A0YIWjlDLPH^CV0Xz0M&!WVF5VsH#o}B;-oI~iO z;|59d5HFy#nE?rL7)i5_+c@-b=n))Kxjx)lmz{qtAEvrg6t>;)d_R&j(Q+#i_1!Jh zBtkJ0*h4O3l+-#5#|Y7B5!e?O@U2&?jz><3w@afV?6Fj+lQTy)&>8NgBj&jLzd2Ug z=Tt6ALL`U}1bGj71~6B<+2vkFdtkiX>g9krah;vH%Fc8j&UEk3c1u&&rNyh#;%D~t zrQZX9DVwTbhw8CpZFOA}Y*%}u-2yOipxut?rq$DolJRbX&J8}?v2||xM{d}NDt;|# zRnnd`C0TFkJ1-E=zDNhKMi+#rh#Nl=q^Bv0^2-2<{lmyB#z*VAIQOkM_Y(*qiT(|2 C6)@ib literal 0 HcmV?d00001 diff --git a/civicfix/core/models.py b/civicfix/core/models.py index 607962c..050a1c6 100644 --- a/civicfix/core/models.py +++ b/civicfix/core/models.py @@ -1,6 +1,7 @@ from django.db import models from django.contrib.auth.models import AbstractUser from django.urls import reverse +from django.core.validators import FileExtensionValidator class User(AbstractUser): is_citizen = models.BooleanField(default=False) @@ -8,5 +9,51 @@ class User(AbstractUser): is_resolver = models.BooleanField(default=False) phone = models.CharField(max_length=15, blank=True, null=True) - def get_absolute_url(self): - return reverse('home') \ No newline at end of file + 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', + ) + +class IssueCategory(models.Model): + name = models.CharField(max_length=100) + description = models.TextField(blank=True) + icon = models.CharField(max_length=50, default='fas fa-exclamation-circle') + + def __str__(self): + return self.name + +class Issue(models.Model): + STATUS_CHOICES = [ + ('reported', 'Reported'), + ('acknowledged', 'Acknowledged'), + ('in_progress', 'In Progress'), + ('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') + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.title \ No newline at end of file diff --git a/civicfix/core/templates/core/base.html b/civicfix/core/templates/core/base.html index e054ff4..b6cc410 100644 --- a/civicfix/core/templates/core/base.html +++ b/civicfix/core/templates/core/base.html @@ -35,32 +35,56 @@

+ +
diff --git a/civicfix/core/templates/core/citizen_dashboard.html b/civicfix/core/templates/core/citizen_dashboard.html new file mode 100644 index 0000000..bfc9d1e --- /dev/null +++ b/civicfix/core/templates/core/citizen_dashboard.html @@ -0,0 +1,240 @@ +{% extends "core/base.html" %} +{% block title %}Citizen Dashboard - CivixFix{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+
+ +
+
+
+
Welcome, {{ user.username }}
+

Citizen Dashboard

+ +
+ +
+ +
+ +
Quick Stats
+
+
+
+

{{ user_issues.count }}

+ My Reports +
+
+
+
+

+ {{ resolved_count }} +

+ Resolved +
+
+
+
+
+
+ + +
+ +
+
+

Welcome to CivixFix!

+

+ Report community issues, track their progress, and help make your neighborhood better. + Start by reporting an issue using the button on the left. +

+
+
+ + +
+
+
My Recent Reports
+
+
+ {% for issue in user_issues %} +
+
+
+
+
{{ issue.title }}
+

+ {{ issue.description|truncatewords:15 }} +

+
+ {{ issue.category.name|default:"No Category" }} + + {{ issue.get_status_display }} + + {{ issue.created_at|date:"M d, Y" }} +
+
+ {% if issue.photo %} +
+ Issue photo +
+ {% endif %} +
+
+
+ {% empty %} +
+ +
No issues reported yet
+

Click "Report New Issue" to get started!

+
+ {% endfor %} +
+
+
+
+
+ + + +{% endblock %} + +{% block extra_js %} + + + +{% endblock %} \ No newline at end of file diff --git a/civicfix/core/templates/core/login.html b/civicfix/core/templates/core/login.html new file mode 100644 index 0000000..d4dd8dc --- /dev/null +++ b/civicfix/core/templates/core/login.html @@ -0,0 +1,54 @@ +{% extends "core/base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} +
+
+
+
+
+

Login to Your Account

+ + {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} + +
+ {% csrf_token %} + +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+ +
+ +

+ Don't have an account? Register here +

+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/civicfix/core/templates/core/register.html b/civicfix/core/templates/core/register.html index 56798e5..ff42358 100644 --- a/civicfix/core/templates/core/register.html +++ b/civicfix/core/templates/core/register.html @@ -1,5 +1,4 @@ {% extends "core/base.html" %} - {% block title %}Register as Citizen{% endblock %} {% block content %} @@ -9,38 +8,50 @@

Create Citizen Account

+
{% csrf_token %} + {# Messages block - FIXED SYNTAX #} + {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} + + {# Form errors block - FIXED SYNTAX #} {% if form.errors %} -
- Error! Please correct the following: -
    +
    + Error! Please correct the following: +
      {% for field, errors in form.errors.items %} {% for error in errors %}
    • {{ error }}
    • {% endfor %} {% endfor %} -
    -
    +
+
{% endif %} - +
{{ form.username }} Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.
- +
{{ form.email }}
- +
{{ form.phone }}
- +
{{ form.password1 }} @@ -53,20 +64,20 @@
- +
{{ form.password2 }} Enter the same password as before, for verification.
- +
- +
- +

Already have an account? Login here

@@ -79,10 +90,14 @@ {% block extra_js %} {% endblock %} \ No newline at end of file diff --git a/civicfix/core/urls.py b/civicfix/core/urls.py index 0dcea45..5b4ba95 100644 --- a/civicfix/core/urls.py +++ b/civicfix/core/urls.py @@ -5,6 +5,8 @@ from . import views urlpatterns = [ path('', views.home, name='home'), path('register/', views.register, name='register'), - path('login/', auth_views.LoginView.as_view(template_name='core/login.html'), name='login'), + path('login/', views.custom_login, name='login'), path('logout/', auth_views.LogoutView.as_view(), name='logout'), + path('dashboard/', views.citizen_dashboard, name='citizen_dashboard'), + path('report-issue/', views.report_issue, name='report_issue'), ] \ No newline at end of file diff --git a/civicfix/core/views.py b/civicfix/core/views.py index 58ab75a..9a0d360 100644 --- a/civicfix/core/views.py +++ b/civicfix/core/views.py @@ -1,17 +1,94 @@ from django.shortcuts import render, redirect -from django.contrib.auth import login -from .forms import CitizenRegistrationForm +from django.contrib import messages +from django.contrib.auth import authenticate, login +from django.contrib.auth.decorators import login_required +from django.contrib.auth.forms import AuthenticationForm +from .models import Issue, IssueCategory +from .forms import CitizenRegistrationForm, IssueForm def home(request): return render(request, 'core/index.html') + +def home(request): + if request.user.is_authenticated and request.user.is_citizen: + return redirect('citizen_dashboard') + return render(request, 'core/index.html') + + +def home(request): + if request.user.is_authenticated and request.user.is_citizen: + return redirect('citizen_dashboard') + return render(request, 'core/index.html') + +@login_required +def citizen_dashboard(request): + if not request.user.is_citizen: + messages.error(request, 'Access denied. Citizen role required.') + return redirect('home') + + # Get only basic data for now + all_user_issues = Issue.objects.filter(reporter=request.user) + user_issues_display = all_user_issues.order_by('-created_at')[:5] + resolved_count = all_user_issues.filter(status='resolved').count() + categories = IssueCategory.objects.all() + + context = { + 'user_issues': user_issues_display, + 'resolved_count': resolved_count, + 'categories': categories, + 'issue_form': IssueForm(), + } + return render(request, 'core/citizen_dashboard.html', context) + +@login_required +def report_issue(request): + if not request.user.is_citizen: + messages.error(request, 'Access denied. Citizen role required.') + return redirect('home') + + if request.method == 'POST': + form = IssueForm(request.POST, request.FILES) + if form.is_valid(): + issue = form.save(commit=False) + issue.reporter = request.user + issue.save() + messages.success(request, 'Issue reported successfully!') + return redirect('citizen_dashboard') + else: + messages.error(request, 'Please correct the errors below.') + else: + form = IssueForm() + + return render(request, 'core/report_issue.html', {'form': form}) + def register(request): if request.method == 'POST': form = CitizenRegistrationForm(request.POST) if form.is_valid(): user = form.save() - login(request, user) - return redirect('home') + messages.success(request, 'Registration successful! Please login.') + return redirect('login') else: form = CitizenRegistrationForm() - return render(request, 'core/register.html', {'form': form}) \ No newline at end of file + + return render(request, 'core/register.html', {'form': form}) + +def custom_login(request): + if request.method == 'POST': + form = AuthenticationForm(request, data=request.POST) + if form.is_valid(): + username = form.cleaned_data.get('username') + password = form.cleaned_data.get('password') + user = authenticate(username=username, password=password) + if user is not None: + login(request, user) + messages.success(request, f'Welcome back, {username}!') + return redirect('home') + else: + messages.error(request, 'Invalid username or password.') + else: + messages.error(request, 'Invalid username or password.') + else: + form = AuthenticationForm() + return render(request, 'core/login.html', {'form': form}) \ No newline at end of file