From 77709c3744799e57368dbd43a728398129e90749 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 1 Feb 2026 03:41:49 +0000 Subject: [PATCH] Autosave: 20260201-034149 --- core/__pycache__/admin.cpython-311.pyc | Bin 115861 -> 116384 bytes core/__pycache__/forms.cpython-311.pyc | Bin 27446 -> 29089 bytes core/__pycache__/models.cpython-311.pyc | Bin 27966 -> 29913 bytes core/__pycache__/urls.cpython-311.pyc | Bin 5563 -> 5776 bytes core/__pycache__/views.cpython-311.pyc | Bin 69651 -> 76648 bytes core/admin.py | 20 +- core/forms.py | 43 ++- ...e_event_default_volunteer_role_and_more.py | 41 +++ .../0032_alter_volunteerevent_role.py | 18 ++ .../0033_remove_volunteerevent_role.py | 17 ++ .../0034_eventtype_default_volunteer_role.py | 19 ++ ...visit_interaction_neighborhood_and_more.py | 43 +++ ..._remove_interaction_door_visit_and_more.py | 29 ++ .../0037_campaignsettings_timezone.py | 18 ++ .../0038_alter_campaignsettings_timezone.py | 18 ++ ...lt_volunteer_role_and_more.cpython-311.pyc | Bin 0 -> 2262 bytes ..._alter_volunteerevent_role.cpython-311.pyc | Bin 0 -> 866 bytes ...remove_volunteerevent_role.cpython-311.pyc | Bin 0 -> 713 bytes ...ype_default_volunteer_role.cpython-311.pyc | Bin 0 -> 1088 bytes ...tion_neighborhood_and_more.cpython-311.pyc | Bin 0 -> 1563 bytes ...action_door_visit_and_more.cpython-311.pyc | Bin 0 -> 980 bytes ..._campaignsettings_timezone.cpython-311.pyc | Bin 0 -> 876 bytes ..._campaignsettings_timezone.cpython-311.pyc | Bin 0 -> 14828 bytes core/models.py | 32 ++- core/templates/base.html | 3 + core/templates/core/door_visits.html | 251 ++++++++++++++++++ core/templates/core/event_detail.html | 203 +++++++------- core/templates/core/event_edit.html | 7 + core/urls.py | 4 + core/views.py | 174 +++++++++++- 30 files changed, 825 insertions(+), 115 deletions(-) create mode 100644 core/migrations/0031_volunteerrole_event_default_volunteer_role_and_more.py create mode 100644 core/migrations/0032_alter_volunteerevent_role.py create mode 100644 core/migrations/0033_remove_volunteerevent_role.py create mode 100644 core/migrations/0034_eventtype_default_volunteer_role.py create mode 100644 core/migrations/0035_interaction_door_visit_interaction_neighborhood_and_more.py create mode 100644 core/migrations/0036_remove_interaction_door_visit_and_more.py create mode 100644 core/migrations/0037_campaignsettings_timezone.py create mode 100644 core/migrations/0038_alter_campaignsettings_timezone.py create mode 100644 core/migrations/__pycache__/0031_volunteerrole_event_default_volunteer_role_and_more.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0032_alter_volunteerevent_role.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0033_remove_volunteerevent_role.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0034_eventtype_default_volunteer_role.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0035_interaction_door_visit_interaction_neighborhood_and_more.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0036_remove_interaction_door_visit_and_more.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0037_campaignsettings_timezone.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0038_alter_campaignsettings_timezone.cpython-311.pyc create mode 100644 core/templates/core/door_visits.html diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 9a8a5125e1db71ffd6225a33557d63636744dd2a..598b79551f2d49b52075d4261d66c8d9ef398d82 100644 GIT binary patch delta 15103 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 cqi&l(lVRsaA1 delta 14466 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 Z4UVHK7SoNs*5DJqZv#h5uEhYc$in? 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 bD;Jlfv9by2>oB%s{E1t{-+6#iRFMAy1-z5L diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 50a0514cc41fd5299eee8a80e0d8ffeef6a1799f..48ff1360be7cc69596c5a628c3c78dd961b8ffbd 100644 GIT binary patch delta 673 zcmYk3L1+_E5QcZnY}&MTvrQ9hkVHd^F|BE=Qg@Bj1W`zclz@g}Hrh)>lU5>0P$(!l zhR{Qoz2qdGG*rQAF9k0iMTEYECrD2oJQNT5ZeD$FR?&I9k9qUYKRdARW;c`Si?Oj0 zi3fZ8q}J0cbyD7X6F0qfQC9pn?|ABSLKIOgTb&~blb2F%ftM<;yw5$7^pamUEV+ET zdh5EBxV_W!E)Qqd4_6zFX7XXJRcp6W`=jEu;=b0k|E0CY-PFFyx$>`NDKT$;6MuV7POo8|aoc%>E++aR=fQ;>^RPuR80zYtr z@zrf;tk;VNAi~9#&@>pi!44@SbRP>0u50SQ3R51U@`+tc7e$? zA__q9vtagnFk3(rBw{EEQXdQ^OTpxHFu4;<-UgF@!KA#HA|KEJ4cs7DWD1NJ013l| Ay#N3J diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2d879ddb425815f05ff943d78e13f5e50056bb63..885e8ec40fff2e392105131f6a2d2658c9af337c 100644 GIT binary patch delta 17518 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 M5Wr}Rjuf-`KXvZh;{X5v delta 12172 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 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0033_remove_volunteerevent_role.cpython-311.pyc b/core/migrations/__pycache__/0033_remove_volunteerevent_role.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d03a81582ed3f9b923887d17ca0956f9f3d5ece2 GIT binary patch literal 713 zcmZuvJ#W-N5S{fGXNMpN5$OU*NXShbaScKUQGtXYLWgLsSvlU(;luVGYx{r(T|q%f zmp_1lQ1~$vDWYwu=p0?DRLuI$0Yql)=b70z`*ueDy1E(w*~>2<(g6ebX@bt&r8B=v z&K?L5EQ6d483PL*gRnk=u#t_eu3+B=IG}f7LrXX>AasA3Fl0K&(~*j+R2F5jq_iJr z8O-mIvj+%6CV-0Bhz)HE&>43ZAxU9>clJr};7pWQo^VOX)BdwgA+)rUNQHWHd%J&! z$61AnPi0mY6{5l^78O@ALw)Jrq;^b}s)Jk#%y<#!s2zhl;RW5}ZGv+ha886eL-H?j z{-%yILo$)T2^Ip2B*jvhVd#|s=5mUUQp|)75L|)fyPX_%{5aNj!cm|U z6o@Ka{y_jG1wVm;ACTgT)3#J}j*==ByX*5sh^)P{GrO}h-+Z%Q$Hy(i#`XP=-hCON z-`psNHdIa?Gi489grxvACAP|e94bvERGX@VWb_1Ky4gq&@T%%cY@l@`WjT2t?kdjHQm$RAdC|c_u7lzN7nN zWdN))EQW8Ewy%#gQ7yOpG6TXI)(^+_8S;Y>`a|Pi{48q)o2&whn$Jt*tPHgs6QGmx z^9u_OfiT_zXDbe}C2yZGi9$~!1V-S^_))K?$b)sj` zqdNB8s1s8ex2Pddu`W|%wXx=`tS>K9EAGOu_21D6@5R|G`)wS8owXQqnGNruoux6c zw_~!Iblo=CoC5p&$=HnW#eyWx5v%}Oq_C&D|%JmdCEUBRbr{>^kzX)9k=Sm>#vtgkz34-nxk{Uw_v#_W|Bt{ zp{AL3W;`gG_K?gnQ(`k|F_9~hB(Vae=_52%`~!6F=%PQ@E0Uh0|HZD=zdU=)4^A&Q H6&U^k(3vV7 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0035_interaction_door_visit_interaction_neighborhood_and_more.cpython-311.pyc b/core/migrations/__pycache__/0035_interaction_door_visit_interaction_neighborhood_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a53f1b338f3448d91ef614f9c95a46eec67b8781 GIT binary patch literal 1563 zcmb_by>HV%6hD8&v7NL6Q;7j+QPd!^G?i!eqMP zLJFZDQb`8r@i<tmGK5+hYewkc!*Sw0fm))W%2wD6(OsOkdsl)@OjEEEdQDd>;?pm!|7amgBt)F z3pwdvxOJPOCo+)rFw)d1WAk}rBkT4DyKmka+?*X;zcX<1Tle}-eka^}weOS;oKoK@ zMQPo#j}V9xDSq>r88|uVliQiv)4$)?cghD&x$l(!;*}c%34F#tnjQlQeEt_{amFz= zpUH>MBpF{R=)xjRH>k5YQjL2j?wDasrlnbIdlzP>=F+eMAMqThP$txQ4I#fZ>lv1RwK%^t~(lRxanxIY26K!TV6 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0036_remove_interaction_door_visit_and_more.cpython-311.pyc b/core/migrations/__pycache__/0036_remove_interaction_door_visit_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c65af287312ea3721bb391583f3e6bfc2f053490 GIT binary patch literal 980 zcmah`J#W-N5S_JszO$1^1O^^RwD=FRNe`L?p+0?MbK@1tJ^z#r|5 zr7|)G_t4k_28_gzkOm=Oz++&>2Vf>AZNv>_-vl_oJ(PyQtQSzP{MBxqC^v~h>31WM zX2B?>{8dNJ;42z?z@b4HAee-tVH&`#_V^;$l9@lOeQbCzX}XY6IVZzDw}#CYYJ^t9 zW>ut9Q_iz7kGi3(KuE40Y;WJbL!-3Ir5|X9lnEheFUq3s+;PgIu+%4nkD zOEXC2PN7)eO$6gHP5p!`tJKT0HI&m6agKet+^JVpjh2~|Dwkqumd70JWlCS?eyq{j zW4yyt#?v6;nbgx#OS?P~J^m=-F;lMSAd7NL-(jFB;{8s0k)blNsjYjqbRe!Py8=PHIn8upje_FWU zY>gg& NJl27e|3u4<{{XSK`bz)+ literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0037_campaignsettings_timezone.cpython-311.pyc b/core/migrations/__pycache__/0037_campaignsettings_timezone.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a010cee54d100e7522e08751f4ab53440261f0db GIT binary patch literal 876 zcmZuvO>5LZ7@kS8*(9`BgWyMdDk3h0rYPuT5lcZq)`AEMi!e+x(`>fM%sNSG?Lm6* z;IX&BlJs? zrnSz4<1Pd{h#`g(l;S>4jlO}Afu15}d_>ITcxX18b|LzD!TKh%UZPIxP)~P^(o5q= z(L9zSEA3P=o@8OOQ-7Uva{LB@9mG)|Gt@U2j&R>J5VwYnC`irph&^nd??KFBtv!3! z00HoxwY~P=g5Vs7IUva`-RF%K5N3r^@p5iq;r;`ncq-R9iABy84YgRpq*P=*&f=U< z!APnXPlYrc(Kr$r&+}MBS?T0)$~UFpn^zW7uHujeO9Q}29^L~vkfzP}DlL*6jG!AN z;UdZh9TS+gf(V-O(yFnw8uNrLgG`6iB$k)Ro}rEbgXSUeGv>~%7bF15P1>s4IUP`RKYu`*0K=| zd7#}1{@h&vK0PG=)=!%9=ST0A4d>RNgX}fH)nLfDQ zIk-A~;LmQ~8T+&QbKM{QzTf-l_r`v&YFn;%gaA%7RHp6QThDY?H=9h$9jkQNkcvpo zvz6M0y7)6KH}tZ4?JbB-o$i^JkJJoM`1Mit3ZODE#-I;(_R-zTPi0SFyF!;?+Z#{a NKGG8>|Cz1x{swQa>52dV literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0038_alter_campaignsettings_timezone.cpython-311.pyc b/core/migrations/__pycache__/0038_alter_campaignsettings_timezone.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8290e60b4f21bd7aef93adb9de2fd5c9fe23f887 GIT binary patch literal 14828 zcmaJ|2Yehy^_DDIvg9VqPC_angb*o@=gbnA_0Yw4rIJsj%Uurb3Hs zUTld9y&j+5V!zF`6k0P)yEoop=-nIEIxDJ3!dKe$*4iq%ARR9sl{Ei$)V|y`j}Nyr z$)>sHLet!aLUXZsu4O}$Y+Z~xg{BJzXyR|*ujaxUxzoWKI zg${JAbFCvC^$6W-&1;ft=k3|E|3EG;Doa8YT~GSHa*JNhR~5OcUAfkkq}Db?+{LpS z%s5YO>sug|7rlM+s<0?r+KfH|-V(w2JPF#uV0Q!-3d+m%&5Lufhx}v0qtURd#w-sj&S`dNji=3 zXf*vKR#(NcavVvgGu0Ip2^NFOe1JZl!9=8%lu)GUUJUN2NvDJ-=Fv!A(3uHw8Tf+E zVlYxwO1q*=RXRH^J0Qw}=o|)j)v6v4l#^aABODP=QP5$MHiXrLR|9x=$P*67!m{nCJq=quPhfgi5+EqdRLI9n~e_y3&Kv zigY1!nsubi+hsjQs8Uan?yZH0qtWn(o@=OHcY~PhNA_V)%?LPlRU`_FmZ!=)sIfy2z4R(pUx8FdWTxHgJ_k z*T(CZRc@iAWtpyvgwalD?+Vy_eGKmCi$E8nB2kpo&rDaHf%S2)P*Y57uM@s127(5X zRiTC3l+ffXqo+rrA)4!l zS;E=r(L)kV^b4BD4)o|~vNq|+3e7RP&DJIzwJHe?mDzc_ENqUko(zsNjN)NT+FjDG zMQ%oUn3#trYtuyy_vZ}k*RIs6uOS%&3J2}F|ja-JQP-7+>WNcyJSO&s>E4F3k?la&1xwo#Y?a&MNOq- z10{vUga4Caranj&6hy%+V3Mn}m}FszoE(l>9PUKrWNVuDvBP+`Rh-7eV1vS1RG6xd zR98zv9SbD6$;x1Wd~;$jZdXStP{zkwN{YiH$_q`$7`LltK)A3|Wt_#!E>WVc0kPtt z39q4yfpaN%A7%2BWu&_-i2{bL%^i?FY30*0<96Q-=!$a9$X61?V4h!oJ$qnNYv5^}SmiuLqprtG{J zN;nes@-Yc!$Pszo0XHyXRWPIreo4&JjmZ*PdtBnN%-9ZuyCs(ms7#MbRz^IY$0v&f z0&$NHpr4zP?F7P?72~-*p^>SIV>m47iOks5G!#??&ci1$Y=<%ok8VL6rza=GhsClH ze+t8P9K(_-+QV6_>8VVe6HVHPTTm#{Tl?2I2_8L-h3q1YgvMNboSx34Jq05&jUDM? zFF%8MdkRMUr1TNxgih`=S;QVIkw{iLPA;VoaXgD9?6!|2X5=z#+s*e-enz=@V}3k( zHcK>g621-mf;>Hk`Q!+B_|Ik1PQr*AEUPj-k6}9rBgcdjU`stefsdjEv!h=9K`H17Pt^LAXpP`#W%yXVJ^FXk3;PI~l;L=)?J{z|6o zbdKv49Bz|j=F6j3F>5=J#tv4RUd^x_N*e3bxQ(xA5O+o3(Q6yTN#SUv*D-EKj&%x8 zGPLQhXUbZYwDB4dxq0*kW~`Y^i&f#{fTuSmTdBEiZ%S4LHx-suN_sOh_0hqZh9P_l z!}V@S)L%A@(5*~aC8y6B9wP9 zQ}2OcmQ_J&dS|i~P$Y#z?>a>p_$kQx(7TzkNX!xL%= z^X1a}7`N+g!h|{RPYRp(8UgPI7`NMI0_Q?0hkO8hs@{GXIHE)!{9iID>@)QLLo8#x z?pQsh%Q)HK3VxWy>U|4>GJS+WJCMVRFfv6!|Hrsh$RyS;w$MizwzCVk=qmC9w@4pj z&Q8fB5(X%OTm^lcDci~1+X z$MX3^!71UEm75!J9k?!EVAASxO6Jvqq%StWMH4=LiDA1*rlhBx0Q3B1ChT}kNQGRM zi++EFDXZTpjpPWd&{r9^<3ad@@r)pCB^~-&qM?u^ER?UGf>6fO{RR_uK1>On3%xL~ z-(=QqRukq=iU4-~Tg=qEVUn5Nd=+6+fo@B-R#Ho(^JV%r6ZQzoC=)b&htYZ;d_)Y` zHzwMt(sz@U`8i~$T#s&VB*v8Qd-T0VVm!zr4qIcQJ{&)nE$Ipt!uOf66Or)|9+|`2 zrynp?@7;=8@N+5n^M?H)vvyf#Wf4sw!?h&nN6gvLW=jF`lRr+DC_!a7eN2$_6Xxus zXVoGiV?jSn;>O${@AR`q+}E(!KWE$ybjB>Hz^v+DFk=_)j3O*i`X$45{IezHOYAJz z(qA!U7cX2ES1rjR{hA5e*`uP26sb?YVce?ZsBr{V%C6ZUcSMz8(NZ2xg6Kuc6~_O! zjl=-bARhgWi8K4^B?bZ$3JgpWyCJ`4iCya?aAF@b!J4E$Fu5Z}hEdEPndx57w7+fz)+XzFU;)h3pEIj%q>h;>AP{u8SJeL&Jp4+zpu=K_uoDk)5HII7o2F9BO5d711vd zHu|(NCWtI-86j+2OwdG^irN|DF{Xr*4}7fPO^mW0Q`j?tIvCm>jwMynYF;=V^xMfe zs{^=OJcf%N+8l>*=;Dwm(iVn!R4MJ~3Xa^Z403A&A`hQ_8$;Z!0i4ZV9HnV_l(&hT%w-R4%RD65WdlZfO`Q%8lUsl(VJba;y(I2G z@+DyovimU1-5P_hl*jGD1#!@952E|VEAUI$f`x!CWSECACVWQk7eg^Ag(~W}C|0j_ z;HwL|KZC4V#8jTEtAe1Mi<#IF>U_*xD&@w53WiO)WAy~+GF1Km26-ySf)#^P?@f2=LKwQoQucN~iAXmf?grIaKBfNblO9+~BlM+kw z0OPziCUN|jEJc|P#^9>4#BiVKDu!8AN6f^~0~ul!95ER_7YF`>)|Wq0U9G~kLNInU z!@Q8-cosFb&4U?abxoWa%V0RsC#OoO40c4C9k0f@1`WWV( zW~9dA?vItnaw{U`NU2zPtP!yUkB{$>Sy21SR~*PX@f zTiG~KLyYopv-7Y{o}%GcaS8kH(nzeh#5L%$TBgyMWXW7P(O9fXU`x1Q8)uLQo7Ls2 zrgR)K{hnZmhcvwilMJ61H;94+dak=}DSRE2~s?hOK2DkT_`~p0*-o91i+S454T^8?077xj9dT6o$ zviAa);tykdr!9~YOENbj3Eu9*lVuJGNm|nNjBm4L4haM281A<4C^VcF#^HGcQ}u48 zk?>Sds7RKXlGXAee9AJ-Gj+PHjvcijWEzSvE%{_gL<7SJMlh;Evb7BMu>=2AGO@J} zXCv&0alTSnT8L_@qsYbzWGI>L-njk{d?KlvG1O=o`m0hP=pB zSG}MKQ{V-c8;Aj9*kKhMCbrj03IUd^~dP-Fbc zC8l<+qhR84!zSZ)tbt2Q$6S?Q;Zs9H6Pa1^7+u%jFf&4a13rlqK#2mzchy@z5=iNK zSlR_zZYUJ416pBxof5wfuTs>J^Sd531mOLDS=#0Z%!ar&|4D7 zm2_(YIY4hsAP4Df3FInzJ0qKFbGwJ$!NArKz=f&1qVgqrC!^uAnZ~*CuJzxuDSG$1 zQq!(UPa-s-_b?h(J{LFvy_bQm!GQFV?Cqm;xh8n ziFy!!dANwBk1`&OsvjW=uJ+LI#}WnLj4T=a<4N3uy9!s~6LB2o00hzxpJY7hQVP05 zF5i^+6f=kpWSls9Q!lS%qvyxu9~is?rQ%-k^j zI9@u8*aZEA(MXrb)?>B6o!9hJW};n~fdjlK@lfw)j7P&WxR2TXd7>g!L3UQ-zL|c( zOw{d6SuZV0`X!^$&@*}gp3ScqjE0`^k>f9Er$WDGB5E{?S7LB$=r{4IvvAYl>D|F- z)N_M+rX#(x?K z(%lL90L!ODe+kjG_Cvz>kyZLDf8Q|FPk-YA?L+-Nq1W+urdo{0@ek%U;xoLBll5;n zj{nJWt>E_1zxYeXkUfR|%}C2Ie4hXC=S?OH2k)v#|7D~PhrNN(E{kIKAj9PmUe<>x+=$S~@K9@_4m^&;bM1}sI>r!3 z;kp@?x{Zm=wK~!QIr(UGwj5t!dYCK*xBVV_J zzqO>{h;~PxF)2Iwb9*|IJ&=YYx-0yCvWqX|d;3wF35W1Jo{4SihzugZ)8p`v#O{M1 zaRyhrVPcN%#S-lkb3LiyzAT-|RNDj&=tWIu@z<8gsT7^fpW7!h*@Khl%sE_iOU;4r z?OTF{IG4dL3*rq)xO~oIVpl};&erqm0X?#H+t*CDm2=pqK~xDExbSTOJR z@1Lk24`earX8B*7sDB90BN3X@ZpL>;JsQG`E!;0)FFEu8=4{*GDs%~hwry-t+$O{Q zyEH+B*QDmnMGq5JLt{wn0KSaj?x^K4W%dCsh!piEOJD%V(ClH@YOlV4_a+LY#Uh+g z+LtJR!wT<1JZ$>?$pWgdf`sVh4BIK5z~&6-3P!CSCKOK6D;cyChNZuNG&mhd)QqR@ z6IFCNl-TTa(7X*)HAbQh)uKEbt#+K}8ersFz>ZC~LRXhD4m;VhmVV;1`x zU=p};OfhU5&6);%a|bfOjMa0Nu)hWq;H)T1I+Un-)*SI34KchqT2e>F5)FsgS{v>` z&A~CkUpE;&V9z@=%0SE1;S`P8&to*spF1)(*_>vi&Afnw*E>-YHWAa|@bk%z=}d2* zV{!#F$;jpq!H;*4PNgG^bsCHmeqSYMst!fTjSNHEA!Tey4<84DvUSlY;W5pSX?7T@ zRf=X9*#V?ht_L|n^p|SC)-oMRe%6$97KcfWKevX_;v;J19G!=Yjo+J*0201^zN27nWLwtS z@mmT!s6KvECywWE;1>N7_|EWGbvaj5 z8M|-aarW)q7uYpTi1nm8shF#uwlFZ E4|NAtQvd(} literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index 8e6a38e..569acdd 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,4 @@ +import zoneinfo from django.db import models from django.contrib.auth.models import User import json @@ -77,8 +78,20 @@ class ElectionType(models.Model): def __str__(self): return self.name -class EventType(models.Model): - tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='event_types') +class ParticipationStatus(models.Model): + tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='participation_statuses') + name = models.CharField(max_length=100) + is_active = models.BooleanField(default=True) + + class Meta: + unique_together = ('tenant', 'name') + verbose_name_plural = 'Participation Statuses' + + def __str__(self): + return self.name + +class VolunteerRole(models.Model): + tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='volunteer_roles') name = models.CharField(max_length=100) is_active = models.BooleanField(default=True) @@ -88,14 +101,15 @@ class EventType(models.Model): def __str__(self): return self.name -class ParticipationStatus(models.Model): - tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='participation_statuses') +class EventType(models.Model): + tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='event_types') name = models.CharField(max_length=100) + available_roles = models.ManyToManyField(VolunteerRole, blank=True, related_name='event_types') + default_volunteer_role = models.ForeignKey(VolunteerRole, on_delete=models.SET_NULL, null=True, blank=True, related_name="default_for_event_types") is_active = models.BooleanField(default=True) class Meta: unique_together = ('tenant', 'name') - verbose_name_plural = 'Participation Statuses' def __str__(self): return self.name @@ -160,6 +174,8 @@ class Voter(models.Model): yard_sign = models.CharField(max_length=20, choices=YARD_SIGN_CHOICES, default='none', db_index=True) window_sticker = models.CharField(max_length=20, choices=WINDOW_STICKER_CHOICES, default='none', verbose_name='Window Sticker Status', db_index=True) notes = models.TextField(blank=True) + door_visit = models.BooleanField(default=False, db_index=True) + neighborhood = models.CharField(max_length=100, blank=True, db_index=True) created_at = models.DateTimeField(auto_now_add=True) @@ -288,6 +304,7 @@ class Event(models.Model): start_time = models.TimeField(null=True, blank=True) end_time = models.TimeField(null=True, blank=True) event_type = models.ForeignKey(EventType, on_delete=models.PROTECT, null=True) + default_volunteer_role = models.ForeignKey(VolunteerRole, on_delete=models.SET_NULL, null=True, blank=True, related_name='default_for_events') description = models.TextField(blank=True) location_name = models.CharField(max_length=255, blank=True) address = models.CharField(max_length=255, blank=True) @@ -327,10 +344,10 @@ class Volunteer(models.Model): class VolunteerEvent(models.Model): volunteer = models.ForeignKey(Volunteer, on_delete=models.CASCADE, related_name="event_assignments") event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="volunteer_assignments") - role = models.CharField(max_length=100) + role_type = models.ForeignKey(VolunteerRole, on_delete=models.SET_NULL, null=True, blank=True, related_name="volunteer_assignments") def __str__(self): - return f"{self.volunteer} at {self.event} as {self.role}" + return f"{self.volunteer} at {self.event} as {self.role_type or 'Assigned'}" class EventParticipation(models.Model): event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='participations') @@ -381,6 +398,7 @@ class CampaignSettings(models.Model): twilio_account_sid = models.CharField(max_length=100, blank=True, default='ACcd11acb5095cec6477245d385a2bf127') twilio_auth_token = models.CharField(max_length=100, blank=True, default='89ec830d0fa02ab0afa6c76084865713') twilio_from_number = models.CharField(max_length=20, blank=True, default='+18556945903') + timezone = models.CharField(max_length=100, default="America/Chicago", choices=[(tz, tz) for tz in sorted(zoneinfo.available_timezones())]) class Meta: verbose_name = 'Campaign Settings' diff --git a/core/templates/base.html b/core/templates/base.html index 73437e3..7a75e50 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -40,6 +40,9 @@ + diff --git a/core/templates/core/door_visits.html b/core/templates/core/door_visits.html new file mode 100644 index 0000000..f1d0bec --- /dev/null +++ b/core/templates/core/door_visits.html @@ -0,0 +1,251 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

Door Visits

+
+ {{ households.paginator.count }} Unvisited Households +
+
+ +
+
+
Filters
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ +
+
+
Unvisited Households
+
+
+ + + + + + + + + + + + {% for household in households %} + + + + + + + + {% empty %} + + + + {% endfor %} + +
Target VotersNeighborhoodAddressCity, StateAction
+ {% for voter in household.target_voters %} + + {{ voter.first_name }} {{ voter.last_name }} + {% if not forloop.last %}, {% endif %} + {% endfor %} + + {% if household.neighborhood %} + {{ household.neighborhood }} + {% else %} + None + {% endif %} + {{ household.address_street }}{{ household.city }}, {{ household.state }} + +
+
+ +

No unvisited households found.

+

Try adjusting your filters or targeting more voters.

+
+
+
+ + {% if households.paginator.num_pages > 1 %} + + {% endif %} +
+
+ + + + + + + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/event_detail.html b/core/templates/core/event_detail.html index 2b5bda5..9003941 100644 --- a/core/templates/core/event_detail.html +++ b/core/templates/core/event_detail.html @@ -34,6 +34,12 @@ {{ event.event_type }} + {% if event.default_volunteer_role %} +
+ + {{ event.default_volunteer_role }} +
+ {% endif %}
{{ event.date|date:"F d, Y" }} @@ -97,7 +103,11 @@ {{ v.volunteer.first_name }} {{ v.volunteer.last_name }} - {{ v.role }} + + + {{ v.role_type|default:"Assigned" }} + +
{% csrf_token %} @@ -229,7 +239,7 @@
@@ -269,9 +279,8 @@
- - {{ add_volunteer_form.role }} -
e.g., Driver, Caller, Organizer
+ + {{ add_volunteer_form.role_type }}
+
+ + {{ form.default_volunteer_role }} + {% if form.default_volunteer_role.errors %} +
{{ form.default_volunteer_role.errors }}
+ {% endif %} +
{{ form.date }} diff --git a/core/urls.py b/core/urls.py index c436512..c83001c 100644 --- a/core/urls.py +++ b/core/urls.py @@ -52,4 +52,8 @@ urlpatterns = [ path('volunteers/bulk-sms/', views.volunteer_bulk_send_sms, name='volunteer_bulk_send_sms'), path('events//volunteer/add/', views.event_add_volunteer, name='event_add_volunteer'), path('events/volunteer//delete/', views.event_remove_volunteer, name='event_remove_volunteer'), + + # Door Visits + path('door-visits/', views.door_visits, name='door_visits'), + path('door-visits/log/', views.log_door_visit, name='log_door_visit'), ] \ No newline at end of file diff --git a/core/views.py b/core/views.py index 74d8d4b..bf9b534 100644 --- a/core/views.py +++ b/core/views.py @@ -10,9 +10,10 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.db.models import Q, Sum from django.contrib import messages from django.core.paginator import Paginator -from .models import Voter, Tenant, Interaction, Donation, VoterLikelihood, EventParticipation, Event, EventType, InteractionType, DonationMethod, ElectionType, CampaignSettings, Volunteer, ParticipationStatus, VolunteerEvent, Interest -from .forms import VoterForm, InteractionForm, DonationForm, VoterLikelihoodForm, EventParticipationForm, VoterImportForm, AdvancedVoterSearchForm, EventParticipantAddForm, EventForm, VolunteerForm, VolunteerEventForm, VolunteerEventAddForm +from .models import Voter, Tenant, Interaction, Donation, VoterLikelihood, EventParticipation, Event, EventType, InteractionType, DonationMethod, ElectionType, CampaignSettings, Volunteer, ParticipationStatus, VolunteerEvent, Interest, VolunteerRole +from .forms import VoterForm, InteractionForm, DonationForm, VoterLikelihoodForm, EventParticipationForm, VoterImportForm, AdvancedVoterSearchForm, EventParticipantAddForm, EventForm, VolunteerForm, VolunteerEventForm, VolunteerEventAddForm, DoorVisitLogForm import logging +import zoneinfo from django.utils import timezone logger = logging.getLogger(__name__) @@ -700,7 +701,10 @@ def event_detail(request, event_id): # Form for adding a new participant add_form = EventParticipantAddForm(tenant=tenant) # Form for adding a new volunteer - add_volunteer_form = VolunteerEventAddForm(tenant=tenant) + default_role = event.default_volunteer_role + if not default_role and event.event_type: + default_role = event.event_type.default_volunteer_role + add_volunteer_form = VolunteerEventAddForm(tenant=tenant, initial={'role_type': default_role}) participation_statuses = ParticipationStatus.objects.filter(tenant=tenant, is_active=True) @@ -1163,3 +1167,167 @@ def volunteer_bulk_send_sms(request): messages.success(request, f"Bulk SMS process completed: {success_count} successful, {fail_count} failed/skipped.") return redirect('volunteer_list') + +def door_visits(request): + """ + Manage door knocking visits. Groups unvisited targeted voters by household. + """ + selected_tenant_id = request.session.get("tenant_id") + if not selected_tenant_id: + messages.warning(request, "Please select a campaign first.") + return redirect("index") + + tenant = get_object_or_404(Tenant, id=selected_tenant_id) + + # Filters from GET parameters + district_filter = request.GET.get('district', '').strip() + neighborhood_filter = request.GET.get('neighborhood', '').strip() + address_filter = request.GET.get('address', '').strip() + + # Initial queryset: unvisited targeted voters for this tenant + voters = Voter.objects.filter(tenant=tenant, door_visit=False, is_targeted=True) + + # Apply filters if provided + if district_filter: + voters = voters.filter(district__icontains=district_filter) + if neighborhood_filter: + voters = voters.filter(neighborhood__icontains=neighborhood_filter) + if address_filter: + voters = voters.filter(Q(address_street__icontains=address_filter) | Q(address__icontains=address_filter)) + + # Grouping by household (unique address) + households_dict = {} + for voter in voters: + # Key for grouping is the unique address components + key = (voter.address_street, voter.city, voter.state, voter.zip_code) + if key not in households_dict: + # Parse street name and number for sorting + street_number = "" + street_name = voter.address_street + match = re.match(r'^(\d+)\s+(.*)$', voter.address_street) + if match: + street_number = match.group(1) + street_name = match.group(2) + + try: + street_number_sort = int(street_number) + except ValueError: + street_number_sort = 0 + + households_dict[key] = { + 'address_street': voter.address_street, + 'city': voter.city, + 'state': voter.state, + 'zip_code': voter.zip_code, + 'neighborhood': voter.neighborhood, + 'district': voter.district, + 'street_name_sort': street_name.lower(), + 'street_number_sort': street_number_sort, + 'target_voters': [] + } + households_dict[key]['target_voters'].append(voter) + + households_list = list(households_dict.values()) + households_list.sort(key=lambda x: ( + (x['neighborhood'] or '').lower(), + x['street_name_sort'], + x['street_number_sort'] + )) + + paginator = Paginator(households_list, 50) + page_number = request.GET.get('page') + households_page = paginator.get_page(page_number) + + context = { + 'selected_tenant': tenant, + 'households': households_page, + 'district_filter': district_filter, + 'neighborhood_filter': neighborhood_filter, + 'address_filter': address_filter, + 'visit_form': DoorVisitLogForm(), + } + return render(request, 'core/door_visits.html', context) + +def log_door_visit(request): + """ + Mark all targeted voters at a specific address as visited, update their flags, + and create interaction records. + """ + selected_tenant_id = request.session.get("tenant_id") + if not selected_tenant_id: + return redirect('index') + + tenant = get_object_or_404(Tenant, id=selected_tenant_id) + campaign_settings, _ = CampaignSettings.objects.get_or_create(tenant=tenant) + + # Get the volunteer linked to the current user + volunteer = Volunteer.objects.filter(user=request.user, tenant=tenant).first() + + if request.method == 'POST': + form = DoorVisitLogForm(request.POST) + if form.is_valid(): + address_street = request.POST.get('address_street') + city = request.POST.get('city') + state = request.POST.get('state') + zip_code = request.POST.get('zip_code') + + outcome = form.cleaned_data['outcome'] + notes = form.cleaned_data['notes'] + wants_yard_sign = form.cleaned_data['wants_yard_sign'] + candidate_support = form.cleaned_data['candidate_support'] + + # Determine date/time in campaign timezone + campaign_tz_name = campaign_settings.timezone or 'America/Chicago' + try: + tz = zoneinfo.ZoneInfo(campaign_tz_name) + except: + tz = zoneinfo.ZoneInfo('America/Chicago') + + interaction_date = timezone.now().astimezone(tz) + + # Get or create InteractionType + interaction_type, _ = InteractionType.objects.get_or_create(tenant=tenant, name="Door Visit") + + # Find targeted voters at this exact address + voters = Voter.objects.filter( + tenant=tenant, + address_street=address_street, + city=city, + state=state, + zip_code=zip_code, + is_targeted=True + ) + + if not voters.exists(): + messages.warning(request, f"No targeted voters found at {address_street}.") + return redirect('door_visits') + + for voter in voters: + # 1) Update voter flags + voter.door_visit = True + + # 2) If "Wants a Yard Sign" checkbox is selected + if wants_yard_sign: + voter.yard_sign = 'wants' + + # 3) Update support status if Supporting or Not Supporting + if candidate_support in ['supporting', 'not_supporting']: + voter.candidate_support = candidate_support + + voter.save() + + # 4) Create interaction + Interaction.objects.create( + voter=voter, + volunteer=volunteer, + type=interaction_type, + date=interaction_date, + description=outcome, + notes=notes + ) + + messages.success(request, f"Door visit logged for {address_street}.") + else: + messages.error(request, "There was an error in the visit log form.") + + return redirect('door_visits')