From 21135ae821c3944f10e2e2467fc0c3a7f0108138 Mon Sep 17 00:00:00 2001 From: Faheed Date: Thu, 16 Oct 2025 18:07:31 +0300 Subject: [PATCH 1/3] easy audit added for activity log --- recruitment/__pycache__/urls.cpython-312.pyc | Bin 9990 -> 10086 bytes recruitment/__pycache__/views.cpython-312.pyc | Bin 74177 -> 75893 bytes recruitment/urls.py | 1 + recruitment/views.py | 53 ++- templates/base.html | 4 + templates/includes/easy_logs.html | 337 ++++++++++++++++++ 6 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 templates/includes/easy_logs.html diff --git a/recruitment/__pycache__/urls.cpython-312.pyc b/recruitment/__pycache__/urls.cpython-312.pyc index 0c55bfb29bf38156f99e83aff768904292f53e4c..adce72e1c30f16b7cc7755dcb141f50e4236ee83 100644 GIT binary patch delta 842 zcmY+CU1-x#6vvbFs_oV)tdp&6mbCer9o>iP%FtOEy6Wa;sbUqn;V7&)HFI-y$|eZD zNSz=Z8MsFu3lmrA%U%?p_MjjM1cSonn+zG_`aB=J_Y?#}^5byM|NQSsa-OAsrhT7% zz6OR|8~b?r!-_A!?!Ie(@9p830y|YIpgSd6{QsJI{>HuTs^?bNTxxMS`l9yBd;Mr| zsiBZBE>7yRw~F20J^$i#^g``?XqV&WFBvCyRjId;=VlUUS^x8U$e47Gty16@y5b$T;aZ^pc#+h_*2>joE=$w^vRAshwH zg_Xn5(`#hH0q>lR?&CNl`e@<^BoeyuBTQ#J0JcOV5}%G}gn3{IxB>hcq3#C|OA^(L z0OzDO62Fvq!gVP~xFxj{?n?rpPo|6kM`fy+miaR<$OD#skk)d-@y9HG%#07)Xap~? zP<%*>rYG_`;mAo#PMSkG8;#>f#NeY$58MI%0S1*$k{MR$fHR6Bg2NaG4kxP#C!V$9 zS#x5^Mvw7jPB*Fwb@&3@Q|M40m9KZ@>RkhyStpsZk~uREUE`!{NDUKZL8YfGtJI+a z+)`B%?*W@MI>{jLo<{SlT4(*|WnA=iMY>EKR-mKmv(Z_6g>2i7)~3S5*FeFS3$JEZ UW-DYF`*GGqD^DBeZ<9s-3mb$3{{R30 delta 947 zcmZ{jO-vI(7>2v;U_@ImkqU+WZM!WCfmDhuArO^fQa;s8UgdKI{-2rK zZ!$59AP8F~CtQcOOdf_5^}D-XP}DzeAE(pfh$=#@dBao!ie2kSkd6dSjZt)o z*}&C+^DpODN-s<6Z4@O~t)eQP#%|Dcpo6Pbnj9l?44)aLXpGsx9Rb(99?^Poq$h`q z*C?81^@_UTaTu%JFr$5SRtv>RD2|gQibk0SR(rvDmhGAtAz}pgCMgY}Kh#zQg4xdQwQ{0(&a z^zc5PZp*;uzF;rp=7il~zWaV6_v5n#ii#{RfGy~D!L?MSHOQnv#-S4won%EGv*T;z zwECM%FmZf02Fu-=JV@k0oExWTf=w7Xm;a+D4P7?04@(hEN)joFvkFC1>Zg_z6$8YF^v2KT7v;T5(bV0^#JwXL%#9n z?^oTbQ>V^3b?Vf)b*rC$G40E@(sEzV$;q_PzxiLD?;CT&k=!!n{v%_m!)b~|vuLS4 zt8PltbWm#sd#o~dSX+2+gAv(;=ar~7jBTs4==8NNI{U(MGG)B=9C`wI0! zwNQ7c4!uY%;<`*9Ys+Xx{T+R;rM(O2hIX~q1D)dUVlFPZiD!p2*rgEN^ z@2kRg7o>uIeuFp_saJj^HnLbmUsb8*M z&K*j9SLn0US^8{swtl60CD)bt=IC?Pxq6G*qPME8`aE?W_Z{V%uP;y+=xu77-mbRm z3)O}CB6X3zSY50yQJ3gT)urek*2>AO9cl+Nt01#3Qgz39ji{W3^kjww`JmJoDnUeO%i}wPQT3@mep}Hc_q1(-N=k*T!CNQMYR2 z2z}akLS36c=+~MF17U3<{Ta|E5niiJCKTEf!k{*lFr-Z*9Mq;0Zu4|#S7|e@S58Ki zSGRkz$s)PhWm}Y(`r6FvEwT34Uv&plU7kdBMVu;ZQFm&yi2aZ@oA5i|AiXk9YEgG_ z>zpJ;bCX(kYc0g#yPjoQYf^1kn@6>KwE2X4wFQL#O=}~(PHQK;KCCUIKR0NL2yfID z6YkTN5boEO5+2Yx2yfDs5#FqI65gUMC%jc#L3mJGNqC3`T$ME7VQn?l9x)Xm+oZ&8 zvnH7;+TM{&ur`U{d)hi;BenH}w`m&)Z`U>weqU1wBRdt>rr%;BI$es9zQq#?d3J<` zPoxbhjj4ux{;IVL+O~Q8AtSRRu*K^)%h{_u*A9AuA%2q8woy$)y24HE?odD&_BMSW zw3D7aMn14J5Nh==_J=%MJj3&Be@;>6$yxSFrBQCMcV;f8p#@-}JY{dNuZlg&dotW| zZf0@&64WdObO2fb%K)8#<$y7O6@Zlh=CK;3wK3?BcV;%&xM8hqE*mxctIT&&l`i>M zZojfY*5tX?7ZRzF>JMxewJ2FVLXaxy!qilZMP-IIDBK}$z%M3(u@%q*=mls151EezEb2|qbKM3yu#a_To0F3XlitFi*kxvY} zdIL1SJ3?KWJLDD^OzZ>f2c5~^ux;J$7F&WwdX!e&OpU=b0;kitNASS6($i4A8VKmi zJf4u(zoo+)46XBeo)myMT2re)>nSM0h84E_hzY>2*geR zn{)?CLx4-UcLWW9+oZp0oN3_*TlFVZH!0z}(adYE8zr{X1}f3`O{i!A@H(ADCBsHb z%R|o3_UJ|%8wK_d10YBZhJ?#zT8VkzjwWURy~Q9w&_=+@JL_0|qd3WH7w`z=x7)>! ziSC)<|6TK{wUB2&vsZX%j!znpm5Pc%qr{`C*un z6CiF(@dO?d&hiu<p^NpUuS zMK;!hdoa}3H7I;6yDMtJujHAv!@< z$HDME(6KV?Q92&k96S_fQf>})U7^5Mk6(NNf&v1gxMOkW(zXSQJG&OI?wY^6v$Jjf znzjX^8wA+3*f6wj^W3H?RPhyRF971vXLOS01u>1uk9@u!ckfn_PTf8nety|LCFc|B z=SpE4i!Ql#d3_nLgZ~S5pAsaTMjlySZnaa-Kgm7&R^A&g?ZyJ(5pl~PFISCUt0BSS~GYL z<*fDdhN(H*sjp$92#J8o!{iVHG8W5lOrBovuwhK`pnPrp3}vrWHq0CM3OLhw3dQct zUXM@f3hf;5h#HVN0mT41l(C31>EF<1=6uW?>CEvIbE4T_t_G`X2s&M*Mp}O`;5V$k zfLjY1X*~gLr|DiJY{a7R@^WB|PO!KSfCwa>B%r0@AEcKI3PIuui=48tI6Mn&nE*C1 zdl^=qE00ZVq;ay3)Xm5;&0!{oEH*3h_;#!%#seIETWE% zx-4QeU{Jobv8);k%_t1Iw|TmF`eKeDCKJtHhHdJc6lI^h_N7t7*KGPYCCrmzH$|@k z7g#^Z;ylPG)X|ZbMbP0Gd?(>ds1T(DYdR^w$LozO%@gdU?26w5Pm)aLE(E)h4|Jmf zx`!$C7%>S6(}S&Hqm9zz*G$&6RC7rQ>(IbfVDI3GEwA&t&)!Jm+%h2$l3y7UUNU1emod|aE?9<%bc-iKG&y9dO0wV)qc7WEDC`H{o0L)~* z;q%JQFjsafYFlK9r*Vb=73UEdRN~-9U`BSwMNSf=08g8JJN5NS;rUcqHGIwHqe?pV zeB=#EU$O0BaBG*9eGONGu`Aom4Okw~B_#!{!7thikNrz zm0K54)o%H8-`y1YHhEtwrejTum<5QtnwTnQ_1CmB^A>8MxxIuT4cj)ik4|IEl{yx5 z(YyhD;(3F-w||tCjx#NXl(3`PZ9^7%+Mk^@UjrODTA>cG1Vd5+Cn25+$FDTBW|TG|V<)Vc9L?X@Z%*Vj4|n=7dqabii3$vH<%KS|=08=$!znmc|}n@_Hrl+cF5o+~%WFW7Z1r5Ag_Z~m@^(V!V$r(zKD zaAdtmy<$r+BcWe3hE~ZxTvufiJE=>feEs@YNXgr7cwVW5lC(^af%Ez?`Ed?2LteYD z-UfX|zr1VTSW_=vJiHP0Q&%I;w1n^k2LgV22l(a$g4W0%5T4DRP;X!S-H2xsECg%K zGtBXlXVaeK!ZF##TFjLjA6)E4cL*4?Cn-!COaJ~VYnWPFU1da$=-O*(x_gE^p>#bqs1=2Y%NBZUFG1-i;{j1MCMJkk3Y3C5e_4>c{DmM`X*d zBcnPJr&n&U>;d!wHWN_#(T_6s51=%%-LS_G1jGs1d&g{Li@f)aYQ-U+y<^-JZ=%aD z0G%X^%Wftt-%9NIAM~un4rb)^(6QB4UYJ2oh&fP9ycNpb0>JVn&fkLRO&~uY-~U0A zX~RQ!{+s;{pw%>_oP1|x(m@Ev&N67lLA4wueqGv+QZ0bfWe$CF@EDJ*=Fv|U)fqXP zMS!Aq?8r2(i)cj;_AgkD&IC#8X$mcSF&EDnluS?xND1={5YiVb>hYu8wgK=CrBUK*BlNrgHV`H)s;~tVLkCl)f zeaEV;|4f4XYWU`3YD)1VkcpLn3Z^or<%JXDm&AoXZZiY$2>DnvmM8k2nV147k(7+c zfs>=GPt!nqY>+Qhs%+RyiQE9=@Ie+~J3%GK$4P05Z}B+`*t>TR}+YP_N0^ zr>2LYL2NT(Tl^5V<25!JeX=||+0u&rgl9zD%Ra;p)?kit;1b_Gr^25K{zVA8G}6HbFG$=A;r7iL6xq@XoYw)ZAhfr} zPF9KF6;!_}H$5>n4DpS$kQnp~WiHwn};skL1HIzCe0j`_k*FX2kvg0`LSMlpU{#(fo853A3^A$6l5 z_muqjl?n6(C-2qyNxJg>A76ZCB8yx^+zBHe1{?wKX3b8JgI4A~4Gk;E*Q%`lPVMK1H@)^Vg+I^srplJAB6;N-A>Ll_N(}}Wp33Ztr{rsI zxE6EFok!JXTEuf1{q$YJND-PN?Y{; zQ5;VZydQAqkBH)e&54(3XHr7_K2^70C|wOZIH9o98+79ChgW#C=8N9tKX|)2ya@tx z%t*Mr8+8fWd+@lKz)0Wjrlifk<#@*5PUD%Hd2tteu(!{n4f;G9r6D}sEIfMzIY>s- zL%QUVvsKDD`N-Ls;ckq_k%`|MAc&Ehh+_PK_yN+AX#p58) zL<76$_wo2ofJ9K5h}IT@a8h>74xY%QYeCZuh)X7pf(;fkr4~4@H!^U1iHi;5Jv6bp ztav|KqYjFRp;UuD{Gu}7@AlGJu<5&5?4=w$L-PE;mMaHk);r_*Hj7a$KYOp*CQ?%@ zmg&RpcOFk|fm?{rFc52t7V?s>QNhC_q<0=qis?os9emJ-D*gtPk|NjrvUW|vbz8xX z0~a_Y#p0+ZCm1L6;j^pK-zJ2BZUKmFwn@?y;>w1yMn?!!nth!rET zoWh1;1_0hIJ_oQRU?#z?E&hngdcf7Fyaw0YvhuJ$dbb)t@FR35B>tSY+#_7Q$ z&v1e~?$P2uFxH;|e*v5$;x*y|ivJ1t3IOkQRgd({)0Qx`#rL=WZ%_Tl9d(82speOY zBrmymGEIB@6^gLkEtn9~Az>K>kGz1%ea>twEv8q==u~1pWjgIeH>AkVe%Uk}`S{b! zSuda&^pxu%d>J{3#oR^P8V?S4xRBehaYBPWp+Q^Iu;_}0W#Ufx^uITC#C^`lPJ~eE z2bZDq)r9ORG&*Sb#nSvblMY$gp-eZDlYdv2mE=6~n%_-nX2(f59H&tuq9J>T=@Rmp z-@R3csisV+n?#6)DtYhkE5khRwB|y{{ev100??ew*&6LbBp~i|Hu2Xac+sNBJt19K|tw-T9rlb6)@@$Fd}EN!m2n zAPK{<%@WhLNzVG~cv}v*@0I#r>#A59b`raJb%ljwBa`Dk_}7{9;2lO`pF2pGkV1pP z(-pn0CK8$S2tP>Ju@D0}Zf{gV`IvR_IiLuY-@E;UGA4WvJjC|Rfr)^fax{^;#wWQ- zD;QkLUqETbWX`wQ3jF$f7Y$*)zb5v)*oGEPJ~%=yVs2FIU7VATaF7vZP3ZY8{G}W0 z;VPm8qK-vr9C994p?T7ADQAh!1Cbt#Tu_vn5@%f$TTc$<4i-0-0BFEB`_ zY4y}h@f1c&L_k;NNPps3^AEU9ve)oDVj9<&mxNm|7RRzDQDRq3g^|17ARv<%~$FtzE`9?spS6%ym{8%pwdu< zY@SsS*Xn&{behb6-gJ(RY2$Y4A>ME}hCaiw~(}q(`ZfK7`hS zq8q@9bE1vB&V2WXUPs|t3@WB!e)11dG5PjrWM!#RW4(;pE{hD7DnE&;v9L^8qJ&uu zXkhBnjahXQ(0fFJ<#bGJ^tvaD&yvr;Xgry022N_@{mt_ne&L9I1sWlyNy*zD3rvAG zwtmb-GZpLs%Ocatm5BM`qu|9S^ZQgAv1rO}MSkQekzGrQOH;JelT?d;yHj?hXlYx? z*kYXAJ9CN*{5-26HI!wxS}d9^cGZ7(ntv0~rkk{(Y?<9N3DgzI)EPMkWNmo+ABL1vuZX1DCJ_B-V1I)}{smrQH=uJm2B{d`#@@12)9 zb61*{eKc)%MyM*z(4yt+%831JWVL0qB~%n^tLJ+b%x>kiMRoBp(l=UenG-5WBCA&7 zqo!K>%kb+LdFsoIFerPsTXv*wv}{*gxkEjfh-2-8eooIP^tkEd(uu=pXDHx|USD)B z=y&_K1e|T|;7(`jAl=SS9`$68uU#5>eSzm=fNk9;``c&0y|v;;)@tT z!H4m@Ld@e8BPWb8y6EPTc~zqYD_}XgwxTp2YJi<#H|cPlgV&CoXfRRy&wSUh$7L4n z)VY^Pf>WsP9?SU*OL6I*W#?^{!cmcmBNdUFBQ^IHAG4h;m>Ax(DJZ`q+;s1vzdDB<5!GvZTq)5iqsm^9sX?O9jD*wNhyc3v3TYK0MHkcn}+a7X>dEtPvxZjX7l}ct=1FEtpZqNrk z?+`xrHG*?vll6-Qi>uIs+8&s`q2R5 zOE9vOo+|iLrDy?pD_|agGmr(5%~eWmxD6HU1V-xW)oo%SN_M)4)nVTMUxH?&s75x2 zt#vdxtLZ!FV$`n%tOx7@+y;mMehhdH@FL(%z{h}p0~`l@4fs93*r$_Q3S1u*S%3n- zWWZ$r+}9GgDkYWyRsdE51YjFrCjejV#X|sm3=#NfC7uP~yOF?WAAyfA;%xw@sqauJ zEO62*aCRwhbZDNe;P{1KwKyRbNUsEP6W;1MR*m=tkdZN)tWKwObA(28#K;mnPlfZT zilV%4$$H=fjHTtAWiR delta 13988 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%0DwE&89k<#66K)SC11a}yp@k9?9uFYoM&7O zy4+w_k7@M#O_fWtEsx8x{by@eNPYj0QrqWU)ZY`Ce9PSII*!Uufax*7Qv`H>jGdY{+GpfVcP(mULD}gJW8@zLUIh6| zfR_QU$c($k8}%s805CP1{B=C;1ndG}M(s2j!OmWbw5J_ciz;;IswJPW&CoH>|G3XJ!%!Lo907Czctx zh1_#wH^s)>d!<&v(ja!(>3#Gb#da<-_+)3`2+54#w6Pfc1EJHlvTryx40+ zFAO;#EAcohNr#}kh z*Nt6iZlbNZ$6c7@$%CNgxx0aglU|!%Mh&)8-K-CNYs7Ph~yTyF>uD~XK_?^Ju>dhpHlIg z%WE%DC3!OXT!lV>N8~e)EF<1Ck5xok|FbTwiJ9LF8eU(6REoZ5kf{72V66=PZ1h6N zZs#Pz2W7+?(8~VEihJ?ML$RLM(<4cDJ8IcquR+N#fAh1^N!uDb&LygM3{N(b!}S0ii7C&uT7GcY!bQXDfelu!G;(EZY<`0loBf{vD34HtTbyGO$moi z7QMbaowiCnupOEkQk7lJ2i$@C3$=2`o22tQvia#JN#&28ekn}_=3hW6p4&b0h37>B zzc_TL8a@iKC3xiXh?IiaQF;CgW9e1RRWHms7Nf2bPbLeV|;~iJM17co#E^1UEnNc0k%i?@-lT1Cm@|71e9RE$dK8l=t z@j3D(dE3iZ^A>}1H@HDGDzl5;BNx2lUc_;C234!9il;p3HH)2-7=_lS>KKQuR~v`$oNd*q%IEh@*YmAxlxo#G$F z=FG@DCyu7g#-xi6z;+NNw2%*ci3%PJalG?jQXsdp=@JBQBk-Q*@0xt`9a zcf}+ZUt>@fSauu*)VK0%N3#fPXo)se+VsQVT^9A>vXAIvTQd`$i5 zOo%B-8fS>lGkM&V#itnSGr;G7UsB)I;tLf24EPJcOO@{0p)Sc^s3pvsbp9HI0G9&( z9T)xgJ#@KpQT0kB$ze{NS7ndCK@qn5S12jpgoyu(M_#$)N%Rh+1jiJ1LWXNG^_Qo{ zram)L{Qd{o(|O|2iPAa*D?2x_ls&Z9u>`xQ;j6r+^<$f?u}#M6riIg*mWm(BX&;X6 zi2Go2z@&cg8@iQEDDZb012hz&=u(zn`e<>lQobaQd|2;F@*w%vhiA01_awZIbEzS* zklloryhl#|=y(z4o6@DEKqYHFt`2)4QghPebNJxB@;z!&rsL(t3|S@)A8c%n5%C;I zE%0ya865M%@l92X#c=G+ttctcQA&7o7alpZ@t%#1P;J~bD6wikr4nMkz{yiNQ1s$8 zJ}Dv_Cgw@_dp=o3>F7e`UOE4h4(E;F)+=xLWVZ5_Of&&b!dw2H25%Ymz^B{tW+fs- zlD8yn8H3=IFdW+~F>Pz*LtnQzGr)a^{Nva4HT31H3NEzFasE8TQ?7GsQx?EG?4lko zT}AhY`i1FGTjkNZ2t4+;a)GSISR5s<`f$wzdG%Fa89`L+e!oqcm+)_(rk{ zB~#xJfhgELYlzm}lH@cTluze5pj1gWr{9AZi8Jr(VE9Y%nArPb8ykHt#}nF(X2f>2 zVX>bL;Bknn3^8y*<8R?PaiD-3h9&1V_-gRd59qtetl z`oa7X?GdfuW{fuoc$Q#$l{_@PYT%1fZHabxV0M{Sp-v=eAYg^7P#OfBB(O93L;x?C zl8&al3|M5=k`w3ns)&7O!nKFNrWKR1mr6rE3biZnb)skBS7lm>V>}T}9QdqEdnhXW z)8*P?EzH70ZY7b9xx_msIv^x?kHd6EzuaU!ScNtW%Nh-$|D}L{i^py$hRCZZ z8!;Y>PBAuiyy2sb7z_4*B?I?YY6EjRz)S0N?-RqRlbtC{dUGBO1?@`XLT_((pcP*| z3*W|8d@R(;-*E>8q_xw9ud7F-4_q=rtJWL?KO3RdIJ<&klW?M3Uy7mW>jcH6Clu-v zxNI5tbc9wMwsWHOxRecwT#yz-tBj4YVe*nWQ2rX^3@Xl(B-^CEB#LqC5BZ1)k2E=AjjgEPz>dnE^E{RtPvz0y$ z;P3l|`e2|S{?$?JBdy^qH$71v;@gg!@;VGY0@X1sgFV9nBGlC%3aaIcITeiq8yd9A zDNQJk1dIZVCa@h!H#aKyrlA?7761ouZ1V%(Z_tWI(nq%V+CHdW%})TuM8G7#WWW@H zffpOJ+5u;yRvVs$y4eJF+NxFUVh&1K^jfw{27fHkGk0ae5W85 z02Tw50{nnJKoEe}W8yAA1b{1EfooxbTUK!lfU8RJGJvD~Yg97Cn|Q|IUf__e@>v{Z zI8EVwMIcHEEOxbkmOykY9d%!jIfG12FFIz5P9h;5DZzKB@JX7cX>X;t-b%?I*w>^@ ga{ak9MQeOJrQz+A<_AwUX;-Iaf8J84O=V9154Q8m761SM diff --git a/recruitment/urls.py b/recruitment/urls.py index 4bc00ac..c9e9b9c 100644 --- a/recruitment/urls.py +++ b/recruitment/urls.py @@ -109,5 +109,6 @@ urlpatterns = [ # users urls path('user/',views.user_detail,name='user_detail'), path('user/user_profile_image_update/',views.user_profile_image_update,name='user_profile_image_update'), + path('easy_logs/',views.easy_logs,name='easy_logs') ] diff --git a/recruitment/views.py b/recruitment/views.py index 68d11b1..e356d06 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -1,5 +1,6 @@ import json import requests +from django.utils.translation import gettext as _ from django.contrib.auth.models import User from rich import print from django.template.loader import render_to_string @@ -13,7 +14,7 @@ from django.urls import reverse from django.conf import settings from django.utils import timezone from .forms import ( - CandidateExamDateForm, + CandidateExamDateForm, ZoomMeetingForm, JobPostingForm, FormTemplateForm, @@ -23,9 +24,10 @@ from .forms import ( ProfileImageUploadForm, ) +from easyaudit.models import CRUDEvent, LoginEvent, RequestEvent from rest_framework import viewsets from django.contrib import messages -from django.core.paginator import Paginator +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from .linkedin_service import LinkedInService from .serializers import JobPostingSerializer, CandidateSerializer from django.shortcuts import get_object_or_404, render, redirect @@ -2394,3 +2396,50 @@ def user_detail(request, pk): } return render(request, 'user/profile.html', context) + + + + +def easy_logs(request): + """ + Function-based view to display Django Easy Audit logs with tab switching and pagination. + """ + logs_per_page = 20 + + # 1. Determine the active tab and the corresponding model/queryset + active_tab = request.GET.get('tab', 'crud') + + if active_tab == 'login': + queryset = LoginEvent.objects.order_by('-datetime') + tab_title = _("User Authentication") + elif active_tab == 'request': + queryset = RequestEvent.objects.order_by('-datetime') + tab_title = _("HTTP Requests") + else: # Default is 'crud' + queryset = CRUDEvent.objects.order_by('-datetime') + tab_title = _("Model Changes (CRUD)") + active_tab = 'crud' + + # 2. Apply Pagination + paginator = Paginator(queryset, logs_per_page) + page = request.GET.get('page') + + try: + # Get the page object for the requested page number + logs_page = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + logs_page = paginator.page(1) + except EmptyPage: + # If page is out of range, deliver last page of results. + logs_page = paginator.page(paginator.num_pages) + + context = { + 'logs': logs_page, + 'total_count': queryset.count(), + 'active_tab': active_tab, + 'tab_title': tab_title, + } + + return render(request, "includes/easy_logs.html", context) + diff --git a/templates/base.html b/templates/base.html index 3738bdf..7ed1a2f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -143,7 +143,9 @@
  • + {% if request.user.is_authenticated %}
  • {% trans "My Profile" %}
  • + {% endif %}
  • {% trans "Settings" %}
  • {% trans "Activity Log" %}
  • {% trans "Help & Support" %}
  • @@ -164,6 +166,7 @@ {% endif %}
  • + {% if request.user.is_authenticated %}
  • {% csrf_token %} @@ -177,6 +180,7 @@
  • + {% endif %} diff --git a/templates/includes/easy_logs.html b/templates/includes/easy_logs.html new file mode 100644 index 0000000..6b7433c --- /dev/null +++ b/templates/includes/easy_logs.html @@ -0,0 +1,337 @@ +{% extends "base.html" %} +{% load static %} +{% load i18n %} + +{% block title %}{% trans "Audit Dashboard" %}{% endblock %} + +{% block customCSS %} + +{% endblock %} + +{% block content %} +
    +

    + {% trans "System Audit Logs" %} +

    + + + +
    + + + +
    + +
    + +
    + + + + {% if active_tab == 'crud' %} + + + + + + + + + {% elif active_tab == 'login' %} + + + + + + + + {% elif active_tab == 'request' %} + + + + + + + + {% endif %} + + + + {% for log in logs.object_list %} + {% if active_tab == 'crud' %} + + + + + + + + + + {% elif active_tab == 'login' %} + + + + + + + + + {% elif active_tab == 'request' %} + + + + + + + + {% endif %} + {% empty %} + + {% endfor %} + +
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Action" %}{% trans "Model" %}{% trans "Object PK" %}{% trans "Changes" %}
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Type" %}{% trans "Status" %}{% trans "IP Address" %}
    {% trans "Date/Time" %}{% trans "User" %}{% trans "Method" %}{% trans "Path" %}
    {{ log.datetime|date:"Y-m-d H:i:s" }}{{ log.user.get_full_name|default:log.user.username|default:"N/A" }} + + {% if log.event_type == 1 %}{% trans "CREATE" %} + {% elif log.event_type == 2 %}{% trans "UPDATE" %} + {% else %}{% trans "DELETE" %}{% endif %} + + {{ log.content_type.app_label }}.{{ log.content_type.model }}{{ log.object_id }} +
    {{ log.changed_fields }}
    +
    {{ log.datetime|date:"Y-m-d H:i:s" }} + {% with user_obj=log.user %} + {% if user_obj %} + {{ user_obj.get_full_name|default:user_obj.username }} + {% else %} + {{ log.username|default:"N/A" }} + {% endif %} + {% endwith %} + + + + {% if log.login_type == 2 %} + {% trans "Failed" %} + {% else %} + {% trans "Success" %} + {% endif %} + {{ log.remote_ip|default:"Unknown" }}
    {{ log.datetime|date:"Y-m-d H:i:s" }}{{ log.user.get_full_name|default:log.user.username|default:"Anonymous" }} + {{ log.method }} + {{ log.url}}
    + {% trans "No logs found for this section or the database is empty." %} +
    +
    + + {% if logs.has_other_pages %} + + {% endif %} + +
    + +
    +
    +
    +{% endblock %} \ No newline at end of file -- 2.39.5 From e7d823d7074519cc982c77eab4e0fafcadae4040 Mon Sep 17 00:00:00 2001 From: Faheed Date: Thu, 16 Oct 2025 18:18:25 +0300 Subject: [PATCH 2/3] ... --- templates/base.html | 2 +- templates/includes/easy_logs.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/base.html b/templates/base.html index 7ed1a2f..5651b7e 100644 --- a/templates/base.html +++ b/templates/base.html @@ -147,7 +147,7 @@
  • {% trans "My Profile" %}
  • {% endif %}
  • {% trans "Settings" %}
  • -
  • {% trans "Activity Log" %}
  • +
  • {% trans "Activity Log" %}
  • {% trans "Help & Support" %}
  • {% comment %} CORRECTED LINKEDIN BLOCK {% endcomment %} diff --git a/templates/includes/easy_logs.html b/templates/includes/easy_logs.html index 6b7433c..284b600 100644 --- a/templates/includes/easy_logs.html +++ b/templates/includes/easy_logs.html @@ -165,7 +165,7 @@