From 2ef487a92f117f39f8ba0e53f694efcce8020c03 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 14 Nov 2019 11:46:42 +0800 Subject: [PATCH] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E6=94=B6=E9=9B=86?= =?UTF-8?q?=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0043_auto_20191114_1111.py | 23 +++ apps/assets/models/gathered_user.py | 11 +- apps/assets/serializers/gathered_user.py | 1 + apps/assets/tasks/const.py | 12 +- apps/assets/tasks/gather_asset_users.py | 41 +++-- apps/assets/templates/assets/_node_tree.html | 20 ++- apps/assets/templates/assets/asset_list.html | 6 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 84436 -> 84580 bytes apps/locale/zh/LC_MESSAGES/django.po | 157 ++++++++++-------- apps/ops/models/adhoc.py | 25 ++- .../perms/asset_permission_list.html | 18 +- .../migrations/0002_auto_20191114_1105.py | 24 +++ 12 files changed, 213 insertions(+), 125 deletions(-) create mode 100644 apps/assets/migrations/0043_auto_20191114_1111.py create mode 100644 apps/tickets/migrations/0002_auto_20191114_1105.py diff --git a/apps/assets/migrations/0043_auto_20191114_1111.py b/apps/assets/migrations/0043_auto_20191114_1111.py new file mode 100644 index 000000000..a07dee6bb --- /dev/null +++ b/apps/assets/migrations/0043_auto_20191114_1111.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.5 on 2019-11-14 03:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0042_favoriteasset'), + ] + + operations = [ + migrations.AddField( + model_name='gathereduser', + name='date_last_login', + field=models.DateTimeField(null=True, verbose_name='Date last login'), + ), + migrations.AddField( + model_name='gathereduser', + name='ip_last_login', + field=models.CharField(default='', max_length=39, verbose_name='IP last login'), + ), + ] diff --git a/apps/assets/models/gathered_user.py b/apps/assets/models/gathered_user.py index 282f9293a..d00021c56 100644 --- a/apps/assets/models/gathered_user.py +++ b/apps/assets/models/gathered_user.py @@ -12,13 +12,12 @@ __all__ = ['GatheredUser'] class GatheredUser(OrgModelMixin): id = models.UUIDField(default=uuid.uuid4, primary_key=True) asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_("Asset")) - username = models.CharField(max_length=32, blank=True, db_index=True, - verbose_name=_('Username')) + username = models.CharField(max_length=32, blank=True, db_index=True, verbose_name=_('Username')) present = models.BooleanField(default=True, verbose_name=_("Present")) - date_created = models.DateTimeField(auto_now_add=True, - verbose_name=_("Date created")) - date_updated = models.DateTimeField(auto_now=True, - verbose_name=_("Date updated")) + date_last_login = models.DateTimeField(null=True, verbose_name=_("Date last login")) + ip_last_login = models.CharField(max_length=39, default='', verbose_name=_("IP last login")) + date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created")) + date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated")) @property def hostname(self): diff --git a/apps/assets/serializers/gathered_user.py b/apps/assets/serializers/gathered_user.py index 956c19c6b..c055e25bd 100644 --- a/apps/assets/serializers/gathered_user.py +++ b/apps/assets/serializers/gathered_user.py @@ -12,6 +12,7 @@ class GatheredUserSerializer(OrgResourceModelSerializerMixin): model = GatheredUser fields = [ 'id', 'asset', 'hostname', 'ip', 'username', + 'date_last_login', 'ip_last_login', 'present', 'date_created', 'date_updated' ] read_only_fields = fields diff --git a/apps/assets/tasks/const.py b/apps/assets/tasks/const.py index 6810a00bc..5b7db13cd 100644 --- a/apps/assets/tasks/const.py +++ b/apps/assets/tasks/const.py @@ -7,10 +7,7 @@ from django.utils.translation import ugettext_lazy as _ ENV_PERIOD_TASK = os.environ.get("PERIOD_TASK", "on") == 'on' -ENV_PERIOD_TASK_ENABLED = os.environ.get("PERIOD_TASK_ENABLED", "on") == "on" -PERIOD_TASK_ENABLED = settings.CONFIG.PERIOD_TASK_ENABLE \ - and ENV_PERIOD_TASK \ - and ENV_PERIOD_TASK_ENABLED +PERIOD_TASK_ENABLED = settings.PERIOD_TASK_ENABLED and ENV_PERIOD_TASK UPDATE_ASSETS_HARDWARE_TASKS = [ { @@ -97,6 +94,13 @@ GATHER_ASSET_USERS_TASKS = [ "args": "database=passwd" }, }, + { + "name": "get last login", + "action": { + "module": "shell", + "args": "users=$(getent passwd | grep -v 'nologin' | grep -v 'shudown' | awk -F: '{ print $1 }');for i in $users;do last -F $i -1 | head -1 | grep -v '^$' | awk '{ print $1\"@\"$3\"@\"$5,$6,$7,$8 }';done" + } + } ] GATHER_ASSET_USERS_TASKS_WINDOWS = [ diff --git a/apps/assets/tasks/gather_asset_users.py b/apps/assets/tasks/gather_asset_users.py index efeecc25e..7dfe0fb01 100644 --- a/apps/assets/tasks/gather_asset_users.py +++ b/apps/assets/tasks/gather_asset_users.py @@ -2,9 +2,10 @@ import re from collections import defaultdict -from celery import shared_task +from celery import shared_task from django.utils.translation import ugettext as _ +from django.utils import timezone from orgs.utils import tmp_to_org from common.utils import get_logger @@ -19,19 +20,25 @@ ignore_login_shell = re.compile(r'nologin$|sync$|shutdown$|halt$') def parse_linux_result_to_users(result): - task_result = {} - for task_name, raw in result.items(): - res = raw.get('ansible_facts', {}).get('getent_passwd') - if res: - task_result = res - break - if not task_result or not isinstance(task_result, dict): - return [] - users = [] - for username, attr in task_result.items(): + users = defaultdict(dict) + users_result = result.get('gather host users', {})\ + .get('ansible_facts', {})\ + .get('getent_passwd') + if not isinstance(users_result, dict): + users_result = {} + for username, attr in users_result.items(): if ignore_login_shell.search(attr[-1]): continue - users.append(username) + users[username] = {} + last_login_result = result.get('get last login', {}).get('stdout_lines', []) + for line in last_login_result: + data = line.split('@') + if len(data) != 3: + continue + username, ip, dt = data + dt += ' +0800' + date = timezone.datetime.strptime(dt, '%b %d %H:%M:%S %Y %z') + users[username] = {"ip": ip, "date": date} return users @@ -45,7 +52,7 @@ def parse_windows_result_to_users(result): if not task_result: return [] - users = [] + users = {} for i in range(4): task_result.pop(0) @@ -55,7 +62,7 @@ def parse_windows_result_to_users(result): for line in task_result: user = space.split(line) if user[0]: - users.append(user[0]) + users[user[0]] = {} return users @@ -82,8 +89,12 @@ def add_asset_users(assets, results): with tmp_to_org(asset.org_id): GatheredUser.objects.filter(asset=asset, present=True)\ .update(present=False) - for username in users: + for username, data in users.items(): defaults = {'asset': asset, 'username': username, 'present': True} + if data.get("ip"): + defaults["ip_last_login"] = data["ip"] + if data.get("date"): + defaults["date_last_login"] = data["date"] GatheredUser.objects.update_or_create( defaults=defaults, asset=asset, username=username, ) diff --git a/apps/assets/templates/assets/_node_tree.html b/apps/assets/templates/assets/_node_tree.html index 803c29c13..fc7f4ae06 100644 --- a/apps/assets/templates/assets/_node_tree.html +++ b/apps/assets/templates/assets/_node_tree.html @@ -303,9 +303,24 @@ function defaultCallback(action) { return logging } +function toggle() { + if (show === 0) { + $("#split-left").hide(500, function () { + $("#split-right").attr("class", "col-lg-12"); + $("#toggle-icon").attr("class", "fa fa-angle-right fa-x"); + show = 1; + }); + } else { + $("#split-right").attr("class", "col-lg-9"); + $("#toggle-icon").attr("class", "fa fa-angle-left fa-x"); + $("#split-left").show(500); + show = 0; + } +} + $(document).ready(function () { - $('.treebox').css('height', window.innerHeight - 180); + $('.treebox').css('height', window.innerHeight - 60); }) .on('click', '.btn-show-current-asset', function(){ hideRMenu(); @@ -320,6 +335,9 @@ $(document).ready(function () { $('#show_current_asset').css('display', 'inline-block'); setCookie('show_current_asset', ''); location.reload(); +}).on('click', '.tree-toggle-btn', function (e) { + e.preventDefault(); + toggle(); }) diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index fcc17c87d..c17b50b1c 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -48,12 +48,12 @@ {% block content %}
-
+
{% include 'assets/_node_tree.html' %}
-
-
+
+
diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index b32d5361009254cb136db5675ecb4f8c6c9fe795..d5225f406774ca2d4319ee463b3b466bc79c53aa 100644 GIT binary patch delta 24523 zcmZA92bfM*8}9KvgVAONGkP7pjy`%2WYi&A^xmU~=)8I-dPxWdQG+o`)QFY@3DKiR zqD1r{AH<|WRojh+O zw(jhC7x60oMEkBTo|l?&le&4{3D5I+Uv~GrFgo<^;dx1MG^W9+7=*DHf@?52ZpXBE z0JGx-^Ce~@&f3%SxE8M>7Q?Do0YAl}xETxL@0gwQdntN(UVakAFe|pe0yqQ<<4W^1 zb|6mB+w*c`7u15M;dz{oSFleX&kM$SecggvVmNVE)CCPg?erK-&H25hR1)J>48=XD zD?Nsq=)8FYHPK_#L_wdpaUrNU4TfN5Oo0V39hO7Q(*P4-8;rmX=+hO9rJ@y0M{Vso z48#4H1kYe5yn?zlFHj3i+0V6S#vH`CQMaT9YQB$A<0hbP$#T?%uEvzOsUQ2Fn#y-1 zc;>vbm<%tOw=fm)W7HKT?C*IzXI^U5l@7!_I1Y6S*CThqJBtkQqCe%TaVIv!kO9ti zsQlIe?0;!0Nd~$FR7P!OG-|72Fdx>(yf_54&{))!u138bN3a^^8swgtZm5MXK<(gK zGaj{byHU5~2Okw}$r;p^Tt+>`_c0tp2fHiHf!e~Ns0Bo!CMb`3W@?~rT@%y^dRhAr z)J{#X{9MdMybQI|zQa^B!7mtz*HF(yC@;BAkRCN4H)?^kQ1`S2ro(}#XW}!=h$~UI zYM*%mHUBl#&OWgGGvqDuc|k+n2@0WBULUoxR;aD(iaJ4G)WRm9u5>2q7Oh6@;Cj?E zumyFZE2tg2fx3`8sCoXee8@1}BJO_}6-}HA_5K$|T|o>M#a7ln9X0U+)B=~F`mIGR zU?*yx{is`X47K$q&1p|KQnLx{^OpC%TW?`e&#K zLr1vw+^7W~oQMaO+ z#SKxnq?kxrDVLsH(ls0Qv zdoxT;z8&hs15guwhPubGs0D05op6_V05$JXi!WeyV&8QtT4BO5ZmUC36Qn~;m%U|Di?Q($KN~9rk(Ysp#GpMr}z=)Q+@8 zP1p-H!En@-PDb6!#i*TFjXKdD)Pj$rZrw$TAED-Xg?grf$2s$0nBM=&R5Y-m*~U6_ zH^-q)umm-69BKjIqqg`YYDX@hcIYqEv+x*oA%WxF6{kddJedZqZedmD{G*c`R;cBlpPM)eztI`I@NgP)@=;1p`ydEAXxF)=Qh=oYYIBKxnE z#F5ZK_M%SsJ!*oBs1;vBUC|wkz^9lM(@x?W5=P-e9EnM=?_@WA2xkkHfo(mJM};(mh3gH^~^wRk*MCSHy@(I2QQx`&DIDe9s85A$QnsqUF6 zhg!ggsD7ebo3is87CrsPjz0Q2Y`T>iz$kN)gJO48#%UDAWSSqAv%PSybd!tc~YUTb*kbzvE#v*2KlAE4qcc zr~hFp44myIOpUs-92kbh%xb6wHZeP*Uf;g6+5a6>W{?mP+$Kt=TL0BV6vPz&mYns=BvZZ7*@lEicp8gKyhaQuY21?N!{ z{$csQE&m!dQL=gNm&tI{R#!re?~Gb-UrdPua6L}IURZLz`$=oLkBUyT3bjS?s1xo( zUHNg;glAA&ehqc+Zedz{YVE-b+y_lM)WRYyE`=$G>!A9#M9tq1HJ@)Z6>Z@pYnX{z z$Wjc)uTh_j-=VhfGU{1*h?*#Tq3fRmbsKkE6EsB5H!b&)uyGL0xG&iz86&1yBo(LM^Zc`X4@P?`Zkn7_Rq!1eJ7j zoQ2wwwbmgH^%m?yUCDLSLT_RQ4E(}9T$xb|DUA8CG-~1PP&?QYbpfML3tNr3aTkW_ z{r`=M9+HQs1q3W|CP7V<0=0#iQ1>!B>MbdT>9L;K6;l(B!ZbJ!^$@N{oj4A)po5qh z&!bQ8;ZrKvF!f?*Nz{oNp|-9g>h0)@ns6v)!jY&eUxezn5_JnUqx$VZ?d*Qk2hau7 zJeRR7-dfE5YbDvgbQ4uX?L>9dL`_leZwJhYpQ28@5VgRqs1qGRjXQ!GcM-K?H&Hu! z7d6k{sD6o-xSx#DE@A&Ok|;)^7S=(nbUx}S{v0)7Eb1P9jk?m)s4e{s^^iS5ZGD2J zZei(B{qms}7=6FX54-*2cb zePJe#bvuw5)xQvG>#Jc7{0Jj(Fmhg>_c@iqB-Wrho;UBH?(s|1Jr7>)%!k^UYGxhO zl{7*vq!sFldzt;we<7#^Pe<+KDompHKaPr?ft{$=<_v1f|H8cZ8gpTu6|TKDs=XZ+ z$NrcQSD_ZR9<`t?<{s3J9!A}|)2M#eFa_uLZd1{Ke^H;&0W016nI5&$C{%kTi)*0n zVFT0-wL&eVCu#?mVnW=EdMLMJ13ZSgFxyw|HLr%gAQBy^=%MLu4#Gsl<4_Bjf%;AS)#giXoect7WHuU zL2aE6{R^`8xu_GbMD^Q-x;2MTSAHII;yu(elxns6=#Ip!#MM``|GMX$N$3Q_P!mnW zd^jJq;(gd0zely_SmP{)+NsK@g+-%I{2>;@PN@F#QMdLhEQEV73*PZrLz1=b9%n;s zX+G2rltR5m(Wn8fQ41P|I`J5bCt*_J8K`^zIcjH?Sbh_#|4vMR`%v@v4pPy*KZ=^* zJSM~Is2#b7+S2E!dltOTnHAN)D3-u-m>+vtegW!2VlCce?zH?tOrrPyB$eEByyy~M zzsBh0xFc?=_elzNG-~ejgbLjv1|0We( z@e_Z-^WIp8kgwf@nK3!-kr<3+u>eM+ChCitcqHl;&B1!O88t3&gWJJS)cEYE1s6vD z&;J#v=yj=z)vzV%Xj3EXWzvA*97@UsACaKf#pyOsfD`Y1{Sx)P~xtb4+o+awiMNGCF)^~HxHvekbXt& zi;pOQpQ5_*_Qq81d5+Nv1TR<=Xk+kvPnpNpw*8P>vhi(jJ_ka9CW zY+z2*{ORJ|iSwZ@GzxVgm3>rn1@%x9H$rVuThvx}v$!8><-;sL2{rL-)PyUneIsfo zcB5|H5!3~oKrQShYX0Y_o%RK8aRb6o6Gos;Tnsg!JnBm8Vg$BDEqD~>#qpNkU>-+( z(mg~y3yHV7hcyCq!uQM=r_XC;9eQFE9VVkrxDRvSNlcATQCpU5o4fZJFgtM-)IvI9 zE1Zhm@D5hNM%&$6H6Jz4C0vG&aFD+L&;G`JGYH<{zF8E+oph*&8jy^jC1%6^I1CHo zBjgSAvh3n_20Vs&aNutD0rVwiB>n~q<0;fb8@R_=5cBH$eR>vr@u>Jv8WKF@m}tC{1`7fIp=D#h^`w#5A3 z`TyqNjmHke>G#`}V>{wU*cKZea96SgqlqtLbIf(neNXUV8RB@klL++s|jd}~}n$6A5sC)kjCd5$~h~qHaAIgdZ@ReF7R8_ ze3=ik|LR!qu5CJIqCwE{@@mn z29?i?T5xHMz=o)Y+t;5;1}c+KD_oA6U>oYz>_<&-!SZ)dSN6>ENq%(w(_>=txy(XX zfw&|l#lF}bhoVk=3%Qj(?35re9TRl4i)D_ z^)G=nuo@=CX{ZIxN8RF;SP*w(PP~mtIlmYDliT{Vn1eV!>PqXN7SIK?z`>XVr=f1m zJk-Oq0Tba*sGU27mGDng|NK9@g%(Hkt76tb|Ihz*sc4HEV<@&lov;ULf{_@ElQ22X zLtSAk>UCU?x~Fm29S>tJEPmWwSQA`E{4vI1@Ci3=?+Nx_6CWTUPhb#UMtu_gfrT;a zFYdEG25S=cMoqK>>Ed-i$*a^SPa;WjGQ43yun*G;S?;)YB zJC7Q0AGMIjs4IMqnFIJ;5cNr!>8x8=UDTEi$80zTwKL06JNGqe{%x2Ne?dJn*HJtC z*hggym7sHO>nEcg!iA`bR-jI>0kuP0to=JoMSKiH@ruRwFouP`k>q23)jP(2Bf^fD z=>qRRADtsn|7^#%>=Lg8l?7LL!07PsDnAe6$Jf{uyocY?zV0`E$H(r!vk3B?Z@4SU zbki-k5bE=zG-}6cp`Mj`sGVqmT5w0yP7iSUys1>Qb+M?9`>_BX#X|TDi(<}OF5d{V z5c@C>E=FzfL5#qw*6!VQ{j%an@)hs{+=JTL1b_04PkR$WC7#4t48h5F+*U6zS7H$P z&8REfVfka0|JCAa<~{R;nfNa^Uux7m+0A_DfB%bEhq7ig>I0{t#XV312cs4+67>+x zw)W-bCe+sMvG|mE&Af*i_rl_2ciBZH(ovClF&Imm)les{Z#FgCn4M8u*%O0tpg9(` z(3$26>_WU9)j!)k_xX_j9{Zn3Z-HUNT~VK~ zLy>;`3lJ)~NK8VVa06*k6Zo{YNFpQ{|vJeCwSt<=SD5CIBK5yW>af#WA^ap zx&MQ$!$@<2b(n5`VXn6Jt*9&5js0;SYT;2&omEf^tcS_4Jto1Pm<9)!Q_=tLe`2X< zf;FhE+h*>w{1McI=TP_Xj>QR{xi~FqK}AsGOPKGO)y?{53)IeZLjS-2>p`U?i2>HI z4z;D5Q4^j<-ODT1ejl~qr>KPm{=TU!@PVL#M~*P3zvaQ~I~hJ*%u zi<u}cM%NF0kJhVT;UYP!0*M9=)#B(fOg<9|yOoIo_3#fh%Q43D+ocpg6W_#`$ z3ZddkW*yW5n_1k}>}mNS<|xZgM4fo9#Vf6Sv*mZ77WAXFU-ePZmET33=$ZM-@(EwK z1%;y8GhtfHVR2b&uWZIxzB!hsUptEzqpo}f>h0KWvF|JuUGblmcxER3&*d|t2IfaC zv;yi1qA?S;M70k>%`?SZV6L?G%@!XrPrAI%yK0HYF5$hgIP9gHFdL?4;zH&Js1vrf z_P*u_%%laFt5CP%fW@a!7w`ZR<8yyI_dnp3Ye&8N7K_@%}3-tdBIqQ!6Aglka)wxdqC*W#b8{fv1X zbu%8A$-MyoH|)IlIr(;|d0(RDOB&!ziOQ!#&7Uj4=Mp7Jlq2yz>hT+99cQ67a|ss3 z%@+S|@iWv3@&-B!n^BmGdo{iTsI$BhnE&7NazNp zL|s`r)VTbXFM&EyIg6`XTo=`^h1tp4dpmvJ080!g&BwXp=&SdQ~##r zlP7Zh(xdKaZi}N(S6ap5nyC3dLfwkq{=AQ$;;h4G*02aQa3f~HZK#2#F(cly_9Q`W zi&LQg%2D5ttE0v@uzWMr!`d0M;%Lh+L;ruE+dxGF_M#q^L#P$rLQVVvwSdHl-Bw1R z`WG;ZS-uQv2dY@U0ct_bP~$ryzngi(&5`H}B{7CdVVq@thpmVoqJF2Tnr7=l|=_ArksvxQab-a5DEA-a=jJ zD>Gqo7biEv@O|1dpibPv@?9XARd-pM1Aa6F)Tr zgI$~gH7+yi%5$P_T`AP-*%UQy7^>eSRKFQG1()MTSi~3NJ_yF6?$u;-F6uQ~ike_E zYQi1nVbp}DFazGSycg>7A*lWlsCyrYnkU-g7;E=+wuXMF_jCyA-iXYq9iyxy- z@CNnsZ_<>mUznKtQ8_bP;ES`t?IKQ`wimvbkhT~<_mOV26we~j_2Zy=#aMS`b znvrH@)Xp_DJD}$4XYE5!w{#l%wB^gG$lc}{^FC@}iNoEAQlsL$s0mA=K9b9$uC#;M z(;R4yLj6=Z1+{~*sCm8$=l!ojC7y&n)1O&Grqu3)`A}C<9<{*QsE^Q&7LP&gz#`Ow zHlnU<8|nndEdQ%{4b}e^>Xy7n&HJxJ@-*%>%8Ip!%b+G0W6m%aV;=HrE&c^H{t9ZL zk1P&I>&B-xv!fPR7%O3v#h?1D!!UCaYAfeiyc9L?Yt%Q9EvOTnFt4E&`p|r3CQIkW zr9-u6wYZ>J-1L>TN@diQR7ZV+HAf8`VNS931*iqALoH~R<_qK?B*11DJ=iyE-e;%`wWJZ9cT?M%W9&g7_h!pv-DA!{#dab?tn z#`t62zqZ!U6ScA-)?tR_m!lrKO{mZK)VzVxX1vtd&#j`}2> zg8qM?yM>BQa1M2X-^}}{1^s93f&7hHaWLvugOgh{eEGns|W_svGA&zCN!g-rMCHvIW@EFx z*&DUh!_3djSZm*k`Uz@3=Er|fKhR{)?kr@MHme{z$+ z9qPyO%@&_PUBEf>5AzXf!LKb&mBYnZ&0-kL`MqjXbg$~8PSDQZz@HK=|Ea~}%vt6V z)U8`@@gdX+Pg?#4RwI6G?NxKS^L&U}a9hQC|9eu=iHD;m9E)9XvBg2TTs|9WU>Veo zePD4t)cBSbcQE^)7Bt-A8RlYhE&6}|-%dpn9<+v^Q4?OY_&O#ceqi~h=1bH)PLSIz zEEKhqnNSx}5H)W#Yp;u%w}sh0H}AiGAn0a^o~Qx+QNNgsu>3T0j`;;@Ct^`=%|=X! zhb(^tb>-*GJE#S{GSlX9m zzdLbq)E|Y?TkMOnN)@x7*%CFdo5g+1;i&I|ldXL{>YGVC=DEF}FP6dL zh1@Obj#|J0oTvBygf(=DbSwSVJdg9}_z1O-iG|%~`9joRw@#pT;x*2~h#~?0|5bQA z>Iap)Mcp${)%*yxBi$?>jsEw4E*1TFyb^2RZq%>ciHf-&uWO?omVT&*bU5k?W}t4- zVvAQ`Z{j#SgxQO`Ex(0Di4&Fx@c$>zDAZ5g?a`;LT1h1e?_y)jQ8K`L4+o)kU>i2V zn5Y2%|2{qzn-M1}72y8|Ic-oovJ>mzZET8Br33tbC7x~`K`l6_jJuGKGQ9t(Nkov) zZ@W=ubyUY@s4H!2_B4lB`vlYn({$A5$Q;WrKz%SRv3MUBG8o<%MECTjfO76+Ac{lZaiLrxzRb*PN~ zADK`CKS6!6sa+4#T+7Fqd(ES$r~kag|Cve3yLr->Im{xc^Ho4SjJ|r-(A5&3T8HVD zUxs=(H&}egJc+vEs}?^nU!ry}X$5CERwmAZx}~kLA$CF*!v8?a8jhK#P&;tJb?|PX zPV@qkV6yjYV${9Qf_go3;s`8>df(&CyQukcS9BIf%~uKi{{!86RP?vs_WlH~6Y2^! zp*rp~kDzYJ1&be|`gxUHzhq`c)CW%i)QLNqeNj6(0`<1c#q9e2f51B2K%MY0>XR+7 zvO8fxRQ`RlKI+8nQ1`Ms>L;QRs1q)-{2HuEyc@Ok{B_$uE-~tDNrnFJ|7olt2dZNs z)I=rB%9f8Y8<{Q4_GUNKLi=D39Ep0!?x7YMR3*Uwk3ce@E_`+s`~DwZ)vYWY>crVm z3n`5HKFBt421h*L+qE3S`vn;N5TLEmVf zTiFt8*o<1~&!{c>4Yi;fs0BU7v;q9r9jrv0vWEL){1DZDC2C=7P`4;yO=l=--t=Zc z)VvjaRJ3KaaRIhK4SZr9UR#{JmODWj)Iu_#CWt`&%_tK6&j{*7^^tY@KLyM1qtUm4 z{F4_-f6CjVGAs6t*0MR$(`hQ^*C>u|#K|c7nVvV#`91|0Bd%@Dee1!mC2O^PT=w^%(HKRi$wUhG4;WR`}+fy1ye|S~AHcN+Q~dTQZvX zXU6_*{g>lG;_}x1LgOg0*4~J=r_{$K;Qae&m_abd8eh|>W2X5h`9kc(Msl^RkH3R` zsY9ENUn#R_Pe8n%`hV1a!I8|9irgCFS1eRVdvb}$&Eomq zRI6hF@h0-|ln-6X|Mf9(9>$EL{W;?wQ}h?^x5pcshySGRKeiE{r?!D{96qlp1FA4V z5uywvA7WQZT`h*rdcOxyJ|Rx!26^RhIBn<1kD<(`{v6lfLe!ChIm=srm*Fog%<=yp z-2b*@>e2BN+`|M_8JL|okdliMLA;mzXSA0jK7}9P1xioKaEgwvOx3H?pAS8+v*ps- zi6@bZR|k$AIac{>ceQbOMMtcM`0}h^V%d`=u^z<{tkQ@Lg`_-IhHJj zz396E2h+A0@8V#r&YZtd_q8DSo>i75(Ubb`47fvSOK!idz8r0zQ2&kmWcuhR;qZTL zNPBb2J)%xp|C{zdQO9gb zW9pyL@1{S)zxu^y#HlS7QN)WGcTXo~p1F+C4>oCi1anA+QLd{eM=-gs)zOYy)CW>O z`A%*H6KtW>AyrA~0*0)@C@@xF9To_JZA?GRo&_{>wU#FLv0s3z_ooLKU z`I5Rl=Ai62^fd;0$GagVmClpyQVkFo10+32euT6AouEwS!@I1OLZ zaE8L)le|b8ex!bm`V~q>yOOI6>PKG3ZTi^U{&*F^E861xk^9oXI;14bZFBI;k=KfR z5lV6YT)h8dsWhiS$44|Ivw_Fe(egcQf>zj&{vovGr~a7s^~Cqp7vIAVD2u57g|%s4 zP5l6KpP_8hNjRpG??!oF_kWwqdEFVH<5S9h>b)^HZlElpb8}opEN?&dUzyUC zc?u9uqI^O;hN7bk{i@+Z7SS3%Bp*udKkA<&*UytnG8R-~_hH~2at|niY_HQVaDe?5-w{h8t&bKH@Nk%d8FgogZLA)6G6OaF>LH;PUt>jygYfn8N^=%Y>7xDid$?qWEY03oJ zy8B0QA&l!o`HTELoK4ZzpV9aKX$-zhP=FJUqTUSKP{z|~2Svwsc!D+^sV&!q_#?*u zMBI&f6s10;Cbs|L+Q((c07Ld_aEc=I+@&X{1+clbVM>HEB$j2pCx{6&!5+q z;FJyi$~t$aa{@}NyMhL zX|KS7)?yWMEvZkYZ$o1Lp@-l!4bw>OeVZgVjhv2u$X%fA8y9-*-s$6!&qk?exj5=6 zD4FPckz8iXgNraHr3fdlgl~_5^!0s1hd4Xgd~114?(K1rwiy<*p+3ag)?<|AKgQ2( zj*-?LMsChK^Bm@6pAnzOyeuR+WqtzoKMR$&M}$q{y_JST)MFTQjrtWP=trqd(f^~Y zj_tH3q`ebyDD~~sd(*C?E#|^@{)io+PZQc76HoN#*#Bm9dPz{wIxQ!zN5_dwR*%j) z_E7qhKSlY5Tzk~rR1i44UV96proO^Jv!1hocKP8nt0OME;EOYBNRPvvb5!*O-C{2Ekuc=UXZ?<$d{sh z0Yyg^oxdE(o^;X?LqkPZ_5L82lR^4~RR5uTd4h{=a&`NgdT;Xj+fXXYH&6q|d*p9f zt|W7eA^w(pUG*paf%2C=|HDY=*lC?hbJB3Dr=-(M+E?P+V*v4WYkz6(HeXo3qVzdO zsmomN9!<&Vm}vbI`S+hhViNUj@b~zHjt8yN|IFcSv`JplZ!Kfb(61JzBA!9%PSNp$ zjc>{X;}|oF{2&|K1wWvVuMc0YQ2J4F*qJ`S9>kFr_ou#r!K-b;0_FnpW69^UNjuWN zDe*kwFK9bR(eX9?$J-diwQb(5`u?Ahh9e9pK>3*Rj1E6iGBVNIV}T7GMAkCw@UWWo?6~H?={nFdvIJtKa|T(qTD`SFj7obewE6^$g_xqT?aT z1aeO(-N?VDw6+EPgmvlHn=;9AL#R)t&tl3gijETGbkrdpMM+{i;D7%{(~!*)k7x|A z&ikmZrQXqEO_0b=vW|K*WeRP<^m}_WB<@QIVZH<8Yg1;~n2I(}8#5<)UqNeZV)mf% z31zO$7;K$O+et={4|}_M>gi~|LCH>O!5nRDo{_Y5qP%;YrY)R#ire^bz5j2I4pu2f zhvas$I+i6q+WTjXHkmR5g6-{e-0ps$Y0*oZzWT*x1%IsaK} zJWR3&leM5jBTP%Ygb4zvSFi!%DdjnRijiMRJ(~Jj%G;xX)h95vvL%1OrNkdHW*hA# zF^=>4|NWo(RHAXVEhG)~kLaMIiJ6i?cgZIv{tw?CzmZQ$JQHg%eg>tH&6D38NZWmi zj(HCM*R$k&E#8?-*-Ruqf2UI)+Lw|W_D;W_t^GVFXv~5#+T`zBz5{)KB{v>dVJk{` z`jxSM$#4&2kGlU1z^_3h8dEBf>`eKUQh~DGCOk&{2K8Q)bJRoV`yb}VXV`+t2XnHI z)sLKx3)CBspGq7+{W!T#sUN3bdh6qV{>su=oyHK#bm}pb`*ga7E9qE|{Qn+vX}|h^ zC*k)2#q=-133cQpPD*=M+)jK5GteGt?FnfcLtLmaU&i`}@P{RmC+HYNr+MUcbS3vI zxrdZNF6IAPm9JeW9q4=8@+0ZHk#SiP#1ClwFmIwBy}NYl72jg~kz~OiM)YXcuYZKg z8(k+^F0^w-)ZYv1e|4$5&q_4ZgW(8uZC2igVU&+xN<5G0@HT3k1pPcO7*k>lMxw7RFHS})s({+s_b>wcVGv0Qa0X4wK=h z=I0nrc?s%_HX`?#w-WnrkTOOKi$D{5h-P-j{hb%|P_cCZ!d9_WagXbNh_ zW}!}GE^3^wEWQoH_5AN9qk&JMp8rdzGkAf8F>IKtuYel37HaDnpxU)WEub4}oPMZF zGz_)%qs(cjg)c;nvq|dt-%4f)?m-RM`D3?b15x+DSk#%!K~1y}we`zU18%qa)2IcU zN42|-n&=K{XCI=TrdOB&!-uo~x~BQaq{nioEp3V#=v}je+0*>U9ErL_lThQ##L~D7 zHSuMP#ha)FrQ&RLg6UEH^7!n(Iu;?25v!nHB&|^^9D!QMT-0N=6bs?cs2vF&;kG&n zYQhw#El-2G=Gjpb7e-yOx2#+hHBVhlP=ib_0@|8Qs4YE!x>+uv?%sc_96Zupk_=`6 z)Xr7Lz`cN)xSN$fLY?V&)Iz3V1kOgyv)U)474NnN$59iWMeWQj^NH0b9mR(R@o?0{ zxljXEL|x;?s0Fk^P1xP+j~aKVl_z3W%Ki*8TH!|2R&PTMZ~!&nDJ+IpP+OdOv|Csd zMp4d>x=CxHCTL~x?x-Cdj~Z_d25wr^Jll~S_Pv8-bnP#pw&W>lM^cS(17=1IPyltN zWl-0$K58dgpeE{xTCk70bd#+71!`eyQ1{eU^9)8XzjvREItGt*rbIQ2GE1N)Xn-2H z9clp|p|*Gw>QYTa?a(~by|4szA{$U=yc0Fgj}||J;mq${C!-ZUQUF87xw|_Z>dd22 zmnhcCMNtD)L`_^516z+;Sa;Np4z%)g)B@(C##@dWFCKkOxRs2~_gMvvRIUo>z%-RZN0oP-iq5LvR-AW}JtyxDIu%oJTF-KC0bI)WQ;e>MmWVPbL|G zXw-nYQ4YA=cHQb3B;1H_aPpEdkU>IJ)(CMQuh=_S+&{EiyP~+9dLVErilhK)sLJd3J!)>UEc3b%fYQht!Gd+*GM7L1w?qV){j0rIF zbZ1t~MmdLB6aBgbx{=WqZ^mYL7Hean8SYF5qpta649A(MGhL24qm3AWd(1Pah5cbZ zLOr&@ah~@*X2T))YaG`<6Pe~S-5Gs|I+Nk3GaqB+Pp}Z>si;e}1GNJOPzyMYI`hk@ z1^$5%_#diWidoKdSe$YUs(sU0?7wb`_X%k0yP*agh>DN3_%zf&^D!STLv8U1RJ$jr z1qXlTZnh-&HRTN03-@C%miXMwQyR5H)qOIWurcb)+o1;Rg4*(asI4B1X>q*OFT^yI zSE3fS!^#ISCFM(~_V-ZZhs<{4rAF;w6e{j#C!>`VMcuU(QE$X|P+Qm=b<>POby$XK zzY(=#yHEojMV;Yk)QOx!oycX>3EW04=m~24lyd@4oA2c#qd;}kfbCFQ+Y>dwOw_en zggVoeR^DLsTTu%=fLh>r)B^vo`bQQIn(Iz56{e#;2PV?ze>pPhSQYgYG)A4t0Mx<; zVFsLuy1CY(7P1p#@epd^4>9oEqfQ`lo?BQM%t^UEYM%a>3P)k!`+uA=1m>a!`U16u zYf#rR9`%&$!Ss05e1@qhN6vTmLLSsjSOK*oRZ$CShSAs!^%#!FEVvwfW%iTNL^n}e z_XxG+!3*4gVHia@0(IsEQSC~hE>Shq#0^ke+XVIE>46%jH)6$agHxw|Fsq8 z2xy?&s4e~%vt#0gZsL5X1=d7O)Ew2X6{=rP)Q$~8?c{LOIAc-mKF5r>!rX&(C|_F0 z_18*c7rDDQKWf0@sB2geb*7zBTiPFW4acFjeimwBt5EHJKrQe97Q-W`r^8$9E^QLj zB}t9ifjmAL-E2ir4NIUVDv#Q_hNyd@C2C=vQ62l5Lr@csMm=WJP&=^@wG&HG{Z^y; zZAP8I4lIQJF*54-61B4AUpQk>*RnWjC+eYYzW%5!{nT85+JUvG_S;cge+Kp5_#I;~ zbcvfdKNh517HQ{u-CV{Sh8k!J>SkML{(#zhE_WlZ?y&)Ry?DEuDnAW(&=A zs1Cca7#_h`^j5ogUet*cw{jJ;p2eG?&bTAy#GbC~dvRoR=JQco_cdyzTQCN9TlpGl zLAO!upQFw=`Pc3mXF{D>DO9`~>OIgDHSPzf1rEYwI4)4;`cJn8i%=ccVkqvw7V>Lbh_sHmOEwl>c`lw^(&&_aGi zo$+-mKfn}}pJ5(My3Q@ED5_m4)K*tFTcBP@-BC}`IMkUgM4iZLOof|J_tO4#?7voe zmVmbEGHNRyqONVy_3q4bqdFABI#}Jx(@+aof)8;MroxpQ+{8bi&h!B4L{6f1_9|*e zZ~A1kMGsIb{LjiE@os<=sCX1=;GC!dOIm$p)K0vOx^%5jC(s@va1d(zNthC6qS`M- zjpuJ5qY3t)IvmAtyn-?K0JY-CjqcMiJt|(wY=`<@KMHj(%t76(8&DJeWL`G^viet8 zg89AZO>V-*n2in{F*S}yZP|R(wO@@{@f7C9N7x!OZ|2#?VORxkVl|BY){WB(zo0xC z2Vu_d+-Jc;%&yP>ZDf9+;woz5`QNjRxE=>!3M%vAXyi%qzQI-4W{dk~lys|m0TsrK z#Oq)|?1WnQOmiD*;Wx1qrr5@p5g~N&!8^BCDgUQh9mJF{)>IK zyPLQ3j=+|BLr|~SbyykCnCW-Af5g)gixQuJek(Ft$V|udyWBtFT!n!%-_5UM#7ARW zyn#BS8hhMd&3j`@%A2tmhVONM2ds{|8HZyej=}Ue8`I%>)ID=(FZ-{@;0ghG$9#gi z_6hgd&4&pnr^jH7LbcC=dVKStcCIMuc`t*yscWK6un}s!wWxO6tbX4<-wpH=0p0Z% zPy^mYZS_B>$K)026`g9oyEOSx*SZR7;MS=AJx~i6j(VCVp}u%5M4kCI)R~_~J%)FD zGP>5!Py?nq;41Q=1}=>nuomXUrl^IDKs{cQP&+XXwSccI{yl2JhcE_jplRjQCsHy=>GDV0`pNEfJJaICc~4c2`-|>`vY|X zPf#~$vcvACtbob%{5K|}Yup;uuovoX9f8`3IT(s7t-J}!9B~VbMP1`k zm=E8^>^KC~ZXs&xS70{g_qLGHnO;II;3?{{2|eoG-C0nVCJ*Xns)Ql8T0-xi0T=^^(LS{5DdhExDK=8Wvq=sC)_}Fk&yQS z2ja1l>;_i<*}dt;q23P%QCofl)&D+f!DUXloo;~Ixo)S}e{~o^KnodzI>SjA9mMZ~ zSd{Xb({5o`P+OYvjQf=;4Qgjfpmwez>QdIiRM-J^DF$F9j=|A58&hDk|BJh8^PvVR ziJG7iCdV39{|<&zZiDLB$I9wopM_4B#4n%KGsS!U9G|4P24i@2Mx5splXk^^<+mlw zdx=MqdVkbqKD)_0M?OzH{|euHX;A(uFC~2O8^8S!e{$WO(V81>!P`;S`VeZzens6Y zS5Z507q#F=sI5+N)0r8wP%e(N^Svfy@)Br``Eddk#!VK#iJ2&e-*O+fg-~1E3}dh_ zs(yyK4o6TvhSjmb?`~&j;X%raFdn=9p~scIioWf(II~~zyp6@XTe+X< zo1dC<%;l(Y;>{mWmw1=eAC}DToh73e&JC-0iRu{or&~Y->L$vGx+hAQRZv^oz{;J> zex{G=_opP1?#?>N(G-QZ+ET2P-m72wN<%M9UGdhE#A$_apq#wnXa+&5!5|(4s~fBm>~~bJUuGz z7qLt=)I`nAj+l~iU(~=O&Ba!~19hfHPz(MU)&8Q@-^B>Z&romJu!pW)IO<-ALgw?m zN@O%peHZYWnC&dy3pLP(7N3AwDbKRSjfsD>P z#w=i#2{hnKBi<yW#v7nerHhE_6nB7kjJinIkT!+2i3mOW3Imje$OhpqRPFk zJPdPD9*w;uew%)xI=p!8I@qHZyym7CZ{I;902l>n*4@b>2!MDs*tN08x@M4Rv!L*b& zTKTZmpENI9{0^3--9sxEdgji&B!MDeh1uQW!!dm;DkfQAskz?Vj=D(>Tlu7wFQYzeZlV_UkHr(dbPEYJ)5ldV z5a}17MMWYSsi!#r=TIJMEFLM_Okk+Rvu;LsTfZC&rtnVSbPI&q2F8C z-*17VsD|gw>(=0&`LFpL_51}VbPJ3|4Vc|5jQXxs9`&;CWbujS=cr4%)Rld2BN?6P zE^BZQHNk1rrMPGDpb$4v3RFA_)vq9C!V;){?_fskVfEutJ3IvgXO8+D-XEy6cxg1pXH6Sc6ls0Hk@@FQ69i zJNjz)!~&s7U4tky4`!gg1nPaz0DIyesK>8)GB-g_bAUP29EFu>_X%p^!xlel<;%%} z+%NcdEb!3uLfyb&W@^+|k|--TM7`pgqXzC|_A`CdnSY8p!8p_88JOCID+q8y3Ma1rXe)Fad-dS-@%xyLINs(&`rfU#yt)WlU$JJ`(PeJuX5m8bb+ zbj=r_2HI@pZPwt7#jl}ms@te*_m7z{g}W4~&Ah0ID`DViFnd^hENY>%QRDf`$Y|nk z%+1zdoB1PZz+X@U-Zq0%x`jle2F#Coqm{ODd(;HIQD1ilTYQu`6&cs}=3C$!bE|pC zJcD}WUNir(ct|R@un5%iofCDb8lu`aF*~6aG7xpoj6i++oDzuh{Ou#74nJW|ykg}< z;qHvmq0X=pMq+)`jL!jc5b4%z+8vAgnOi(|DVZdz-!jvHtO+uf!gxO z2xoq?y4eP`u#Zp^jj{6QsPUGfUd5|XJMgo4(Y%F$|G?*OGWr(zA8HFDBHh4gQ7@M4 zsCRj1i%&vLI2&~)t5FNxf_ihFvhqVzyX2|eg0i4aEEj6wXrE;s^J|}$EQ|~ zNbe@ff~qfsny{SN0(FK1%%P}uqs*yJo_}kw(kj-WR=my1$IXkVh26G#FM}H}5_QwX zpcY&a1J~N>`=TD};iv^IHCJO&-ap=kK!$%6-P~^;N3HlgYC*S913W|BoIx2~JOXu3 z4NwbhW#yq5`23$hMiWfM7PtiUD*X?$VU8#_K~2;Ijm$Qv1$DRj zepViax>TdBJRjBXOVm8;Pz%|EfzSWntiivitxLe)wl#1Bs+_^fv8aIxTe-ZItC@|= zHfDF!goDgU=0bCQG|#^p>?NQV%rB^wKR454aw{!}T1b7fwb>KZ{$tdFKf}?u0JYGp znVkhu^<`0)stRhndYO6t^5fF5|5hT66)rAj2b8`iyJt#nH5!E(5!}P z*V1ffc110qx0MI`WHjLjtBA9T1?E!JnXERyGxwP%&C959?wGI4h#1#DC+ZtiQH;ed zs4q1Bbj!>)zcM$VwrCq_#Ya(((JxkhVJ6P%>cdfI9EJKip3TaYP$y8+Y+|-U7VLYy zEHKgqyeZ}v7T<_k$S%|bCoF!};y0}PubCj5n=mEn(nVXj1Zsz>SiC7#)AQfU8pNX} z+G*wER=$Xu_%3R|f3PctWq0L)=2X;~u0ZYBCM)ki^*>_epUo>6q0j%j7VvVo0m96T zW^UAg#jRWcHDFyUH^vak?_0c+*#mWr`=b^%9Cd<|P$x1E1E2pJt-*HGz=zF~sP6;k ztb7r*kn5NN?^*nXnJ}m8ABvhV0`*j6!Gu`C;$={mqGnEe{#z2zih7#ktl=W_YgC8t z%_FFVUbga0)Pzq_<0Q)E%2`nT@?&$XXywn%Rk{2i{b}9XW`S>VyN*Dtl1)huY1HEW@Et|{tLbo9w+-~rZPC`MDBVC7}z26Kmb1l8}Hm9Ln0 zQJ;d(tUfx{eU@ZLeU{WSd!u&BpJAERsEPNYw(=@!>+Yde9F*6UQ=vYbvZFo)>tPmb zjrvge7$+=lHjqC`;OzdHXATT=cB z^=H1kC4;UYKJA6opG z#S@lxH)T51r7UUIKrOskX`X)#(7^%&t-)y2(-4QMUx$IOOsI~(q26qNp}zHolyUK_ zWh7;)#vK+vYvmhO|I*^&W!=r08MUwyW);*KH?Z>i zW)IX34>tYLWGWGujN0O3_zs>%EhM&_iq;f;rBskn!FTtX_k7f3PG0-K^HY>#@g^+QcK&*JONU8spqpibZd z>KoBL)Hum2xp)Sws^>pH8Et(ZRL74{kIP6@hp`r)foeD3;$NEUEWXX$YaTXFn&(g_ za0Pqdee`vcwXW<|G!O?<{sgtK;3{q*qfrYRk6O@l)It_wVO)ke@eJm}=cpG?o~l8C ze{pa$9-y42n)}1$Mbw+LY;~Uha%9F-cN6VGJx=>jm*6UD3scr`@ocDa1=J2TLM^B% zYC-KWZ4m!x6f065QPaH{ccR*-spS@y0d+zHYWXfRoPY+NV9rAgycV@(TW~fWMs@61 z+tv3%m4~7x7>ioSCsscV_1pCV)Hv%=^Xx*_>1Fm4@I8)Hitk667-0ixHZ=)|y(B%> zsCIOs&7agoVh!TcNnxb@8j0f(?GusmQ9q4%8&U-Mbksc~zMOV#iG4!;jP>!~rm`lf zFb(7IT~a$5ygup?e?fUGfk-+JvWf)6TiPJ+So_sD++y2kd&u(YGLX8q^l41|2Kf!d zvL)a)J7WVbwZ^=6yp5#0G@L`j#v~oL%nRf%k>W`o5&H&@(^kh{l%KpY>2}IXNxxhD z5R7IK>xl7nfP>q76v1I+2N8He#aR5F*q`KedD4?E6B~+uc?1MTg(@%FlADUhaex>WLBaVvQSjrlfpd3o7Natp# zW1Q9L1*79M@$RTEE`1oV8g0`N(>J78(tOf%`i!7XM=2ZU26iSs6^Cg4q;!0jMsrDH zT-(4mTE1_3!)bIIU*Te_n@72rJ64=gXSE$qb`@m#e1igJGHwqY&Ch#=La ztp8EiTKe6w$@&scK)IFmpF;Wd@jTeBe+!#r2bFhe{5PH7Ctn!(4a?(K0&g_=FY$BI zr=)D8FKwh0Zw%U#IInx}1ZfL>^d+P%>0{DM65r0fQ>0aaKJ0%J>)e&bk4X)w)Q6A` zJ_!GJ=o|3&q;PBBkGkxXN8>qCN^9E+^D<62DKGW!kj~NP3VudiL-Ie6DpTKE*Z(gH z!${l7Kea*1up>*zU#8JA>gJHvlmCU3g7{3@en(zMQ_5v&|D1Ab@||4RTZh`%#q{k! z-7)HPd`?P6ncqJ=zbKWj$Rx*81kd6+%5?%wd39PR6+4pul{P2H-$fno6RV5-uHyBg zZ#v?$NIl6{V)jC~jQY-~ z@l%T>B|nk2-{31^ty!#&){ekG3aLlkc>29Qx+maP($`lV{ixKTFLV08={;kxNZgD% zsxaU-Ytzt${`WJBO{PFv@)c;;-rB}t62|CDU4GILi~mKwfj%pBd`*L7bZmzuFsV%% zMEzf^cmU-(ijnVulLEcmzlW5W_SH$PY0Hgw0Xzk(Rh>g4@e)AA8CE7vVd~52AW@#M4(A|H%>sq5vcy((D6`gfw;Kh$L; z@n;h+H)S15@Brxru?6^1Ag)&l$7YAOh025EchmXxag&DsP$)yJ2&sfs6eXW4FbEH& zsj4HStJGy=k^AxWQQO)~W{zpZ2jDk8!Mvp21b)OMbh<*t6KkB6{0Z{>S;Z?(U2Yq# zAnhYaQN;U`B1qdwr-|jDjlR&|$6s&-7Pj%mP~V^YR6IhRpNdRY8Vn+smkC}UnW+pW zWh0)6HWSFdKGG0dM64n0kK>z1cVZK$-$QUCb*phN{Yjf$NV z^!Kv&>D-b07#h|m{YiR#lqQpg`kEvi?QjQuBS{loDDd+TKl3rhCHgj?E-^{RK8zy% z`uLN~BYu?%9JTnFoCarX!eo>WywSJ|;iRXNQr{urq_(rnS4MB zvgy=rDXkKao|FHXmMuv-DllsY+D*bd)Q1s&7iW^@lD?o#SJGDMb=0sivzv>E|4W}b zl4j+f*Uk=nar;Ad6ZcO$lk6v99!DW@WTjnv=Tb;Eed z6G@GzFJcRLJxnp;1>79ISCIxE5ztY?5%{Xqj#xb_i~s156KB%?3tM0aZO#*0Vg1#v z1o>68sbG_SN85j`zAZMTJU|TtM^$cN8hZrGNe=#k=WTIWuk#x#|BU({NCl{`O8aZH zDUTWB+BJ*xmy>HoEd-8PmI<{HlH2GVUN@lCPV#dw2_x1a{Y`r2x_ckczO}X0pI&B> z9#fx%SO)A*{kK?}@vG^}Dp76K1zTG;Vw9ex-aIb^JuiY56sQ2=5^3 z-=gmo(%*0NRds!9Bj!`zn8|-5KUGg;K{8zlgwW|IgT9A#@oVB$N$bh4#eSr}N!Ljk zXy1l`bc~{YhRX(i9-w@VIz4PVNjfr;Zjf(c<-TU%j;TrGZ<%x~jXtr8<-}@{zI)w} zy6;Fjx)9efgFZTT;}^spldnfUH;en2azoM_`j;ctF3{5b*a_E(e@Q&>Mmqe)Bt5A7 znN*$1jttbwCM!re*78&bj(z+rLF{eX>3EwqsmW(2ww8Pkj3MnM=}1jX$3y08LhPun z|0^;BsW?lpGwBD?3F|Ng2UC81oFpGjnn(LaSd7W;(dLi_CV!3mcv3F%mx--Y+>XiQ zCs6l=jn|WWHl2SbGHFRgX*i6^gXDGmL5IYaA5HlY<-OF;AodmcY)q1a6iVze^;e1M zNJmUZ2HL%c`*0v_np^!3#41tN(cGspk9CMAKZW4CScJystwR${5@^n)p<@y9|JeYQ zsViW0ulbNn1yVQay3p<+N z(UhAp==%R3z#B)qq&7xb>Pu4p=J6SY^u(@MpQhx~lMm5Ydj7+#b24o5M$c0;8bT~R zu^ps@bhz_IeG>8;NhxXfHSIRxElDgFDU&TE6)vN%M>!TH82d=*Yhbf%5 z0lUyS73J$R{seDO{~sx-8gi^AR*N>5XkVQ+bZ>e7>6MJh?T8|6`0hBm2* zy?GSUAD1e<5h+On+Irip;VwGgC*Mm!j>e>0fgIn&a4_|osPBq+8pLAo z1?lxsoB9S67SiSbuE7Sx-XiH(K%d&!iTJNL(#E|=IdJ`-s+ApA@e&R0QTdR3MbdQA zNG9w~I!XGSvW_(xn0Bpfq8{YiQ@@Winly=&n>HnJHoil\n" "Language-Team: Jumpserver team\n" @@ -96,7 +96,7 @@ msgstr "运行参数" #: terminal/templates/terminal/session_list.html:28 #: terminal/templates/terminal/session_list.html:72 #: xpack/plugins/change_auth_plan/forms.py:73 -#: xpack/plugins/change_auth_plan/models.py:419 +#: xpack/plugins/change_auth_plan/models.py:412 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13 @@ -152,7 +152,7 @@ msgstr "资产" #: users/templates/users/user_profile.html:51 #: users/templates/users/user_pubkey_update.html:57 #: xpack/plugins/change_auth_plan/forms.py:56 -#: xpack/plugins/change_auth_plan/models.py:64 +#: xpack/plugins/change_auth_plan/models.py:63 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12 #: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:144 @@ -199,7 +199,7 @@ msgstr "参数" #: perms/templates/perms/remote_app_permission_detail.html:90 #: users/models/user.py:451 users/serializers/group.py:32 #: users/templates/users/user_detail.html:112 -#: xpack/plugins/change_auth_plan/models.py:109 +#: xpack/plugins/change_auth_plan/models.py:108 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 #: xpack/plugins/cloud/models.py:80 xpack/plugins/cloud/models.py:179 #: xpack/plugins/gathered_user/models.py:46 @@ -264,7 +264,7 @@ msgstr "创建日期" #: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_list.html:37 #: users/templates/users/user_profile.html:138 -#: xpack/plugins/change_auth_plan/models.py:105 +#: xpack/plugins/change_auth_plan/models.py:104 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 #: xpack/plugins/cloud/models.py:77 xpack/plugins/cloud/models.py:173 @@ -607,7 +607,7 @@ msgstr "端口" #: assets/templates/assets/asset_detail.html:196 #: assets/templates/assets/system_user_assets.html:83 #: perms/models/asset_permission.py:81 -#: xpack/plugins/change_auth_plan/models.py:75 +#: xpack/plugins/change_auth_plan/models.py:74 #: xpack/plugins/gathered_user/models.py:31 #: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:17 msgid "Nodes" @@ -693,7 +693,7 @@ msgid "SSH gateway support proxy SSH,RDP,VNC" msgstr "SSH网关,支持代理SSH,RDP和VNC" #: assets/forms/domain.py:78 assets/forms/user.py:76 assets/forms/user.py:96 -#: assets/models/base.py:29 assets/models/gathered_user.py:16 +#: assets/models/base.py:29 assets/models/gathered_user.py:15 #: assets/templates/assets/_asset_user_auth_update_modal.html:15 #: assets/templates/assets/_asset_user_auth_view_modal.html:21 #: assets/templates/assets/_asset_user_list.html:21 @@ -714,13 +714,13 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: users/templates/users/user_list.html:36 #: users/templates/users/user_profile.html:47 #: xpack/plugins/change_auth_plan/forms.py:58 -#: xpack/plugins/change_auth_plan/models.py:66 -#: xpack/plugins/change_auth_plan/models.py:415 +#: xpack/plugins/change_auth_plan/models.py:65 +#: xpack/plugins/change_auth_plan/models.py:408 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:53 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:12 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:13 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:74 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:64 msgid "Username" msgstr "用户名" @@ -742,8 +742,8 @@ msgstr "密码或密钥密码" #: users/templates/users/user_profile_update.html:41 #: users/templates/users/user_pubkey_update.html:41 #: users/templates/users/user_update.html:20 -#: xpack/plugins/change_auth_plan/models.py:96 -#: xpack/plugins/change_auth_plan/models.py:264 +#: xpack/plugins/change_auth_plan/models.py:95 +#: xpack/plugins/change_auth_plan/models.py:263 msgid "Password" msgstr "密码" @@ -801,12 +801,12 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig" #: perms/templates/perms/asset_permission_asset.html:58 settings/forms.py:144 #: users/templates/users/_granted_assets.html:31 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:54 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:73 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:63 msgid "IP" msgstr "IP" #: assets/models/asset.py:136 assets/serializers/asset_user.py:27 -#: assets/serializers/gathered_user.py:19 +#: assets/serializers/gathered_user.py:20 #: assets/templates/assets/_asset_list_modal.html:46 #: assets/templates/assets/_asset_user_auth_update_modal.html:9 #: assets/templates/assets/_asset_user_auth_view_modal.html:15 @@ -818,7 +818,7 @@ msgstr "IP" #: perms/templates/perms/asset_permission_list.html:73 settings/forms.py:143 #: users/templates/users/_granted_assets.html:30 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:53 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:72 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:62 msgid "Hostname" msgstr "主机名" @@ -937,21 +937,21 @@ msgstr "版本" msgid "AuthBook" msgstr "" -#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:100 -#: xpack/plugins/change_auth_plan/models.py:271 +#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:99 +#: xpack/plugins/change_auth_plan/models.py:270 msgid "SSH private key" msgstr "ssh密钥" -#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:103 -#: xpack/plugins/change_auth_plan/models.py:267 +#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:102 +#: xpack/plugins/change_auth_plan/models.py:266 msgid "SSH public key" msgstr "ssh公钥" -#: assets/models/base.py:35 assets/models/gathered_user.py:21 +#: assets/models/base.py:35 assets/models/gathered_user.py:20 #: assets/templates/assets/cmd_filter_detail.html:73 common/mixins/models.py:52 #: ops/models/adhoc.py:46 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:109 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:76 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:68 msgid "Date updated" msgstr "更新日期" @@ -1080,12 +1080,22 @@ msgstr "命令过滤规则" msgid "Gateway" msgstr "网关" -#: assets/models/gathered_user.py:17 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:75 +#: assets/models/gathered_user.py:16 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:67 msgid "Present" msgstr "存在" -#: assets/models/gathered_user.py:32 +#: assets/models/gathered_user.py:17 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:65 +msgid "Date last login" +msgstr "最后登录日期" + +#: assets/models/gathered_user.py:18 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:66 +msgid "IP last login" +msgstr "最后登录IP" + +#: assets/models/gathered_user.py:31 msgid "GatherUser" msgstr "收集用户" @@ -1188,7 +1198,7 @@ msgstr "手动登录" #: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:73 #: assets/views/system_user.py:29 assets/views/system_user.py:46 #: assets/views/system_user.py:63 assets/views/system_user.py:79 -#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:71 +#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:70 msgid "Assets" msgstr "资产管理" @@ -1237,16 +1247,16 @@ msgstr "系统用户" msgid "%(value)s is not an even number" msgstr "%(value)s is not an even number" -#: assets/models/utils.py:43 assets/tasks/const.py:87 +#: assets/models/utils.py:43 assets/tasks/const.py:84 msgid "Unreachable" msgstr "不可达" -#: assets/models/utils.py:44 assets/tasks/const.py:88 +#: assets/models/utils.py:44 assets/tasks/const.py:85 #: assets/templates/assets/asset_list.html:99 msgid "Reachable" msgstr "可连接" -#: assets/models/utils.py:45 assets/tasks/const.py:89 audits/utils.py:30 +#: assets/models/utils.py:45 assets/tasks/const.py:86 audits/utils.py:30 #: xpack/plugins/license/models.py:78 msgid "Unknown" msgstr "未知" @@ -1333,7 +1343,7 @@ msgstr "测试资产可连接性: {}" #: assets/tasks/asset_user_connectivity.py:27 #: assets/tasks/push_system_user.py:130 -#: xpack/plugins/change_auth_plan/models.py:528 +#: xpack/plugins/change_auth_plan/models.py:521 msgid "The asset {} system platform {} does not support run Ansible tasks" msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务" @@ -1353,7 +1363,7 @@ msgstr "更新资产硬件信息" msgid "Update asset hardware info: {}" msgstr "更新资产硬件信息: {}" -#: assets/tasks/gather_asset_users.py:96 +#: assets/tasks/gather_asset_users.py:107 msgid "Gather assets users" msgstr "收集资产上的用户" @@ -1706,7 +1716,7 @@ msgstr "Jumpserver 使用该用户来 `推送系统用户`、`获取资产硬件 #: audits/templates/audits/login_log_list.html:91 #: users/templates/users/user_group_list.html:10 #: users/templates/users/user_list.html:10 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:59 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:49 #: xpack/plugins/vault/templates/vault/vault.html:55 msgid "Export" msgstr "导出" @@ -2288,7 +2298,7 @@ msgid "MFA" msgstr "MFA" #: audits/models.py:87 audits/templates/audits/login_log_list.html:63 -#: xpack/plugins/change_auth_plan/models.py:423 +#: xpack/plugins/change_auth_plan/models.py:416 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15 #: xpack/plugins/cloud/models.py:278 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69 @@ -2317,11 +2327,11 @@ msgstr "登录日期" #: perms/templates/perms/asset_permission_detail.html:86 #: perms/templates/perms/remote_app_permission_detail.html:78 #: terminal/models.py:167 terminal/templates/terminal/session_list.html:34 -#: xpack/plugins/change_auth_plan/models.py:250 -#: xpack/plugins/change_auth_plan/models.py:426 +#: xpack/plugins/change_auth_plan/models.py:249 +#: xpack/plugins/change_auth_plan/models.py:419 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:17 -#: xpack/plugins/gathered_user/models.py:143 +#: xpack/plugins/gathered_user/models.py:140 msgid "Date start" msgstr "开始日期" @@ -2888,49 +2898,49 @@ msgstr "Become" msgid "Create by" msgstr "创建者" -#: ops/models/adhoc.py:252 +#: ops/models/adhoc.py:254 msgid "{} Start task: {}" msgstr "{} 任务开始: {}" -#: ops/models/adhoc.py:264 +#: ops/models/adhoc.py:263 msgid "{} Task finish" msgstr "{} 任务结束" -#: ops/models/adhoc.py:356 +#: ops/models/adhoc.py:360 msgid "Start time" msgstr "开始时间" -#: ops/models/adhoc.py:357 +#: ops/models/adhoc.py:361 msgid "End time" msgstr "完成时间" -#: ops/models/adhoc.py:358 ops/templates/ops/adhoc_history.html:57 +#: ops/models/adhoc.py:362 ops/templates/ops/adhoc_history.html:57 #: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:17 -#: xpack/plugins/change_auth_plan/models.py:253 -#: xpack/plugins/change_auth_plan/models.py:429 +#: xpack/plugins/change_auth_plan/models.py:252 +#: xpack/plugins/change_auth_plan/models.py:422 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:58 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:16 -#: xpack/plugins/gathered_user/models.py:146 +#: xpack/plugins/gathered_user/models.py:143 msgid "Time" msgstr "时间" -#: ops/models/adhoc.py:359 ops/templates/ops/adhoc_detail.html:106 +#: ops/models/adhoc.py:363 ops/templates/ops/adhoc_detail.html:106 #: ops/templates/ops/adhoc_history.html:55 #: ops/templates/ops/adhoc_history_detail.html:69 #: ops/templates/ops/task_detail.html:84 ops/templates/ops/task_history.html:61 msgid "Is finished" msgstr "是否完成" -#: ops/models/adhoc.py:360 ops/templates/ops/adhoc_history.html:56 +#: ops/models/adhoc.py:364 ops/templates/ops/adhoc_history.html:56 #: ops/templates/ops/task_history.html:62 msgid "Is success" msgstr "是否成功" -#: ops/models/adhoc.py:361 +#: ops/models/adhoc.py:365 msgid "Adhoc raw result" msgstr "结果" -#: ops/models/adhoc.py:362 +#: ops/models/adhoc.py:366 msgid "Adhoc result summary" msgstr "汇总" @@ -3350,7 +3360,7 @@ msgstr "刷新授权缓存" msgid "Validity" msgstr "有效" -#: perms/templates/perms/asset_permission_list.html:244 +#: perms/templates/perms/asset_permission_list.html:230 msgid "Refresh success" msgstr "刷新成功" @@ -4832,7 +4842,7 @@ msgstr "生成重置密码链接,通过邮件发送给用户" msgid "Set password" msgstr "设置密码" -#: users/forms.py:152 xpack/plugins/change_auth_plan/models.py:89 +#: users/forms.py:152 xpack/plugins/change_auth_plan/models.py:88 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:51 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:69 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:57 @@ -5762,8 +5772,8 @@ msgstr "" "具)
注意: 如果同时设置了定期执行和周期执行,优先使用定期执行" #: xpack/plugins/change_auth_plan/meta.py:9 -#: xpack/plugins/change_auth_plan/models.py:117 -#: xpack/plugins/change_auth_plan/models.py:257 +#: xpack/plugins/change_auth_plan/models.py:116 +#: xpack/plugins/change_auth_plan/models.py:256 #: xpack/plugins/change_auth_plan/views.py:33 #: xpack/plugins/change_auth_plan/views.py:50 #: xpack/plugins/change_auth_plan/views.py:74 @@ -5774,20 +5784,20 @@ msgstr "" msgid "Change auth plan" msgstr "改密计划" -#: xpack/plugins/change_auth_plan/models.py:58 +#: xpack/plugins/change_auth_plan/models.py:57 msgid "Custom password" msgstr "自定义密码" -#: xpack/plugins/change_auth_plan/models.py:59 +#: xpack/plugins/change_auth_plan/models.py:58 msgid "All assets use the same random password" msgstr "所有资产使用相同的随机密码" -#: xpack/plugins/change_auth_plan/models.py:60 +#: xpack/plugins/change_auth_plan/models.py:59 msgid "All assets use different random password" msgstr "所有资产使用不同的随机密码" -#: xpack/plugins/change_auth_plan/models.py:79 -#: xpack/plugins/change_auth_plan/models.py:148 +#: xpack/plugins/change_auth_plan/models.py:78 +#: xpack/plugins/change_auth_plan/models.py:147 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:100 #: xpack/plugins/cloud/models.py:165 xpack/plugins/cloud/models.py:219 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:91 @@ -5796,8 +5806,8 @@ msgstr "所有资产使用不同的随机密码" msgid "Cycle perform" msgstr "周期执行" -#: xpack/plugins/change_auth_plan/models.py:84 -#: xpack/plugins/change_auth_plan/models.py:146 +#: xpack/plugins/change_auth_plan/models.py:83 +#: xpack/plugins/change_auth_plan/models.py:145 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:92 #: xpack/plugins/cloud/models.py:170 xpack/plugins/cloud/models.py:217 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:83 @@ -5806,37 +5816,37 @@ msgstr "周期执行" msgid "Regularly perform" msgstr "定期执行" -#: xpack/plugins/change_auth_plan/models.py:93 +#: xpack/plugins/change_auth_plan/models.py:92 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74 msgid "Password rules" msgstr "密码规则" -#: xpack/plugins/change_auth_plan/models.py:213 +#: xpack/plugins/change_auth_plan/models.py:212 msgid "* For security, do not change {} user's password" msgstr "* 为了安全,禁止更改 {} 用户的密码" -#: xpack/plugins/change_auth_plan/models.py:217 +#: xpack/plugins/change_auth_plan/models.py:216 msgid "Assets is empty, please add the asset" msgstr "资产为空,请添加资产" -#: xpack/plugins/change_auth_plan/models.py:261 +#: xpack/plugins/change_auth_plan/models.py:260 msgid "Change auth plan snapshot" msgstr "改密计划快照" -#: xpack/plugins/change_auth_plan/models.py:276 -#: xpack/plugins/change_auth_plan/models.py:433 +#: xpack/plugins/change_auth_plan/models.py:275 +#: xpack/plugins/change_auth_plan/models.py:426 msgid "Change auth plan execution" msgstr "改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:442 +#: xpack/plugins/change_auth_plan/models.py:435 msgid "Change auth plan execution subtask" msgstr "改密计划执行子任务" -#: xpack/plugins/change_auth_plan/models.py:460 +#: xpack/plugins/change_auth_plan/models.py:453 msgid "Authentication failed" msgstr "认证失败" -#: xpack/plugins/change_auth_plan/models.py:462 +#: xpack/plugins/change_auth_plan/models.py:455 msgid "Connection timeout" msgstr "连接超时" @@ -6186,19 +6196,19 @@ msgid "Periodic" msgstr "定时执行" #: xpack/plugins/gathered_user/models.py:57 -#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:48 +#: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:38 msgid "Gather user task" msgstr "收集用户任务" -#: xpack/plugins/gathered_user/models.py:140 +#: xpack/plugins/gathered_user/models.py:137 msgid "Task" msgstr "任务" -#: xpack/plugins/gathered_user/models.py:152 +#: xpack/plugins/gathered_user/models.py:149 msgid "gather user task execution" msgstr "收集用户执行" -#: xpack/plugins/gathered_user/models.py:158 +#: xpack/plugins/gathered_user/models.py:155 msgid "Assets is empty, please change nodes" msgstr "资产为空,请更改节点" @@ -6446,6 +6456,11 @@ msgstr "密码匣子" msgid "vault create" msgstr "创建" +#, fuzzy +#~| msgid "Login" +#~ msgid "Login IP" +#~ msgstr "登录" + #~ msgid "succeed: {} failed: {} total: {}" #~ msgstr "成功:{} 失败:{} 总数:{}" diff --git a/apps/ops/models/adhoc.py b/apps/ops/models/adhoc.py index b9c1c4a74..3eebb6636 100644 --- a/apps/ops/models/adhoc.py +++ b/apps/ops/models/adhoc.py @@ -246,30 +246,35 @@ class AdHoc(models.Model): time_start = time.time() date_start = timezone.now() is_success = False + summary = {} + raw = '' try: date_start_s = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(_("{} Start task: {}").format(date_start_s, self.task.name)) raw, summary = self._run_only() is_success = summary.get('success', False) - return raw, summary except Exception as e: logger.error(e, exc_info=True) - summary = {} raw = {"dark": {"all": str(e)}, "contacted": []} - return raw, summary finally: date_end = timezone.now() date_end_s = date_end.strftime('%Y-%m-%d %H:%M:%S') print(_("{} Task finish").format(date_end_s)) print('.\n\n.') + try: + summary_text = json.dumps(summary) + except json.JSONDecodeError: + summary_text = '{}' AdHocRunHistory.objects.filter(id=history.id).update( date_start=date_start, is_finished=True, is_success=is_success, date_finished=timezone.now(), - timedelta=time.time() - time_start + timedelta=time.time() - time_start, + _summary=summary_text ) + return raw, summary def _run_only(self): Task.objects.filter(id=self.task.id).update(date_updated=timezone.now()) @@ -321,10 +326,9 @@ class AdHoc(models.Model): except AdHocRunHistory.DoesNotExist: return None - def save(self, force_insert=False, force_update=False, using=None, - update_fields=None): - super().save(force_insert=force_insert, force_update=force_update, - using=using, update_fields=update_fields) + def save(self, **kwargs): + instance = super().save(**kwargs) + return instance def __str__(self): return "{} of {}".format(self.task.name, self.short_id) @@ -393,7 +397,10 @@ class AdHocRunHistory(models.Model): @summary.setter def summary(self, item): - self._summary = json.dumps(item) + try: + self._summary = json.dumps(item) + except json.JSONDecodeError: + self._summary = json.dumps({}) @property def success_hosts(self): diff --git a/apps/perms/templates/perms/asset_permission_list.html b/apps/perms/templates/perms/asset_permission_list.html index 18e30bde8..57079b4f8 100644 --- a/apps/perms/templates/perms/asset_permission_list.html +++ b/apps/perms/templates/perms/asset_permission_list.html @@ -23,12 +23,12 @@ {% block content %}
-
+
{% include 'assets/_node_tree.html' %}
-
+
@@ -209,20 +209,6 @@ function initTree() { }) } -function toggle() { - if (show === 0) { - $("#split-left").hide(500, function () { - $("#split-right").attr("class", "col-lg-12"); - $("#toggle-icon").attr("class", "fa fa-angle-right fa-x"); - show = 1; - }); - } else { - $("#split-right").attr("class", "col-lg-9"); - $("#toggle-icon").attr("class", "fa fa-angle-left fa-x"); - $("#split-left").show(500); - show = 0; - } -} $(document).ready(function(){ initTable(); diff --git a/apps/tickets/migrations/0002_auto_20191114_1105.py b/apps/tickets/migrations/0002_auto_20191114_1105.py new file mode 100644 index 000000000..87cec4056 --- /dev/null +++ b/apps/tickets/migrations/0002_auto_20191114_1105.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.5 on 2019-11-14 03:05 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='ticket', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='tickets.Ticket'), + ), + migrations.AlterField( + model_name='ticket', + name='type', + field=models.CharField(choices=[('general', 'General'), ('login_confirm', 'Login confirm')], default='general', max_length=16, verbose_name='Type'), + ), + ]