From dba5db4b7dd5541ab88d7091686940cd9fe6b603 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 18 Feb 2026 07:32:39 +0000 Subject: [PATCH] Autosave: 20260218-073239 --- config/__pycache__/settings.cpython-311.pyc | Bin 5771 -> 5837 bytes config/__pycache__/urls.cpython-311.pyc | Bin 1653 -> 1759 bytes config/settings.py | 3 + config/urls.py | 1 + core/__pycache__/forms.cpython-311.pyc | Bin 2195 -> 3185 bytes core/__pycache__/models.cpython-311.pyc | Bin 11085 -> 12014 bytes core/__pycache__/urls.cpython-311.pyc | Bin 2124 -> 2122 bytes core/__pycache__/views.cpython-311.pyc | Bin 24735 -> 26303 bytes core/forms.py | 15 ++- core/management/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 168 bytes core/management/commands/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 177 bytes .../cleanup_requests.cpython-311.pyc | Bin 0 -> 2933 bytes .../seed_hospitals.cpython-311.pyc | Bin 0 -> 5163 bytes core/management/commands/cleanup_requests.py | 46 +++++++++ core/management/commands/seed_hospitals.py | 47 +++++++++ core/migrations/0010_delete_feedback.py | 16 +++ core/migrations/0011_hospital.py | 23 +++++ ...12_hospital_latitude_hospital_longitude.py | 23 +++++ .../0013_userprofile_profile_pic.py | 18 ++++ .../0010_delete_feedback.cpython-311.pyc | Bin 0 -> 709 bytes .../__pycache__/0011_hospital.cpython-311.pyc | Bin 0 -> 1214 bytes ...atitude_hospital_longitude.cpython-311.pyc | Bin 0 -> 1008 bytes ...13_userprofile_profile_pic.cpython-311.pyc | Bin 0 -> 869 bytes core/models.py | 31 ++++-- core/templates/base.html | 51 ++++++++-- core/templates/core/donor_list.html | 13 ++- core/templates/core/feedback.html | 34 ------- core/templates/core/hospital_list.html | 92 ++++++++++++++++++ core/templates/core/index.html | 12 ++- core/templates/core/notifications.html | 2 +- core/templates/core/profile.html | 16 ++- core/templates/core/register_donor.html | 2 +- core/templates/core/request_blood.html | 2 +- core/urls.py | 6 +- core/views.py | 63 +++++++----- 37 files changed, 427 insertions(+), 89 deletions(-) create mode 100644 core/management/__init__.py create mode 100644 core/management/__pycache__/__init__.cpython-311.pyc create mode 100644 core/management/commands/__init__.py create mode 100644 core/management/commands/__pycache__/__init__.cpython-311.pyc create mode 100644 core/management/commands/__pycache__/cleanup_requests.cpython-311.pyc create mode 100644 core/management/commands/__pycache__/seed_hospitals.cpython-311.pyc create mode 100644 core/management/commands/cleanup_requests.py create mode 100644 core/management/commands/seed_hospitals.py create mode 100644 core/migrations/0010_delete_feedback.py create mode 100644 core/migrations/0011_hospital.py create mode 100644 core/migrations/0012_hospital_latitude_hospital_longitude.py create mode 100644 core/migrations/0013_userprofile_profile_pic.py create mode 100644 core/migrations/__pycache__/0010_delete_feedback.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0011_hospital.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0012_hospital_latitude_hospital_longitude.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0013_userprofile_profile_pic.cpython-311.pyc delete mode 100644 core/templates/core/feedback.html create mode 100644 core/templates/core/hospital_list.html diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 50ad71ddd41eea55ea431048d273c9609069796c..404de93122d242d1ddaf7e10659a70c6acd600fb 100644 GIT binary patch delta 166 zcmeCyJ*&&RoR^o20SLCIPR(?m$ScYCZ=?DL7GcjQ<5bQRuPSZ^hA5L1=3oX*@69r- zAGw68*!6Q$Q!*3vZ?S@DP1DW%0`5%Kw>W)WT|6D*LxX&7aY2|t{{A6FJV3LH1VIEp xkod)6lbfGXnv-f*R1D-Y0&%g}<|-jJ7KsNuq79rkctvNhU*wf<-~vIgJ^&#=EEoU) delta 78 zcmX@B+pWvHoR^o20SMf@r)COFyBdzR2dDL*t5+&JK?&HvSic11<^&Tmh0S0S(?D_<-Nnqr7(6+P%~7<$yTSVdE0D+dfdNDoNdVOV0Be^P(EtDd diff --git a/config/settings.py b/config/settings.py index 103f1eb..cd49a45 100644 --- a/config/settings.py +++ b/config/settings.py @@ -193,3 +193,6 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' LOGIN_URL = '/login/' LOGIN_REDIRECT_URL = '/' + +MEDIA_URL = '/media/' +MEDIA_ROOT = BASE_DIR / 'media' diff --git a/config/urls.py b/config/urls.py index baccfac..701370b 100644 --- a/config/urls.py +++ b/config/urls.py @@ -28,3 +28,4 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 684052f515f12d21d208e2a8ee132623bac3580d..6c3785420c9a51d09571b8037cc1251005dda962 100644 GIT binary patch literal 3185 zcmbVOO-vg{6y9BX*K2zT0pbKOB}x-Q9D?1bO{GXl`jZ&UUr3XnN|uUcyn``ad!5;} zNKfTZsT^|PkSZKFM5#oHl7mkX#~v&7vX=H>?I}`E+(2;R(!Mu~1O7=`b-e!c_Pw_= z^WMB~W`1jH3vkf>B){YyN*wnWzSNp{DD1re;TflLDz9;QKFRYa3!0GkBt0N|RIldE zi%BsrB_(DPHD6v%$~-4bjySK=ya9rD#vpW?N3Gxl@#P-X=W`lyl&>eJr|+aj?@!O%djOs% z(RiDZw3*WjBk*|!`>HkXp|JM`gl8P#lDx_#1%V@;#hMMW^IF(|v0mYLtR+R}0eN*B z@qv$LLjWK6yDcd*AAjv#^@5Ms;1g)@ky`k;nesuVe#iZMQf zz-3Avm2#A*kRe}YLC2Nb~hq9aw>(IRLTjYQh8l1X(%hH z)T2^bb1f88?}%U|nj_8Uh^87Zxjj&F2g9)iJx^k#xl+L_#mHllDVaKrE$Q@oqnOT+ zSVpHL#_A+m{K4_!JZJ}e*#>{(BY@?1zv{_TD`K^?Z!K$eTwIaxM=?~|2XHsiMlmBa zgm4-GYupLMF_ICS6zxJq@HR`XtMM_-oTlq)DogcJ(edA2NKI`SH@F-V-r^TR^qnO_guAt!FgMP+F8(PXHhA`7izai;v2$ zdy{@u1m;KwUG=ds-bB2#6K3I-S71Iz4U=)k@oVXtC}u!54iv2P;f!7|sjj_*9Wrg2 z)VLc7G}bPz3_XL;jlfFT|ByU3#|p)gd05r1>|4sISz;QEm5HpN7XgqK#?Ju9Dw9#E z<133jE7IHU!8LKceRFB+gcTjNx)YV|gx#H}h6Yw=?9jmGx8;I$C2oaADxncOG*a!2 ztPQNk%4fEs)+b|D?|7wm-0mH(_FP&Et)DIXw)(AD!s;2T^o-d(V>^DaE3m@>toZPE zoV32iz%f#ayl3fbNx2JXMZkT+m;^W$*dgUAO24i2BUNM(#%_jP)a|!0xU<9VTT|r{ zSdI$!y=3qllA+`9qBO4aax~zLm{e35c;i1f-INBGI-=v5%jxtS^g};JI1Atei|+LxRm^4RWzcM6 zSwsXHL93VQO9mYRk-dZZ3d#yVi&Fqk{YECq$fPvfGUzZ^9q9qlNXDeN5jg%4xR)?y z(HMT(u-`LQeF_GgsPQYnvEn-!h6Ac&!eS4ws_We9wWqhr(Lc^vmnQM)nyPe7*de#B=4g4=8oFbJ;+0U`4#lhC!L@7aH)`zs<~u7qTM5tF;n`~VGFZMS4{qJE zu8v#biAs3F4o~a^C1e~xGvmCCjAIcsM0ph>N9e~WZ`4J(BlwY0&9IBQ{T2q7QrI1= zk0Ysz=|Wa__q1O3CCawM+*~wWG8dxkCSkbO3hD5LEhAf?o>rf*8w5o*vBTK$PvLC@ zj~}*Euvi+F@<6@;eZzg`7X1>w!`q_q7GTH2^L&--w(6fMH)Pd6Rc_d7^}OXix9T6* wg?Koyo54CW2pbU(XZAbWsUQ#8Z3ZliUDWR%8G8fh+YGpu@1lOcg^{hsKZ8HeXaE2J delta 639 zcmew;Fv_|&E;sp>6@RDn&XyVlnV)EuosQ&-yh);!cyv1Buk=}0HF!7BI-~^+PI$YCB4Mh?y*Tm zL6YewAAW@pi$$jXMq8F-{h*ayi9~&BZdb8~~y=z$MF>s1;vZAmi*)E%8 z)2g^^goQ%Y%eY&1T;;|qWhac_qVvYf&6=1Z$q6;CL{e%jEg7}4=~O%!l_QxX@j@?B zLmwMg>QPKP0Oq+(SLMP?-qn<|Ha)^&LsAvJV>-q+Q>!_8P_w->6+Nd6s!Cke?7PM$ zd!X${9O;06q#Xel%fJaj`YwIjycpbcx4he)ceku0?)3jDlXHhR+~K@CJbz-##G9M9 zxTk@1toK=5yy+vJG}F_TCgE(!hxQC!%QtVJ4g?Wy< z$<6YUpy-7xWp=fkEXqqp`p{B&2HTnnZCCka=zklkUS5UPmyMTAyW32f3*HYo+3{V!*6`eV4o>7VO*q ze;2c(fpz z(;1?sNDDSGp_4p=U4jTN0!U_Z5am9EegMrZv*C|&bHEGCT_YAo8qJ-aNyH+oL1dd< zBm_-bp{73snCBh{uDnpY#aYar`~Lb{bzk~}_x!=nI)1k==MQf9hw}cR>&~n>dvVj( zc*~LZ?az6J;cuZ~B|^{!TDDH>>O4L$7_)>UhWYw(YvOAZFQb%K@g*gQ3%^f(oKJ1 zZ?DJ0OAa9HoZnNZB6QQg+y81|j#KM*#VZCg83HpMb#?J0^onbbY)(NHQEqzlK!Bxu%` z2f~ri>EYpBnP4+NSDfA|tH{+@hCD-0R_x(}bh_f%>S^rljHwy*l9EWjp{63h{T}*7 z#Scnm1tVwSe}DZs_pkXzmKHR|pcYHv+&}s^ealcw@B3TmU;J*rh27#pp_y!iTih(0 zS1ojJO~dz!+Oi3*9H@F3FJrxmx-76hRytGDFoM0m^?;3wvJGAVhir$#Eo#=GWICm0 zqH!_`nvD)6-wN3UTI1mtP@6OR6}F4-*x zvV(asuwqoWydGYA{z^1bl3a(^w&ftbKn0E%}kI`@HYjkp7qjyFB zy0I#17-d-s;NWi{VCKHU;K&UC$w;bEu0vqdFXmHEXDvGLAZV5sV;L1FKZ%wx`g!%h zz!?xFgMJ{yR5YW)VbqUe$wXK6#gj>SM0s;sNoNYlPSAdDTP0F2Bn5V-m(F_q(pj9W z)Xi`c9mVqir{D{(*S;(B^ntgE@1g(kwsjzziHuMx?F;BYIJ4g8d!5(Qx3IqAA2GDC z)G?|Rv$D-HmKMgcFl`9*GLn%j4plPp3Kn@^G;zKV_K&gcbp$fvE&h7!X^lBt}oWjY)7}W9%$(2E$7e|rW1{mC)h@s$Vs#yku`znyF^%? zOUC4Z`wg}{nHabL+g^xkfz~y3&gn5#m5hmP=@8DuE_*g7+l1esjqUXXT!Kx1Ij7SK zA#4jx=)Z+76Fvia2PasI{~imPQbS~ z-HmJf9D(hp08tSoD(iuNCwD)^4hZi+O=Hh_{YU@XdQoJ7qBkT}(-%4}Me(?3=95WT ziR)jq17KjEBK$*Q)#cn8Eo^utn|T&9N)3QcjWnwErY?-5^Tinx-y|6I*5ba;@IIHRL&fk~AFsFDN>=e&P@jqV*=imSU delta 2555 zcmb7GUu;uV81LQsZ**bYwd+AiCNOrqm$lUPmXxm6BVg$Z;g z=q{$aneGO?hUqm-_kdoDI!$m^OC4xlX02sbALxG2S6fzsRF4*$R}AbmMH=WM?sM)T zRfGNXuZl0KapQv?u^LQH`cvg8nlXRE`Duftk*lRIScW*B<}5-h3Bswbn@9+L$XWzX z30xp(c@w?t3(y|xX}Vx-;6nM|t!~a7;RsJ3*<##gI%p4bYpG&iZRvyg0eaDXk_*uv z!-4!AM{mVu9tO#3gjN8J1K^E)aO12mE+mt(BJGiqDiJ#q2`xhsi4HpI>dN7fMj}4a z2EQbX5J9K}&{xD%BFPiVc4>xKa5Rd*BXlB+0O;P`swQXTX=$61ktQS(lckhMcA%q6T%aU`cXw#Lx_Y zg-y2%sESJHH?{5D0KHS&W*x%GTWMWgUv&(`*xfE1*hUj|XI|0GY^xp^(H*jun3jk< zE=yv0vYc$`5=s5E)%)V8K~hUOlE^yT2-(r?dk04oBl~vjSVqxNw00w~?d_rr+{?)f zSx;|x+qf?Ji?`b^eg427*}!_M~3M?jf2sh zAVw+-U#cgCj0~YP0{KkhQMD<+?Wbp(f^`Ocjmzny-!%oscH_e366+l_JZ8;E8`~6_ zkd)+%Za=DOlX6B#krYl#BPamCpsHkqBphfeeMBO_;7iTH@IJK15y~Z577Yl4`7_O9 zMJ}`XKU(%w1R0OW9(hdB=rWGBp(RGe*4|tTh)}I8*v}9FwydW=rK)1Tpd2qH7M@+h zsLYy{+;!(>7VPyb_eUc2%XxwctQL)eV;f)*J?*;PM9$*i3A%F4)v_sb9?b}c@;|Sc zDY|){rHm4ca@K=rkI|1p$9A$1n{|tb6~>#B$>pNYF*_IEg6@;>sdwM*DkcGGl`wCs3@0 z>Q1WZ$&{3V@-D`EB}~K&G#cV1ln_+v4S!|S&L!xicWs#SqmbvfBJXbDaTYdI-IkU# zO@O{u)@|>Int@)DWUiOI&e7BBdWv4VpYJtu?ny^&$1SfTFjs8g3XufS@ba1Nf+kZ-Jw;Vb5ks|tMAf_oS~H*=XU-!w!-`*5*n{vXe}4O;~yDtQf$cmv_T z`^0BB1;P3jfOd-Ra<9sLA6;<77aj3}BR)H@b{Cx8v#}*laNb|=1aI~%czPE-y#-J2?C?D^XW7o(GnGdpcX4aDru8cEn4nCk zo#GKvNpDBfuVa_gEjv|FN*RAD`e1-vo9v1(iiwp!%Y2qE%$cWe+lTg-)2cX?lD3eq zVF8T4ww_*WpK7n-TJM>jh569M_WL;g;EB;sH+4kmg$_Tx+OdbWblw`MwQ=ZKd7PU* Ock({7J$TLx=KH_;TuHY8 diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 77f725c45cb0d4d8b3fd4d9ab7b99a9af6160adf..116ac3842142db44aca461364847f8c1c3455352 100644 GIT binary patch delta 118 zcmX>ja7uu8IWI340}x1uPtE+ekvEumav`${A8$r}aY1HDVorQcW^u{pDa@vflW(#Z z@QVUfR&l{3izl@TobUu3bq!eaeFRhXZt Lfg1#i6oJ|Sbdw|3 delta 114 zcmX>la7KW4IWI340}%Z8o0|D;BX2OX0Dp05Qf_8Rd|GO1N>XBS_T+eG)yS1i(N diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index c9d8df3ea69e1da58bae81a7ceac0acfad91957d..2dedc28399e3445c8f4114dcb2063edaa7e8ebad 100644 GIT binary patch delta 6105 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 K-nW$})c+5Kd%C6o delta 5345 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 diff --git a/core/forms.py b/core/forms.py index 114e4ff..7f0ecea 100644 --- a/core/forms.py +++ b/core/forms.py @@ -2,6 +2,18 @@ from django import forms from django.contrib.auth.models import User from .models import UserProfile, BLOOD_GROUPS +from django.contrib.auth.forms import UserCreationForm + +class UserRegisterForm(UserCreationForm): + email = forms.EmailField(required=True) + blood_group = forms.ChoiceField(choices=BLOOD_GROUPS, required=True) + location = forms.CharField(max_length=255, required=True) + phone = forms.CharField(max_length=20, required=True) + + class Meta: + model = User + fields = ['username', 'email'] + class UserUpdateForm(forms.ModelForm): email = forms.EmailField() @@ -18,10 +30,11 @@ class UserUpdateForm(forms.ModelForm): class ProfileUpdateForm(forms.ModelForm): class Meta: model = UserProfile - fields = ['bio', 'location', 'phone', 'blood_group'] + fields = ['bio', 'location', 'phone', 'blood_group', 'profile_pic'] widgets = { 'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), 'location': forms.TextInput(attrs={'class': 'form-control'}), 'phone': forms.TextInput(attrs={'class': 'form-control'}), 'blood_group': forms.Select(attrs={'class': 'form-control'}, choices=BLOOD_GROUPS), + 'profile_pic': forms.FileInput(attrs={'class': 'form-control'}), } diff --git a/core/management/__init__.py b/core/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/management/__pycache__/__init__.cpython-311.pyc b/core/management/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80f29213d00d77e0198fca37e21a700b2c9824f5 GIT binary patch literal 168 zcmZ3^%ge<81ee36W`gL)AOZ#$p^VRLK*n^26oz01O-8?!3`I;p{%4TnFKhjb{M=Oi z(xlS7l2ZNDiqz!NlKdk5^8BLg;)2BFRQ=@qqE!9d#Jt4x)ZEm(68-r2%)HE!_;|g7 m%3mBdx%nxjIjMFQC{^$mh5Vs{xC||9rN;FV}3I-)`vD&&D&*Y2sZrEKH zV%ZXh9^94#hgKl9NIA3=1b;w}9DCfgR`O~kB&43W8Ns3A)Hhz+VMUO7s5+i~^WMHU z@4b05^IQKOk4F)-)K@>P|IH!v7Zv)A?J>_6fw_e+!i5HmP{gE;g{uo1#+gRO_Q1AXnQqkrB>^yR%Tz^=hH z!u6mL-m$EQA98mg+JiyF8tiBzVnlXqHu^h>wqcK7Z*{I7c^JM6{vQl-X$;kewqJ>} zGs~Y@BU+DQ_Hu~owM#JPmAG%3!=O6a80u@cyC<+O^+&LX_4#dD>DL;L)T2KmJXGg^ zM(bgqu{&XZE&LM1W$V#e9O}c~xbLqc4(wXT*c<8yK3;E_e;D^id_%os4-w_@LV7Vb1?q?Ko6;_)gHDxnJs5IPO)r&O)Z$^Q0aAPxf2z$MQ=QdzSv2bG4_= z{*3Mf{Qmut7cKWz;VA{Rr}UmYrBILyx{-y&GZ)V+oH*-pmljW-DqM8A!uiE>C(dfL z764%(EN$tzfE(_?i<>BGL^232Nk*w88?}gsO;~)%h_%rjTmq;fnrN&^idf@B>SfmD zPLz%HZzxi79zx|9?JbB?J0L2ma!~4OcXe^h^HAGcP`e;FfImYO0bl_fXKND+GLe+( zrdU=ho84F9Mb(hxo&o+y%q28>_1&PNUUk`ZgH&{lVvI&1#|^8?8>DRLF1NBS8$@&2 zvRYLPm-7P9oUvLpT=uF4Q(aa!wq)Xlmo6Q!|P_e!=da6;gw(eXPU z-kUU2c`KE-fsW>zpFK_;0Jfbv+DaXD#@}(?nd-18ee4+urV}qHX`Y3!qZ93s>DI`! zH8Nw5%rs9q!y`AZe81J)a)fkS*xwTNTf&qrOqs%zBaHkQYYP)CVPbpo*LU0d4!8Cl zHjikJSRl~<411%wve9FXXx2X6-ltoFVGD*S7>|TrjJ|cGj{q+JAI**zF>Z>n&}HxdecsCnvtZFe7BvP zYbEEb?C8|~~| zD?4Y->wgr0c-_hxcGj@?s?AqTzUuJF+h1Ayd(CrCV&glGcXe~l$`Zskdw3G_tW~(sx`!nZ3>ZoO{dxG(P4N)S-bwpq zNGLH`ixKLF_j8HRDt2d2L}Xu|Y&2Thv(?x3vc@14*LLsz~#ZC-xX)x3Cv HzMJen6VAVz literal 0 HcmV?d00001 diff --git a/core/management/commands/__pycache__/seed_hospitals.cpython-311.pyc b/core/management/commands/__pycache__/seed_hospitals.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b243ce412c431b66791640b401f76c8bbeecc0fe GIT binary patch literal 5163 zcmahNYiu0lac}*0?2y+%Y$s&%j+6MF_MIIbjeT~Ummm1-Je&&&iCEkogK&R zdT+j+Z|0l%X1HI4l<Ml%Vyl%z`#v7b0ph$t!?p`A$_& zNd_;+9e&!l9OU+L{CJKLm_ZjXgDkiPi-0}Ppv)qaS)3_z1XIQUfu!(;pvQB{h|UM`cOU+4|C^=ex`2fuKog+!VhNN% zIaEL;ETC8wRKr5J4;H~L0APGtcEoxi*T=n zb+8^bz(&|a@p{+{TVN|R(9s_7f)D%%U^m70z+UKrZk$^W#e0$eG3bLR^izBQ_Q8HQ00*hIK{y15;Rx~) zn~x%I42}U0LzFj;IDi1dAW}SmxCA2(_b6gABtfBLRY<{c&_G9@5StC8nlR?@j>8F< z01Hl1-bpwGr{N5oC74)qs%WyPojGEjDmKWvIL}CatuEpE%zY+{;ap9=8?kTB!XBTA zUCM`OegJ;JdHB{VDErmC{K?{ZIKTZ0&gRwpjOOKgVm2RKxLESqle2ZWn5V}knUUh$ zOfKcpF4sX@FZB`HG*ew_MUpT_)1;aU7o0l~wibOSRsQ zF-)w*{Q@6PNQzi6mFmck7LR{rzctyV^rA$rG6XWW95fx|&HHE}0DCJ4w^iO{B!uuSCvbClluUjxR zmD|8|3W}ida$)w_fNeMD4cMk&ARG=hiGcy%=Bp%N*ZumdC+?7dt?m~_&4Q%+2s+0B z0gU#RkhR=#09j4lkRTtK;;nZVUJSm8a=-iAe{MQV+y=&y{;Cjal54YCpeA#=sCC)U+)32^3blQ8_4Auu`%v5RRz=}4W)vO^2U+%fFfH!l zB|{Q1T(N>Ez{|W-44Xn2LDrg_BC<++PDoCtPV|Xqi06poR(7kTP;tA633w#IN;xyG zNRe%73HyA(fVFC-T!jwH3C-G2SADDDnQLgn5J_bseQBF)VjgR%KC}2_gMg>ykDueN zKq%k~gvIyUek%Quxc>|PUteF3!pzNB$$EKBP4S~>c^4j^G=)?Ma-`a?CIvS5J5AUT$Ykw0BoOe&how z>*Qclps_J*t(@r$%*BS;uAm-x8)yIH&#)|zbg0EWO;AANxh_e@Gp9DAv}L!lu)n3z zZ*9&A9&-5ef@!qyT5`gZlw=yBd&5t*9{UAqA!$%dO6Q^oPY<*OH&EIBP;(#<5dGz^ ztr#TrZ>6*06`a^@YI?RFCWWk_jkpYfMsb)tzeFAVq#%(+-P$F96z4U8>%Kc)ur%GB z70ddFSWV?&D>s@u5IY(|VP7bmFDgk#EHOA6PjkN7pc@z|lA%fY!4}ufkLpwlTIE|Q@B zL(OBEI&|h;d$(3iHgKk}bJv#?HufyB9M3P3VS6+de2DO?P#Y-d=V;X^ycXPe(^uzN}G0DG7ck2o;xUS|g)*JUInTy3Ot58FqYL+lV`i93+0>ahohk!HAN z&L+i-}r1Jn9BTa%;DNEKbDK_nHwA;w+k!HCL5E{=?(~h%Q zVH1>p0y(|*BYEE)B)vndL>i6F@>rD9A~N6Gf~!SHF1qH2S!#mJ>XgNBVA{ReZtk;> zNVYbC%n^1sCG2rv+TCjR4BN*~A+3|84&Bclr9^5=bqrNKbiK}wjUvay|C#*^hy3qY z+j#BJ^@r_aqMaJIt4`pXvuD2Oi`b8ewssolu$LVs(^FX*MrYU^MTk{*IuJeh_Mv&Q zC1|(CZN)bve#Z}v-r_b~vZlB|dga##zt(qSRrA!U<}|nA za^=gFSDJ2c{wdC%UcK>h?aQ@SI&Q2EOsx(~FDR{DGR+WB!c==cXDX@}-XUPR0G8qB z(+fT9Cj>dAt;P{o8Ep+V8b<)RW>Y|_vEG2- zZ2m93p!00|bn&JV!!^y^8)hXDA!HtPFv2UMiuPJ^P(5-r^#2zBjxu`Z=ZC JnTJj%@?X4GH{t*Q literal 0 HcmV?d00001 diff --git a/core/management/commands/cleanup_requests.py b/core/management/commands/cleanup_requests.py new file mode 100644 index 0000000..b307ced --- /dev/null +++ b/core/management/commands/cleanup_requests.py @@ -0,0 +1,46 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from core.models import BloodRequest +from datetime import timedelta + +class Command(BaseCommand): + help = 'Deletes old blood requests based on urgency and status' + + def handle(self, *args, **options): + now = timezone.now() + + # Define thresholds (days) + thresholds = { + 'CRITICAL': 3, + 'URGENT': 7, + 'NORMAL': 15, + } + + deleted_count = 0 + + # 1. Delete by Urgency + for urgency, days in thresholds.items(): + cutoff = now - timedelta(days=days) + old_requests = BloodRequest.objects.filter( + urgency=urgency, + created_at__lt=cutoff + ) + count = old_requests.count() + if count > 0: + old_requests.delete() + self.stdout.write(self.style.SUCCESS(f'Deleted {count} {urgency} requests older than {days} days.')) + deleted_count += count + + # 2. Delete non-Active requests older than 7 days + cutoff_inactive = now - timedelta(days=7) + inactive_requests = BloodRequest.objects.exclude(status='Active').filter(created_at__lt=cutoff_inactive) + count_inactive = inactive_requests.count() + if count_inactive > 0: + inactive_requests.delete() + self.stdout.write(self.style.SUCCESS(f'Deleted {count_inactive} non-active requests older than 7 days.')) + deleted_count += count_inactive + + if deleted_count == 0: + self.stdout.write(self.style.SUCCESS('No old requests to delete.')) + else: + self.stdout.write(self.style.SUCCESS(f'Cleanup complete. Total deleted: {deleted_count}')) diff --git a/core/management/commands/seed_hospitals.py b/core/management/commands/seed_hospitals.py new file mode 100644 index 0000000..5600d30 --- /dev/null +++ b/core/management/commands/seed_hospitals.py @@ -0,0 +1,47 @@ +from django.core.management.base import BaseCommand +from core.models import Hospital + +class Command(BaseCommand): + help = 'Seed the database with Kathmandu hospitals and coordinates' + + def handle(self, *args, **kwargs): + hospitals = [ + {"name": "Bir Hospital", "location": "Kanti Path, Kathmandu", "phone": "01-4221988", "lat": 27.7058, "lng": 85.3135}, + {"name": "Kathmandu Valley Hospital", "location": "Bagh darbar marg, Kathmandu", "phone": "01-4255330", "lat": 27.7015, "lng": 85.3115}, + {"name": "Civil Service Hospital of Nepal", "location": "Minbhawan marg, Kathmandu", "phone": "01-4793000", "website": "https://csh.gov.np/ne", "lat": 27.6841, "lng": 85.3385}, + {"name": "Venus Hospital", "location": "Devkota Sadak, Kathmandu", "phone": "01-4475120", "lat": 27.6945, "lng": 85.3415}, + {"name": "Vayodha Hospital", "location": "Balkhu, Kathmandu", "phone": "01-4281666", "website": "https://www.vayodhahospitals.com/", "lat": 27.6855, "lng": 85.2935}, + {"name": "Grande City Hospital", "location": "Kanti path, Kathmandu", "phone": "01-4163500", "website": "http://grandecityhospital.com/", "lat": 27.7065, "lng": 85.3135}, + {"name": "Teaching Hospital", "location": "Maharajgunj, Kathmandu", "phone": "01-4412303", "website": "http://iom.edu.np/", "lat": 27.7351, "lng": 85.3315}, + {"name": "Kathmandu Hospital", "location": "Tripureshwor marg, Kathmandu", "phone": "01-4229656", "lat": 27.6935, "lng": 85.3145}, + {"name": "Kathmandu Neuro & General Hospital", "location": "Bagh Durbar marg, Kathmandu", "phone": "01-5327735", "lat": 27.7018, "lng": 85.3118}, + {"name": "Teku Hospital", "location": "Teku, Kathmandu", "phone": "01-4253396", "website": "http://www.stidh.gov.np/", "lat": 27.6961, "lng": 85.3025}, + {"name": "Nepal Eye Hospital", "location": "Tripureswor, Kathmandu", "phone": "01-4260813", "website": "https://www.nepaleyehospital.org/", "lat": 27.6940, "lng": 85.3140}, + {"name": "Everest Hospital Pvt. Ltd.", "location": "Kathmandu", "phone": "01-4793024", "website": "http://everesthospital.org.np/", "lat": 27.6925, "lng": 85.3345}, + {"name": "Om Hospital & Research Center", "location": "Chabil, Kathmandu", "phone": "01-4476225", "website": "https://omhospitalnepal.com/", "lat": 27.7175, "lng": 85.3485}, + {"name": "Annapurna Neuro Hospital", "location": "Maitighar mandala", "phone": "01-4256656", "website": "https://www.annapurnahospitals.com", "lat": 27.6945, "lng": 85.3215}, + {"name": "Norvic International Hospital", "location": "Kathmandu", "phone": "01-5970032", "website": "https://www.norvichospital.com/", "lat": 27.6897, "lng": 85.3235}, + {"name": "Blue Cross Hospital", "location": "Tripura marga, Kathmandu", "phone": "01-4262027", "lat": 27.6948, "lng": 85.3148}, + {"name": "Paropakar Maternity and Womens’ Hospital", "location": "Thapathali, Kathmandu", "phone": "01-4261363", "lat": 27.6915, "lng": 85.3215}, + {"name": "ERA INTERNATIONAL HOSPITAL Pvt. Ltd.", "location": "Kathmandu", "phone": "01-4352447", "website": "https://www.era-hospital.com/", "lat": 27.7215, "lng": 85.3015}, + {"name": "Birendra Military Hospital", "location": "Kathmandu", "phone": "01-4271941", "website": "https://birendrahospital.nepalarmy.mil.np/", "lat": 27.7085, "lng": 85.2815}, + {"name": "Capital Hospital", "location": "Kathmandu", "phone": "01-4168222", "lat": 27.7045, "lng": 85.3215}, + {"name": "Valley Maternity Nursing Home", "location": "Kathmandu", "phone": "01-4420224", "lat": 27.7125, "lng": 85.3245}, + {"name": "Medicare National Hospital & Research Center", "location": "Ring road, kathmandu", "phone": "01-4467067", "website": "http://medicarehosp.com/", "lat": 27.7145, "lng": 85.3415}, + {"name": "CIWEC Hospital Pvt. Ltd.", "location": "Kathmandu", "phone": "01-4435232", "lat": 27.7165, "lng": 85.3215}, + {"name": "Nepal-Bharat Maitri Hospital", "location": "Dakshinha murti marga, Kathmandu", "phone": "01-5241288", "lat": 27.7185, "lng": 85.3515}, + {"name": "Kantipur Hospital", "location": "Shriganesh Marg, Tripureshwor", "phone": "01-4111", "lat": 27.6938, "lng": 85.3142}, + ] + + for h_data in hospitals: + Hospital.objects.update_or_create( + name=h_data['name'], + defaults={ + 'location': h_data['location'], + 'phone': h_data['phone'], + 'website': h_data.get('website', ''), + 'latitude': h_data.get('lat'), + 'longitude': h_data.get('lng'), + } + ) + self.stdout.write(self.style.SUCCESS(f'Successfully updated {len(hospitals)} hospitals with coordinates.')) diff --git a/core/migrations/0010_delete_feedback.py b/core/migrations/0010_delete_feedback.py new file mode 100644 index 0000000..3756f65 --- /dev/null +++ b/core/migrations/0010_delete_feedback.py @@ -0,0 +1,16 @@ +# Generated by Django 5.2.7 on 2026-02-18 05:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0009_bloodrequest_user_donor_user_donationevent_feedback_and_more'), + ] + + operations = [ + migrations.DeleteModel( + name='Feedback', + ), + ] diff --git a/core/migrations/0011_hospital.py b/core/migrations/0011_hospital.py new file mode 100644 index 0000000..be6635e --- /dev/null +++ b/core/migrations/0011_hospital.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.7 on 2026-02-18 06:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0010_delete_feedback'), + ] + + operations = [ + migrations.CreateModel( + name='Hospital', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('location', models.CharField(max_length=255)), + ('phone', models.CharField(blank=True, max_length=100, null=True)), + ('website', models.URLField(blank=True, null=True)), + ], + ), + ] diff --git a/core/migrations/0012_hospital_latitude_hospital_longitude.py b/core/migrations/0012_hospital_latitude_hospital_longitude.py new file mode 100644 index 0000000..ba98870 --- /dev/null +++ b/core/migrations/0012_hospital_latitude_hospital_longitude.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.7 on 2026-02-18 06:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0011_hospital'), + ] + + operations = [ + migrations.AddField( + model_name='hospital', + name='latitude', + field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True), + ), + migrations.AddField( + model_name='hospital', + name='longitude', + field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True), + ), + ] diff --git a/core/migrations/0013_userprofile_profile_pic.py b/core/migrations/0013_userprofile_profile_pic.py new file mode 100644 index 0000000..095f467 --- /dev/null +++ b/core/migrations/0013_userprofile_profile_pic.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-02-18 07:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0012_hospital_latitude_hospital_longitude'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='profile_pic', + field=models.ImageField(blank=True, null=True, upload_to='profile_pics'), + ), + ] diff --git a/core/migrations/__pycache__/0010_delete_feedback.cpython-311.pyc b/core/migrations/__pycache__/0010_delete_feedback.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adbdc325d022992114cb0261e6ae1fbba0b1c80c GIT binary patch literal 709 zcmZuuJ8#rL5T3Oib2f>TMCp)tNHlI@(}5I4LPCjzNE8V~am~u-9ge%$-pkqs(p^D8 zNrU(YK`8tfiYw5zRCJD#DiyPS97r(h{rt_&?7a5N+L{j}ix;0JM-1SnQF>YF$mK&K zpFx0NDP(NO7+A0m!g>$FMmDwj3uiXKIqg=4mT;a!u=2~O0n>gq8LPOQ$h=58m*&@B z=+YnznE<-X#%yR?fX=ipgi?O9E+O3d}+osXpK_5S`w3A4M`f(IRkN7B+QYbvB zuqb&|pyER2QY~py6TZQ`h8}QkDCgSe%mStmR+?)s(G&Bh@iF^V^jgV_Z{y3{nf6|+#3FckN#r){)I7I{m0s5{0;qYwM_s3 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0011_hospital.cpython-311.pyc b/core/migrations/__pycache__/0011_hospital.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bab95c16cedca3b0aab3b6d4dfe5bc38759edef2 GIT binary patch literal 1214 zcma)5J8auX5M5FfEmCq$a(vNAv63Rb4-Le!OCRFk&JLUp@`3Ylp@yKeYl${R>Xwup zU*+P8lxc#fxY|Jw6)s(-43K68urRg?kjfncr*f0bQlby}6t}A#&FsF}*?BX3F+Q#% z7zb<5Y%U}8UKq(pkCfvppgczyVaY*lsV24Mnk*q1T}N2{2jLWvHd2Yx9%!#lty&5z z50H^Q632$j^|sxlR$zOs&(*eviQ_jCPw}4{8OJA}JVyl8B#de@mYPy6B_pD2B#(m7 zSnQ}9Vot$$f=U@HkfbXTD4t z;{6cgwB&a2vVMLK2z~`CiP%i{3t#R*mO7pQ!p?H-PQnz>rZhZC_~hK&{G17#k${-% zgy6c>*yNcTp5L(p%i*$(AFgou<~2j%Ijb9ZW`hzdAed)6)NWgJ$J``4T=NOFEywAGXNn{)y! zaPB$|AKNB%-wuc&({r#(ivlRqyg;byHgT|j*U0jW8AmituA3&bLDwOm=S=gjuH}eV z2n&-AaWQclHu0(GD4t!8^SLAXhKlm?+>+h=6Ea;9S95K-WznIUd368wP}98*8MWL? zbPP`DY$3x|dC?+QP%;>^>nusCy|yqRV-lev@?{Xx+W zi$2Q-hlL_58NG91$=H9uN(+P1LRea0`QO2rRWA3|!ph}?v#hc>s4Rw+MV7yMSon#R zXL`Sc<(d7-*O%U0W98LBc{MDrvi$wSLb-RZxAO13{po{;Y-(vRwG>V*vHWtBRVU9x zX-(5VAP^sgh*H@Jb@!H-bUMlIE_9NHH!Qd5&Ek4ogqZhX{+9$S#{LZ2N#@G1l2_@k rV2UrxUjq@PBuN5JB!i*fzWqgNK~f|1t$3=3`RNbh;Ny2rHV%6u+|_$95V-EF^{o1c)NC)Gc#`gj9iqpbH3uiDWssBXxSVQ-6rEWnf^e zgi!y3QbhjGNE(WuiPmjnY`S8xl8suM@e6 z7X~p`{g6-=w~I{iugsLm5eNr}A{!HAO9XeYElY?h-J&RXnh1;9EzfcgQAmlXL^&=W zDo_NR={nYaFKXc){r~RiNVY}{Xs^Qc$3+8;T827xyWn4R#7!Z)8 zggzasP~cbxXehkYVs5a*FA&=He3v;r=C)}JjJbOb@j6}-b0tU_Ysg>|%sGMUQ?Lmv zz49m{TxVebk#P4`L+6^4hd2&590yWTMnPV3oZZxAB28$7_Gmz8(DrB?iMes@9wGO| zb&+6@FKtc>%1zt|dvrFyPiO*ubk?-CL!Vk{D-Dv=qIBeDMPiPeg!_8*EJT`8*Ef=TM6 z>js^0m9%m~a~h|8)J0exdljTJZDTr>yU{gJF`W1rKqh01p*P$ZpxcXIrq-~Up+(p? Qh8J(12*>GPy!pF70dd?0l>h($ literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0013_userprofile_profile_pic.cpython-311.pyc b/core/migrations/__pycache__/0013_userprofile_profile_pic.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6041900522b6c398bef3aaa133f31d6ebf66bea7 GIT binary patch literal 869 zcmZuvyKdA#6rHiXUfbD7#6m(4pvem1CJxX>k!V052n8#UTx8_+Og7%w9^;3AZVL*^ zG$?<-L!{sXDENdRZLyk`iq6rdN&|PCb=WA(Sl8#=duQg%u|F*?S_sA;_96U^5&9)b zGg>n+T?ep_D55w*G4^n*cnU@edWfj<4pEiiq1r6^2^Hi!mM^5XvEIW#@;&71p zMaYv}=rN}(%7bR5e48^e-2$+W81gVho0 zOf1X*NyDHgI&&;{RMF~3ezGgHq>LhAmTAO&N(v4Yt2Tioe$1dOV{1EP5#0oN2C4Ie z2#XNtD3$Hz)SW-mS5{^11u1_hakO?)|iTW4l+i zHPbpm5RPT2RNdA`kLAp+H79L4nlS0mPX>II_G=gFyPs;gD% {% trans "Donors" %}
  • {% trans "Blood Requests" %}
  • {% trans "Blood Banks" %}
  • +
  • {% trans "Hospitals" %}
  • {% trans "Live Alerts" %}
  • {% trans "Vaccination" %}
  • -
  • {% trans "Feedback" %}
  • {% if user.is_authenticated %} -
  • {% trans "My Profile" %}
  • {% trans "My Records" %}
  • {% endif %}
  • {% trans "Settings" %}
  • @@ -340,13 +343,43 @@ {{ user.notifications.count }} - -
    - -
    - {{ user.username }} -
    - Logout + + + {% else %}
    diff --git a/core/templates/core/donor_list.html b/core/templates/core/donor_list.html index 1818a0c..48e66c0 100644 --- a/core/templates/core/donor_list.html +++ b/core/templates/core/donor_list.html @@ -45,8 +45,17 @@ {% for donor in donors %}
    -
    - {{ donor.blood_group }} +
    + {% if donor.user and donor.user.profile.profile_pic %} + {{ donor.name }} + + {{ donor.blood_group }} + + {% else %} +
    + {{ donor.blood_group }} +
    + {% endif %}
    diff --git a/core/templates/core/feedback.html b/core/templates/core/feedback.html deleted file mode 100644 index 6451f56..0000000 --- a/core/templates/core/feedback.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends 'core/base.html' %} -{% load i18n %} - -{% block content %} -
    -
    -
    -
    -

    {% trans "Share Your Feedback" %}

    -

    {% trans "We value your experience. Please let us know how we can improve." %}

    - -
    - {% csrf_token %} -
    - - -
    -
    - - -
    - -
    -
    -
    -
    -
    -{% endblock %} diff --git a/core/templates/core/hospital_list.html b/core/templates/core/hospital_list.html new file mode 100644 index 0000000..8e01635 --- /dev/null +++ b/core/templates/core/hospital_list.html @@ -0,0 +1,92 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Hospitals - RaktaPulse{% endblock %} + +{% block content %} +
    +
    +
    +

    Hospitals in Kathmandu

    +

    A comprehensive list of public and private hospitals for blood requests and emergency care.

    +
    +
    + +
    +
    + +
    + {% for hospital in hospitals %} +
    +
    +
    +
    +

    {{ hospital.name }}

    + {% if hospital.distance %} + + {{ hospital.distance|floatformat:1 }} km away + + {% endif %} +
    +

    {{ hospital.location }}

    +
    + +
    + {% if hospital.phone %} +

    + + {{ hospital.phone }} + +

    + {% endif %} + + {% if hospital.website %} +

    + + Visit Website + +

    + {% endif %} + + Request Blood Here +
    +
    +
    + {% empty %} +
    + +

    No hospitals registered in the system.

    +
    + {% endfor %} +
    +
    + + +{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index 34766e4..378a591 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -224,8 +224,18 @@ {% for donor in donors %}
    -
    {{ donor.blood_group }}
    +
    + {% if donor.user and donor.user.profile.profile_pic %} + {{ donor.name }} + + {{ donor.blood_group }} + + {% else %} +
    {{ donor.blood_group }}
    + {% endif %} +
    +
    {{ donor.name }} {% if donor.is_verified %} diff --git a/core/templates/core/notifications.html b/core/templates/core/notifications.html index 14fa0fd..e5c80c5 100644 --- a/core/templates/core/notifications.html +++ b/core/templates/core/notifications.html @@ -1,4 +1,4 @@ -{% extends 'core/base.html' %} +{% extends 'base.html' %} {% load i18n %} {% block content %} diff --git a/core/templates/core/profile.html b/core/templates/core/profile.html index 4ecf840..d69206f 100644 --- a/core/templates/core/profile.html +++ b/core/templates/core/profile.html @@ -9,16 +9,20 @@
    -
    - -
    + {% if user.profile.profile_pic %} + {{ user.username }} + {% else %} +
    + +
    + {% endif %}

    {{ user.username }}

    Member since {{ user.date_joined|date:"M d, Y" }}

    -
    + {% csrf_token %}
    Account Information
    @@ -59,6 +63,10 @@ {{ p_form.location }}
    +
    + + {{ p_form.profile_pic }} +
    diff --git a/core/templates/core/register_donor.html b/core/templates/core/register_donor.html index dd78090..375f8d2 100644 --- a/core/templates/core/register_donor.html +++ b/core/templates/core/register_donor.html @@ -1,4 +1,4 @@ -{% extends 'core/base.html' %} +{% extends 'base.html' %} {% load i18n %} {% block content %} diff --git a/core/templates/core/request_blood.html b/core/templates/core/request_blood.html index 71627d6..8d91805 100644 --- a/core/templates/core/request_blood.html +++ b/core/templates/core/request_blood.html @@ -34,7 +34,7 @@
    - +
    diff --git a/core/urls.py b/core/urls.py index 1feb659..9d3763d 100644 --- a/core/urls.py +++ b/core/urls.py @@ -5,8 +5,8 @@ from .views import ( blood_request_list, blood_bank_list, vaccination_info, vaccination_dashboard, add_vaccination, live_map, request_blood, profile, volunteer_for_request, - complete_donation, submit_feedback, notifications_view, - register_donor + complete_donation, notifications_view, + register_donor, hospital_list ) urlpatterns = [ @@ -25,7 +25,7 @@ urlpatterns = [ path("request-blood/", request_blood, name="request_blood"), path("volunteer//", volunteer_for_request, name="volunteer_for_request"), path("complete-donation//", complete_donation, name="complete_donation"), - path("feedback/", submit_feedback, name="submit_feedback"), path("notifications/", notifications_view, name="notifications"), path("register-donor/", register_donor, name="register_donor"), + path("hospitals/", hospital_list, name="hospital_list"), ] diff --git a/core/views.py b/core/views.py index 39bd9ef..de394c0 100644 --- a/core/views.py +++ b/core/views.py @@ -1,5 +1,6 @@ import os import platform +import math from django.db import models from django.shortcuts import render, redirect from django.contrib.auth import login, logout, authenticate @@ -7,9 +8,32 @@ from django.contrib.auth.forms import UserCreationForm, AuthenticationForm from django.contrib.auth.decorators import login_required from django.contrib import messages from django.utils import timezone -from .models import Donor, BloodRequest, BloodBank, VaccineRecord, UserProfile, BLOOD_GROUPS, DonationEvent, Notification, Feedback -from .forms import UserUpdateForm, ProfileUpdateForm -import math +from .models import Donor, BloodRequest, BloodBank, VaccineRecord, UserProfile, BLOOD_GROUPS, DonationEvent, Notification, Hospital +from .forms import UserUpdateForm, ProfileUpdateForm, UserRegisterForm + +def hospital_list(request): + user_lat = request.GET.get('lat') + user_lng = request.GET.get('lng') + + hospitals = Hospital.objects.all() + hospital_list_data = list(hospitals) + + if user_lat and user_lng: + try: + u_lat = float(user_lat) + u_lng = float(user_lng) + for h in hospital_list_data: + if h.latitude and h.longitude: + h.distance = haversine(u_lat, u_lng, float(h.latitude), float(h.longitude)) + else: + h.distance = 999999 + hospital_list_data.sort(key=lambda x: x.distance) + except ValueError: + hospital_list_data.sort(key=lambda x: x.name) + else: + hospital_list_data.sort(key=lambda x: x.name) + + return render(request, 'core/hospital_list.html', {'hospitals': hospital_list_data}) @login_required def profile(request): @@ -18,7 +42,7 @@ def profile(request): if request.method == 'POST': u_form = UserUpdateForm(request.POST, instance=request.user) - p_form = ProfileUpdateForm(request.POST, instance=profile) + p_form = ProfileUpdateForm(request.POST, request.FILES, instance=profile) if u_form.is_valid() and p_form.is_valid(): u_form.save() p_form.save() @@ -67,13 +91,20 @@ def logout_view(request): def register_view(request): if request.method == "POST": - form = UserCreationForm(request.POST) + form = UserRegisterForm(request.POST) if form.is_valid(): user = form.save() + profile = user.profile + profile.blood_group = form.cleaned_data.get('blood_group') + profile.location = form.cleaned_data.get('location') + profile.phone = form.cleaned_data.get('phone') + profile.save() + login(request, user) + messages.success(request, f"Welcome to RaktaPulse, {user.username}! You are now a registered donor.") return redirect("home") else: - form = UserCreationForm() + form = UserRegisterForm() return render(request, "core/register.html", {"form": form}) def home(request): @@ -276,6 +307,7 @@ def request_blood(request): context = { 'blood_groups': [g[0] for g in BLOOD_GROUPS], 'urgency_levels': BloodRequest.URGENCY_LEVELS, + 'selected_hospital': request.GET.get('hospital', ''), } return render(request, 'core/request_blood.html', context) @@ -355,12 +387,12 @@ def complete_donation(request, event_id): # Notify both Notification.objects.create( user=event.donor_user, - message=f"Thank you for your donation to {event.request.patient_name}! Your feedback is valuable to us." + message=f"Thank you for your donation to {event.request.patient_name}!" ) if event.request.user: Notification.objects.create( user=event.request.user, - message=f"We hope the donation for {event.request.patient_name} went well. Please share your feedback!" + message=f"We hope the donation for {event.request.patient_name} went well." ) messages.success(request, "Donation marked as completed. Thank you!") @@ -369,21 +401,6 @@ def complete_donation(request, event_id): return redirect('home') -@login_required -def submit_feedback(request): - if request.method == "POST": - content = request.POST.get('content') - rating = request.POST.get('rating') - if content: - Feedback.objects.create( - user=request.user, - content=content, - rating=rating if rating else 5 - ) - messages.success(request, "Thank you for your feedback!") - return redirect('home') - return render(request, 'core/feedback.html') - @login_required def notifications_view(request): notifications = Notification.objects.filter(user=request.user).order_by('-created_at')