From 8eb6cfa9c9ecf79c324b3ea1865839dd7038017b Mon Sep 17 00:00:00 2001 From: xinwen Date: Thu, 9 Jul 2020 14:06:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(ticket):=20=E4=BF=AE=E6=94=B9=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E8=8E=B7=E5=8F=96=E7=B3=BB=E7=BB=9F=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=9A=84=E5=AD=97=E6=AE=B5=20(#4274)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(ticket): 申请资产工单修改bug --- apps/locale/zh/LC_MESSAGES/django.mo | Bin 55113 -> 55060 bytes apps/locale/zh/LC_MESSAGES/django.po | 53 +++++++++--------- apps/tickets/api/request_asset_perm.py | 42 +++++++++++++- .../tickets/serializers/request_asset_perm.py | 31 ++++++++-- apps/users/filters.py | 3 +- apps/users/serializers/user.py | 6 ++ 6 files changed, 102 insertions(+), 33 deletions(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 234bb9ca1d9b76f03f2d336555ef98e80076c1d0..61bdd1d0d2c37b5dc2db3d5a07de9a9d6733b184 100644 GIT binary patch delta 15461 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 delta 15510 zcmYk?2YgQF-^cNjAQECF2(co9*d+E|L9Mow*wl)ds9nmbRitQ%S&G=D_N=`}OKTQ? zT2##%Rcf|8pKs33^Xhp$SKrs~cg=I1bKiIR?=yW(s$*+Xt&2$I7I7S>aSO-s!@-yu zM_?e1#sc^Smcxx0jd!pz=4t6Tq1XyFZU6@0P|Sp*u{2Jz`~lQDComnJZRxlv9j}l` zOX8t*e1@9PC)RN?pdV^rRx=lBfpE--QJ4p7VFY$WjUS8J&_v9PNtgwfm|J39FLBfo z|HEK9+`}MrS~*TO2u4j*#Edqpnf1;0(Vu>8u@ZJgZG1lJ2A85Xz8ckUmrF%EJB&KY z^OzI=LMZM(Q+Q4Ph$^3!2 zSl{`JiUwwE=Pi%}b>|VNBPx#?Pz!bE4Nyng3N@~~*$=~rhoMenE^5O|P$#zzv*SV3 zqq~HGtnXZUy!_W?nQxWT-?!d*JI2JW=t&ZNp@0cx78|Z>s zrw?j_pQ3Icu_NcNXEcLEL)?mgqHiZ}fybzgJx3ko8`Om9KjagDSy3m|4|C&4tc`Om z{uOHyze0_x+S&Vb#9$HPMx9+RF^Gf~8jiY?(Wn85sJA%@bKx>9g!?fc-oY{$(8W8U zDyTb+L(MZBb&_LHk6;>Voh7LGSGiQwag#Od#5}|YP|xrhs^bG|e}?M+8g(LmUA+l| zQ2lbE^5Iw(OJaWPf|_p}>cpm@Hsmg(qL*O;IsFy&tRA8UzC`u&@8*5s zWJbN!MNyBS7HR_>P|vy-YTQ87NsPwSIMvI$&P*yAxCAv|pLO^FHPJ~7!^@~U{1D}>GK~)B`=A1T#1uWkDy|lcc(4Q4w!~~ zcPxc{P#c_wT3`k04%ee@WH0L7`QF-pF>jg=u?Xus&#CB$!+Ut2=Mtz18ldvcPz$w3 zEzr~QL(!jj3>L#lmfwat;sdBhcob9NMbtdMplG6R1zgIn+HQUZlWIfZ9N;*}p0Ml66QQ4>C~_SEs-h67M{mI?L6k{$K(MWTMBDw!W(L*fMF zW9mBFsp#d|gqrX1?r>)@M;3uWSl06O&899DP1pi;#9dKGI|8+_Rj38lqbA;gW$+|wobO=obDRZ> z6Gx)HCt6s30BYljs7H}x?a8Q)93e>aTf*JMs-%Ukt`w7(1-bQU8^kZ+QMNxN92{o`b zYT z%bHa%WkaY58(Q22BZ+&X#!a{U9MlOUqh7|f=!R0+Pesq}7t~H~nGaBR@Hd8{&v5U~ zbE76MVsS~-2~|POQ`h3A)*g$xp{}SCNO{$`3-F;6&7?U=e1=?WmX7 zJw-*&_*c|~cTq?C(DKe$Z$p8o0a;PcIKSnKp+2_JsCi;g@6h{ZE7Y^^h`NDZsFU~< z`NPI_=29t2Vms>D-9SzFx5a74dGACB>Km{k>Q0)V7VL&v@FUdtp_ZS3+URubjq@=z zru)nrmkG1!^PkHSWl|E3Qw_Dl=BS;=V=?>~_5H9EweWe=H`#U6hW|osEcJNrUCE6a zUm4XNgBll$+GrO{`TP%{qMeRKEi?rS;C9RZih3lsQJj4}8U68u<$p#$;>+l2C)cT@#mA@}zCvv%?L_bBvS0-92-FwHBGgfCM!gf;%_CTy z_$+FH;6(4G4#kqhA7FkQgX?i=BImC=js4tvw!=|J|0U{WS%q3?ALjPqZ#LAOU7zG_ z@DBPDKSquF2X#^*lf5I3M12Y>q8?RaOpk3b0OKa}{59c6B=n4iSjUN|ozAxWc8p*H z$FT|dM^p6ba=c>%iFr%$Gi2^3zNlGmV>~fA%Ea8{+us{0Wb@aToTU!5G?$xHI`z zYASbT@vTL}?{mB(p7WJ==ij1sydHI@yHFcFj5?tU<^#+}oO-U;F9M4am%u1&h57>f z91Gz$7>e#mDq&RqunvLq*gbJkJc|8rBUbv_`{KBd8HiKQ_Y6WEd6>mzFp#*0+1PB2 zdMCPD+}G1}hFM~~b(n6>MLnZM*8Z*e9qJqHu*FwU6W_D=vBk~;FQ3-Th}u{-GaLi- z5KB?fQB}f7?22u0GU_Y&Hfkf`3%v=8V`1WGv#sUFU|#ZxsF&^=)PlRr@6Ge(@95_` zyi8Oy;JF!?>>X_w>ds1<VGjVt5S0@o&`kK#s-UJ5zr# z=dXdSNNA#tW*^kXK1Q|AHWyg?GIOKl_nJq{AFchI#lK-H=DB0}`{v8VoWH(G(=PEA z%!gXAI%-2Ps1s<0`U2@@4m8J@(@>v^WOJ?MccD(~xcRer)x7Ik6qbmZGvJ`M{J$D{hsKy7#tYJ(drf5<%T={i@a_|f5>H9WT1S?&!?i<&UhER5QD zS=0heEN+kbMjVWKcP63cU4^=l4HoaT_&`d`^FKjF3!F8tVPWD2SRb>m@D}QTnlK)9 zM}trkPe6^IhT6~q%da)Rv-|;6zcZ+LuBu(1|65eF<3~zh=5M@-LQ!{G6m@5HPy<_| zChBDNHHVqw&FQF(CYzfqe*`t}S#&kgeQS7Wrd{bRloi#U%i>7XTV4uvr`4>ziP^@C z!~C=lG-qN7;%%rKxQYDEIrmrE=YRYvZ=osXTvW#usD;*Aevf$^3y{Bv`ilM+`2ln) zeCv%nZC*s(z*X};HYR>)asAbtzmDjG)!yIraj1B<#j7v_@nzJ8?xODO5$X#ic#W42 zG4o;|`GOdLQK*k!RV5(_4)5>iGfNGkFt0IYUeX7zrb9EMai#5f4qQM z@tUQT=bC zp6v_E2W;{F63UL6rv~bz-a(CTW_H|SpZ`9VaLq}WnT~VJm6qRuTJR|95nMto?6=i> z8M9+~;!>CmyQ4lWpI~X6ZSgUTCcfcPQOBIyybh&MaVONk!KfWiL!H0^bD8B=qwa9K z#RskZ6l$Xv%sdu#;7CvQOGH;jVavZVeRp~T15kIK9W^ctb75hN>!22HXtqHu*vs07 zm?Nb=|Klt%3Dq$Pbq5Pk6KzB-aKPd#n1lEs>f`Ib%Nth|m9Jp&d#Lg4E$)k&XP7w? zT@BbkMR)Q8Y6GXuE9O0Ge_^q++v}GB^|FRqTpG1tHPptMSbGBM`(qsHw`C4$oqfCQ z_y0!{+Q2!~(Ox!hnt!4OyhQa&yT^M+GNMi@A8K3_s$W%1`Mg`c8RjM5&f14#E8+=z zT<>@J8i{Zc8TWbr&cz{=2NoV?G0|L&+Tcml2JT=e`W^MYH}a##MIGh&=cCe=gf=qV8YZA7 zTyODNtVjGWR>Hc+_#YKhmuB%Xw?xIUYJAH-I zFzXNe2P0gLI_g}0u4aPy<$DR@{qO@SJ%IHPH*x??-RKVAKXeEsijYq2`OS_87~*i~P*HPD^Wu zGe5Ep!%;^#8g)mr%@wGfZ$mwzbEpkHH`Dy&#X+c(&1Z2%)CtB|+%83)e@{ycHpifj z=u2#lvn>9@{0ntQFDwo`>BYgQ6DWjfur%r&DQ_mAHo5{c;bshCediDreUV&H0`H+F zdV}g1aLS8wqT&K(G-|>+SOVWey;LJDztCKbnr}O5{)4EKIgf5tDt}VZ+gswaH(?{J zL);2=67x`BAd68GEk`Z9-r9GYhs@*HhxRk5g=(Jh7H*B2rw?kLerN3SKa4~p65~+| zp25=iKP-sp&w6)O1{V`INB!D8!ypVk=f#Ckac$H*Eik(ezx$|#2mI_UJj5LJGv}`X zpOcXDG3CxsN4?uR{%H9N7T-Wk_z;8fF{*#s^WNVLA*lJvBkQO9^v?I?hA6u9-x8`( z&bjl{CpLz>&m2m*^G>jnDwUttm+yH!sl0>~8Mb}08 z{6X13X-jSfxh?26;~zR=T|=z%znGnP7S5)$w!HdO&_B3J*rM-PTVK3Qelq!P_$Nh= z>NIg>+VW#d8$;U3LVczW&!7M4#(9?xu_WqIKSsGg+!l2$pe&_LCv}RVE10+x-PFT1&mLeh23e+$A`p zPSl&yA(Hx_B%kOIw>GtoWXfVWY^SkYT`7lbsw=cLr1YWuO0G9;Pw_G8i=-%}3ULVb z!JYJLjQqPqTHcgkTQ$< zAxeEp58@g)0CHScW&2U7ae)|K)zLZe-Mh7P?j85%tr`Ituy2{Y1 zYdCQo>TmEf%BR#Hk}qTZ+TatbS4kPci-C{mSJ(0Z#0RXdE>Eeqp`G8*lq-??I{h>> zqT!_mlK#~OgyAsaW;ltq2b4?Rxc~oWI&yC>{z6E(9?^dhwM`a_=j29Fve17H9>Hiz z-;_S~6;RVAdyfw9P|~Q8+zZMwVqI0S3pS;ELcTolYD#g+U`k`k;-ut?!7co$>54KZ zQ@?2|%*9NUx|9p#)6wS|B~AnWbGbJ5wB-&Y1ysuA-XyANEo!Jv>BdZHDLcr=PzF)| z?{$)R8>KC6zta$E?bEH(hZeUcZb^M9rG>TqNnL;3_4C%$w*p_-lpiS{QVMzv4*zEJ z|JPk=3mN!~wtkjfL98o*QpoDL@DJj>xD)lO;>DD))bp37 zQyitNbuM7i=8U1NCq7IGWxz$^qe-VK=W;ufX+mZ@)+Cz~>r-@1B)`V$id$JdntBo1 zbY;aC*n@I}`Uv{;#m|U?tPfQuC-r7Ho8oKp4D@x9dRGa^uIsa=n{=&8NV%VgezTS@sJEuxoz|VyyHJ0P zS8+eNjMRHjuas1xYKZ%kD2Sr#7fK6yjG%QscA)6`05g$WL`g-x66$J-pHS{o?szFD z5B27hw^tS_rzmwOKKugBqwOr^7v}k0UqUMh($ScjgbyVf^?c;6U|Grua=nQE#udbs zDAlQdi*K*LsKk=fwTCi|`WF_LFxRHE^6xs#RgLm7`44=PYF7(#x6xFQR5{8C>P4}H zbr&;iinQd9Tm28bPJAEJQwCGMq3CLYX()wg4??}W#VEBXy8eg1dR1q<{$1l6f|Hc@ zX{bsGrX02o`>4NUqMi5L+X=M;p#`dC+%q{y0TfnZ;7XRDgD!RrjZy*Etax? z`ZF9tX+?Q$gL2s<%gE{alv0aQic*e}m(rc`KKxs}v2(af!tviN{d?2QyG~^~MHPSA2ugh4gs?KK07K^iE_5ZZ3 zpdO`pw9^IzuP763;{ImOq-!6q zk53pF*120)uY{iQVf^2~9^JwQ4d~WCEUtgTpne-0wJ2C{J\n" "Language-Team: JumpServer team\n" @@ -211,7 +211,7 @@ msgstr "IP" #: assets/models/asset.py:187 assets/serializers/asset_user.py:45 #: assets/serializers/gathered_user.py:20 settings/serializers/settings.py:51 -#: tickets/serializers/request_asset_perm.py:13 +#: tickets/serializers/request_asset_perm.py:14 #: users/templates/users/_granted_assets.html:25 #: users/templates/users/user_asset_permission.html:157 msgid "Hostname" @@ -485,7 +485,7 @@ msgstr "每行一个命令" #: assets/models/cmd_filter.py:55 audits/models.py:57 #: authentication/templates/authentication/_access_key_modal.html:34 #: perms/forms/asset_permission.py:20 -#: tickets/serializers/request_asset_perm.py:51 +#: tickets/serializers/request_asset_perm.py:54 #: tickets/serializers/ticket.py:26 #: users/templates/users/_granted_assets.html:29 #: users/templates/users/user_asset_permission.html:44 @@ -540,7 +540,7 @@ msgstr "默认资产组" #: templates/index.html:78 terminal/backends/command/models.py:18 #: terminal/backends/command/serializers.py:12 terminal/models.py:185 #: tickets/models/ticket.py:35 tickets/models/ticket.py:130 -#: tickets/serializers/request_asset_perm.py:52 +#: tickets/serializers/request_asset_perm.py:55 #: tickets/serializers/ticket.py:27 users/forms/group.py:15 #: users/models/user.py:160 users/models/user.py:176 users/models/user.py:615 #: users/serializers/group.py:20 @@ -648,6 +648,7 @@ msgstr "SFTP根路径" #: perms/models/remote_app_permission.py:16 templates/_nav.html:45 #: terminal/backends/command/models.py:20 #: terminal/backends/command/serializers.py:14 terminal/models.py:189 +#: tickets/serializers/request_asset_perm.py:16 #: users/templates/users/_granted_assets.html:27 #: users/templates/users/user_asset_permission.html:42 #: users/templates/users/user_asset_permission.html:76 @@ -918,7 +919,7 @@ msgid "Success" msgstr "成功" #: audits/models.py:43 ops/models/command.py:28 perms/models/base.py:52 -#: terminal/models.py:199 tickets/serializers/request_asset_perm.py:15 +#: terminal/models.py:199 tickets/serializers/request_asset_perm.py:18 #: xpack/plugins/change_auth_plan/models.py:177 #: xpack/plugins/change_auth_plan/models.py:308 #: xpack/plugins/gathered_user/models.py:76 @@ -1009,7 +1010,7 @@ msgstr "多因子认证" msgid "Reason" msgstr "原因" -#: audits/models.py:106 tickets/serializers/request_asset_perm.py:50 +#: audits/models.py:106 tickets/serializers/request_asset_perm.py:53 #: tickets/serializers/ticket.py:25 xpack/plugins/cloud/models.py:214 #: xpack/plugins/cloud/models.py:272 msgid "Status" @@ -1699,7 +1700,7 @@ msgstr "动作" msgid "Asset permission" msgstr "资产授权" -#: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:17 +#: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:20 #: users/models/user.py:505 users/templates/users/user_detail.html:93 #: users/templates/users/user_profile.html:120 msgid "Date expired" @@ -2432,36 +2433,40 @@ msgstr "结束日期" msgid "Args" msgstr "参数" -#: tickets/api/request_asset_perm.py:36 +#: tickets/api/request_asset_perm.py:40 msgid "Ticket closed" msgstr "工单已关闭" -#: tickets/api/request_asset_perm.py:39 +#: tickets/api/request_asset_perm.py:43 #, python-format msgid "Ticket has %s" msgstr "工单已%s" -#: tickets/api/request_asset_perm.py:59 +#: tickets/api/request_asset_perm.py:69 +msgid "Superuser" +msgstr "超级管理员" + +#: tickets/api/request_asset_perm.py:102 msgid "Confirm assets first" msgstr "请先确认资产" -#: tickets/api/request_asset_perm.py:62 +#: tickets/api/request_asset_perm.py:105 msgid "Confirmed assets changed" msgstr "确认的资产变更了" -#: tickets/api/request_asset_perm.py:66 +#: tickets/api/request_asset_perm.py:109 msgid "Confirm system-user first" msgstr "请先确认系统用户" -#: tickets/api/request_asset_perm.py:70 +#: tickets/api/request_asset_perm.py:113 msgid "Confirmed system-user changed" msgstr "确认的系统用户变更了" -#: tickets/api/request_asset_perm.py:73 xpack/plugins/cloud/models.py:205 +#: tickets/api/request_asset_perm.py:116 xpack/plugins/cloud/models.py:205 msgid "Succeed" msgstr "成功" -#: tickets/api/request_asset_perm.py:81 +#: tickets/api/request_asset_perm.py:124 msgid "{} request assets, approved by {}" msgstr "{} 申请资产,通过人 {}" @@ -2525,19 +2530,19 @@ msgstr "{} {} 这个工单" msgid "this ticket" msgstr "这个工单" -#: tickets/serializers/request_asset_perm.py:11 +#: tickets/serializers/request_asset_perm.py:12 msgid "IP group" msgstr "IP组" -#: tickets/serializers/request_asset_perm.py:21 +#: tickets/serializers/request_asset_perm.py:24 msgid "Confirmed assets" msgstr "确认的资产" -#: tickets/serializers/request_asset_perm.py:25 +#: tickets/serializers/request_asset_perm.py:28 msgid "Confirmed system user" msgstr "确认的系统用户" -#: tickets/serializers/request_asset_perm.py:58 +#: tickets/serializers/request_asset_perm.py:65 msgid "Must be organization admin or superuser" msgstr "必须是组织管理员或者超级管理员" @@ -2778,10 +2783,6 @@ msgstr "最后更新密码日期" msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" -#: users/serializers/group.py:50 -msgid "Auditors cannot be join in the user group" -msgstr "审计员不能被加入到用户组" - #: users/serializers/user.py:69 users/serializers/user.py:229 msgid "Is first login" msgstr "首次登录" @@ -3948,6 +3949,9 @@ msgstr "企业版" msgid "Ultimate edition" msgstr "旗舰版" +#~ msgid "Auditors cannot be join in the user group" +#~ msgstr "审计员不能被加入到用户组" + #~ msgid "Always update" #~ msgstr "总是更新" @@ -4758,9 +4762,6 @@ msgstr "旗舰版" #~ msgid "Tips: Some provider use token except password" #~ msgstr "提示:一些邮件提供商需要输入的是Token" -#~ msgid "Send user" -#~ msgstr "发送账号" - #~ msgid "Tips: Send mail account, default SMTP account as the send account" #~ msgstr "提示:发送邮件账号,默认使用SMTP账号作为发送账号" diff --git a/apps/tickets/api/request_asset_perm.py b/apps/tickets/api/request_asset_perm.py index 370d54b7f..40add8659 100644 --- a/apps/tickets/api/request_asset_perm.py +++ b/apps/tickets/api/request_asset_perm.py @@ -1,9 +1,13 @@ +from collections import namedtuple + from django.db.transaction import atomic +from django.db.models import F from django.utils.translation import ugettext_lazy as _ from rest_framework.decorators import action from rest_framework.response import Response -from common.const.http import POST +from users.models.user import User +from common.const.http import POST, GET from common.drf.api import JMSModelViewSet from common.permissions import IsValidUser from common.utils.django import get_object_or_none @@ -26,6 +30,7 @@ class RequestAssetPermTicketViewSet(JMSModelViewSet): 'default': serializers.RequestAssetPermTicketSerializer, 'approve': EmptySerializer, 'reject': EmptySerializer, + 'assignees': serializers.OrgAssigneeSerializer, } permission_classes = (IsValidUser,) filter_fields = ['status', 'title', 'action', 'user_display'] @@ -38,6 +43,41 @@ class RequestAssetPermTicketViewSet(JMSModelViewSet): action_display = dict(instance.ACTION_CHOICES).get(action) raise TicketActionYet(detail=_('Ticket has %s') % action_display) + @action(detail=False, methods=[GET], permission_classes=[IsValidUser]) + def assignees(self, request, *args, **kwargs): + org_mapper = {} + UserTuple = namedtuple('UserTuple', ('id', 'name', 'username')) + user = request.user + superusers = User.objects.filter(role=User.ROLE_ADMIN) + + admins_with_org = User.objects.filter(related_admin_orgs__users=user).annotate( + org_id=F('related_admin_orgs__id'), org_name=F('related_admin_orgs__name') + ) + + for user in admins_with_org: + org_id = user.org_id + + if org_id not in org_mapper: + org_mapper[org_id] = { + 'org_name': user.org_name, + 'org_admins': set() # 去重 + } + org_mapper[org_id]['org_admins'].add(UserTuple(user.id, user.name, user.username)) + + result = [ + { + 'org_name': _('Superuser'), + 'org_admins': set(UserTuple(user.id, user.name, user.username) + for user in superusers) + } + ] + + for org in org_mapper.values(): + result.append(org) + serializer_class = self.get_serializer_class() + serilizer = serializer_class(instance=result, many=True) + return Response(data=serilizer.data) + @action(detail=True, methods=[POST], permission_classes=[IsAssignee, IsValidUser]) def reject(self, request, *args, **kwargs): instance = self.get_object() diff --git a/apps/tickets/serializers/request_asset_perm.py b/apps/tickets/serializers/request_asset_perm.py index 7519f4b1f..54e5ed79c 100644 --- a/apps/tickets/serializers/request_asset_perm.py +++ b/apps/tickets/serializers/request_asset_perm.py @@ -1,8 +1,9 @@ from rest_framework import serializers from django.utils.translation import ugettext_lazy as _ from django.urls import reverse +from django.db.models import Q -from orgs.utils import current_org +from users.models.user import User from ..models import Ticket @@ -10,7 +11,9 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer): ips = serializers.ListField(child=serializers.IPAddressField(), source='meta.ips', default=list, label=_('IP group')) hostname = serializers.CharField(max_length=256, source='meta.hostname', default=None, - allow_blank=True, label=_('Hostname')) + allow_blank=True, label=_('Hostname')) + system_user = serializers.CharField(max_length=256, source='meta.system_user', default='', + allow_blank=True, label=_('System user')) date_start = serializers.DateTimeField(source='meta.date_start', allow_null=True, required=False, label=_('Date start')) date_expired = serializers.DateTimeField(source='meta.date_expired', allow_null=True, @@ -33,7 +36,7 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer): 'status', 'action', 'date_created', 'date_updated', 'system_user_waitlist_url', 'type', 'type_display', 'action_display', 'ips', 'confirmed_assets', 'date_start', 'date_expired', 'confirmed_system_user', 'hostname', - 'assets_waitlist_url' + 'assets_waitlist_url', 'system_user' ] m2m_fields = [ 'user', 'user_display', 'assignees', 'assignees_display', @@ -53,7 +56,11 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer): } def validate_assignees(self, assignees): - count = current_org.org_admins().filter(id__in=[assignee.id for assignee in assignees]).count() + user = self.context['request'].user + + count = User.objects.filter(Q(related_admin_orgs__users=user) | Q(role=User.ROLE_ADMIN)).filter( + id__in=[assignee.id for assignee in assignees]).distinct().count() + if count != len(assignees): raise serializers.ValidationError(_('Must be organization admin or superuser')) return assignees @@ -61,7 +68,10 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer): def get_system_user_waitlist_url(self, instance: Ticket): if not self._is_assignee(instance): return None - return {'url': reverse('api-assets:system-user-list')} + meta = instance.meta + url = reverse('api-assets:system-user-list') + query = meta.get('system_user', '') + return '{}?search={}'.format(url, query) def get_assets_waitlist_url(self, instance: Ticket): if not self._is_assignee(instance): @@ -118,3 +128,14 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer): def _is_assignee(self, obj: Ticket): user = self.context['request'].user return obj.is_assignee(user) + + +class AssigneeSerializer(serializers.Serializer): + id = serializers.UUIDField() + name = serializers.CharField() + username = serializers.CharField() + + +class OrgAssigneeSerializer(serializers.Serializer): + org_name = serializers.CharField() + org_admins = AssigneeSerializer(many=True) diff --git a/apps/users/filters.py b/apps/users/filters.py index 4fc052c20..d12d3234e 100644 --- a/apps/users/filters.py +++ b/apps/users/filters.py @@ -1,6 +1,7 @@ from rest_framework.compat import coreapi, coreschema from rest_framework import filters +from users.models.user import User from orgs.utils import current_org @@ -11,7 +12,7 @@ class OrgRoleUserFilterBackend(filters.BaseFilterBackend): return queryset if org_role == 'admins': - return queryset & current_org.get_org_admins() + return queryset & (current_org.get_org_admins() | User.objects.filter(role=User.ROLE_ADMIN)) elif org_role == 'auditors': return queryset & current_org.get_org_auditors() elif org_role == 'users': diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index b01bddf42..351f33337 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -320,3 +320,9 @@ class UserUpdatePublicKeySerializer(serializers.ModelSerializer): new_public_key = self.validated_data.get('public_key') instance.set_public_key(new_public_key) return instance + + +class MiniUserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['id', 'name', 'username']