From 586d6e6abb6c782eb91fd03594e41fcbe8e74166 Mon Sep 17 00:00:00 2001 From: BaiJiangJie Date: Wed, 31 Jul 2019 16:57:21 +0800 Subject: [PATCH] =?UTF-8?q?[Update]=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=BF=87=E6=9C=9F=E9=82=AE=E4=BB=B6=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/zh/LC_MESSAGES/django.mo | Bin 78676 -> 79397 bytes apps/locale/zh/LC_MESSAGES/django.po | 207 ++++++++++++++++----------- apps/templates/_message.html | 18 ++- apps/users/models/user.py | 14 +- apps/users/tasks.py | 32 ++++- apps/users/utils.py | 53 ++++--- 6 files changed, 217 insertions(+), 107 deletions(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 098558e3f1dd022335dd3739c200d3209cf8e940..2247e8f62680751357e3b8bf5a430219446218c9 100644 GIT binary patch delta 23965 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 W@=i)S-?gJ}Y@N7iTXevef&T|}n-I_d delta 23375 zcmajn2Xq!i`}gq;gpkln2pvM`Ep!m+RjP;xC>?^*ktPTP7DYgsl+Xp~MWlz`t5QUy zN|g@Mk)jll_xro&;(t8v`M>Agb0(j;u9=;knccl}13u5fyTK=J1pB|I37+h66b<&g zEI2cV=S@yTy_&L~*W)A48;d=00KUdq38**oyivp%T6*3PoR7zYJTF%(&&y2vv)07q z!`pdY8vFyp@Fk|hL@}Nh;(5N8nM!gJQJ55qVg#1QeAozcVJtE?Z?3rqvlCxO=I$kG z?|H>A36{t5SQPtXeq4&#@B~KVV~pYYUew2)mz%_J)C`y5@3zqh1{#eC zaT-SAOw@$8p(gYbYUi$@w)`cAVv3I35=@WU`Vy!K)+N@FTf*b249U!Vq@k2-ND z2IF~5jF&ML-a_rb3rvJ5JF)$k&Wyy=#060cs({>nuRdy_t2(j&d8lkBksq()r*3%%Tx{pW%95_a>v z>ev$XaLhx^{3wRvRr4-t>z-mV4C?M4!W5``8;!}aDr(2xLtU^js(*7#fgMq|s-I6q z1Ac?*FatHfV#}|?T*SLjTYCdj;Gb9+wOwHljXM7=RR0>NThtkK3kRZ}rKzZAU?pZk ze;<{UR4$nhQ5W!fxUEcyYLCF&mAgcda zRR61}d;bJ|z4s~mxS174O`sk|V-qZb!%#c04z;zLQCqtcb#H$`UGN<0)?BstK5G2G zuqI~w%4dhfzCm3pMa7%P0HXZDl^xfNx`Z zdM77FR_L z^e$$^mS#WHcoR@7U10fD=0Rj!-@8Ud1OA1&aIyhzOVguvB0FklilXjy8Pp2iL9Mhg z>H@7T-vu?{{-}wKws;2WAzp@B@M;X@`rdX+{Dd0l1nR<2 zZT*+13yjCW#PJ>CRhSu{q56fhx-1xlRk4!AUt(qA**^QP3tb|i72QI8!2F4N`2NQH zm~4o9MoOawu7{dXGt{kWi&|MP)Hs7s;|?>w!FF?=gbRF3cnQK3%9d;chtl_L-ikH?UT*9Sd#p5%z;->*9ji#E}Rs28u{LJJCa8Pe1NAU{g}SFBQ4?B(dbrl0CbAW^vVExYj-x)9ZlbpQHEM^_d=(ha z_i|7vLLv`pMomxycSK#N4+i4|)P<&4JO_2bg{TRyK;5D(sD8UJ4<5n<_{e;UQN+&z za{n_AzTn(OUFSY(XI_lr{nrH(k9I4MKn<7$LohFDi=$CbdwFYbg!-M)3N^7l77s!_ z%yFpx^HJk(MvZp>wS&J}{`6?}Uo*K$LQm@x)F)Wz7`KJFP!CHP)IiNJ8Fs>?*cUb7 zFEJsG#oRanbt^Ym`!-bn{ivNgVfmLnl`s+^W8F$pq2i3FfpennWi)C6RWKR8XYDO5 z-x0NdeyG=NG-}23t$iu#;ogLr=sDCv{fkuep1(vrJn6o1-+1z(wze|n$J(eB^hRCC zN3A3dHNnlOl^@0w_!#vpBpBx=lGef8%jk3jzw+BMAXVxpgL}_ z_PwaBJ%IW^xs1A1*RU+!M@=B#1b2Q7Ohx=I>Q=VK)YutyomdRk`#+6}I?h6MT!DIc zHlgm}4orcl`x<$*-*Vb;KqOJKA z)$tORze!|iMvoUJ%~l{4C=(NNp2$P&4Q>~Qwg==rl@CVFlxu9noCd%-GqT#If?z( z)?Ox|_x!OLG1+}ZDvO#xGmOSgsQ%N;rKkb7qVDO><{zjX37+CihMGt?YQee9fs{?pq`CcsGVAdn!rZXc)L;e{1~d= zRn)C`gj#5#Z~1uV`d%g~dUz^gMr?-q1nYyk=W(bDe2*Gv9p=NmsEOXgX86R~8_ab5 zTA>!y4K=aes0$CmVmJ|f4Y-$z?&WdRLvtJTQJj93%a=mk^LnV)uQ6(cF_<2EV^$oE zn$Y*C3$Lx2u|a1*uCrK-3N?bH?2 z#O`7ie1Up9($8}f$!n zQCr;u^P!L0xh1H6%TW*I7V{U(M0^>wga4ow7{0(QBnPJA`d&dQdU(pCR`f1viyEW0 zuoLQ@`lyx9LiPV1>);lPLl(LTWWdMd3!-)+`yzMYqNs&dKrN&e`Wmn)6>UunYKyyC z+}C0sHPA@Z05ec4S%_Ns8q_V?iJI__sGT^E8utNeXP=?^hc0&GMJ(q2>wYwv9h+qsB#M7vIAH2f7j!{^YxFXiZPmybQn=lWyU+F$@Mx!3Sg&2)H zQ44xtW?1DG1k2_G$$Zx2J{l57kAoo9HqkA3FpdPjym;m!&Ld=gku`q^US=7!{ zM!f~KP`9ozroc7Uz6-;M51`IJj;Zk?YMehYiQfNbR8nEWP3|6tV>;rZsC!rwHE>(h z06kC_{u0yRILwCgFg@-$+hWZ_G7$fl(hGUW~?jg*MnqXPf#Ok5OYmXYQ&lc{#1{`7y6Rlw$YKvEx z>#;oXcGQ->#4eaIxGA7BRj1hoS`YMgPZDDf@o zgdeaLZbhv$(GEAUlvt2BE9%0vQ6D59qWZ<6wt6^fWz$g?UW=O8j~I$)QMckMW<&oa z6@7MR+Ud3`64kLZYGRd8?G4PvsHe9%YAf5JCe#^qq5i1z$D*F8DX5jsM@@7k>Q-$+ zo)zEQPDL|6j&tz_uEwu-xsGq|b^}#1>!Bv_5thX^7>zS92OhxMcn393sXhGJ0B>Sn z+_;xl7mMuE2b0h1L`CoU8f=g2QCpk&NB4ABLJim)wY3XT57kZ#!Bgf1%o4;G5G+nU zXuq3SNlZi>gW0hYY9~fw;P-zV6>aqb)E2JAp|~Hlwe=3T*Q+_|#8}jYhoiQ5Eb8H$ zfx71lQRi*I`b_9YWSw64A-BLu*fIhCw1a+s8k+vXhY23VeVp*Y5oS+^Oh*}ne3s+x z;XHx5&~?-;dx*N12~W6t9EzdD;i!pZ#jIEaGh%(z&UG*conT(tk~k7NF&+!xRxE@! zu_%V0bidtdpl(4|)W9Qf2rk4LnCFz+p{{tCxG!pls{iI}h}yYUs0Dod8~dUTpIgH) z>o~@oZZ0z8&7G)$4x1-1jQE_jUpF72-uu@UXE^Q7%Z-{qA)iX%HA79Lf!PAn5qGj! z{nS3joQ^tgk;UsR-eVrO{8jTIYQnF~;4?1vlUgMWY6Tfl7s_cCMa{H=`5ty4jzRT5 zgt_n}=EE1*6my<+zqSWrCF1jDmUAv{;q<+kRLZIYYK9T#-N0Eu9CoMFyIwJ$N(nY&Q~9zjj~6!yWhsQwKuJ6oV8*a`K) z6^r_u8G(Ac#$WbbWf2LTxD~Yn2h8J^zknL(HtJTqvN+<3i}Rx!Zn&@0$xsu^iE1xkaTzQ}T+!kIs1<*Kdip0>9FIEhM~jb3uJ7HjhUeB0 za?{N)BWmV3QCn9QHE?6pKpoA`%rC8doW=9Zm6qRX@ezy9qpyJ;Si?W4r#tKqXB6s! zeuJ5sE01;J=ZY@YAd5rU&X3e+{@x&s0pt( zx0!oU-vJL{4!nRG=QSq7H1`AN@%@iVDiV1x49mC%uL`PTEsGmtPU04pAA;&X78~GH z%!fCz0H%82&M#-yLQS->*#ZOq{ug5%x>>^ji@&h=8`MfBqb|7E@~cr3+-UJWi+@J- zJ7Zq8_Iu_N^CbrU`@aMa-OMth28=R`U|!<#m` zJ@t>QJ?Worhtgo+{jWeJ2_5QSV2e-_X@PpkI-x$vhFN|A>cXp0{db}6@qW}jzKuHn z73#uC9=RRKiRxe2EcwXZ|8gWWU=3?%jG9mj)BqhY0S+;TVl?q^a~-xMzJ@ih>SOoU za$n;o#D_2q7JuRSL=S2-z+4A*Kuh$2tTh_|#j_HU8o0Cu%UWyuL zn|aFe4=|a2|0j6iE|3znf-IN`b6Q*xHGvxD`=}3^))s$_n$Tnn#o3l$Vy;6?WVgj9 z%_~yB{~uW5A529Y_R^UNb>V`j0p3D=vem_e*ca7*fH@j9k(sESS%i8v)?;bhYwa&l z=Oy}w_dhq42r5dHN3EcV|de=-`1+L@{5ch>@yAr5-RoiT54m2mBCbk@P-e!vrqb7J3^@({IwG(0gI@6k2F@k(v)DBks z*WUlCB&w2VfcmJNh`P`Q)P?qB z>i8FC##ffl7~}@dW0pYmt8DQ*7JpziH`|$=P%H0&`t>~&HPOXR-&<=PcA-{u0yTka zmiH346Vjr#KGNc{sE4yA>bz#w-Whc(hN3>{rlT&n#oG5K>f{l9OCe^D1sn$VdS zwbE*49n?S#%~qE0VsS6jN_~qbnzK<8T4wFLEq@a8a((X#m28+K*v&XUYDINX`R1q# z4?w-HBTx_Na?}Kmq3-1w^Qw8z{2O(CP$Dc@h;86!_P*x~TEHqsIR{B*^{we;5f3Fwr_pw|GA4 zo-eg{59$I3Q4_de@js{mQzmvhmjyLmA&W~`Tn*K)j>SzA`!3PS8oHRDqb@YeoM!%D zZa0sjZpAg!M8iUzQK$))!@$F7b~Xo~`j7IdXr}XVC@w|KFgnax4%J=@wRH_p1Ac`1 zOz(v1KL<78<*45gJ5d+7gL?Ralelp*q59`A{b(xcP|j?Kx?l&hyZMRX4V(@&Kt9wrol=+|JEOjMOfqMiOU-qto!N<+ z*srL!<*dbCGM7(chGXE*|JkTyrDJZ?g{ztGnJrN(?riZOi$|HWEWZjhfo-TAJZ$+B z=4JD~`4R))|3j18JwaV48g=igV0CO}?XyuASZ487iw~eKcm{ReCG3dLEpC^>~wb20G!{|71>V54=|Vg8Jo&>4&Gn$OLUly1PZr~xA_E`S=ZjKvi(5piA1H$>ga z4^!IvA45Vb>w#Lq5Y&LvQ8S*88gP}l0rmTPyT!Xv{SROYJZ||b<}LFfYP`QO@K&Va z{SPLQDV1x;j#_acvl41T@0(pv1AJvpK=uF5T#cIOUW*T*`u~m^=Z?j}soi<0eJV|9 z$YqIGa~$%gCvTp`lhU|>7Nb_W*5d8vA@j6(-F#%eHj|}w<77nbl%I!+w!Rc<<~6KC zJ^u5Ydv^6niEb79OQCqhL zwZ%J7Gd^bVWeg06`X!b%T~OfPlA=)`z3-yhyP+;P#o|p^llTgj)$jlO5kZ0ffFK5S zD`uiD`~;_9PRDNUxqgH$i!|@-~A1+fzIdh^`QVO+_ z@@8$biM7X|K5#mtJ|}uuz7OhyXQ0Kyqj>*y!LcL;;2cbfnRB`esBv3i4!!@~t;2Y0n1#B~a*Owv$59u&ikj#>)E5`8fV)68RK6f; zCo7`**Fe1m4NwzmWcfB2`1ilg*3i=&j2d9HInkVM&M_CGR|Y%o$N@%H<~ZWjV10%euec@bDsayPf^!x3LFjSn41&-<^qq& ztftH+R}t%xJ3?Kb@jCdJ_x5sfThtNGc@ODxhI$6-BdLE$+onJ(f7~LzPMiYkk*iP1 zPpO`O>nGs^9pBQZgF6y9g3SS3=oD?kEnZ{&#*ptpxkaq^T*qF@_ko)Gd!IhE-=paG zg?BkEaf zG0W+fm3TR&2JJDN6N~wXXVLZ}^&I4$z1jaVBzDqRgmR4z)rd#YVF2~dD9tHXDCsF} zDR0xS3+o`aM?6{l!Dsp<-bv&UwBYr`9bJ}!dvPm`|ANb$@DY=axv2{?KSTQ!| z#80Vjq3xWt4UOO z;RJbI!VAOJ;EL9rvmKq~08R$^A{e43qhnlE(U| zEy()Rp`L{LRGaW5HFC_SZx1|3+kHGmNtf`=!$d! zjy+ffHNk554slBcxP&)sp#9WC8DyNruZaJ9>?Fu+ZIv0P6!j7G*-j}$eLcf_a|!0z zS%;`!q+vRpkCMyC;3+6N4$zi>wo15__Rn0}t4!_yac#;%+H@2ow}+UovifEaI4Y3) z@3EC&rat_4(NVuCFH`Q*X)bmk7el#4J%|Y$z@`jTpHi24F3Mu+Iy(Me13%-uaLU)@ zf1!P~_50TxO52-by*}#8kmyb44wPlYl__zQDwG+t^}ykrkr{JSZj-x7Uw)B#e^B^E z&EL?z8Iq55s#}QprrMVsvVig@`N>$)#--}jqCSoM2~5lQI&Qsr|2td93v|$Nm9|E>QIa{SM>4y2 zh;^*C!9KP4b8=^!Bl4RIIh-7Qvg zYIczC$X+4F_=UAj}P}eu_9#}>9|2e@?8(81K`;+^J#?!cu_!8>)9(PdMP#-Ai zQrDArC)<&Qb{!*eu;sJU zw;;KJ+}2IsVM+ zeM@}|{lXY$5^eb@XUP9SzCC#zS11?B|3+R%H|n?XDS!C(UJ-mvpua~LW+(86ac>Uw z&v7()9U17Cj`9<^9WE94d5oVY$?vjrmCR@tQhmAApHlzH`YfY=e)1{w`#;2z>!_ck zu0LJBi@|i#afo_;R=3dx>gUp4TU=r1wx?|taal@j>ZNczMMpB?KN;&G^&-|^f3>K? ze~-j-I(&l3Nvx&5iOwJ4PV1b{OwS~qQZG)wl=R6>Nk&e`RO%V<58BsI&x2zrC8)nc z{xim#OkKwWT#3~a^8P2V0dmv%H_E3ptfI4yWyE(WlPp#)6(udXH%A{T|1#iyOi8{8 zr84zHl<%!y9_lmc6T>(ya4T-dqQTt%KWRKmpra=Z$vEi{@m!or?zRo0_I2b_s=|?k zd^gGwYrjga0_|_(6^x+FV!U5)34NZRjz`qzksnPd!1e#Q9{oATxuO71Yh8GLiBwaORP?^og<821y)pP)W~dNE2a&ilvZeQz5LI$lsF zQjcbU!aNg?sE@V5nqhh3qV##6Qi!tAF20ER1xiI>p<`6K$|q;wJQYNSR|f^&e&Dm7spo1~^FWXX=YI1`A4L zea;dV<=md+ztZRbe7lIwD?-Un{2iTNSpKY85f@NCpif2G|FQu?@OQ>}kCK8COrNA& z@DBCKcJ3AWJSTp0oF~?c=TD_lj!t9nYl@Bvj=;|kIjIZzb2iX4>Pe~Z|Ic94|I`0( z+M|hcF!~ef-_UOnHlw7XWF&4!dkN|Z^p{@?NTefClCq8ZaLRe=zf($cp~rNbKwU?9 z+UintoTJpCEg}%PAEjyQU~wpIIvQC2lNN7g%#_rZ(e{l#{~yw!3dv_AS5qHPT}M~y zg;>Qz>J7==!{qeILVhJ?rY$@9&BQuBrW~RCPFp`4<5$`yQcprIul4(oK39o#^zv!^ znTFr-Ey{M1-vyf7kK1&dPU%jcSG4Q6MEQ<-4RXaP`G`ND&*$WlQUCAJl3=@?H-ma4 z{dJV0{|NH`^ZE0kb?Qvx4|H0N6UY^(6r%G@a>Fo|{95bVl)8>#lzz17=!G3|hV==h zUW2m8F5JsZN}xIyTS{!j=xA{zD++evG#h`V!XTq=xtfWgPj_#5(d)dQl2< z(Ff%3lmC`-*v{=}PN)3`${^al3`{Tyzd|`NA&L0n%{B$cEsaSRR3z?v>puK^uT3X@ zZfY|uyhyuV6_Z4A6fRsiNuW}m=C);Mo*9#qpG(`;;OB$39r!uoM1i;=?Q&6D&~D}b z|I{5Z{pcDPEWTU&WZC0K58Y8czV-e-2@@BMEcVvhCEtoadnhC*KKgKUa9pNi5p*tk zEJmlasTr5;Nakdb<%_g+vtv@PkA3yOUvm7(GKm7qh)Z=WlCvKkug=esCmQi{#EAy{ oJauBp|MOIue>$lp-8tEepKi9Xr\n" "Language-Team: Jumpserver team\n" @@ -167,7 +167,7 @@ msgstr "系统用户" #: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22 #: terminal/models.py:258 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 -#: users/models/user.py:330 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:331 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_detail.html:63 #: users/templates/users/user_group_detail.html:55 #: users/templates/users/user_group_list.html:35 @@ -218,7 +218,7 @@ msgstr "参数" #: perms/models/asset_permission.py:117 perms/models/base.py:41 #: perms/templates/perms/asset_permission_detail.html:98 #: perms/templates/perms/remote_app_permission_detail.html:90 -#: users/models/user.py:371 users/serializers/v1.py:120 +#: users/models/user.py:372 users/serializers/v1.py:120 #: users/templates/users/user_detail.html:111 #: xpack/plugins/change_auth_plan/models.py:106 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 @@ -279,7 +279,7 @@ msgstr "创建日期" #: perms/templates/perms/remote_app_permission_detail.html:94 #: settings/models.py:34 terminal/models.py:32 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 -#: users/models/user.py:363 users/templates/users/user_detail.html:129 +#: users/models/user.py:364 users/templates/users/user_detail.html:129 #: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_list.html:37 #: users/templates/users/user_profile.html:138 @@ -721,12 +721,12 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: assets/templates/assets/system_user_list.html:52 audits/models.py:94 #: audits/templates/audits/login_log_list.html:51 authentication/forms.py:13 #: authentication/templates/authentication/login.html:65 -#: authentication/templates/authentication/new_login.html:91 +#: authentication/templates/authentication/new_login.html:92 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/remote_app_permission_user.html:54 #: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:14 -#: users/models/user.py:328 users/templates/users/_select_user_modal.html:14 +#: users/models/user.py:329 users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:67 #: users/templates/users/user_list.html:36 #: users/templates/users/user_profile.html:47 @@ -750,7 +750,7 @@ msgstr "密码或密钥密码" #: assets/templates/assets/_asset_user_auth_view_modal.html:27 #: authentication/forms.py:15 #: authentication/templates/authentication/login.html:68 -#: authentication/templates/authentication/new_login.html:94 +#: authentication/templates/authentication/new_login.html:95 #: settings/forms.py:110 users/forms.py:16 users/forms.py:28 #: users/templates/users/reset_password.html:53 #: users/templates/users/user_password_authentication.html:18 @@ -765,7 +765,7 @@ msgstr "密码" #: assets/forms/user.py:29 assets/serializers/asset_user.py:70 #: assets/templates/assets/_asset_user_auth_update_modal.html:27 -#: users/models/user.py:357 +#: users/models/user.py:358 msgid "Private key" msgstr "ssh私钥" @@ -971,7 +971,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:349 +#: assets/models/cluster.py:22 users/models/user.py:350 #: users/templates/users/user_detail.html:76 msgid "Phone" msgstr "手机" @@ -997,7 +997,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:457 +#: users/models/user.py:470 msgid "System" msgstr "系统" @@ -1116,7 +1116,7 @@ msgstr "默认资产组" #: terminal/templates/terminal/command_list.html:65 #: terminal/templates/terminal/session_list.html:27 #: terminal/templates/terminal/session_list.html:71 users/forms.py:316 -#: users/models/user.py:127 users/models/user.py:445 +#: users/models/user.py:128 users/models/user.py:458 #: users/serializers/v1.py:109 users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_list.html:36 users/views/user.py:243 #: xpack/plugins/orgs/forms.py:26 @@ -1223,7 +1223,7 @@ msgid "Backend" msgstr "后端" #: assets/serializers/asset_user.py:66 users/forms.py:263 -#: users/models/user.py:360 users/templates/users/first_login.html:42 +#: users/models/user.py:361 users/templates/users/first_login.html:42 #: users/templates/users/user_password_update.html:49 #: users/templates/users/user_profile.html:69 #: users/templates/users/user_profile_update.html:46 @@ -1312,30 +1312,30 @@ msgstr "测试系统用户可连接性: {} => {}" msgid "Test system user connectivity period: {}" msgstr "定期测试系统用户可连接性: {}" -#: assets/tasks.py:471 assets/tasks.py:557 +#: assets/tasks.py:479 assets/tasks.py:565 #: xpack/plugins/change_auth_plan/models.py:522 msgid "The asset {} system platform {} does not support run Ansible tasks" msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务" -#: assets/tasks.py:483 +#: assets/tasks.py:491 msgid "" "Push system user task skip, auto push not enable or protocol is not ssh or " "rdp: {}" msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh或rdp: {}" -#: assets/tasks.py:490 +#: assets/tasks.py:498 msgid "For security, do not push user {}" msgstr "为了安全,禁止推送用户 {}" -#: assets/tasks.py:518 assets/tasks.py:532 +#: assets/tasks.py:526 assets/tasks.py:540 msgid "Push system users to assets: {}" msgstr "推送系统用户到入资产: {}" -#: assets/tasks.py:524 +#: assets/tasks.py:532 msgid "Push system users to asset: {} => {}" msgstr "推送系统用户到入资产: {} => {}" -#: assets/tasks.py:604 +#: assets/tasks.py:612 msgid "Test asset user connectivity: {}" msgstr "测试资产用户可连接性: {}" @@ -2212,7 +2212,7 @@ msgstr "Agent" #: audits/models.py:99 audits/templates/audits/login_log_list.html:56 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 -#: users/forms.py:175 users/models/user.py:352 +#: users/forms.py:175 users/models/user.py:353 #: users/templates/users/first_login.html:45 msgid "MFA" msgstr "MFA" @@ -2479,23 +2479,23 @@ msgstr "改变世界,从一点点开始。" #: authentication/templates/authentication/login.html:46 #: authentication/templates/authentication/login.html:73 -#: authentication/templates/authentication/new_login.html:100 +#: authentication/templates/authentication/new_login.html:101 #: templates/_header_bar.html:101 msgid "Login" msgstr "登录" #: authentication/templates/authentication/login.html:54 -#: authentication/templates/authentication/new_login.html:79 +#: authentication/templates/authentication/new_login.html:80 msgid "The user password has expired" msgstr "用户密码已过期" #: authentication/templates/authentication/login.html:57 -#: authentication/templates/authentication/new_login.html:82 +#: authentication/templates/authentication/new_login.html:83 msgid "Captcha invalid" msgstr "验证码错误" #: authentication/templates/authentication/login.html:84 -#: authentication/templates/authentication/new_login.html:104 +#: authentication/templates/authentication/new_login.html:105 #: users/templates/users/forgot_password.html:10 #: users/templates/users/forgot_password.html:25 msgid "Forgot password" @@ -3022,7 +3022,7 @@ msgstr "空" #: perms/templates/perms/asset_permission_list.html:118 #: perms/templates/perms/remote_app_permission_list.html:16 #: templates/_nav.html:14 users/forms.py:286 users/models/group.py:26 -#: users/models/user.py:336 users/templates/users/_select_user_modal.html:16 +#: users/models/user.py:337 users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_detail.html:217 #: users/templates/users/user_list.html:38 #: xpack/plugins/orgs/templates/orgs/org_list.html:15 @@ -3071,7 +3071,7 @@ msgstr "资产授权" #: perms/models/asset_permission.py:116 perms/models/base.py:40 #: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/remote_app_permission_detail.html:82 -#: users/models/user.py:368 users/templates/users/user_detail.html:107 +#: users/models/user.py:369 users/templates/users/user_detail.html:107 #: users/templates/users/user_profile.html:120 msgid "Date expired" msgstr "失效日期" @@ -3625,7 +3625,7 @@ msgid "Please submit the LDAP configuration before import" msgstr "请先提交LDAP配置再进行导入" #: settings/templates/settings/_ldap_list_users_modal.html:39 -#: users/models/user.py:332 users/templates/users/user_detail.html:71 +#: users/models/user.py:333 users/templates/users/user_detail.html:71 #: users/templates/users/user_profile.html:59 msgid "Email" msgstr "邮件" @@ -3893,7 +3893,24 @@ msgstr "下载导入模版" msgid "Select the CSV file to import" msgstr "请选择csv文件导入" -#: templates/_message.html:7 +#: templates/_message.html:6 +msgid "" +"\n" +" Your account has expired, please contact the administrator.\n" +" " +msgstr "" +"\n" +" 您的账户已经过期,请联系管理员。 " + +#: templates/_message.html:13 +msgid "Your account will at" +msgstr "您的账户将于" + +#: templates/_message.html:13 templates/_message.html:30 +msgid "expired. " +msgstr "过期。" + +#: templates/_message.html:23 #, python-format msgid "" "\n" @@ -3906,15 +3923,11 @@ msgstr "" "\"%(user_password_update_url)s\"> 链接 更新密码\n" " " -#: templates/_message.html:14 +#: templates/_message.html:30 msgid "Your password will at" msgstr "您的密码将于" -#: templates/_message.html:14 -msgid "expired. " -msgstr "过期。" - -#: templates/_message.html:15 +#: templates/_message.html:31 #, python-format msgid "" "\n" @@ -3927,7 +3940,7 @@ msgstr "" "新密码\n" " " -#: templates/_message.html:27 +#: templates/_message.html:43 #, python-format msgid "" "\n" @@ -3940,7 +3953,7 @@ msgstr "" " 补充完整\n" " " -#: templates/_message.html:40 +#: templates/_message.html:56 #, python-format msgid "" "\n" @@ -4408,7 +4421,7 @@ msgstr "你没有权限" msgid "Could not reset self otp, use profile reset instead" msgstr "不能再该页面重置MFA, 请去个人信息页面重置" -#: users/forms.py:33 users/models/user.py:340 +#: users/forms.py:33 users/models/user.py:341 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:87 #: users/templates/users/user_list.html:37 @@ -4527,52 +4540,52 @@ msgstr "选择用户" msgid "User auth from {}, go there change password" msgstr "用户认证源来自 {}, 请去相应系统修改密码" -#: users/models/user.py:126 users/models/user.py:453 +#: users/models/user.py:127 users/models/user.py:466 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:128 +#: users/models/user.py:129 msgid "Application" msgstr "应用程序" -#: users/models/user.py:129 +#: users/models/user.py:130 msgid "Auditor" msgstr "审计员" -#: users/models/user.py:287 users/templates/users/user_profile.html:94 +#: users/models/user.py:288 users/templates/users/user_profile.html:94 #: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:166 msgid "Disable" msgstr "禁用" -#: users/models/user.py:288 users/templates/users/user_profile.html:92 +#: users/models/user.py:289 users/templates/users/user_profile.html:92 #: users/templates/users/user_profile.html:170 msgid "Enable" msgstr "启用" -#: users/models/user.py:289 users/templates/users/user_profile.html:90 +#: users/models/user.py:290 users/templates/users/user_profile.html:90 msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:343 +#: users/models/user.py:344 msgid "Avatar" msgstr "头像" -#: users/models/user.py:346 users/templates/users/user_detail.html:82 +#: users/models/user.py:347 users/templates/users/user_detail.html:82 msgid "Wechat" msgstr "微信" -#: users/models/user.py:375 users/templates/users/user_detail.html:103 +#: users/models/user.py:376 users/templates/users/user_detail.html:103 #: users/templates/users/user_list.html:39 #: users/templates/users/user_profile.html:102 msgid "Source" msgstr "用户来源" -#: users/models/user.py:379 +#: users/models/user.py:380 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:456 +#: users/models/user.py:469 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -5115,43 +5128,43 @@ msgstr "您好 %(name)s" msgid "" "\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Please click the link below to reset your password, if not your request, " "concern your account security\n" -"
\n" +"
\n" " Click " "here reset password\n" -"
\n" +"
\n" " This link is valid for 1 hour. After it expires, request new one\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 您好 %(name)s:\n" -"
\n" +"
\n" " 请点击下面链接重置密码, 如果不是您申请的,请关注账号安全\n" -"
\n" +"
\n" " 请点击这" "里设置密码 \n" -"
\n" +"
\n" " 这个链接有效期1小时, 超过时间您可以重新申请\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " 直接登录\n" "\n" -"
\n" +"
\n" " " #: users/utils.py:121 @@ -5163,88 +5176,114 @@ msgstr "安全通知" msgid "" "\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Your password will expire in %(date_password_expired)s,\n" -"
\n" +"
\n" " For your account security, please click on the link below to update your " "password in time\n" -"
\n" +"
\n" " Click here update password\n" -"
\n" +"
\n" " If your password has expired, please click \n" " Password expired \n" " to apply for a password reset email.\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" "
Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 您好 %(name)s:\n" -"
\n" +"
\n" " 您的密码会在 %(date_password_expired)s 过期,\n" -"
\n" +"
\n" " 为了您的账号安全,请点击下面的链接及时更新密码\n" -"
\n" +"
\n" " 请点击这里更新密码\n" -"
\n" +"
\n" " 如果您的密码已经过期,请点击 \n" " 密码过期 \n" " 申请一份重置密码邮件。\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " 直接登录\n" "\n" -"
\n" +"
\n" " " #: users/utils.py:159 -msgid "SSH Key Reset" -msgstr "重置ssh密钥" +msgid "Expiration notice" +msgstr "过期通知" #: users/utils.py:161 #, python-format msgid "" "\n" +" Hello %(name)s:\n" +"
\n" +" Your account will expire in %(date_expired)s,\n" +"
\n" +" In order not to affect your normal work, please contact the " +"administrator for confirmation.\n" +"
\n" +" " +msgstr "" +"\n" +" 您好 %(name)s:\n" +"
\n" +" 您的账户会在 %(date_expired)s 过期,\n" +"
\n" +" 为了不影响您正常工作,请联系管理员确认。\n" +"
\n" +" " + +#: users/utils.py:180 +msgid "SSH Key Reset" +msgstr "重置ssh密钥" + +#: users/utils.py:182 +#, python-format +msgid "" +"\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Your ssh public key has been reset by site administrator.\n" " Please login and reset your ssh public key.\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 你好 %(name)s:\n" -"
\n" +"
\n" " 您的密钥已被管理员重置,\n" " 请登录并重新设置您的密钥.\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " -#: users/utils.py:194 +#: users/utils.py:215 msgid "User not exist" msgstr "用户不存在" -#: users/utils.py:196 +#: users/utils.py:217 msgid "Disabled or expired" msgstr "禁用或失效" -#: users/utils.py:209 +#: users/utils.py:230 msgid "Password or SSH public key invalid" msgstr "密码或密钥不合法" diff --git a/apps/templates/_message.html b/apps/templates/_message.html index bdcbb6d5f..19e559d36 100644 --- a/apps/templates/_message.html +++ b/apps/templates/_message.html @@ -1,8 +1,24 @@ {% load i18n %} +{% block user_expired_message %} + {% if request.user.is_expired %} +
+ {% blocktrans %} + Your account has expired, please contact the administrator. + {% endblocktrans %} + +
+ {% elif request.user.will_expired %} +
+ {% trans 'Your account will at' %} {{ request.user.date_expired }} {% trans 'expired. ' %} + +
+ {% endif %} +{% endblock %} + {% block password_expired_message %} {% url 'users:user-password-update' as user_password_update_url %} - {% if request.user.password_has_expired %} + {% if request.user.password_has_expired %}
{% blocktrans %} Your password has expired, please click this link update password. diff --git a/apps/users/models/user.py b/apps/users/models/user.py index a6cdf9f0e..c2a568c34 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -402,6 +402,18 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): else: return False + @property + def expired_remain_days(self): + date_remain = self.date_expired - timezone.now() + return date_remain.days + + @property + def will_expired(self): + if 0 <= self.expired_remain_days < 5: + return True + else: + return False + @property def is_valid(self): if self.is_active and not self.is_expired: @@ -411,7 +423,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): @property def is_local(self): return self.source == self.SOURCE_LOCAL - + def save(self, *args, **kwargs): if not self.name: self.name = self.username diff --git a/apps/users/tasks.py b/apps/users/tasks.py index ab025cae3..cbdfd4848 100644 --- a/apps/users/tasks.py +++ b/apps/users/tasks.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- # -import datetime -from django.utils import timezone -from django.conf import settings from celery import shared_task from ops.celery.utils import create_or_update_celery_periodic_tasks -from ops.celery.decorator import after_app_ready_start, register_as_period_task +from ops.celery.decorator import after_app_ready_start from common.utils import get_logger from .models import User -from .utils import send_password_expiration_reminder_mail +from .utils import ( + send_password_expiration_reminder_mail, send_user_expiration_reminder_mail +) logger = get_logger(__file__) @@ -43,4 +42,27 @@ def check_password_expired_periodic(): create_or_update_celery_periodic_tasks(tasks) +@shared_task +def check_user_expired(): + users = User.objects.exclude(role=User.ROLE_APP) + for user in users: + if not user.is_valid: + continue + if not user.will_expired: + continue + send_user_expiration_reminder_mail(user) + + +@shared_task +@after_app_ready_start +def check_user_expired_periodic(): + tasks = { + 'check_user_expired_periodic': { + 'task': check_user_expired.name, + 'interval': None, + 'crontab': '0 14 * * *', + 'enabled': True, + } + } + create_or_update_celery_periodic_tasks(tasks) diff --git a/apps/users/utils.py b/apps/users/utils.py index 3ccdc15b0..f076e8df7 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -89,20 +89,20 @@ def send_reset_password_mail(user): recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Please click the link below to reset your password, if not your request, concern your account security -
+
Click here reset password -
+
This link is valid for 1 hour. After it expires, request new one -
+
--- -
+
Login direct -
+
""") % { 'name': user.name, 'rest_password_url': reverse('users:reset-password', external=True), @@ -122,24 +122,24 @@ def send_password_expiration_reminder_mail(user): recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Your password will expire in %(date_password_expired)s, -
+
For your account security, please click on the link below to update your password in time -
+
Click here update password -
+
If your password has expired, please click Password expired to apply for a password reset email. -
+
--- -
+
Login direct -
+
""") % { 'name': user.name, 'date_password_expired': datetime.fromtimestamp(datetime.timestamp( @@ -155,18 +155,39 @@ def send_password_expiration_reminder_mail(user): send_mail_async.delay(subject, message, recipient_list, html_message=message) +def send_user_expiration_reminder_mail(user): + subject = _('Expiration notice') + recipient_list = [user.email] + message = _(""" + Hello %(name)s: +
+ Your account will expire in %(date_expired)s, +
+ In order not to affect your normal work, please contact the administrator for confirmation. +
+ """) % { + 'name': user.name, + 'date_expired': datetime.fromtimestamp(datetime.timestamp( + user.date_expired)).strftime('%Y-%m-%d %H:%M'), + } + if settings.DEBUG: + logger.debug(message) + + send_mail_async.delay(subject, message, recipient_list, html_message=message) + + def send_reset_ssh_key_mail(user): subject = _('SSH Key Reset') recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Your ssh public key has been reset by site administrator. Please login and reset your ssh public key. -
+
Login direct -
+
""") % { 'name': user.name, 'login_url': reverse('authentication:login', external=True),