From d177b82d2d341bca8efb18b728d71743d9e3f827 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Fri, 3 May 2024 09:57:24 +0200 Subject: [PATCH 1/7] fix(login): check for error before automatic idp redirect (#7891) * fix(login): check for error before automatic idp redirect * hide next button on login page if username password is not enabled --- internal/api/ui/login/login_handler.go | 2 +- internal/api/ui/login/static/templates/login.html | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/api/ui/login/login_handler.go b/internal/api/ui/login/login_handler.go index 31f16b8555a..ae21d84d877 100644 --- a/internal/api/ui/login/login_handler.go +++ b/internal/api/ui/login/login_handler.go @@ -95,7 +95,7 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom if err != nil { errID, errMessage = l.getErrorMessage(r, err) } - if singleIDPAllowed(authReq) { + if err == nil && singleIDPAllowed(authReq) { l.handleIDP(w, r, authReq, authReq.AllowedExternalIDPs[0].IDPConfigID) return } diff --git a/internal/api/ui/login/static/templates/login.html b/internal/api/ui/login/static/templates/login.html index 72837c7f976..7c063d99127 100644 --- a/internal/api/ui/login/static/templates/login.html +++ b/internal/api/ui/login/static/templates/login.html @@ -36,7 +36,9 @@

{{t "Login.Title"}}

+ {{if hasUsernamePasswordLogin}} + {{end}} {{if hasRegistration}} From 2648db694dafd6e50f718d17d0f0b34f93040e97 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Fri, 3 May 2024 13:29:11 +0200 Subject: [PATCH 2/7] chore(stable): v2.46.7 (#7901) --- release-channels.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-channels.yaml b/release-channels.yaml index ec2fad5cd35..d8b29a5ab7c 100644 --- a/release-channels.yaml +++ b/release-channels.yaml @@ -1 +1 @@ -stable: "v2.45.6" +stable: "v2.46.7" From 7e345444bfff6053fe4c5bea4202cc54d269ae1f Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 3 May 2024 15:13:06 +0200 Subject: [PATCH 3/7] docs: feature settings in console (#7899) * docs: feature settings in console * update default settings --- .../manage/console/default-settings.mdx | 45 +++++++++++++++--- docs/static/img/console_feature_settings.png | Bin 0 -> 315135 bytes docs/static/img/console_languages.png | Bin 0 -> 213256 bytes 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 docs/static/img/console_feature_settings.png create mode 100644 docs/static/img/console_languages.png diff --git a/docs/docs/guides/manage/console/default-settings.mdx b/docs/docs/guides/manage/console/default-settings.mdx index c2b7773789a..239e43297f2 100644 --- a/docs/docs/guides/manage/console/default-settings.mdx +++ b/docs/docs/guides/manage/console/default-settings.mdx @@ -15,8 +15,9 @@ To access default settings, use the settomgs page at `{instanceDomain}/ui/consol When you configure your default settings, you can set the following: -- **General**: Default Language for the UI -- [**Notification settings**](#notification-providers-and-smtp): Notification and Email Server settings, so initialization-, verification- and other mails are sent from your own domain. For SMS, Twilio is supported as notification provider. +- **Organizations**: A list of your organizations +- [**Features**](#features): Feature Settings let you try out new features before they become generally available. You can also disable features you are not interested in. +- [**Notification settings**](#notification-providers-and-smtp): Setup Notification and Email Server settings for initialization-, verification- and other mails. Setup Twilio as SMS notification provider. - [**Login Behavior and Access**](#login-behavior-and-access): Multifactor Authentication Options and Enforcement, Define whether Passwordless authentication methods are allowed or not, Set Login Lifetimes and advanced behavour for the login interface. - [**Identity Providers**](#identity-providers): Define IDPs which are available for all organizations - [**Password Complexity**](#password-complexity): Requirements for Passwords ex. Symbols, Numbers, min length and more. @@ -25,10 +26,30 @@ When you configure your default settings, you can set the following: - [**Branding**](#branding): Appearance of the login interface. - [**Message Texts**](#message-texts): Text and internationalization for emails - [**Login Interface Texts**](#login-interface-texts): Text and internationalization for the login interface +- [**Languages**](#languages): Select which supported langauges are shown to your users. Set the default language if no context is provided. - [**Privacy Policy**](#privacy-policy-and-tos): Links to your own Terms of Service and Privacy Policy regulations. Link to Help Page. - [**OIDC Token Lifetimes and Expiration**](#oidc-token-lifetimes-and-expiration): Token lifetime and expiration settings. - [**Secret Generator**](#secret-generator): Appearance and expiration of the generated codes and secrets used in mails for verification etc. +## Features + +Feature Settings let you try out new features before they become generally available. You can also disable features you are not interested in. + +The Page lets you choose between the settings `Enabled`, `Disabled` or `Inherit`. +If a feature is set to `Inherit`, it becomes available once its enabled per default. + +Feature page + +Features can range from UI changes in the console, to new APIs or performance improvements. + +:::warning +Be careful on which features you enable as they can be in an experimental state. +::: + ## Branding We recommend setting your Branding and SMTP settings initially as it will comfort your customers having a familiar UI for login and receiving notifications from your domain and mail addresses. @@ -85,13 +106,13 @@ To configure your custom SMTP please fill the following fields: - User - SMTP Password -SMTP +SMTP ### SMS No default provider is configured to send some SMS to your users. If you like to validate the phone numbers of your users make sure to add your twilio configuration by adding your Sid, Token and Sender Number. -Twilio +Twilio ## Login Behavior and Access @@ -111,7 +132,7 @@ The Login Policy defines how the login process should look like and which authen Login Bahaviour and Access ### Default Redirect URI @@ -130,7 +151,11 @@ We recommend setting your own default redirect URI, if you do not want end users Change default redirect url of instance: https:///ui/console/settings?id=login -![Login Policy Advanced Setting: Default Redirect URL](/img/guides/solution-scenarios/console-default-redirect.png) +Login Policy Advanced Setting: Default Redirect URL ### Passwordless @@ -280,6 +305,14 @@ These are the texts for the login. Just like for message texts, you can select t width="600px" /> +## Languages + +Drag allowed languages to the left column. Languages in the right column are not shown to your users. + +Choose a default language which acts as a fallback, if no language header is set. + +Languages + ## OIDC token lifetimes and expiration Configure how long the different oidc tokens should life. diff --git a/docs/static/img/console_feature_settings.png b/docs/static/img/console_feature_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..b8bcbeaa40f4947c5dc91e548fb3745f976200d1 GIT binary patch literal 315135 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ɯqAvK`*a)CKok+(pD&gP|ze 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

yNcCA`V+ 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

{XrSna-d)2snT8KXb1)O-S>DiX#`7zJc$zD( zPmb|jy>If4HtI3T4=YL@`$xxSobL_F&W17E$EgPSIk&{l*@+EaKv+nq30>FkuDdO$j1#??-H$aFx{&wnN+;|bkV3}NWv)##X0^L zi?A^5HgKp}O#e@5(^8oz4_B8nLA#^i?wzYG$0-Td!-*P0IDL(`gB4T)3!nLY={K;- z?F~3DEVW)FLEtQ{gd*+zMGq41?lA7`(21+OFXTu?_W#Z`zX6KU)7gK zKEA5f#^Qu+^yr^ta?wCd4P1#*=Fef(!qxKeZs`IQsp0xcjM02N7GmDKh+Wlm&Ql6@ zMU9ry$%}MNXWuwzDI!B3InN<6XG(Jbhf^vrvPC~Z=(Z7jra(L+&s?{}xOp8ZY!%I< z<2A;ShMUg2gVauj`$U9Nh6ped53(Z@DLp)yPX*F;4g_d|m)abl+(0R_*I}~GKF~e) zcZy{b_Y91~KUUVXqkc*z)0zpQbg_pJHj4eJ$5MK3cHZV;Kt!l|lQ?TAYkv zEa~LziZ&^{-!tQc8vy_8fFDBogv5lD?zMdcAyr`4c$K32mX-xCwqvmrPWE+x;zzF+ zX`@;RnDn+$h1z_wrm_NU+h3^t*K_hr__U_#re3=q@0|{U;ZY*>Pmq|hfX4c|$h&4y zaV19=(bWMfZ(ds{P@17jq~}@3L?{HmopA$~Pnn|A#e&9p51YU0G+Ks-Wn4$`z9_JY z@(BL1EN);U>8w}eys*HAmlN>N*J~(0 zg&CeFxTQuJ^Buxw#MM-0;7uahZ~9dfj7)l^BCmn#llh~$y&LS6`p2wiX4xAlZKt^f{uW3f1YhKt6UX$&dv#nY}W99h8i;&d`tQyYXF5~{b| z9>FM9F8k%_{O;v0RUet|Ku%N37sKI6mJQHNoSw}Tcw;fZm@+(8drlYlPZAo-{GUiT z$UO-eTM->s*h)T0{x9-X?tWLU-!p@+mc_I53uZN$MtrwobK0`<A$puRm zNt#UEj_{3@0TnKvti*Dhe5OGMCExyD8#+OyZ!zdyGi{@1tk^B~6Fk8zA~6R86k$xk z)H$$WX*!Ge*w(;1_^-17Y>oJEd(a+<_5w60@bIuI*@s~l`#F8k{6F;17!dmo zLDf%+)r+aSr^)ST+l;mcKILvRM(JxsEmnAt+~A*2V_1~&(ssc}wVx73@P-;=m{v0M ztYcs>b=zylU0$&vN;}N_bTxF)69Rk@R{P!{Swcuy4pM1ztnK>};(h(q#>oiw&35aH zJxuwCsr6U)m4fJ0Aa0Gu8hM^JZ=o}tf3R#hS?^6rQhw&BJg1~#Q{UKLH!7iS(tL4C zMw-r`-9=Gex<(C)Sk4xt4&kX{%%r>$D9md8WYo=#FeZRM#dP=)cv8%0=6nXilWlhFB>W5AUT3zp2Xf4Pm}I&5dg>l7eai;l+MMIt zk{J6zK1mRxeVDa}$9EGy!LxDsj3GtBw(Z3RzJed=Vn+i1g=!OgO zp}$PeC#v=fOqXTJ60ek$-*VtDw?FsaTZw-)r%!#Mm;X+*?McTR|H4+`+q1Qwnrj1& zBx#hH-WPY-VeA98D~Hms&h(PH9WhUM2S#Q;4MT?GwdchE)}y(78^WTX({EnNjaHkd zx6*Y#H41#wbl_?iQ21SMfKqduq`W3fIryyV%qxe1C90o=SF=Swg6A50=0^r{ShmFN zk{;ZNRw?8C>CZwpIL3{_NnMeDnnOF=EUZhZB|*qpDZ=&cYj{UvWE9kK;`mwYtIPuM znBUIa(V061zida%53jutyCgR(OXzJP7nt36GHd5%S&$WZy;L<-imwHeK})RK@oT0teZ^G^2%kW;CfzJp5Le4z1>h}Xf=rsEXuTBx9njGDVW6)|W*Xc)XXL(MDvTrK zf&#DIGa*Bf%DJ4`rT}6#()W$|*Hx<&+rN$;Gk+#}n~rDQh6eS8nd>nTyy0Nz74YU` z+Zh_kiHHJOk@N=t+$DAEX`5Yxa6_$QlCc;O9+@lk4vE6Y5sw~w$baNQUB}$Fns<(- zmK=A7xoaJchaO$`!yrXlRzExpna|E~I0ZcVL4w=w^(b1M;R{$ohfkPb*ps5aozcit z`zHhi5Tke7&~wbx{pX93ZzpavR30~j1TS2y+VSyG4g_wm`%9V)=#H8>eO#Kd{1$8I z^Jp2v7{P^;Fvb!%^8Tmy1eYtn_Sb>Fcf7Qwz^2(~4_pDM1_((x+IV%wkuB8f)TRW5 z9-vma)bHUIA(GfF7s0_^Q@gc(yQl@?)D%+BcC-CD5U!(;&Wuym%@CcMW?k(eIuAds{&Z36 z=34vo#=95Y3c6s_*B-rd;miBB(ty&s)!^fLQtxqk&@fy~u+7N@YE*>>ieHToloM{r zziT`lbkox>yGijpo<}nKm29yKIA^v!+nS}X)uv6en*BKhiDQob`s$toB@0H~$v@A| z8I*>cP=vCWr?xhloj9AX&bx#V)136Vv+_1A`I}{Dr!}4DN>xi=TMcf(BlAtrGSduC zag=AN@ZVQE92LfQV*V%KN(OW8ZFrizQy>(6ZZ&FjadZi}Z!i;I02NH!i!ZtUJsDmW zyW3Ench^y)T35W+1TR9p1hx6fKAGV0)s1YMkn*vTRBsu2nXGYXwe?z;-p9?>Ruip6 z6Q3UYyk?VfyqqOV;fV}s6TIQy>iWJ11rSUrXvqACU3F&wT@Qp z6Y}#cw4IF8;5ndjfxdBE!*MFAD8|apvv9xDLf*gbh|B-dS3dXs;oOgoZ=S^EujR4N zhL?BNKW-R6;x4ou%7#({ko#ui`?6oYfua@+YR@h3!-Xbru6+mbk{*7!a)faejO71X z#RzXgHJvZ=7B3YsMI~0Z4(!w!F>r#8`>=6UhqtucUg~H&k?+zESDSgI;}-06PWNz4 z89dDpmm0K{5FxGDFL6wCH`+-O0+BB_+P)60IU|HSl+$W^;ed{5->Pr!on~AF9DgvT z4qH0es6bHhwAI@uYJ#&63*O}FG`o~NZQn_$t$Fw}S;era%ddE=OsQwr?b>2Yv!%O9 z1TI$HZB(y(*vRy^ep3jQR-E0%_8r4g7T{}&QCA?&7JV0w`mxe+ZrC9zH9hgbdsXHP zza-zIVNJBB7&~gCAC!wnM2*sJ2J3GI4@cn%mnkK@U@(BF{ZaAgDM}*m;uSwuTm2lF z;eEP2BO07e*MtI!L(PRYDJ3`j)Zk~j&85Z+(kGNzc9N&?{?G-|qr@5@1kjrjJJ6 z1ckXP>o{l?jyo8q!_HX>V$?IywWT%(hAuZ!8>I-bDU~;N-#${%4HojQ#S9HJ{BB=z zU_)+890=mzFrUjtgZ^}g6TTwzcjlX9%lDXQUdJ-C7mf`+dW+bs!605_%ZZGue_Jx% z_C>u4Meo`-j7ZrEvNsJaKpAj{nG&ZbSqD0MA^5voi{B=0UEvyB{nL;>dAboQg$e&L z0A8(`TlSpP52kTxwn|K28m|<6yFIdv;)&Mx^0y8RXFw5R+L&i#KPCNa_Y4oPnuQk} zfvy#jAxb_P=H9`DZ_B{-1mt! z8V$<0RAFteLEcwn39Nq2Sk$__@X-F#8TX^p_mw2YCHkE(yPM+OpR>QbiIcW=1?AAls)@wIHp&<>oo12TiS|SVLZ(C`OVe`M%8$0JZ_}MZu~GO2@OFVMKmh_ z4ORljX1xf&{PyOQ4;JABu_m-1S{zYbP%|7Qp9zp-dDCK()cGY^BOq}50o$QrsJ%{n zsb5Gl(RcqHWy3A|F(O#YfN&cnP-@-!?QzF+t<)+ySq7n}DXB?^F7ycVSQQ+Ix%G{o z7$OQuJ3nj4Tq_lq-%6It9XnBeD{s8^8#SC;+NS+scK5m8#{g*UB9D8v){k}P>n6cZ zzlAt|Q(}IaOkr9IS0y_+3kz}q@ayw)YG|M(k9OM}Qd(N_IZ&N`-Pg}S0#*Eyngt`- z&Ob3FSLgTX!*sc6?kXDgSuZf6F)Fqp?vJ)b$oKcSG_$%U6u3w&pyfXJG;Lj6V!97mI|AqU;?sdgcsgHZdj>?2ayrDV>2N*QBO@UY!_K% z@G|1P@2-^O$Q*0!$rioicN|*RBRE`r?QJ$@*vW_M0#2W(;sm1M>3HbhDjTGlzA*Dr z8j#~$0mf6wc5Xg7v|3{TPMGN9Bz2}`n<5X+wbu7Wp>`6ufJaXx`1Qm9mw{s=NVkg6T4*( zK!9o%&#{?Qze_^A8eKv}V7ftb)5MTOh{ME*4+T4GZl9c51@aio2ccp8e&!KO$75hJ zw&1*56!~cY6Y`#u*|MoS&HxXyS~Qd4D#hi>U?=MR)=h8cDk&Rs#W`#L5D!F`h?~=b zQ=m`s@!Kt|c9!|or`j;9NpB6?ef4=*Yjdqp(`yWlXc(UFw^SdXQoPGx+hk%faaha#u180*3JHe3OzOI+kap=X765 z2W6p>QEWY61910Z>*TIrDfTus3MqAxKrI2R0xibRCvC~eEE|ne_!y#`j7z)8c-Aew zr3%vZn;`O~AeN=MYS_DlV9QYqWz2YUo*+5w#3d;V_)kSg1B&p4H>dpc_Fo&~Tq~N$ z6kl7g%3kEKSDBIE?$?XH(_t+NPO;NQkr2_+yNeE zX@lV-3roAZ9LUjf-4`_ERrr=yD3?+&v?sG~%8@f~h22r0&PnAJPx8lT&7`&f<<-1I zrYuRSW6X;FSJOW_elsVsIzGbFw|PBPP3b4;UXuTAQGzD7;sNSPe2&o(iNWduYHWbb z;iOHyR&wj^cy8GlVsefoTeTz_7}@ay896*^pW$FXoVywH{rGhzaLdJ4d`62EMxLjN zoYwXLlkDZMM5Pg5vc;jtYNkO%%dlJPk0#WRBO=pHw1{OvKgnPUby^zv0#VF!%q92u zpF9VJOImL?l6C_sWn=Y}zO-W4Q*Sh&+J~}Ep_#T&ETk)(H&<#t)?Re=&Z2=Vr?|MX z0@e3!59*8}F1`I=*Age|x%VH7dulb(1Gk6@&dCy#*nMMVrH9$gHyz((3OCr#I#{Pv z>Us6@vRl8$y1`R8Y$_e7oi+2#Q%e*^)F7p^Cy9PWA{~#!A0*m=ELCPQ*kg%a5Z}#M z`F-W~wA8oKCNTIuIIKHx?$D5I-o*(SXq!1@Ksci#(0yi;3jOHYf;-&#$V$#CVj)-T zi~Pi9&+MT2-hwrsesa7<*+&xyq}}T&**4s_S?qPm6hRVcZU^Q$ur<4WJ`|9W5Yc-M z36sxVG)!EU$Yj9tcA6`7?3tY?j`Hy==Tnca-l)MG-~SLq_-mZGdI{FCL;WTL zf|<*?MJ*14;|`zCdrNbNmpgT!8Ozb1`Vi-CYl=eEikuN4j==%4ZYoMf?P~2!j>5+x zl%iz3mQAB%(mz~DDiD`yY+bAAq$wJ0P?oAaU8namp`T zTD5$mkmMS>F#9B0WHjBVD0^^yav6)DD*C z-H4iQp}##wHGTk7SeUj3`%j;j)rd0G0`|zUp3NNNg*VRv?+>I$mJ4t#2SSEp`?IZA z4#ff$Mll@6t22pr6aF^g70v!nMP6(O=hu|9Ay>ST= zAZP*vhXi+b>j1&soyM)3#@+5B-`?k(JH|cx{$cQ^yT@8pHEY&8-}#hzQ$yFQU>o;< z2HB$&592DF&1b{I?#*0w?gc5Zigb~pL_W_T-)1Mcz1D0s$I1-&G4!cyb3XdSdc|Q6Eib5BX!yuj#&@O^hNTzW4u#=^p>x0JsK6V@4TBq z6?)RE88+EHXND<4%VE^LHQtjMp}ozt>~2wtZib$o%dwTT~4_gbcT$gf|xYwis#`2;~UHXJ|-mpYeJXx9~zTPAI zYB!uBDqZ+jJcrb0IGvz+q@rm<-@Fs3qqhb+n)&&f*_1A9SjlDB z50sOAI|n5YQ6hc2Vt|PZ>;3(lYS<>;anwDaF&|zh(NR4Sb$F;Zzgq|SvSOf;Ovp#| z>)gFRDatv&Fk8ps;3q}dRHzfxpm_(wNn7Maw9KpoVu9H0Xup0)mJVwjPR99hO2&%75OCA@@VQic#-`d0087`&?Cciz80}guf&Cw2f4{EX(PC}#m zWTA%-<7(VgbQm^a3h5`WaeCa&g@r(m*^E++B1+tFf$*Q?WSw(``A8$h#ggrKTfbQ+ zBbqGEza|1$_8t7=;3VYR$+e?vJd~_S+r=S4JC`1bg_^qczIk-D@|tzDxccx(@6sHh zW{EP{)=LK7lfQ#fRj^w|S`HrWBF>#ZSUlCx+Dnw*RMxmFoo7NmXL?Cr*trjM^H8Jm znpkMrZv5_$Knr?#oO6*jcA<`Nv7b2gF^=-g3nSQNz*4X7thv~CMIlNf@Rdefa1x?~ENQFn^H~WAa1UDk zb6DK|esoxbWvrN{-gmrC$=877y>TJ6Gh_Bgj4gkEn{4!QF_2IO<+@Qx?7=(}zZjgm z?68NJO3W-5*2gdNUZQ|B3_7W4JGmFkMvaB{OT949_7H5Ah?Zs=>h%_HM~CgD75*h| zkm$5PRG)th?{ppQ{Hwa@l|E=ZVmFFm&&8saZeKz;Stl*(EB;tq%1~K%bK$THRB3S3 zH1sa6_KOltMc=kPLG`ooOTxj6m#B}j3Vv#lTFM!vwa|7p4XqP|*_!HCUX-)GoyQh# z#$V4sufNzUY4v#dW$DQ&MTmK#aOAy=Z0$b$yCFC<-Zx!4wYv@H#^S&_bIy z1SN&4yt$g)@@fjd=jtTKTA;HAk8%*XBaKQ=ByT>bhvvkfB1EyCzu5%J6c4wz16zOt&5~7C*EY%YHS#WHy)<_H zFOy@WjHRu@v?tHtNa39azNQeD{bX`RottKh2ob_5+jq0)p`91&U|!v^ByFAT+e4CzX7mExjm@0T0YrRv~gx>lyR1i~A*(CsuO3avxbs1t|SCehV$Ntx!|HiuB) z3NSg$w`t`!I2Q?cT?jV^!ROpmz;@j4pEW{+WbJD38MbMpO3b|+S1Q?L!QFbZ3X0xU z4U6KXaC0$_=~Sm&e(LA}(f`z}ANdxZph#IgV4_%O7#Qyc5h63kGTM5Qrl~)QfKzkW zHgQjg%-xRS>-fXlalpP4$7^U=2yo^QRr>uDM-Y$V!UWDl>w)Hf)?VMVcaTAh#CP+3 z;rc?y!P5@!C&R4KNLMl|P2Q+r=jn%_T$GZBpL*!2sCL?KVv1Ya6OH!jnX||!!ELs%B8L>t9xv#tnqbW{Dj>Uj#TWfop9H=5 zSDz$IQ~vF*rEu4cMh8%Oe2z~D&(?wc@q3Md+V%R9Wb6muQH+dmRO}%&B{2j3BBL^l zbWDUISMxKVf3eEW)TC0U#Q3R&yYeg*uZ$d*Ri8a9LvV9beCH0-$u+fG7xJpy`&ej; zy3`?6h5MckZ?dhedD}LamWmb(ieM_Qi#1*Av$u&k#2ByOSnVQ259E2WuX2LNJT_+~ z%<>s3H>4iOoh@cZ*LP0g0OhNEv2ky^+P)NvspHo=9;C?B^0AWb!^kkdAgs0>p2EpM z8dIp5B=D2Dy|0{mCYoQa5o^4nvh!~n)EATrMH9C4g8N)>7lt0*>czSfm(^0N7|@^X z9~vv>mUumwh&C`{7wxHmw^?wI`Ur*PFZ`I-DrA2sCABFJ>aa1g>AKcij5R7~b%+az z8K^+>v@h5rw5$IFZ`OBtd9ENO>ihoX2r^8X=7iy{)-Ra#fUE=6Mvv{G`K+%SXUPA$ zo9{}}yWNd^jOAikcbi^tYP_gkr`XU9l~0y4oh8@SLr++Wd0un0B$$@_Y_kwH%8;wxuP?-98h^lM>BK)ZF3soq5JZ zYJ%Wl44+@2WX(dO)(A$PVN^Ag;b^b2uHp13-|!=*Sq2xCS$mt|&64@J4TQhShJV4+ zB6R}ycroenwhk;5N0fG(F{WPMV~0OyN3eV#w$w8eX-`>iA-3k;gp`ljpZVLO=p~MT zn(Xevow=2x9fL2{PxL{d>Fc)`4<5dd#rExdhx(i4D`9^Cm+>OXC-1-ZA0(CvGF*yY zgRD3*rWfcw?_a&d2qc6@*F$o@sH@w|8s%h>8~|Ji(SdfviyC28+x9-5UjaP5VZuBW z@UwuHs+X3?Gi9bXZd{ikfHY*%N}JTd#U@Pru+XZzK+IpQG3W+vavT(0o4f4flS4)8 zM`0dz%&RW{*vvTI^8P286y*q8=^?k-^ye>DLJd;noPIB#cA$?x!J-#PFOlD+i|R&h zgt%D`aaU6-#onCQ2+%1)xGcs^9KMSyP-w*2*yu5tMZejP9Id-E$_$KytN`o>S;%b)CcCDNsJg4S4-vKrefa`sq4c~+zq2ISqZ-RGB>SgM=oe% zx02+v^J4EeitKD&@1WoXaYRp|pqNdKu)JkQd|qaC7jn`?XMyWF!Dbu@Qa&J<6AYS$ zcGhn^R+XdM%4-@s`!x+WTAEu>YLKop$m(Vp`}uq8kyZhgMf+m@UAk;ix3MzHU*q+_ zHno+9ke+;D7+JDcqUbuVc>!njBp8_ChYs#r#v51e;VMy z-EnJiX2UFCUcAIOut-^5EDPLpI^=62e2idIJ^F@uN~iVP!)pk3Ji)HJ(c+vhn1`#< zHb}0wHBY-3WoX+u`6lQuez`rxL0UQ=o|kwK5-wb(pU()tUE zrklh!qA1iK=nF9jjI-;;g|%p?6La3`{g+Sd)XLlOZR~b8yS&SyqD2!DsCg-M$>po7 z*-T7;gfyuhl7&D2>6a(|aI#;Ah)}*Cb=0=J-uYOiIo1SqfMGqTB?^R6KfG^;BR@!1x@LoHhc^`A+=TT>qa1>|}gPGR<;8Hf`kBl@rTM3Z9Id_oLYGEP)+D?@)w>8gR zk;0Qb%paG8HG!$}&zXRoU}mYmjD7+aTZ-28+bqr&6Kr{Og4512lbZFASLdjdTKY^w0M{G!L;Y10#O|TYTHVcjAG~a~ae~5;@C*<9QX6A{g$*`hnUx zmit@Wf6sW||2^XsaR)QA2x$=0Ke2PB6x`0*u7cb}2d6rcd0hbwb(}~R5E|O}&6abf zqTF0Tzd0w09dz#63zQ;B>t_PEx8bFBUW^$`?0O~W#yV(jf-y{ew1DyF?C8H zmfq*sfQa1W!hWAv;DGnA88I%EYEG zkiClba9i-$mY-jD{9SfOB-z1vCjBdfNPH zbmsXs;$wTID^P+dG-<|(ajU3QY;xjAMwIiZ^`URZdZ=Y^v~}iGFq&W3hZ06Jj-NdV!?c9zGeOD9Q#=Tcw-M9|6d79fwh_le>Iv%H#ettPz$O{w|+~e46BLIt73@d4=1=3r* z9=Sb&{ufgRAK*8tZaSU8-@Uub8pW12*?}3qq)os8z+3o#1q}{%yuDim97I!XY;Dg57Ob#Eds>Qd)j&a&uJ>JA2N*I5T|s7XIG0?MSf3+Ge|?*)6xDR>;+~ z1gDJ{qwWE^>eryfW?%nvzbZGmNu~@h(?B(cTeAU&Ve;6Win8Tj5hlcw8KU^*gma2C zz?s?wG~tJ?I=$~uy_6i~I+8Z3R1VyV@O0vDD3#8;dli_D@6D1@)omdOGR(0_zv^lg z2NyCTdZV7q*_K(hojr`oJ=67#Sfx76Z)!J%>qZ3>1BV4Uh5~nsCP=J>Y1T)%54Vv3 zal2fW0%e3}G5bx%r)TZC!vU#HL-vUZ{jLT3fqwKT=T`JdD$gu}i(TW9Z~R)3Kz|+P zPiFZK?BUHzzuNY5G^PeljTh!+f%r}J^QJz1*yG?Et<#lgcAH z|5+?Q1UkRH{I^(${(G??q;b|)+r4B9j4Y}KfF2QQxAi({`=k^MYrsx+jInL4JB5ac z&27?#1lh;ISjfrH7j$P=kAZbG{P*IhXNCWY)GTo+rY0jgz2EQWoE{<tAYrl%c+n?E~jtBB+wI0hXSOp%4QN8fLQlUW29;-D*dIlqzp z!EN~;9i3y$Tk5QEue9CdMB5xoD072}8=^&J(a1aMK8CEs4+{WvsN|bE1>6o1>gBkj zG&?rb>W;FqeNioxY6dT62~3{hWy!mCy1q{1Ob_v8Z%6OhkN!Bg+;N?FK5x@E=^YrqN_!FQ>eXlpiv{Y} ztR9f|U9wE<=6(!b=4Bsl_#B+{^<_68=W^+|QD-T@1W|p!KmL!|%_=Yll}00^2Z`;t zxL1b84aLlkR{13h>9;rp%(zK3tT+81GZvPy*hA2|Y#*_3@X`Bg43+GtLvXA8a*g0e zQ^1YG@GrL(Z|@@}lh=WJbKQW2`;tt%8fizO&^sM$^11Z`)ruC@8%UBi^$Vtn_&dfz zDZ~!MSEYFEx?X8k+MRsO%<2~l%b z4@bYKmIOuZ>{52z)xgA9?8Tq&;iWI=v%{8eX0>A$(Epf#dM_fN_PCBB@%jJq5U}cF z9s;xgmD*OkX~ZL@&0<*lQ8+0sux{Uqz+QuSUzmzs_eU@Akr4pJqYz5I4!aXctp@kq zAo{K(X0OdC_o*h*_4E}$wo)I|C{P*6Q+2-xn|oF*WFPw7x369%%VE$0Rf< zPE?o<9ph+j@uCS`erLFY`Km$hGVeF zaMW7r=nB=_mE8T3_@tCPT`jwxjDzQKnDQBSi+jrQLmdD4+T!}bK3$@|Pc#k%eJI6} zb0}Pyil;89kgJ5~%=cD#=pUP&K%)guE^iWUPrn*#-7RBn3Q`=foLWA9eSptHXfx(r!vn~ggq)(mf+Z4GanC`|j76{9zK{skzC3>(kB6AqK;sYnU)v=$Kb-2CCBD^R(K<=T5-(DYtsp+ z0JUKn81MX^#OkW|g=+LdyT;gRh8}Xz7u(+4A{*C+XMG5(IE0jeOBLclX$DIvdY*pDr;Y3}~iY zIH)yUPCV*ITf+fP&{!0D>jw1LJ%G9P8*~1hD2&}NkZ}C#7a`O)C#jBz3nQ+x3|h0< zgU0c2^h1y>6@go;HsLjl^l-6$mb)1fM$y5OUHBY_Tud!P=Pu=(-+v2F@NA>RO_oy^ z-zNBXnW^w(43M){{JDLdc6WDNB>N}E5Y>(A(a+NiO%Ed+zUNyAjPt&WyO{B3HuO1b zwOvj-TfWvPwfd^9gtxoMX6x6`$qC8S=2AKN>!3yHadQ{5*`tv9Y0;nAWdkw*Dzf`p zGiS$riQPeU|D#Y7CA^c}0pC5=i~aVhkz;1T2Ab^Hd`3lRa@I*%55c$8tlQ_arTJdF zKXjI37vXhHAc9G1`5C1TP=RMz9yQ<=78EQaqZIGb4>h2LB~`Le1XKGm>f9|xxChpbd1=?2@`)`@*t^zwUQdAEe(#x`^q=$4 zJHX3PaB&7{&E?LFy)pboH@PzZVfdhhuM?dp$bA{QvzQ4T z{xJ2&+ZH#`l=%$2iM~Z@kKmBw|6!!@OLJx`Iv~LHFJYP^^~>kBT#?4dp4;qIso|eY=21eA@t@S}>I3EVO%vzhAG*%G&e-Fp5u8?FfV-FYCUpd?RcT zBPGqSi_EaXRuyr#PLU?ca%^*f4J%ig6KV&DuBvy?u+G;g2rUnlk+2vg`AKj4Ot-zaKUz z7&%e@s#aD$>w8$T#m?#5wi+v^bRHY^C9>7%!yiOxD5ut}Zq|C?zg*X!r^h@h=YHqK z>MdG|0%h@H7WW%JS9o0Cq892L5yW9t4taII`3NB9{MP52z3TDN&K*67&6n%tA=PC~ zaFMf&R^3$G&VMlow1CsxOyBNjK_|i!uq}REL;c0$+a6`hZzng_fHg`z;VGtLM5uQ4 z7+f2jH347ado!3uy7#Z@V z0om`r8RQ-UxWfN3#{r#YrpB%3238>5l?F6gnij;qPA5G?ZfqnxJ?tq92&tb>zVJ_p_LJ9 zM_$G8?|alhj3ZtdRO?q2U%ZSu(#x7z2s*=K>v!Ze6B-|wgQBIOZkrWRN46()O?gdN z;_CU_YY*o}B$j?3i=%P&%YTeROJ`Cb)moDg=Z=$zZ3=D;95u!n8}&B%dZsASfl?iM#8Ao+I8JRx)WAcw;u}udS|1_R;)5*lO_D0ntz_d`MhxCI|OLP%FPGTL~8FC~#sA<@g$zM#x?L+b6m+*1~+vsbWT->`Q5 zZ3e^GVg}Bx-vRF0iQU2f&f?)HMnb@WCQ1cTkkjL`b89zYS3vBu!rpt=1qhIl@csjL zYxRBZkBowR+fGq;EbIKo*x3=QKzQIdzG);JR1vM*2e1tXZPXg}c(iQeQrVjzcJm-4ax`gIY>fw~ zn{Clt$l(`4da*q1hFWbBZ478oHWCDINIsSpkkCsy99j2UrrcU zt=VEW<-Qj6F;(vtZ)Wag;G%o2p$_+@MYx?-a&|dvS3oRCg(65HjmJ&I?{FRly3a@OzE-V#c0jOJ$5m=K8@Fr*9r2#-X_ z->5(DU`cIKuDdvAGs^8$P9`af8>i0S_&MokwIy>=)6-ac=dVS*DJuS!w?@JIC6Mxqr_k)`=OAVKsc7Vcjvq6X^G3V(Z7{IueTs|vJu9;+v->!X zv7&e)muu}@Q5(gZI|r5=-{}O#8@m26im%r;c{1HWpyLLMOeb{?o*nRMIi$c^puy9gk0njFT&0+4{ z5ufXHE({CNoZeLl+kWjLmq!=rjzs>ovwL`g+jG#(9Fy<|_MXA|WslRLgjSHu;P_U_ zu=+^V0*X(p$a{Cnx)oEI!Bl}t(aoIonkx`Is9AdkE8UXR({m_+1VNvaMMxg;M*QJe zNN=mb!_!Da-(#8VgNJpo@Jnp}v`#Gk7JhHsw2h<*&KV;LK3qpu^K3dh@HYPP1Zmo1 zo5}9-5lW%Iopig4r&aBA!>ev&rfi90p|R}|L|A~8q^r?Ndbr}t7R`Q2O&t!33V?br z`~;=>gk3IWFzV|n#VM6p`N%3D)cWJKF{Vq@g@3gup9mP%#wt5F`(r5O>-M(!LM?l3Ah%( zKUEmWZ-b9nOL)u2XK3aC4t*BqVF`}Dgr&^TSBT{@LU_Oy=H0wHYaNBUr(Tax>g zcWMQ$?Oxzc!uxM+VjgHJ_lWx-56Sj0NrZXgBsy@p{llvpI|7!|7a_D((Lso^)4vx#c9qxctR_2S)0k@7QlNKBBO zimnvVot=9r(a<`k0oNSN1Ng~^pgw=m=$~&Xo!rj}{qbxDBj-4*u;QQ%TeiGvgd@9O zqYS+;a3sb9Z;>n_b!yTL^Kt&RN#cmfrD92g-id@dDv8%dB4}?BH<@bp2$@AeeAyQ7 zQ(;Z@@b2wQHI0NNNbTHjkIhbY+?I~7+VdtKXbP{^frfI10aU7G4sVnbi*P?0wNEm4 zh%wkzDo<6So^!kQH9-D6@z#fC@G6(hlNR%0h6 zw>e;SpO=-Zoj90k5B0j#w%$icit1wNk)j+YJH6TYB(vzm;0$dbwh~vEqQE3#DUiqW zrRMJKq5?Df%eF4Z4GZO@(hF^lg~xbFFvE%v9;#D*PNA@SY>D4W^~Bd4(`vy1yPL|W zLA6f>>UXW{A1bbnN>U0VF2qpAjYL(&Ey~@@aBq)J4%|iZVF_TNz)5er2gKd4nT40s z<~c@Gvf|r7<)@4cXKSdx$oV0Ipe)GeX8*ABC$ey))WwlO7cB#p>Y#nMR+h2Fwzy@R zDT(6f37{P>9K8$ZAP3VFkY)OvkuCVgUmWdAHA8xzhHO&tYB3wM3iSFOE>Hy%+--dN zXZNW7Pj-r*W=jb+N&e3*F|l6H3;-OziE$V}aw~kf0usn&_W3ILY?s!k{9+>Klei)0 z`WLI9Q!K-rr`$KRwYYwJqAPAu)&rk>d4Bz=8ev#AV|lzbe*Y6? zyvbAF*SbrMy?>PRq@{(y4IagNQd5ATR+=;vm|SX)8rPu2LYdD>WV8})7d^Aj4|$LQ z37hkiagUvQWg6H5CmME$h|E8zQLOkQZ&ar3U!4;8Pl}HN|5a=RU=iJX=_8}C5Nm(_ z-z+t}kT0jMV%^?yOIlpkHX*`$v{0_e8?Yg|Sp zKItW|{0Tc@cCzi*{!Bo|iyj*w{UqCYp{7BRrah~M(1N9E*f|j?OW}!4Rt=!2meZi% z_Y3$0JswI@OLXoxBDOf{pQ7^=s4>~pv=z;>t8&v+r7i^<^RgnV;8& zcyim&4^-N0n#?|g5Xu1kBYyRY|8psq|LduEv?^01q5W^1R<8xp2TGq`lsd;oS56aK z!6dpP76l&7z*@nl3*hySX7UXt=zWNV`aRHVs(sq)?c4}>jxoRwy?X_);D)DaIGq3M zy8w9J<7-Cx_nM_-9hsGX1z;g&4AcsJrb6b~`24U)`Sceqd$KZ6Uoe%7h~KQ~R(oXS_gXr}m@Ra4_NyDX)FYUVmtzTAtKjDi0Xj_a7=-+l}Jx8GV~ zD84;8@D~vnipjS35#raK*vr2Wh;#SmoYP?jI0eZGOo<+FI#hms7CN(^;X=4%Q-{`Xgj zr(`_u+pf2I;)7G8-vVva>fc^0i@T0ygG667KO~;{FcQceeU{#A?8)2vSa*LOI%zq{ z`+Z=SpY}^?SviybyneZ_c;ntDG7)F+pEtX#?08B4MIbvXjZD3+V9{%0W?$5Jg`g{f zX3G6Be)&=&06I5mF3G$HPCit~;LD3i^GEEG8vsbJN8wF@Rqm_IGkjV{uQ@KR(_tJ{ zt=cb)iiWR>4Yeq~sB@yfiWPbWfUDm96y;Gxz3j{zQhmrXD8x*olTLa2RCalQx)vqd51*#omso_6E&R18K7s3K2CH-K~)8PHXkDzZrtLrPE?S4b5 z5*X}U^L6{-19iBFGt^OVwL#S@_(P&twj^pYMtkAADUB-c3qc_AcS)Zx+5JSmTiV zv+WGuqQR6=Ly(wlDjz>WM6PL$E|WqquGz`pKmA29Z^M%wdMCJyuRGrQxpb=i=iyyK z{;vuSAu#)pP(7 zhGO5ggncN7%R6xxC(VC2;jj`JoCDW7)NJk;mIH@R-4z~ot=>FawI>WeX} zdr8)P4$tY&cEs-fZiu3R;W*tC{Wp(>ip+y~cljN^G*?OVaf8oSieerp?95F&fRY^*E@>6}a!;b|Ns)cmqCI^1f(uzgQLY@o08;2ZPUrtGR`@g}2k*ZR!*mDrLUckcmyu zG;nH6;qY~;a*+^RF>8CZzu<3&zPdrv>9Ii@tR|v-njVU$*hVLU%N-`YnmBFTAaO%s zSbP^P8SMB0R-1ghsf5{I8ZWyF@kXUfQ!PW7kooVav;Iz*d}D#Z5UkcerC_~zJD<{L z&S1sDcBX2=LejxhtMhK$x1}buhJz7vHNI(I2EmAi_AFe|=z7+E?>j1Y>a!e%j=qnL z(sY>(;Dj(?cWbqe39R>ljc4cl%bNR547(8oD#VbBQ!c|F=ldjPxxtRdF~%a!cpXgC zudjzC(LhkVZn~f>WarmNFMU>)h20#7K2EJ>_e^G7h^bVQlqhapkoU(^Q|%Q3Ax-j( zMojI_b&urC@u&BTV~^t_mc8+h?4JxN??04k-K2QA-DFhczR~0=4^+~@V)4H}OT32v z!LRk`(g;bQ6hPH(H4a4&kRvTQS0Ykjp+1y{K@fSUZ=lxtyBxW;>pGfYx-)$qgsHbsNz;QhkT+M9o zI=`rNX-T3@;I=k}*S~hIC-cF#2Dq(c=wjMITzE`JfM_sPf73&#xQYE_e{b&%yQZw` zle1PD8ud3bcABznw~X2N)ydK*BOi;DQhTk~ zhn$1q3+sF9O1Onq?4`=$_ops$I=6>GzEy*iI3Awj%3JfFe&~7JdTsHC1T1QWn37Do zr80hUElI?5OQ+_a#uLFtoDIg|7PFAkBQ=R$Z`S9fvujmxZp@{}>q;MQbC{puS}!^t zjNnjfOq_ZLo^LQ}yWX(pz(}<$n$8%jKU+VvXQSBU(>5RdA?NJY;VCGf?su;Dytp5i zNQc}ZP|y0mv0ATBFWF1;_KdalzZl7`67_=km2(wBTp><}5$scWno!l$x>mAto&31o za@Wemy`z$g;z4(4-u;v$LB`F}gKriw+fsbVgCzBi%Lk&q+$ynn?IpMEQVcd0@fp%` zy_+TzvWy8|HHIbkl_j#g8*I6@MWtOo#QU=_gz&?q+J!ImUca8lc}%)v3dAF*uxD|^ zObu7eG10SJY|;DekbVtYPUf1YkvO%7dCL{bRHGYf+!@6@5oo?B4r^ywUEj%5$nARY zph)e&sqe=xr80xcuxOJ+l|&fVM52GyL+mc5zknyRwio5wRB34PC&LJL7-&h{$7`iR zr^Y7&!QJNA@)f6>>wdJhruA|y!nL_CXP&n>PuZ_GB}#Zw*ZW+BKoqCVr28W*V7Xmb zS)vEcOFo9I!GNFc?CN*9ykQLIsMY36NXEfLQiIpJ;>rD!xad-wqUM8!DZs7wU_7O= zZg&vVa%yucR^vZIRi6~jzMPE3ub16+do5hMeW&DVSgp5IIKo?OC=uiI+imfehSkLM zciC+*Lds0sb-(1#o`ZH8rO?$&wyt@D);iWm{vGeoGdr`ADEt7=(cZZ{`O6@SF89#X zzd}DjpVOkwm%?SCxIU><><;s{XEO$+ifOm+eVZP_bn31@)n3GnEE#>WbRp%Z18|8W zQ|V3tuH+}xD7BNob&rJu3I zg!bA@4BF1 z-WK2v&|}Y24iK?_E&OMpLj!EBQbc3WAM6`G@9Gm5hU(X4ubZh(@($V_+L){x_ojo&dTEbAo(XOePW9%L)#D-4 zZ;cL_|5L=7`;Lz2&n*9dm4!BmA=SNUU3>M1`;+qPwceRMvpc(;4e(-yyY-YLOOhuQ zAvT)D!)2io1PU1&{B)Qe;JNiHV`y?p$MDIns7K0KM#i)YPyPk_^1k@IyI_j5Fw@47 zXt?Lfy7ocD2a>pXU+ZN(rJ`|ZmsGFhyJMZZyUWVCZU0}1yW@3rf~Q9op_6~fK3-ad za8|19S8Y*T6E9iZdtLK$llZvxWK{S{)?9~J_QYrn5FI<>h&N0vh>6x0F4fda7WIbS z)*M+bgtzjH4JNM5wPlyOcsEY$InbpAs<^xpK+dB6A+|H@H?vE?aQAik;Mj%>B`bK_ zg^uHw67^J9L$s5ZqWs?lSF%D56}r`+CogOgt^BL5oJFPcCF^J%;HJ+A^a{fx1PQ&# z0$*YyB!-Td~;RKq^)M=~KR zDG>MX%KUW*@E(WlMT-`-3@-nNE$(Ui`wdIi-Gy2{Mf{_=fakOZMGLE_pPR;}(H?f>9lgGT}$rE~w zwXjlLc~QYBBF3Rk-oB??p_mnjncDDJ8k@GzJG_WaTd%4;Fx<6Qp zkUY+%X<$#>j^L|#u}Rw%dTMWMJUC%YBPAI@5*mW%a?W$hAJ+QYSEp$U)w%l9HvV+; zH=EV6U&)LE%880=>IW@lP3P$a zvE<|V(sIf!e%N8Z%kCJ3n58^~=C@5ghh~_(=w|Z18O(*!vk-idnkXL=wZ!bwYu=io zx11s*3m=o-eJ7`#B8e;viH2n4h`)a8*LE=FDC`h6q1nF_H|y_;kQ-Y?3)?bdDp zOVUo0@nQEgP2^Jvu+ZEn?7ZSRr>mqF#GOSdVjSkLu5Xt27qB9pH(3%;MX)wZmKvzO zks1&>%_9fD-ujETbo2 zK5KzD++T*r&A;5#F=>3aEp$#!@p;#EHH4&y^-Xu`d&*qF!cza}%**#nuIp}l%nCA2 zPV{LWTk~z1)~Zs8VFM?{qQ@Kl9sAufAoKl+C@hZu_P@+t!d60(beQM(0l4>4FDoZd5H_ocIZ?spxZXs)6W-gUH6l z`yh92hdxFW`jV2psY1GRuFVhz0u8<8a#rrb!O$4LZ01RXX|BscJM*9A^pQ=}NW~q$ zC&cbr337InKSOeh-8kkV$!Gb3u|kf?{_?S~NqmltOydy$+Yi#yPrtsZ*}dqPBHA3N zPjg)B!PiA7MZH-g!OJM<;hHkUs{9cN%J4%6#mZn?|E!~aPV5PVRU+A~{Y;Hp_FmCb zhp@l8Yvv!*h#eVKI~1m5JrTawB1>P=7V(a4QmD5n5~oC2 zPUE9022Gq8XgdIJL7+Ja(`I;hR2DBHp z5sv`vLy=wC<|{>1)@@4;qBGlQG!7jJrF;q68jaBX_op-qy=%;v4pD|f-1MGB`YKlW zEGrj_S6o!eL0cq{P0%G~?0wD@rW6S4^*jubbJe?q(ub__9hxl{Bpdve2a*N{-rpqj z6LU<*ol=-ER!E9VAh8X5M)d$uE8hKoMJ@K}s?~YRYuTLoff97lC=e2*EX7hjMB8s> zL$sR=Nj%in^UiLn@xr4zM*OacR|UD2_XYZOzeAg-@wK#=!5_7^5aS62E}xi{=3pe3 zA_uoyy3=hR5m~Z+D^>JmO1aDCaAfjHlJ!&^NO>!x)px@2^=lu7)UR5}-SeQ)yM0~p zbxQx3idp>qF18BC6d~`%yNa^~%vDo{X<<_O)sQvDyCr$w7h%jgNnu^&m*%p)k3rx;%Jm2AC9m*%(v%W|{|Qu~bDEYO+c12tOwmU4z9Jm?9d^dUn; zgCw5MMr+A?qHA>}93p|u1Jn?M6tu?!lV-y>cMUuOUx>ez zRlDud?El5OtF;=ES$-agdNzPLPwE}pQ2xpzUOLNu((y|unV++{QN9`fdrf?;1MxhT zlC@gn2>mxLrp0#W?Wx3B6cA(>tJ2QXMp1&A?!+Vu9na~vRj5VY-3D2NRH0|)+P*Ce zx=MkR2!WCtq~1f}_GZ3fCOlF}8hA`M!>?Z<c zEwK2HjL=j0E66pc6c4fc4N0d?F_`><4MNSSnw7dfGx#h|4!}w;mqtIc6o%rxM<|jh zHrkAK#fvR~a(|gKZsAq(@_!FS3ySN-opVrm%fD8~#NMLxq}*hHA&7`Ebf}?P%O;p1 zV3tzl#k#27OfQNC!={(R(bj6}>_lfmU47Iy+c{4-4%62!@dN@fZdxt6xpOc(m9S#jeK;Pa^(p^9-_-IFH9RdYx zmHDFhH+>abPq!48bvUw2QUZPwA)8^`B_#zEmTMM)gNR9+PeQPM+^EAd7--)ty3l z+enPh(6ys$Aiy4!j0*U6j<(F0s%QnG1It%mOTPS`e5ld(@`F+!f(&i4?b`sUiR1C~ znPD%qO$GiN%c{vnPGPJ?dflO3f}Wp;Iyn)JbK@U(z0@7}=3>4t5HF4n5Unw!y*l;Xwt z-tdV?O!}0Mie68C)^bx<%-rCE0#@3IaOiN8hFztcBQ?R1fEkn`zhcQ^x?s5`6?Z~G9V4?z#)PP{QIobCH z2j!cN%WlIerSCEWzloOQD5MW^{z+ga=^B~qCB-+;u|ZOLM*we$Jf+qWdEMBlXg88~ zHMbnr5$t!1{6lQ*mTLF+G5%SADYfl^~^Im_E5n}3Z5mmRY3=+)y z<^9V&3PN;zbqq7S(zEOM@kRQw#6uL=U*=JOe(f36F_S`y6Ut@lu9~&YfTP$gO4X(u z$9Dcp@0GLN^?8%nldGIItGkQ7*j1#vdPgy6NLs?N_us9Bl6~Z7!6fTx?YC{;$1=_P zZhy1G|*-zRzkii6Iw*5(^SP>&Eb_f*i#o&r#80 zL%Sk1S$r1`sU&2E&WIN0&xSzYUca~;U>vITdC3d7y)u&M+ z9cWkgtu${(>~vnv)usX(^SUX;c@f<%heV7$Z8lKX8B!^q^zp@+qK zzDv_LR{FZV1(oF^V@D3%kuXPL!=Loy6j+LsQZ%Xe4=7*2Kj|(HTFoRMObA$M`2j} zWb|5k)wCWn3?TT#Xs_MeYvJqUa zJHozMpBcU(kP~}6PPx|8+uO^-f!xJs$dJxgRCUS`=n{d2(zN6zA+*K5oLNs{(yLk7=hx2Snmfru}`a^PPxf`|{=M4pp#kRR|#o(FR2jRx6RoDP6A* zja8NfPK4PV{1?cI`R^IO$itI!nV#WHJVSg5`{n*TYh&f%zJ1tecy#G~JrHVF{}pQP zZ8pa8k*(Pw{xG>R;}b!@UNx@bT3JD@W*do6d(%DgEaYuQdm%?QnpjUD z#4Ojq;kkkXm%G8}5Ta;3qHb2aO8~v6FAdC`>1aO`sgqnTq0|wH)J(=ZOCLu=I3kZV zjtg`sW^%V^pk_60cA}Ej;DYXi`wyy9`>eY?&-#tY`GZ8??g5t%U52gxB|9>t@u?|u z*NDVbxPKu%&J1%d)yq#SOo#kGnaOo@2P+y!`fhRE>)z)QdA(D6C+gRjU~u4Q-b$z- z0ShZ*2ZIA0wgCW?Ek7k!iFZ<*3niP0QkWa8%~7~=z>lGwhdXOm%fgjl{2K~8JNKjI zwi^vuyMDsZMC*oyXP2-$OGSCMMX1a?FCibC(xjvEv}@>7dB7E$y=}UA;^G>ym`<>c z6wMO|kNF6~eK>n+3+|T>x_FLhZ`x2*-dXcO^OYnUrS}$7p3p^J#F3dbxEAAZ;5t4J zAN|Sl$D!%H!>n}bJJxsFSq@ImL2rE?CRIcaH)D#8yDjUCeu-CVe9b$Y@QuEeZ6R<< zqB{Jhm+B3IqR*eE?0--pi#r{tP&Q(EYk+TQ?9h20di;m!GO^qRVuZKl#SbCeaIm|+ zyRddedJbna=zXFuQLnIN>P2XC?*I&tvzm-O)6J^>#(tu#1URjXcIn8W8(S%X-E29 zetvXlU92-V=);pD!dt#|>Wks&xi8CWdgoJjyuH%<1#B3XedU>+E84ZZd^K>)Kd|;( z=L^Zq>eH;9$i}6xy9-5rfzeqH@8IE5HXI(-wPoSy^$4d)Nope6cb9nBA17lYPs_(= zvdZ#AuUqzH`TJV#;l62YshM$~CJ#(KDB`rxLe6gX)g47>n(|{H$f^X{4RRRhBq(uN z)#99b?F)Bqx0~7>>zBF(oN4O1ZPZf6Ml#;ZogzP>{2e4w-7nUP9ogpI95rR1ygc>g zK4%nzF4QnC$=_LzYiaG zY2*Ea=lxZha5E{B5Cp~}e5q#}{R^q6v{9*1Esap2lCLg%ojvo;)P8soTtb&W>o*4F zYol?Yrs>@>jfw42tJdjzLpO(pi}uHkr6B0|TBukZ^-@5UH#pV1H{yRYLs z|E0(FNAz2vwY$!o-gA2}1wulC?f{+TTI&yD(kQ}NAPkH!n2$tJYUb9dnN~e+8M8e6 zRXd-{zgXTG@$|HnFUJ5eyjzsl*Gs1c);`n-So;(%@NYWgKCVARR7Lw2S6(enZ}46A zxFrtc%#DM`m!d_&s5?{@@j!R0cSd$_;BiLZY~T4!US+ya*|tS*M?U*>-zwzsM$ETk zrRc?3@Jr9|qquKlMkEArsJqLBhILk$jxn@LZohf#qH0v<>LPaI_4UgWgF;Ct>99?0 zAo@rz&5jfa;hlFA{@uPyp0>EGljG_)zx91KSG`r4&Q%nmbomk9tEzUa{QH40*uG7o z%OCz={-^6XQ~T;rLsfV@-F56j#ZPqk!iQfBQ~uTBxaJ`z?ZcGS_Ym9Y7NM&%J9>66 z?rPjB4D6-m@VXPtA$Uk1;+{e)M|w+Ks?<$F2^SJ0W8S_xK)Z|SnuSwGxwOs4W- z2tOy0?PfgwjZ!AHA+(ugd>=G_`h3yptIa9ip22|@cgaxNkacsmTst~rpp1auB6!Vh z#?3w{#QNs9rgNqn5s5`vQziZjz4#1TAuIw+H)lW*s(-^ zd3W|!IsD-MLmS)I{nK)4;5f#E1Y7UY{YQhq8#j5h%MoDhF7eku-sld<7%`DUh~7cQ znn_-V5hkD)0|1K!&4q#%i-Q!3yM~=47pWul=@%0P6XvYz2HGq|4J*Qz5(Az`l^7k* z8{`Vf#9R}$F?+bL2IHb~VZpmS6-o}2m>1MYOy>-r^>LKb874e3T?saWPmsHs0&7NNONg7 zZmuz{y!GzB`8;RkzrV0{!CmGySXd!)^yA37Yt*i?#TrMAoUvyra{6=l7vVkJUFn*> zrTPRRY0$ktqdR?v-luv+qh-rWXXieyylaUyU&2nx&_~Fqq~+smV<^zY5l=hpXeWb2 znlwmyG&nf*!(@Sk4omF67X0b6q0CO ztNqyvVU4A;o2utA8MVMl8V!~pP&fckY@J1a z@67jcd0!h2XX5&B`QDf{o`fcW-vgV5vZ4t?F|Ykxcp{I~@9{t$ZoR_Pym=MGxWohU z>!SrgcQX~G!T27r!Jm6m?)7&5S-*AEuYm8`PKL^Ba{sJroB!v!re0zsC^6yA1s1a^ z;`%onMP24oCH~Vm?ayL;D@38r#NlTSO~k?va{NUhX&A=*G8$lK(6c@-4gyGTu1MA) z!*Z@aQ4$3ni2wadQHg;PtJS>xqA%g0C>)$%hv8uP540VzSNEo>HxqN?a0$$ zmKPNIU;d=cNEFwQ$AsvY0`9iD*c5zepwJbsbdxjKld_-Zbx#h)g>R}KOza8s?}DA+ zO|LpAq7s1)sr3P?PcOx|2Og-CuxpNDj;+8+ zIGcAt`V6~GuPVi;Vn91yR&DGZ)#MxMP26qsHLrAWfy=ZjpA(8X_wRh@F~&RL!!%Wd zregQx#$>qKAFAKFB_`8mZA==q)pL5~INUQ8VKiO-O;Rq;kJddmdB#kM9agLuM-Y)} zUovvwyO%rMXyI?}JC=>A%`TR8d*(J6yfvl6Z>P)gW-22uAy&idwMcKVs387>A#tdr z0TPsh;lONn8$_W_UAzQ`vc}_C=O-9pj z&dm9Tgq$AR%=;2K zB2XTC3f$I;v!B4CZ|0gY4>HqMeir2bi+PdAcJq|Wo0V_sda{q?+VWa)0ZZBioG`CB#Q@MwCnEHad6+e{A$I1d(Nk>{P49U|RU?ZFh zf8Yrr*8cKV;zd`L&aQzniJj}|jt~tic;}oR*q7~+_>s$VMZOka2Db0s$Hg4JWVuvW zCqdnAVpq8{6)|@qz5LY!OUFQv|5VQZ#}KVr6d-w6HM>Ffh~PG3y+)YkVR)9Ne!bV> z`lL_EdG$FBFRgmB0{XO6G>YbVsA%^(zFAw>UuL@NZar&u?Y;q4dKOFGGtg;&5+Mj6 zs>r5PrOb>YqH)=MKvtE4zpd`Bc&@9TALrR9Za8gs{i^GBAS#9MEN0+ZYP-(9O*zj4 zzBlKexcHs3DJuk)1~Dj_XfR^#1&UNVDuOZWB7G`ntm3c=)bB8{+vv~swk!Sj9!>KO zwpgK#hkO-5vcLXG(`){w>1*vYo(|1CJ+7rvQ3p(Ov{bum`hb1W_ODTI^R}V%d!7ow z=sZD4L{T->(P11z$+P!)z=(0HL`()aATiw*Y%f#=?Hd0=srKy3>|n2wWC1xUT>xwD zJ7Za+9zvG@i61(%m@g7LU<7Hq5~g(AWCN72Whc~b>-jCdQC4%^#30kD`*`eS&z=f* zhOft*g;;#wE)Qnj5_87)d>B|6^#nFP`ad{-_v@1= zT`&(1@4<9M+~q56iOdLTema%brH(cC1?%SfJyReRaq6}N2uGMTa?qeRk*BypJd{yN z%gA#gm-YJ1dYV!CTz7mn3l(@+zpDHKZ=EZ59oWO~J-|*2)BT%#P2}6oFrB5p8Hw`$ zbLR#Pn!HRdmfrl}=(;?#{Ryx0b19HcWR!npkj^40pQ=~N<%-dO_>5=t)PQF;wVtE@ zit23hp_T0?K6IHI`eSyb&#vsF-67m9h%;{>mVMiIhf|z<@)Cko9D(UR#->c^Mvo6# zhE*5__ShTOxcG@cD(!IaYeHy1A%wB#7__3xkhw~rro36 zdvT-TUF-%#&+h!P@d?X*(?Eltj%D3Jizx;jl?q%MCZhq@gx7DQ8U6+XxZRMvO!B5S zQ~#G4>!h#cRIiwx;~4H-)`elKX%u;Wu)Q~auTgLi8X}($FZtz#Q@V8qU7P-QVS(Hi zySRIK6Pi>(l1toU_Xck^udoMJOgm2_1?+qL4u*_yZb#w#LV-$_>tPt8V7fi~pS=12 zVq11#(g(BY^3n*2ub?2qPaM1o)^D0P&}*kPnY){{>b~e}EX(rmH@kBj)3r=fTG5yb zPYh~qN%*o%BN(Fux{0B=&G%wk3f@UxX)9Fs`g;H@DkXVm5;uUwv|Y~5Orm`a(TdOn ztaG!*=k4%bS-VHX7nK=n2Fs4^q-ETLDy&Ot8I4}ReU{_gy^AP>8aT6@5Bc_g$m?^P zdFJ;o=&Vr**X6d0QGUE@TPNAJo9{G#Y7iC6`WP^X>NhD~%6zF{F>@0Xl0uRIc9jFnQH}q4g@R zF<1jf{o*&LleArnzRVCy0JzFF3iQ@^=!eUaJI) zUCBk~+TVZ%?9sLQlqb352U|1HKJ6-^uw<0+{Z1J19gcQfAx3#0mY6RIbuPQSxfF3# zPHl0%@WS@GR*!RYcQzQ8aYc@H6!_bYPh@+g(3JRDm z)ddqFl^{A{bpJ%+1D;?CMno@jh0KKww!TAJBG=ZF57)fkwsr@}%I4cRG`pTmq+yn& z$=?Bq)QN5Rv0U9PaWo^v86rL!BmQ#XOu2z_3rV?&U0___)MCRbpPK6J2d7ZYUX2zYG695yGueeqD#R`+7f#*}>d3|I5@HLR5^94{D(8lBmhdl|#y*kp) zrMXq45_>4HM3ZwBM$i%IY9Ju(h3fG5f4Ky~sD)K37Qn&GJa7+K6p05YCcE}Ux@j!4 zEM;{1Vg*ekA!;X1S<4QW-lyaYmBSS6hRXwi!5v%s5-wlniS3V3zp$N)FKP^+g-j6S zc|l%s*wg*tlLsze%LqsPV8o+e_wBI>iCf<|S3SBzdyiCJaR~p`!t}5Q%%^PdU%I_S zpm;hXfiAUJu;VyqB3Nv(_g2>klTpOH-y)MSuI=Ih znJ;hC$bdU_JB*e#pKa#AW`pz8XL7tp&2lT`W(OWm$e^>QS^04w{(*SjlxwcqjVuZK zY}EKi^JUD)+9)6Fwiia9rMlSByJs--m6>m~@ZQS2)TxR~|fi?`Lnd4aE7;WjxmP z??DF51_+ni+G{1N!NqKQG63G&JnB`0&=2xZww$-sc&U97G5cEI8%cs3Jx=VXI0kOX z3>ptId)z;knsWbB#b1hg{ant(oZ#tRl(yYFxTr{>O1%Aq=vA(!s%TE1@;4Kdlrjsc zS7105^7V(OurPxAS?KXIMpYcBJI#$V=VgMd97$?P0SxqAs*=zi5gcB7Hd`wyPauCI=-w+rp1^*tiVz2FShd z=#D_!wI~;g{h_j5v9oJBD4-2Z0jd3(7$Et;Hf9W7qk#&2*Rnq*`Yt-QoNw0u2qafuyziH0r`v zvBtkgv2Fc5eAkoHV4FC$U9hu@2Q9euqF=SwZd+VMRx`>|X5t%U(nx%9DhBEeGLf81 zzlv5Ct7K~nQgiE8i;ZHBbdw({8{obt20gP=H8bL8olo0Y!@~y2WPB>whzp@W47q?&KralN1W@~8DwSt^cUp?`)e%N z@`c!oeG65^#S`lnLTeQ8;C>jw$FpX#6#b910RP+IV zmJ}{6$6YD2+J6)5L4X(UEi=?qzx)EC17rbOzR$RsMh!~aCyt)y`d{&A(!!>-bRFzL zvf`HEFzO@*ur7tDTTYE>aL`lsOL1xO-wY`JY4K|S0eF_e-uHV-P%$ybzW5tMZh-w_^Aw@n(@r1iddc#QlfPnz@{IRyZ5@e8Bf(6F3a%8l0T3K1( zPqe5L**&g*A3pEl_L|Abfa~1w>?os zg(li5jF6=)ub#e3DBND7Wuir5pgBJ~_C3YX63%X0J+LpmJc2OXwIj)msSRt{zaj}? zjM`DFpwO;KE&E5rfc2#C@xWXzT%-h@rdihPBVqM9a*6L(~Bza3)u0c z*QpZ3M?kV&8=NA1r255_Cg^xr`+|>wq~Jpj--i^_IX!ta|@d{)lpc!|=(J83%ou*UTKx zj%s$Ba$BuW)Xh%6!PlxQ63Hm@8%fFkYW>!4Z`e|gKjUgeAz|*!W+OET>T9a@YKO<_ z6AP=vi*qM+DA(Z;a06(3arRr!-}(R=-vM1x&0ZSL)bfAKZ!-Rs-_VyKd>qx}^%O5F zSs6maLVvo7*Ae_A8GMaim@;wYZK?*gJEus^b!yp&MD>TeUajdQpv%yd%Y#jd&`f1Q z)V<7{1l-OfQQV&y09o602scSL#^=@wFJ2PXi)&wn^zP03^*bBrxc^v)yj$kfVy9obUOBzGS*ZR{ zzCDJzFYxg?Ml@VLc7`Eqf;#IKI~n5{jOwLGx(u*MF!WI#?K602b5Hycr$%b}mI~QA1G?)q3i=F=l8HIF z_RUc*{FW_qTTXjD?Ye$WpFfl5k453q*)vT88eZ~;MIzT^Nzm=DYlN=LlgzIJK|!$3 z9sbqj5_w(`#@!g6(o1~O`c0GHl~ka821WPrfbVXT2o}u z`NC@_k2dU-9ed8%|1GwypPU|Z0KW?LNTaHiUPLw3W(|}_i{Q_fWY~$57ft0A-FT!> zYzigZ^McQf^Y3np)UJ&`2(g4DwHaIptzNDZ*Xa!OCRdIpe<^!neL*(MM#S_>s!<0I zVb%O!UI0X)ee&@hP5xrXFNZdZmi=6LTyia3#ld5$xt|Z|AUXKExITUw=Iug+Zc^yQ zx{GJ~5>O+qEE5U()+L8X&Hw6ukuIWdBqchK2Dn7qzi*o@a}JKU#ovq4bEke!a(H%l zUw^7IVC3iDer(=O6n8~s{U6$3F1#ia6orNv;-^Cj&y;PxijxbOCv+o+_a4$dnL?l` z!E*|g_7wMgt=IB47=?I+u+lmYeUHy2OqZ@78aJ5Ng>q&4eUm=J|QK*_fPc z^ga=_2mojo158*E(X%o-7`Tq~Sq^vU%rsgB7YA=ky<xsSFHCV3}JA+-Ro%m zki@j8MIj@Y9ffw4oaTFYdB09*z!Lab+lo+4b||f78Hp?&OQMMP{gXgV*)rJ_sd9<< z9cEkK5E!1K4goiz@)2ePA!rbZ{hMGziERaH4^QiPuGL{4Xc1e2wJqoesDYrL@u`7g zLhonZ)f?#Hw=XbkX#V?5gwM+^rVVr(4xO4GQqE8~`7o=?%a-UB-l@XEHN~UCh-3Ol zwOb)8_j^gfR_hVEu}8DO+G@0J5fsdst)t_otukAq*3O1UHw{G`iq8Z-t54FXZr?9k zdj}2=p+HARCs6)E3oyGrn8Kxwc@{xG*=%R4+bc9kR??=0LfwLi9Xy)8Q#NvpjC*Wg zuoL$VY+$~+7>L-M_%uSrOs14+xEGe%(>oG;M$wt1^UJw1G z;bqI(w_P8L9pPyGJ(loeocG2j07I=l-dqXerMFLerV3EPvdiyy*@)jYlo4rbTWr%8 z4Zy=|=_6|A!5S<`G=!0Zb!npyOV%A9J8*nqPef!BE-A;%q9yMrbsoUY>wGt| z(FXh`^&w%6a8s`e^s^(Fr{8Y=-l$4Ky`oR`PEhAn%$yNJ?XtV}pp|cQ-AA5|h z%Dv}B8ou9p4N$iGT3rE|N&f*=2i-I77k`eHKS|cY-sC{V=G@85FVv1a_DmhBq%TUq z+{l%3r3Q8qXQVc_{_ z+Qw|VS;@J>Hb`kV!~s(lkeCuhcmaA%yjh1vJO^CIc`C97%?VstiK}t3KZPEr>luhc zlHi~-dQh;KJPtTP@TBkE=GvT+XfkT>o52`W7!9VQfXuGCcNFgE2<*cYJFLnr`V-Rj z-E-X4f>rqX^oOL`WDfS_ij|C0*-bU{5Opi`161~OznRbZQgX4n4+rX-t00(s1q_L1 zE$$$oL@eu$H9dc^#K12Wa*uTCwb84(NW4O)O*7?p6lgu1GGfhvRU-yS5(+d1+6}Aq zC{j)F;0!%EBs85C&*d8Q+p0Pg+O1Y{M3?PZ!l~!x)N?J_u~<5LFoq)d-+JK2KWxQ` zg)8Nh?usk+B%;sJPb#*a^rDF_Uw3A!)?XspOmT?6;$yl+3p&+L`s`tN_Vf&=-nf(T_?(gq^P#OD7%2-uteew2PmEVro@!_~9CxSS@ zB0u$F`X@Ss5EgZj*g^r#7u}dl`5M_{FfEcqgbBSe*DyY~c6$3u_IX0TQ*kQ+&shKM z5r4|sFb~*uDD_gb;x}9cI=$vwzurCE5DD5W7P)2>BC!`Khs(?mZ%_;BTHgFzgDzUY z!z>QpEMBx`O{T^eQyhx+WA)D6>anQl!GL+28(zCyu!~V#@DLmAo{Jaa$VKUQDoA?aRW0_3!;Jn+UfTCIz04%Xp(;oF z&!b3UB=RDg`1p!uv}NRwWzp%}+H65pI`^}asX^Ou&QeU7ix39Qk%0K(huO8IG-JQ? zTXF8UTWk4{%AV%r8Ey|w(nS=K*R)0+_0EjKNWy+5N0`3x^NuL<5`dn}qk%A)F5^Z` z?WftF%tTje?-I2mML^Gtvt;1}$T!IA)i^5fK&+@x&x{&Eh)a%Wsc50e^jU0qN(-g*e+?r z;V|Xq3tfB(aXfk8Y=9)cIZ#k!1xDS) zMU-?wF5oJn4tj^Hh6(&15BcE`cn4852|yM5t4$HtkRoRb!2?--uPyu@^h9dCFO~Oc zNiUAT(ZkKWacK$8^=(Jol~7Jva8Lj(o-#5J$sgO~OMp49-^qwa#G1@h%t*aBkWi!p z1`O)-r$PYOo|A~c+x}-lI&}_(SM!-;$R}gQKXl32nt{3DA+J~ckm>o{Z_I~Fgq3^H zap$C0v33_m&TARy*@43OI2nEPa&Pl`#k35f< zSUp>S0*xd2_4PB$_CYmV%XZ9d1mNe14-@us~q|A(TBDa|WS_aCmo{~m9O^6%mu`k#9pFZusBqyJ;P zLV?FcB%AU-#{q5V|NiR#FuJ_+--XNeuL_d36e4C6@v`sy`z^0hnX#Wh1)!NK1C(1= zxw3^`ee|Wk;zA8>$aE_OP&Hi-gB;Opa^C8SAJ9~a*|3V1+3%59<<7N)LWqRn?ivf! zzMUT?+Tj)r_c5@Fk?z^>6c+5?F4o4X+anL(1+V+kN>$SE58}lBC?XZ5(la3jq8+uU zUmnj%8#?{`Q^J!(QmV4Fsw~a3mE$NWzIxA(z`F1sF2#BfaDTWu3(wvI`wW@G?h@d- z5FJIS!imgv(-Ad$<*Gi5LTX@Q=ead(uW_T7EotZfRn&bxyQx&{;aZ*Q{$MHId3Q6e z-*u?;$E;F@oVV?6OQ}>G&zu|i8)El7=H-f1L#Mqk9?m}x4#5>QL+15CMWpl8!fqW z{o(8LwaIV)SNz~16T|>>kE{$VgabgpKY73j4Oef&yg|tu4l-*xhmG)DjRee!^0i-{ zHRjlw?HZ!42fN0a4^yL(W7%3H zg1B~tAR2W}JhOn>sEoW3`m4a`x93q?9cXaOGp>`p4z)z+yWNjeEtS z4;N9rq{@o%2k3a|M6nKt0vP#-XFEATOw0J=e5&_3mPvvACxt7(ZqH?FNi} z`Wtsp%>Tapw4pD!azOjfKw{SHOfBUTpUv5*bX-Y&<|;7i!^thcl}xkg?;84og#L4{T~ zTOUv5XyuRn^eAaIjGreK{M+Tsvi}>^$bkpYA9LHufnonmyHgW48j;s|SokzW-kQycOtutg%03 zSc*d<^6jb>7Mamz;`)o9BCS}pSdnzNf_mJmW5@?)i%BPd1Jv(r@D9~S!f3hmtAkn> zJHz4SKQT>W8d#||E*!%FM=G<#X~pWr<9C&Um(-t%Jh|WnrD}lfheujF;fxr-%v*j% z%$=-m=zK|hP^{ij3Lwn-<2vt(M@y;#pHd0U>zJ6(3{7&tR!YJEvjnZJ+#9Gnuf>*4 z*2^=%>Zk;;?5J3LU1I9z@A}&tkkV$=eahyGKyzK<B98 zNq^N*0_5TE0GkEv3WKJV(;p5zS#M*zfQB~KMGB3-o4iU^O)pQJO`K>R9>>F1v?DD( zbMTlBt55zkw=q29(L}`=+o5gi50_TQ{X;l8zfx&nK2c2wRsSl@GjoB6bY3pv$@%*2 zv0nnIN?9L!zw}3CpenoTY~6 zR*SwHp;l+*MW}J{$``oc;e*xoN&vQURnEDI;`^1P(;?JQQe@Y>j~d(|;-?O98D@C3 z4c{-Ghr@ALbm)>fGL%HJwy9m$*WX=E<-2~%%^P{NDj6agE~uP8-mAK$TCRd8oT`%w zHDYaY6F!#Wp;l;-{<^SDgPb`4% z7ULqW^PXwNt$oUOX^ihrG5mtpC35pkhMOPUmM_zLrc!Tt3kB<^?zy)9&4zCQjGRmP zP>cKhScP6k4=>1oK6izUe<`wv`|Ih!p!Qnnd#}5|t>OD*FW?@`KL2t5=XBTjpe{Ik z_O+q*q+UwC%A>gtne%ZQa}qW8^x@URU)v3p7IPWC7K?ci!I@Xb7JneGE_H6AJkfY| z#BMxDT=$F84qo~cY3=#l%|g9@r?ou9?ySTWai-3gQQiXX`>WpvzG2PK-Kzv0V}b|z zu5lw>eFpPapd>??E3Gh(a31R4^S%VD-aZ|_`b6C}ThOjW{`@vO$Z4@t7rXONgx+5} z^Lm|0zM@{LDqaI?|26Y?dOW7OcuQ`^++RKK)~@tZvJp&r+iw%MT6LVFaDO>(ypw4M zJgKj_U5buu5cl75H2J!}`&;S1vX=Z(gwHF;0v=Nd=Avaoy|l5b<77sC(7H zdIIanX!eptOJTOGz{o4z#!AoS6vEbSU?bI36;2HWWkT&#K0qjY6&8#uB;U`LI+{DL zLUGZ*BbsNF&ASA^9}iH5LjZqfPf({Fe^u%aV`5stWmYZe-q!zNUO}RK_$gW4qp_CP z=(Tw(pz{AY^{0eb(N-`{!@jMBZ$Y4Z%TA-IJhCbIccJLX{b^FEpi!M~@9Go}-8p{A} zgYG^+uB(c?&7E}P`*jc zu7PROKe8&7F@Udb_M&T660KPMxyW%ifjG!Ez7kiPMjmMd?aJbtQ!eAyo?tu5*D0+{ zEGOKTwf+<+GJGH46vt(5D~aWxk-$2CCY)o7Hoov!p9;3Q{chDvUzWtL6Ja)6IG0QaV`t)xJ+dP0fe-u>Bo@iM4<)!QCrd5q-R--9EhTPBd~pe{{(hS8XW^Ja1@m%i=3g2ME0(u6DKi54W06#=fC#_9>o~B zb`XlmO96XIcY8eU6Ygc{WS>MccspEgZr^V3b4`ZfNkR+?l~M0u3yrNla@R}axD*G^ zLk8OL9~bF))eek{rwGT|9hE90-5ABKJR~X^H5#K?{&vC=f}(Eo(=`W7dwxV%yuX8v z(V{y*HNPL(>!e62jy}u@xVM8^w{Vm-0|p)B*V5dmjz37J9vzHgL*I-fP!Yd=PDi3FCWG9e$PUwq;5;wJWo2QI79i;FE5=?bkyfCq;H|alZih=jLJ}NJWsP zM^e1Z4d>3pFIKG418cvW{$yhOAmX0!aPAHhzD8x_O~)Ft8}o}d2@fdn|tul zc0p=8h~OfWK%w{f_U;Voz5)1FJR=1wj6J@Kq4UoB-p|k-s`)u7nbvjEh>kX30LRY$ zDtjoH5P&Sz|G1y_F=6Ly-_T=6H-ri}T#b`Msj+n=4&EFe%D>4~DQ#uRX60;*C`QHN z&@mK$8}g~LcGRFSRi{b|c(yEDA7qwhG8rnETJEka&a3xf?Y>S;n1M}*u&%kUE){3E zKeO`tCY@OfzxH$+>S@26P6HH`yHRe=2fNdBPzu)&85~dz>P^F=eL-rD%hN)ZTjUGN zi}nr5h+`&bA_?9)AHV|1MBW@YC1k#A@u;X#EZU^PXui_Zr~itn3&da$rlEr zuJLqOt5Ky&&+nb0)NZ?~gutk)@~LP}Vx-r22hp~0`i*s-biX7GddTys0MSLgx&9S% zKC@aQj?_`rab)Gp`C!t@s#OvLaB%+1{h)ya)cfD;9p9>1juWrmkdX4`E7&uV>1u@vv|65NI1`r<00ODh&ez3(8$P;ty zN0l%yhKuFk(8{BAKrgn|&>M?|wc6B9*SBus`v_fDrseIS;y>G6x22UzqKMBMGA}XS zebKDa=>-FbFJ`LdX}!bC&$`b+h4v@RqC*9=s^Z9I zR_SHHXBe1}v|?Bjkzw^y36AFk$>xn(GYOJ7pGyFbo@q;B&;muQgQQ5KjmFO{q&{+k zhDYhy5Gf3LYU;Zglwd%3rny@!?Bp~#Fg-JA`>9HcEiB2>>_6iVKK$n0h zeBk0RU6)N{FravPWz$cCp%=&)j;MANy#w+ltwN2c?#<*6jYZ z622}#biymzcOL(s`5Y~TfZJ^f`{<%^Z#Oice$22uVZj}~sk#5O{QbUUB`GAV4xpFO zE#Od{Cz|ggOnrhxBak#YAo2MvvTJz>b(u6d1!I*nxen{@ON4bJ5~ufO;nt=yrBq#vF{-nY{t&fBgQkyvk>eN;&dbO@&q$O)f+_@&xb;L~d3p$!4W z>p!>xhJq<<8B4;Li<)j9B@T+S=S$U;dCPKVjC%SU6ieP5!xpe<8^!$K1VRwxDZ*5q zEwDRwLo8A}lJSn*KQK^p0yahUIowfKRu?*GqC}fC$CD-1u$$i9+ zpgiN=Ux=jk@eWuV%0YGht?ls1dYO39y&l?U>PninG^W|;uy`GG#4>r1xHlP1JhQIH zM)vO+>#Q2QZby@96Fq-dIl!ySLc^Pg?Uh$3+P7>o&3+#hS1-2kud2+j;G_-GR|nfMDil|^?^>1d)@B657tPC> zCM_2*|2MYR>G_EMbbXiq2c2WgCl_oiEg1sZ40cc%&(LS6v@Eo;r$(hEMZ!F2;}3yn zWQrCn{yFR#Ym~Nc>*}rEmenr|G&I+%Wtg&^Sl{@yVlabI4@CGCc>0c|;E?2dfaI|C z%3jgfY(LZ&+*FWqdyO49{K|3KJXwjP}k(jZgI>k4h7cfv$q#b9qPbZ)E- zole_0!xMu;BQjgo#_FN$<Zm)%2n zWrF5dE6T%cWokhEkng^g%5u#!qpSLB>}_K&s`(LC5TQ25 z5^*GC(FAsD$Y%x)0&<9HF)9a)_`G&@H!PfuMk!-Or46`_+mY6M9Asv?mw_jhUsqZkA-@*a z#6Xqc=GG7j9+o9K+T!;WC=e|pI}(GGsqSkcd?2&czxqwcS0X%_6w}9fDzdf5q4e?RGWa{$VIZ60k1% z{I+S1XMp-u6EePj+dJGJZHFY%J-LfN5=pd9LVSDzDU>e&F%|#&RxZOfDfGzT*AbVY zp-6amY64iy&`cz*f7UGcYnI@TvgQKq4XntvXxxiudvHLVB{=37#13j*VxU~=TfB$h zsl+asZ%)u6?{|ebZOL`Uijpg9_nI)i+c#Hpzk{gk@M=RXMwEY^}PI+2f$}8N| z88S7f^>2vC)SJJ+?ZZF7ZE}Q__}l$4TdPccDFhLx?jSrRBJXtZXMy}dt$>hx7Jx;) z3C=SILIb`3KkD8xEXuFz8&(7nkdRa)rKAO<8>MBCZcsX;VUQZ6q`P5A>6Ff)6p-#7 zy1N-d;63rW{`Y-7kC(pR-s5<`%!lD*&b8NGd&O_XuHZ0%C~>r#cjux;X;0PC>uo2r zMcH_%D2iG-HZ#|3BQSEd5i&fsL`F44a3J)f{Q6*`5t45!e;);M3+)lCoR$q(7gr!n zF5^>^Fg8?g)$qK2@K&1y^mBrsEn2v0xC5*dCJ=9kc6>M#V*dT?eAR)+>syG87m%hR z^A>4IC{TYTDV`(UeEqJCE6mf#Lp9WUJZ4fCKTx~0g8))!Y8)5E08DY6!a+ZMsq1kB z2F9L!w(zz(X(?KLMi0@`;+WLDi#_yU`4L>A^#aXnLYl%wN=o!$&^I6o8Ym21Gb9+I z1j_)$Y3PfY&$;L($h+|Ta*Kw{o{8*3_CJ1bNU85DE18!hR%dUnq(N4V{yOn2Aewu~ zHqO+>+usTQpe?rlsd*Xi`4YWKuD0TJG^?d7p|dWY%Sn&Cm9sda4Xxhsu}+X>#Z~E? zONU_I2dj@%m`*ek_Vf4#$-YYw)Y|+ASss*wNkG=1Hf8m!)P>HM;J{?bjRva)7A_AU z+P7=u`GiLg+MTtz%j5<&?|yb!gSR^inRQ>@8X*+TeZNi7viPLI13xD;bh=u%9rcnE z)HFB6-c3@4fVuUQg_%TSJ0*1xMejq1RjtT(`9vkvSo$ia+4Ql3AQi>v)6nf878PL5E>^%RFMFs|t2L{bmHyb~V^)0c zEC4$!qjNS`a=>HlD1Ld8(Y$mHXdG7>XgIm{9;G0%t=BtS zB+sB$F1dn4_Zn|+ts1FCaWh|mnrGND;P0|t>`(Nae2uWmgh}Xj34eslH)mM^O`Q|u z!w0l7DuQe5{xiUabTluXxPJ*fuh8u9@v^~S>3B0C%8D*-#rCbJUY*N0j`7`sB6Dih zZjkDH-G1XO^tFSdg`!Va(po86eeqoNMb73VTW4J}sBEJ9$26YPT1NnC&G&nKKuq0M z6D3AwBZrDeJTZ@csR7;+mbQe~O{>>z5ABivP*xYCAXK1Uu;kQi4bU>+)v)vALGeT{ ztrorx1{o3-FD&Bnzx+PId3Fh6>%N$^n0gMtlN-*RV+mZdt8BkV1LY?Nenufnkm zX0N>^-!#BtEcBeTO&4Q{io>Y=xt&XPyBErEtms7R-g}CNib?x$6tB4#JzZEnCQDdtD{bYS;Qpp~rnr4La6o9`5>AlJY+t!c5X%V5-hP$s2{y{Rt{Wo&ui)M%&kg zm1gu!5Ue8)A^fw4Bt^Kgq|42TmJtn~aAA4Q<66Pr0D0@d?scwV4EPow_NgC%$`<%2 zjUM{qNBiOIW`~sYSxvZn@-2{FKkNt^LXWdE!i(0L+n`upzTU3@EYla}UO2K9!9pKK zs}64MBNC}wKCoa!o8s(7_K^7R`)M&#(AO$26*TYI=C&Gbh^I>#-Z`XKF82KeGHM+1 zQ0fvmzLnrARFM#j*%8I-4`8}`hPf!p17M7Dk348Jj*Qi=>S!yA{#|EYhRhzI zeSN0Dm-BLAIdj``@M~ng0)3|n0U5nwli$mw92Q0YD3o-rRdHt$IS-OB7ldM!)Sd#< z4qSTBs=4gScFWuAaJ!+#hbFXbC@zzF!RMo#P4(v*UkX_$H8UQFf;T5*1E`@Ht(n`I=V5*sxXLZMCf_^OI zy*&D1{X1Bd^b4$V`3I~5iZpF`x-5p$-SQgv?tmq_#j(1O+r(pBbV6wEhmm{EFWKwr zF4a!>-}CxNfunxf+)5XjsnUwpl{;P;#Q%Jq63Egh-?r>g3O)4Ec1$3DbPZ(1&t#4O zmpkb(+gAqf37xA6>&}_BgBmQWE?wN!DI;P)Q=$#BV;xN~rnarc&W zL9sinPYtDyQG}8gY|h9|w!$P!tL&S6lyFjJ zbjKl=x6QLJ2<3o@v(KXPdLHA=ZxUe00kcsvZ5e%y(E*HU+X*L47K6p%|k5Gr{@5xQIo$kuky;00mKYX&1Jd-13;&vOSCTQ@(m-jvvY5!A~s%LqZ({@ z-TOkz^44E?NxT6Uber>elYzOhfm%JOYt6X4b$G22dP%c_PA zeQiLwkpV;q@kW(XQ42||wKl%hx%eS!=N;J$6j`o(?VNgaMm~T7Ezkl@QiimT zB%Y%>9r=L02o8yK93m*Ah^wC%)@CR17z8BpS`)A+0I}6uAjaajyah;Kxm3R(#CzQr zkN4;r*lHJ5#zIMK8M}MZ>a##$fF>7rr`^_B0J#d_BvJ{yUpHgT1g#USL43EumK64M zyH-!h&dt^!XgRNiFKdbUs@JMnrO^O|&(f-C+~>t<-kDz%OGBs6^9=lW*^L6);|;yK zR~@vYrCd%}=T^`$j~f$pVMA?eF)k1WB$J1OO$?LkfQH%=v82jPAZb()Imq*r73dWo zb`5Z^q4#y|mtr^3XZ1Z4+qe8|{qnZjpY8n$(>H;x;$LI@fLa692V~Vgg|s#7 zgy`YG@ZcmB*f#sP&hzY}Ww%!7+JUn+>j2%m4WuBVA9EfzMJdc5S%kcJKc33tpyd>l z)V0>sQi&7zqi!1*IkOar94;Q-4_ouK$=9w*GoLQZ7rjUL(!b^20%HmtXgss!r^;&0 zRevl2UT`-z$(pULJ|*;Ba;fX^!!1I`Bm`&iN#Q**@W+Qt^RF{CLL>x7b5OBde^Al~ z5cxg}ll|Ph{a|31ddaWR^wH-%b0@oyN`78$jjScPnam}SXkryPl!=g7Ew%$V(Yx0+ z{eg~rPq||!)>;kTFYv(WZzuUPqG9vhbY6ek1TuDSO{<+{xi}fmBf_=rq_f~`p&(T! z+2C!6d%fY2BbgoiUfgQGf7*;TlPKqsCojamyrLjStVrfsX=B$lktZA~33H`Sns!~z zNxr1H_5DGP%hjv_+zSr3iNoZr9E}5C^jOQ39=>BYTIgFz8{cXG*HF>{E5eI(j_P)% zvq~AFS?hT#^mi=sZ}t;@R!qvHwVKT^ei=O(*RecYv!#fdfs%@l2#0^bIqrSTD*ju& z!+ew9uVB&spI|YcIPHamjV1qG#eYNe+3GfyW3^6^oOt>*pWb**6zSf&|7=*lIt3NI z3%w}7-+K-OdxWkjxJJgt=Sm?4s9hhvOUKunCi7j4R<~E;)3Mfw-yeFF&Sm!6B<3W& z=gcg6NnjsFgpyLbzn#h((`jPC$OqWsEQ`Q>!esu_ zUR%830Ep`(Xs|dF2M@K?c46Euh>65{_I<9))(lJ_z~#0dPUt~|pWGCts`|z*Eq+N) z$h*fAUlO|FF6r%^1%L*C@6#*~W;QWhb3Gg$aEl5**FFW>_{nxH%b^^>=Jnsbn4<^sh zN3+f$F3)l*nRV8z-Z3NY;I5TTfU?tt@xm_GlG(y{W@$DSwcOFk;H(DNdu=bH!yjlz zy<)Mq=}o}G^=vk|V5ek{eSo*HvR$sP1rmPjQ^$^S)x=SW=_Yuq2RTXJ6#SSUKpL|x z#`}A9k{Qx3_+9RQ;rDPajAAe_wP>?wtRd>DWgNG~1dkI_> zkw`6&UuFc;8!c4q$p>1^bf3>oJWqZ8%4)^u2qVr)(MHY*MvFjS>wdo(I5f3n_b*^% z-s{5#FdndN92hZMsH<6{s@1YR&em$h6;Jts?>m{=y^eQ--woa^r~{*BN4p%SOSd#! z8r1bfDIbVFO=Y)8Xmz(=`KUc=J~XX3Z_9qyu|m4KdmP+QFufy;uIdilA7U*S6!%yN zZb>RN3iO>mK3oIFX6FJCx-W877}0{E8dobRJi{nyw6VYOZNgrioC;I2-tF)PZpX|)G^>LOf_AzPq0N5S~s+bClewq@LliwM3`TzBCK zwi9+Cn}T$Mxs-t=306GvM+Vw{v7Ah}#Ag8XAO?XSK6d^B0XLp|mQFF~ysYj5K%k5! zm!sq`<)F}SHUVUMeYH~Gt(k(G?a9v%wd9~P#WEXPrrW**7QO9)uL@Odh{Uz^2|10k{M4DCzzg8qdQf*CO^wv9Hu`Ufr=-#VItg=AlF`nDbU{&Q|+eY8R zN9enG<#9>hGT$tkoe6n?_0n!cH-apbx?0f?P~oCfh1sLa;l`w=9H4mjioLY_=?qq# zMKcRJD4fMh3@GUul%Q-IrpUerZ_#lUcY*LsHqLmVp|#SxetQI}A+&`gjJG&>0)3vPR8RUr3-xUs_)z7thE;QR}w*xxUm8zD-u` zwO5k7I?id@I!)XylU)MwwD38>!?9?KX=5fE+cHvs4j;`WA?+y;=}epY%GB`T+{e$i zt%GfhXA&Ym>2U4R-!vKhmwY3}F9Fc|M*x&LKk?+}%;Zm^p?xP#EGSZZr?5=@R`KEH zWKXyxkxq2QCizC%k5BrL?P&4#m6YL1U{>3p?W2@RCj0RFfoVWX2X{+xCnmWLMmNs) zPm4xA87OS3Q^2(pQ!k6mky59Z1e_J-2L-=|7%m`VJbJFj0aY1TAdYsuUOYh`69tv& z&%Wp`%M>lRMkiz+d_V`q(L;-+vGIJpjFR%?WA&y$YeY>8>|M-Vab9gNQ8o!Aqsh*w zoRKtza?&k^U%5md*Jgsja3SVVAg@NG&v`G>W@(I@Kowq(rsv*hdT#uM#9sF4?nj_K z|K+*LNGpb!r`qN27tG0TB}EE({`optHFaW9_CBmr9B?dVjan7C_{MlT?E0Gw-7DQH z!`bjP39ZR0gRspk9m1C6VQ<7-*7iY9Yh{bgiKwq9fA>GlK|YULU8(#w=c zx@kM7&jOz#1Q!-3y_sZ-Am5Blx5~$Nq_sUdf^6){Lc0MJ;R{83??D5cl!8v}o#U8J zR3b&b^gvFtex7Bu0%f2XUl=nJgXC@Rj}T@i8WD~PE9+$D%id z$~cg*m!3=`pI%#c~=k zkA5uYwP)s3g+rkcGbq+ZiuKv=nRe`7l5g^l>fd#!bN5Df}v}V z!5t+fEFbNAE9g%cbkwZeGwS+wk&?P`XI$8Hkt$MT5`){$hR$z7Bmfsj9+j^66eER!)U|Jy}O`wCdYj!AygLpNCs!vS#=!*bpq4!@{XURK{s+Qr>p? ztaTy$c>gD5z(qe)3^bzQuqxv+$~S2*deqADzLX7EcpmhanwZ923SG56-)hytaN8UA z*=$RcnkisTfBRV-x&NRU=0x0zS;~gU*C@3{_C*|`UpUtUzxtUUR+*$%ACsXp2@A#k zLG=1M08cni-XRrTwqXQcJ$4o{-P`VK{Swi>NYOw9be0HK@6o=yGlW%o1s}>>E$@Q; z79dc70U$1rwEm+mJ#b~)U@$K$B~<@2h~*&@l8w?mBW&bdi+6c=MLdr{gR2o^L)`f~ zs#-HKFWVrOGw%5sew1cAk1`wXzHSb%L4U`VCG{Ji@IUU~cOM`SVQV2o1Oe~k&nz_r zAO@z~PRp#8`rhZx&SO+J}|i} z)Ds4Se=xk^+B}fl_0R?8%UXFYzZ5{-LtvOqC|A!q5kq_vyxJ~kMG8L~b zOX_|m275kF|5u~O-wf9NOLB%1!9T!K}@#{F_Zhxw@H*g@GA;EF*n z#lW0Lt@Le_u}}XCkN@Y8{QGavxL;dk{-4#%|6gqt|3dU`{=>~y3|6ey^jUvs`)Ix? zccR;8AH5;(5H@1e(DYZ;WTsTcoit)Bqt?P7%#afE*{;w0&{<3!5Y0)D75!k6N(?`S zP`2yhGPxfC?i1v2GTw#Pa@enhjywOncIrD6oU`vcf+k#t9i3i59*Nw!i;Q#op)WnZ zJvn^XA2C5(_309g&2x$%Z0p zKHL*))oLMgWm^?=6UC%qKh#B!LpuF`{^P$^`|GxynyX#>K5^16#%3!X}Pd0PCW)rpAb9L&;v zNsg<@Bd)|hU%LINGc*x5&M}0=Og86D@EZQxh>$;U=nm2WvrSj{H`(*^wDYDwy=N*l$ujH)tca~^eIfctqK9ELrHjwMd%hCjmFi09~+JXX&B zXH$P$It2u!FNK%cqz@WCOm`E(kt0tdA-&Py7&Xg=l=IlbYKg%{aqEWWGYIV%{Fq>g z+iUpGn?S*d1bUU_lki>Kq%VJ_vbU$MI%{=4VlJ+k{;)ldPpl3TdYoUxw9&*v|Gp)5 zpNMaA`h>$)5}~>Jzf$*q6DUQFBvk%PEiF@Rq2dEO#%i5_J#A`Cyj|(3Uo-vKuK)OX zW`DCZ>$B1oMSXBIk4d#d8S8lEN|TE8_=M5<>puz%#VLxww`ct{TiZ*|KMc8w&f_o1 z8(v^S@yF0ZaIe=C!6?$kW0l(sD}qn8>Gxpj5_j(E!jYB#nFa74Li3*#Q}7{4BhfVZ zRm!;FgS21R2YCD(!wGu&0IGjbT+>HCg9>tCR@Gd7^4OV$H_k%!a&i@4|Ng(v+kgJf zzsUAHrhZ2w6_5})9zbWc-;;nl?z)3h9)t{HbG5()F}VZ3hIxY`l|p`#hsSb-+JgGW zbH+;({`fhsy|l?t%mYuQ;JM;savu7xCR5A&#)mMjc5Cb$zyEeVe|;wsjs(hBj&>TO zPPXmJjC%rzMU&FOBOdxP#8i@M?6`{f|7uw{6RYIc+Mj~fO^@>lq({G%q03f|19<* z6jFDQawyV=@*jIDX?EIc|LG@zcRf)3)J(6Q_mV+!K3Za*gz%5A2S_CZNKIt0M91aH z3gMR&{~M_&0IAh7QIP9uw?}DiA03qOE(0F@)JOTZ zN5yX+T?~Z0N6J}GvVZ*-21q5`@l@(+$k0t}rr%s9!TAdV6rYRCM~i(mC8Dzltm5hT zvo5>i8I6v^lcmhmwSorCc-Xh_`|p}v1Spm&hcAK>u#W)QZyKY(WV_on}iRBGV; z;S(9vc%Dkfg}k_bIyu10d}u}H@e{R1PM_HX5_6)8{Y6%A09g_92^zBk)*rdb^OyDG zO`1o;o#5)qc{C5xHUm9v1;D7qGxDntu}QlRdMdq)=Dq)y^=C=|{O5F0m;lTd`VSJM|Jm-}8KFo6NEJilkG(hZ z_|68QfAkE1Kjh(2*vKU7eMivR1oE(<{@F0!@l?JQK-?EY^>{qun(-HZJ1dm{1M&!h z_pgybkM3u?{EY#X00Z*TsI=~SDjB-xk^XH}tiY;VzWI*K>4ImYbU2zm3RVLQuZ=`D9k{TKORuCZ7D@*flq$UBRPCTbldIWG) zJCERRq|yPT3U&LByq?E@q{{F&75oAa0N+O(xGIl$#KmIx{zfYFmei485gmY3kt~_N zky>!eRo-uUPdt^*FK6wcreZ=Fd6@BrK zVEmUKr-0v*N{DIijtqK#Ka1~gq}JbZRr;IOLM=Yej6zxbNUo}Gal^B)<+^QLUfab? zlAkNwlh;?+hkbByyR-elG~05cdMPq$*%WxIA^m&=`}g6={|LSQ2Tq)5i`EcWZsYr7K_wI7EBdeY-5uZD|cmOdjo z+j#BI1a5AwfDYVFeq-jtM*2eaV(-(_1EU?}9BzR^i74i9Xi z2qpk8gp{@PU#DWpB<0j~t`_k}!URcEtmykIt#_g=1}cgQuZ_LS3pui^np9RBIL8ch z>@fVWt|*U)Sfgg|=|+^B^wX*dbb>McvV+MPP^=q8`}p@7sHb-bazM$EZL-2qr^y#T z5;#1=hQI2{Jz>lAgIVMYb*q{^7v8<(UFWl6RCvAGOS~679=_k65d$?cjznKSn$0$% zGWnL>JDsI^rP{~N@c|@JQ#rf5(YOyY|W8w-8Lk3lNxKVYCAh9-Y)1;so9ul>+hM z712508;zT7_o?98q4GWdPnQDI#W4;a5V=aU+MZE5=~b~V#{tD<#xoMGDrKoVDQ@a~ zg2S4}df!p`N%>E!1x_8D&VP1uLY$<#oAd1bxP}^csL0k-&#E@xTcE8f*g~0@T&&CR zVOgK-IVD3$qO`0^cA5NKS2+tfdjw=2tE%`lK7i8_pu z4inef9xa?60_G8|#aau!>>ruyxQXy;EBFk9Fgy$s`HC<*UwmS>gn6Fq9ZJkC_qp+B zT{$$x7{1UBv|uw@G|g;78^M)vbO1TUqt*)c zxx0RkS!T!=ZWO1>^hM%0*3M{me`4)2*)`Ly$e3(v+xIO}j#>vO<~S1!Q4q@2zdA2vokG9{f6UiaCFdur%*2=gmP1?Nvmg=^H3oGs5e-S#mu3^X^6 zx2&7GEseI~&);6VA$B_K6vi-mi>H_ubYh5o6hr3R$t*@+YjRmrbX*Iu=+t4yo;(Hc z8P?cJ(bTNCA{LzPXcl_m?O8hcioHjJY|v8(qL!D|Qz@-J@^l)I$T%&^;HuAcUFfZ9 zZl#)hPUO+2bmWUqYVOgImgFh+W;U%6$2PoNN6AxxW!U3eZYUS%7NpgwIf4TR-c&U8 zr)x`WDAE|7CVlBG?nD6{9J~4Iw+a2`1%~qhzURofxZB>xhtS6BZNabs39XN&7-T!y zECaxm_CRCsJMJ(-`DES4hIJ1PXIbH%QT5jlR`5#$&}7l);}w&0^APt?W<{8}a{>?7 zf$!H?(yOWCG)-#d0!>ij%R*+>Q&$Z@yUz>x;`d7O*~kobzU9eBnyRxpN~BqhM+PZm z$q%;ljb7rvnKyhD>Y9}bS1T`rJwIAyukA>uhN^1=LV37$6UQgVU@>ztl*_1Dw!%|D8(V_&`axi^ZPqm-Jt!uXfXNLB{@b%pA}d8A{BGzL&i9b;;1BV zV)vYOV-ZAd%eFW0%dtXL(G-`4T2l6pX+cq_Uj?>V`!zHREQPRW4L7`M@7B1JdbcGb# zU=C19C@>u(Y<3BCYdo^Ph(f6&lOMcoJ^9|PxpR*~Hf8**jkb`6?!oxCg|iw29w&xC-6TY_!e z#3F7j{Sa-(a#tSH9~OmE1!upXd&7N4i+C&HlLQ2}SvNGBnLoaCQmj@!Oz3ACnrkfv$J*O%u*&5k3ou|_RcIF z{q*m8O$&kme~G;)9=;T2nsDnQw|F-t#Or;zumH1UBkP)Hdn>deV7)JpxRc9F<^lMY9x4B5#fx%;BPxivVdY0e@2p`8w%%R! zwO#M!okV<}UAF-v6q$$|w zdI*ViNSZBJtHY8Ss_Q4^ao)?hTwiXa)q&I*SPv_{UGq**#O29LkF5^NV}5D@zwze{ zzU2S1M!apUwxg-?`ljA++$^;maWb`4={Uuad^r`g%2B&lPAC(!wslVA*Ogi7E!a0Y z=XF`lE-0v%cfPZ4((*g1B9#n;8=F6$H985PfR5&pDcXVvz&)EUKTrXqI2>b@*q0zr z@-Jt!ZWJbK&iQi!O;JF*RwwWxOgO8^Nv0RtGiVg{(VORng@5wkL#*5 zSzRtM$#(G3@OfftD!-1_nRzLx){~4BqwZ`Z7Lrs8?Iqb=nwAAwc6`@%&4YoTdU+DiHW(&!rtwR4u9@^ zxXjM1*rmx#>M%6_Q#8$?nRS}Lzf2$a?taqt68!9#7t8yLLyx7lGE;;g-#97CJ zzCjry=ZwD|b3NQ?FUsC(Prs_?JF$4OM;Nj2QK%xOrvqd5t9%P|srmhqA<(=;>@<@$ zgL(S#ntqsg0LvIqJe?>=nrlPn!%+LdPgSlZ3x~T6ZP{84+mq$eemP_j9h#iBUF%L6 z`v2N&h7bYlQ~+vo*`B7L$Ss!AbK=tw!E7(Lk#PV za?uPEcq0WT_w1t2v_+&zX9_kGTPZ8Y?G4VdR`2iKSEG&JT{*7JwYMg4HXFboOV2@g zSVUe5<*XcK%_tdHYAQDh)YNZ)-no3HSO_b<*YGsHj%FCpL_p? z5x*w_3>?4NN5sb5G6_DF<+6qpQLM4Z#S=p!Im( z`@sf{rQVGDjN@~PgR{$nFz9`kHrctYU`~Cap;+wcB9_hLwqj6>1*d&0gAUny*au6~ z5dJSwW9jL>p|4g1Io-d8KHRuz&?st=Z1h@zK5J}^S8IP$stb~L=tAa?f@7HP#jRc7 zHmSm5X-)0OUv;canueGeRD*}uLdjezzSR3WYh1tccI~ZOuDg`o;56qBOe$pQ``~10 zq*AAN56}D~)TeSD!d5s<=3H3rcDNCjJ)zdU_G46Sh4biwbZpP=YZSlDkn2`KR_GX~ zGaRQjr)vgOxjPqRBS5}8cULe>^F;G}I~yb~@=6i&1|Id9xMenH8R;%!ukf=RK|W_J zIpS(t2%0d?f{+MX-zgkV1HF=UJ;Z{(G$sBy$D;v$az(;lR$?kk=~`E6nngWsVtsV| zkk)2suiKweP(bX}6+|_Ea0GckGY8=$F;0V+UYSAfaeXLM^okBsPWa|yES`jgh^tx_ zDlV6%2Vkx`T8~av%ADk+is*{oH-sjyTg%AztC>Uif9eQt{RS0MI0A7?-ciumEMTu{ zJ6-~}6Qn9ikq)n=w>u`!Y!lu)z12=rE|OXY6H$Uy3Rjl}-HhLKE7X!=Sz)LRi%gRC zv?I;Z-^gKP^_&q+_E`8lFr$zV#o}#JV>L_Lk^S@>chx1b?slx5ig!oZCx-9#K*p&e zGq{keNmr0Xs?a^Xm;fac-j2z}1-#A+y)9Z&M(O&nLvBm0n+U`D=LM66tQD0OyvYsU z;ssq1vbCEY#+WR+p(PXEMAAgWeIaH5|q;RvlNYO6-jT=g}Bv!x+xhSV6Nm3rl`#WUV}R zAr=^Q&WEpF!mbx?E5sZUQ81Do6PaD5G?Dp3cwFaH3^|YA8o zH6Sjww9FMPF6pcnkNNzB*c_Ro7WnFY`MU!<6K>1&IAF5NvStBiDyjL@(@X3pR7-R) zBUV~8sMq<9-5f%%=<6|;T3j@!?WXtR%{^31=yt4Ur+ey52igjPj-+3$1}R6~wNdeC zdci$R<2Ss|bN?1>?_krf{H`=#;nt~Tw{&t&!szsMzVM-)ao1V8Vx^)+PDOp2PjRs7 z{4yjWrvsKQB|h9r<RB}yaba*`3ner~}f3U4=ERXkM z#oBRQ7p!YZ>{HK{>cm!(4K^o4_$0zX#ERwxz-6f^@bPuXLeY%z&g5yWl6D7^X03Tq z`L^J2{Urxz{#dN!{b75LbGAQ!@E{?R5d*h_E|2SY1l;b{bljucfq?4Mk2q_aP(7|4 z)dOSlR}`3NL?vWO24~DW`3v`X0&WQ53x$H8BdlD2SUL}gsZEI7&xJoMZ%Man*rC@L z!##(6=*wSs_#SbaJbFWIXM?Z^~?sP}T z=P{F|va~gn-+lL8ckOy)FB>AcL+_DpXSe#M712$~V>x%=tqd!v)#+Ipp58wvd$nBT zg!_s$tW_5SC{3}5>KDJ-h4EVlNLE8N2QC4vWF1$94!_h{+-vn$hyps0qTI=p)Hc;c z3)C9cK8&;QIttJwBe|!-EXB^R&^nG*uJ@G9HF?^mj$#t$u-1&(|BJpR0Q5DZ$r)o% zPP5tW^wM%@WE)AQ-?T%dQL6h2Q;wm;s|T1=+nx1KD}nRMUpU5bIw5kwemsQ~Fay4- zxxz5{5aoV}txhSf&;91qS#oKZw0-+#BW;va`Ch8u3B>H_^K~0FoaZ)mr-_V4D|7+r zD$`i3fr!VFfa4#n6-3Cca=|BDeb8_&dyBfl{kWGd*RRGpFUe}^w~i+0{ZSA+pxqY| z^`0a1j3e{|80JMBG>G?b#;fJV#F*Z^^^ct5d$}97n)E=5#U*6dY8fK5UjWxgPw6Oy z5lLX}&|_|ny(pMz$q4nRIQBLJZPB?3Gnc<#;6yH1C0Z_i6(<0Qw< zx888dXQ59MQR4zcV0Gp7z8UyIK`ecQsyev%PZ} zA?E(D(GhSr+Ucrp`&uydVwGfL(#eOOaQ%`bbS~9KKyLvZs=sqC(`)Tl;@b0j-a-m? z>kVR3X}$uyL3bC2a8+hvKHc*!Pdq2C~X2?RCJ1_N0T&rJ9Rv4FR zLpl6XLZ1x3?%O1ol^MVaBryU+Xv&39YsgM=i(dzBdMsSJVX2>Jt=YbbD3AcNIHhXi; z6Od?0f-6H@OlJvA=;&fWL6s>oNHE1ihRmZP&mMfix_pvVBgmY>Egp#9IH_CF9xOdo z*D?9HC7}W^)an;K<~kXy)mL)F#Ek+jWph?V_fI#NdXuO_Csztm09QClf_cjM!y#nV z0ZyaGOf3LDECo`e_~IR}he{(H4mlyw2(l~P?dM?v(F1jTYFke+ZOEP1@0tx3HfozV zN;}UwuQ@BHi|RQuJ{}nJI*pEO{s+hIEk2DG1l-imSnCXO#A9417j-O`+V|W)1HPH< zlEY7)WO&h!pQKtHsl&xsJ9&=NR)-56j6M1l_j3Lfy)||OlmY226PbH-nDp6=LOprK z5CaQ%o}*_+@)XR{*ANKMwvSp`!&dT4TocYkJe3OnCDAA6=quIVYR`LqOR$Tm12JxE z*OTk6MS2@WQUnh}-L~LaeX*?7REgkw#!akI%Lm6ZaZEjT{ZIy{|Y4 z6?FVqmnAUXSP6T6!Fpz0TU6K2<_{Hn6feEioTnb)#cn-j5lOE^Yrg|zlwx}lI69wL zFlAFohIWqaHF6gPRIEgnNb9Ye69qc6^c!*Axc?-t-S=Xm4d-z=ww}B>65Zg~Cm3w* z9ADl=FEALt%kH}SOs@^8n94?`i^JmLIlWR{=Hz?-|Go z*hI0QUstfk9zWJB2XW%w>_tNP)YTjm&{(@T7{6rwc;5}>a(V&&#`w3aDMcaRwY^_? z=wWm~2ml4(1qI-MYAd&+9p|B)w(lMqsfMT}1kOjxgrwHAoJyLgpxsYj0Xu0leVR;P z2jwnI%UJXfZOgSCHeBy60cIp2PD->ZRf(%jQ!}nAzh2gUk%b`(?Hy>##FP;2YdAWw z)mk9J6iZ#A4EJ6ESv#ZAL*CmAXLcb%-L$0&@NWk<3HEr4vS$;@-=>t;y&0je?Dqq2 z)Bui4Hp>;qhh=1E$8F_*Gj`Sh4>sUh({M263Xxyvm8QxRtL5(n?-42hDZLF8i%*%N zk)YHPZ7Mk}@Qb6y>z5V|O%Hd++a{H(2bZ!7gmogc=kfo|)?+uoiT;0QYhJi3$pf7+ zTltg?xI7Txz9w=9T^yR;`ccI_q#(bA#Nw@otBhaD6wHN5lYaxR`>ee~=h{q~~ zQ}H;IIAb9Jk-2s`HWEQrzSiS$t_?Br#29U za|^Oidz0gBry0{oO+s2D{PwMK)>dV?*UP`rX;1&x=W-qL7njG4&LQi z9T~o-g$YxY`9IVxf@xica9)24f0wPmdJjpALrTcCGEpkcKvPBm~$0P2yDI}DOoqgwn!rzfMWkCODCB7&l_--(t zx$wQcgouw-+_Ht!f;%uYFUb~MFtF%}{t=#whxHF~4<`tA#SYd)`(`g;7+M%^~-Otg}1sUdnOSu?3#Vk23kD$dIHa zd#(+P0lH}cYM@f!XuWu^G)E7}1mM*>*nuDD(*j0Y5Jq0*mbk3DB|D9$Dw4xG9!4(A z0;E)Fw;E@dO5`D04sN7~%q7T%`t#k5!co$>rm;rAZbp0D2vRovbddsY!>N>JNVN zpxIUheF>(mX4FrEbE2xc*bx&EI?O1|N>kIB%Y?Fb2keOA41;pFdh_&KH$_9(WEOX0 zAS+d=os?&ztA!OtYtT*?ikGu>n=ems&d=&g+;H9E&C@POfISDSS%Zgl<8-O)rqEeU zjkgMHkMC4_L$PfohE2)nd#-dJZ|1TP3OaH{YYv&UmFDtfOo>jD2HA(}3P}ox_-wb) zAY2;M&Bm-%ZY4X};OGZS`tCZPIae-E*tmggMa(rbKCckQ)_Q!N#CxK$Roº0IXyZ2y*Pd0)&(yy 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%0Ahw4DD)S!Stgh%$ z5=AF^8AMy~%*U*`Uo&9$(b$@ATPr^Xw~0$u;h${}< z4_YmU&BP_Ola6Bhk{1nFA9q=ns)GpvOZ)YhcF2mIlD0I`<~*##^U5u3XkW5tdQWzb z7n3z5b|KUa$RYj-$_$6;IyuQt5P};L^SdRQxKeDd zI1M<+iX6?&k*k;ll;?Cy!f>oY!~qk`0ph@&*?K%kZ5aw1-xH%_NTvyjk0(dNsPu#v z7v@og63YYDi+-Dp5!ZK@?_4Hx9Xt4Ap~{PU?cFDwjLW(!WeKL8-`?$6TdTh~zS}tW zw(+{XIuF_Pj%aqcq2*c1xi?SJWBBkRY>1i@Jun=$wcI*q#|I0h4)umi@jBg`-Pg+H zgLTM}mmzhB%T|?{r(JR{PyJ^&HJBEXT%$zj6^eoH!u&pn7Lak^fL^z%PN=^w!b&;?3(nek6O8oawPgX>du2rvWXfvy?tl>z|qqZC$S`aPe^TMnVNXOY)iq*?&1Nx+6zbj&m75jly>A7tXP7WC!3@tKHZ$2&M9u36g*ZGOYQntnZZWMVky+mXa4 zE*BGO!KE*03B>BpYD|_~wPiP(QVZtt;7ALi=b;KQER;gF5BM#V<@4K#h3>V1)Uc^AGL7^YeY2} z_@pUrR-WJ<5SaFW6*x4#eyq8QUv#4{q`pU$Jo`fqZwKxT^$cYxcvToWpl+$e8e_sL zTb{*ovEJv*Yo9PC<&9eluN7Y$>?(|!EA6uX-GMEb!Ya&uN-o=Qk zGK%e)ysMLpAS}$fhlu#%301m6d_LYCueIx_Sa&XfRg&Qs{?hpB-b`*_)-Wl)#X$_w z!fAVkA5cHt{$hf%e3I@6Qw-;h*N`n6cDJ&|w_Y1@-a1+y#MypD?Xy+sR99ZWcIaUL zxkf{bNX{QBX2HX8BiZQH91SV1X1>G2D8q<9@WOujk-%WZDO{$77mJU~eP%*KUnmRK zw}7={9@nrDpMTdHpaQ=foudNJ@TC1&7ifG{Ag}O|e&$@n5WF55#!y^B8SrmhGdX4@ zLgMooB5&jucQy0nE{ml7ZliB;KiUOd<}e6-IvvT`_dXC;?)o_vgq)H-NqfBVedT+C zYMM(Xl`Of(MwYU#aAkh}0Sm*y`w0^tDp29khy4L)=!{fJq-VJ(=XMd^yYfjl>c-0_ z@;{3X2=gW$klsz*TB@`LW`lIH>v)k=II03si8XAI{3%As$`09ueQgeEng>k-zhN16 zAWKH_Hv)-@x;>?XE8_R&KtrD($exO%lvK zQ-toK(K&=TJv8Ieryf_zmHKQrvOvuQBkCVu^mUP?R$3L%9HFKCeq zZm1;W;mAI0!I5T` zwW@FGcp$wLS9<`Qipc^ARQfkYD23Icm$LWR@sX5e;|gWtMejYgXV!}x2ABU|-#t-; zkckS4@5mM(>ey1#rASyEGg|(|FW|}~zx~rj@iL^QRclwxRPt2F6ytM%@hryFyk-I% z{cLXd83o>R0dD#ZQm8fV_t^Wa!~I~}7Fbw26YkXnYYQ=G^ae)EgUasJp|Bne*_Gtr9Kt~tMpH&P5P$<|B)g>tQ-2G`>F4- zKkULAvvc_(iNK;r+%~>X?<<}j~{5met>(sNtT!xat%N6fB5kqj{o(S z^jOQr>$(kNV?kWSqxy|g`rp_YAqN~x`g~`A6NtQj`t<+(`~UFs&p-KrU`vYgpJ4mf zwSV`T7$W;;fD{dk5&Mna|F5p)|JB9+Zg+oO!OkDr*8w&w+e4cf`cInhiWM6#`9%Hu z>+pJRg6!nief{+}4L82AyuINymC@ljXq<)-o0U*GfVYllb4JIpB`?b>A@ zw&^ElC{53*a94U)wV76|?R8K7gQ%5Lak;Z2g52)8q&)7Y=5=5}q(*e~J7!2vn`DIy zSj2Xn-PMWAqcJVJ$79ijyL6T4=Mw%Zw*S7a&xAZn&|cd?FB41MzM}_oR8fA3 zjRP*kWepZ-MR?|O6-CU`86Vp2{+b#8;+=e-x;BCxr( zd)P>Fms*u&Y4ncKr0BkEOc6$llV ztxdvPiyL^dG(4S&>Q$yATfa9w{(H@#_j{FR_b39tE0+rRI%b)rh==}AA?_N;Ke+dd zKrHF4@^J(5PsBc|eq%-O#h{@Yl?}}I$-emgS22I*dFaFHp8)F3;|J4ZQJ!X`Acaj| zqksoC$m)$)9%a`mZ8H87|J!lZ&kh?e3cDu*mo6K10i17wJmqRA)E^KpAqFV7j|?*G zvZKGl#Q(?Me&>$)2sKYu_T_p^)Om*SnSR_y^B*dWknP*aX@^wwK{Y)D$S%O1^2Sc8 z3RD(FiT^_kpur{-%mQ+&mox;TZo3N`r9De+Xv=JH{98RZN7(upL=FYNEypB$~j!4?CtI0(ms|&GsHIkia(zO0r4e zBYpT66W$w&J|!(1snrfJcZ>fAZ^);IW8+UG^P((vdKwXP<()7_)l@nmv&q0SqN2oK z7GxBL&*wThi6MfL9k2eLWpccLoQQA~FabJh;ISU_aozlT?|wlV@XEx5j2QB+^%4l3 z;RFh}f6FL|&)AbcnHD%4(rx+TBO}@a#$B@LH1yQ(s_t;24nt}Vn~zcw+sYPvMQ!0T zp@NSujoP;2#tN9ae7rXgp=8ssMP($I|2eaW8!k$dr`GDS9NTOQ*nr`dIa#sy6!g^oY7|5A(3-W!pYOM98C{66KZB zM@EP*CESy+7*_xIOjgSTc8_EJ!^EOcrFd2Yuag8_kEVmZnl@tcFa5;^(fRuy@GtmV zOWf1l(QU`;Oyrg+8+EZdi5}#%0aG)Mwc5de6RbY8zZS??K7Mz-<}7x*njW-ksB00J zwReyjaO}Q6?d%T;PfW12$0){%DY@@)l9|4Oz5RnJip7Q%{Kquuedefsu~kWY$be7-5+h~a01+svI>2U9JkC<-kISGDgJ)Le`xKA>$J*ePmH{1v`Lb$ zJ$Sf0UEbn~#;3JxQ5Sl@5hgYLZwo9;@h5OX!>?D-!WKX*1*6iI$(Yy0aUv6Ah zfxKpP!IaPzeTYlHHMmR8rOqh6TQfGa!%|t*T`3eZyiFp9#7LgM)W%1{m0jauLJ{UV zE7aiDABfLLTA$#!#10N>>xT%REy=0D;WX3jE`ANU6!0+Ot1$jILk9bz=>H0&(spvb;+A2?M*F>1D(Uq?~UtiFL|zC zj@=z&P0W3H{|sdE?c$CFx3lcFQX}@Qz=4|bAmDP^Jw(H`2**tudkSe5M9@Ne>p9A~ z4aq%c8>dyilE)hDH0&}&V|WV>!ayVyw%}nxqfyE>7M_&{%-f_j46aU8v&WF-cVy`g z1ursa>GJzDa}BFFzyHvfjoOVNk%1HA$SMn{jd@eJxokBTp^o8E4ySYMMO)q(f?>L7 ztB1>3eVyg>6Kf$l1u!8vf+5FShus`)IUnn%yHIVOUK4W<=V7~SFK&yP!1(Aot(!yh zu_iuK*|~>~taYc~F3!TsDJh5{d>@XJ;y)?e@P~#SULmUPo#exyqw3nOi*vwx2GbjD z_CxvLqM;9$Jy;MTUpI}&aYDrhpe~bn*=(NM=Pf46%8>9Bt0 zVoC$^%>!(xF@2L~cWAz*Z83CM`(F0I^Q(&1NlV=OQ->v5n;98@=;oO3yM}Y^s$vSj1bGMJ&x6wMOeiYcNs{$-bE%pPNytYgfX# z+gxM8c9Il@s4DaU8`G z4eSPYi%Jd?>M9+4e!7v2K&pFjr7(OttYP-<}|>tLICeEds7K0(3Gq-a|}@ zLr?ra-E5Yz3l%*;?08Q-^`e?p0{UljLP1Zt19iWA+cYAnA?sg$0eEtoSS0YeZjxB9 zOM8HiJlQ)a(0{n`xg~ff`TossMPZk9rg66)AQ6)SS5oH1-d23LOAMKC^Amkl=y}J3 zAhKj-tSnqtGfgH82ATGI@aSP#^@z^7%qW^(*(%}9Z<3`(*Oxk@8}JMb_nuW2na%|! zMb9wlk>JrwP5Wsy>{rUIP4C2Ok3S@RFTt@=n!Kx87}=+B1E+t0{*9%Y%Z8c&Edn%b zggNyowGm#{hI~&i+G{eGsUBTkqT#x^aiO{1xQd2xXUz6adTq~>la&y7ojj+nf3`@&`^qFBDuczD^$KoY5aEsp zz~T0N&7XP{rt1&g2l3#LS^CP0>y3uPKla5r`dNJo&*V~sSr8S0P?e62#fJ&Ay>Iru zwrxWN7XOQW>ZqHYK2g>ue@)2$z z4L5(@h>KA0?@vA&Y2B2jUOk}mIo&PS9V|?{Rn^Cw->@`GbPdjGmB21PupBY*CMdc# z$@%b;LvvP3Ysw`IyU$s%x|q&R>3eeFF4w_M-*$z8O7ldTOVow%)iQZv>!RzKM^8k# z6>F8t;>Wwk1wwqjYn_Pjk&7THX;3bO2Yo)G_M(k)&AmsO%-RAtiW8R6h3{_5?7ZlSx$Q>rhxqH*ReNhoyXUzm)DTMQk>+&e&K0pws1ScLK0&j zWlh0qnH8~C@w^haRbkj_9;I%F7VFDxT6u%#fT+7WTX4i@U7_|V(+m(37#@=oq;mdo z&H=JJI-QZfCiMEFIvX_0+-5a*z zuS5;=cI#^?_2|uQqS8u0?F@aUlGFmpj2 zQc28!?fQqLa2J?H!TuNCZ=vD`KN?NWyj)0QZlA0MGi-e+Sy1zGDXG0A&XcG|qqk1s z4}Dl^S!d{Slw(`Nd9OtulPGMf-pP7-B1aFNdXD$lziWY2RWI26JjPpX(nu}I9^-z| zLQ>S%0cwh*oE=^Fj)0TavR+quIU=I6`j(isi^72R5_JV!Rjnsi&5Xt8c!|`_b7aiO zS>aQlC`WQ9x_0rZ;8x*@=_Jave-1Oc?h~P5;A4O$#Yiihny^U*1A#E9h;oh8Q9{WVr0beJs_oR23z1j-p zTdqjE-se^((p`eZ!rXYd;s5B-7kbi+p3aDQ(RequXmqc#@)Rn z@L83iU1Yf-RP0C&UGN-^(&ek=b**6RBr7%;nk0`YL9MwD%MVuDC3&BgmZ&*jQcoS_ zVA&RRog6;kV_mO6y&Bh9_e?#sgqmJ=F3?KrP^+UYtrglXF-{-4fLvLmP86u8Nh<%( zECA>MXZNM6!X?=SCqH)YrlwOIOy)kNJYio|winjQ=i7QxH{V9KJ=>^M>s08+%+xJ; zQ>iG$PUvhEHd_JXDYUZ9fL`;fnvveol;=W9_vKu6^FS`Zx&y%ysA zwdC>qq>#2$A~W>CbgKIt1fP!s$xAcy5h?rrhrAG_{^1~%r~CO_rJ@|NPlc5GxM5cV ziVq>b<5h|fJHfI2*mOJMwoRlk)D5$|ThlzK6VNxWV>WO;giHSuGpgSER#dTfJ=v** zdxfGzoM9&p=?f@~);mDK4)y}uk**AB4XFX-`TDU3uY9Kks$;||yQ`@FUcw@S9C zdSBZ!D5{yY|Is;nw>y^o97X5_aBWqWgfiIW|SepR@n{m*Wr2O9L=(N@EdFJew;iVx-=_lY*} zEfUf?(PW_|*MsQ)j4LC`?}ZMf@RJF(-)ci+9wgr`k>JS*w(&0<8&PG8n-lvw#XTkR%u5*Sa5HA%iY zbvkOQGG_a!i^Uf=@Hn=|CT#_;q`BzHxn=he!IO?$Wd#j6#HzLuAN~rJC1&7?-pOS< zv+Q~zUaGc*7Fneu@V_tRD-M70SJXR21-5l&UL%~*%C##Lw7RyB_P^a@n^}^$w7xcM z)Ue<8BM|$kKQ7^&&kQ;{&LLLEEk)KJzF^mPfsv5^BW5+{UcB%9!JA=+kd)GW-Ei)` z*xFt4-l39771M^zP=xZ*d#!YZ7s&OJ&rzmvL1Cc_#RM-JB&X-NPlqC)mP^pFatql@ zn&f?XlH0NPCPOgF+w#!Y=5bEFR;)RV*d3Q-%~s~6_-9S|48eL-GUss{{>?(Qv5j5XO{>rHWo%sOml7wQ(xR}#im|Qr zBIzTFovA7@&ne}PlBv`J^YhKW@5wtrOg)Eo8oRr+1V3u3obGt*aBIvQ?;_fltWX_i zfYt5cG-^U$=i)rst$*m+-p`GArqrb3OySJXq&P`@yV4@{c!pbJUw)IydbqRdvUXTi z+Omgc75W<7!{SjkH(gZ+THB^%Xvy^cJLCT`T>j292Qi~;Arw(huUtrJ90qP@@G8K6uc=EJppA6zb zHrWi>-z&L250S(3I1drq>W7_CQhglW)pii(`kCXV0j|>Y;D~dn{)#J}g(SL34uDdL zNSi&pm|#ig>naAzLSZ9&7{ii-4^fTs&_;#aop6%7nP6E%RnX^-4{4t}zH&*yy;|>* zN>!dX|2;BtRkibXyn3lBhWTTY7q{fd#bs0pWtqhK)cMv3t#wMVo!nPkI_}%v+dL<+ zoZK1vS6nRXd0FRvIo0*HIe~r$M@v)Nu+qJkfqL9W#(eHgRZxr7SdVOC-YNoqNw1}e zSd&q1SfkUOa3O3De6fF3Qj=%-4~%kQMe?yb6;gN5%3x)^s!5lU%RTebP0}#&_A91y ztYesP5O2#)1EpuT0T0#v{6y&P#z?yNhcOi&v(**enz@~KdCjG%-EIO+uhbt1<1I_V zB}!`E7uFUxA6F&uc&t(Eq+j*Kor9Pzd0VRSEn*zBQH+#lj4zi~wF73M z8Jn$AR~e?7m&?iF^L6WoNAii}Gv4>Av0Eni`V10JXO+Cyvd5}cFXUa<2$SqF zt)~&qsNM_eBF&xntk2Hb+wD&b5iCLW9oTx+vj6HpLu)!n^S@E4PbM@}I%UN>byMlU zFAFfopQ*>J0#5}ScBA6xd=m-W)z!B)curbrD;5%XbB7&mxnlSWTIxImo6P%j@WNYd zY)8VPVqET53Tla(@)a@mb6tPS6SV`y&uX!bz#Q7{?aoq01oEUT@0ZOYU5NOR7*TM* z@={uP(Y>d$dxTM#WC~6EMi<}!`7Gzan2*@`LW#B6U@|%T%jBz!^+cGhM?qoBvIvP#!5qeD)g0E6vkH=ujXj&)tU`c03E5UHMukyjGdkv zsEG*O-q~2=J0=zQ)fX6a4;#qm=yu_q8po^kdR>j_SIb>Dwsol={H8y*1w}JJSl3)< z((l8t)N}Wf0rf()Hf;24cK4u8k+uY{Wr)iuhKR3({}+x<=`xt|vxXPvThAWBfu7OM6mPRb8K1`_*huUl*Otdf1fW zS!l&wVDjdA)1%+ZT;$ zPFqq#Xtc;aZ?4huJTA0)&T+e9`FG*q#Gan8w`Z}TCT*&azL7$)fCwcFrg6zXq2Ou! zWp-as&`**56H>*$lq=GENFb=_y|3MbV@c3azn8bStvs7F@l@I*TbxbYyEq@5p`4** z`!m>zpB)!Db~N})Ic1pBlqZHY*#$n`uqEH*`zM%U9p&GmlCV}-*kYw#C@(W3-&u=4 zQn2~Dg~+O3MLO88y{{u2>A(jq!Vs_Ftu0Df25$CtV92!9$ioVHz@*%gYO6RWTPGRf ze3i3q$vWJ?CgRqF(qHv#brK@r1Z4ktCv6%g=is14M?h^omzqx(LRn%LvM0ATQY|lf z9o1&#>e~A9TCUF&3kxSV*8TURcBM;H>T1RVv6N$uv%@nR?|SIqwV^WEE^h$;&s3QR z8DFVN0EsBFv^G{~Ru#xvq_;G;BUA!;E^{~mu9StpfJj!72@XE^ z+48pXfIAhbfqKm%VPP(7oWF?QcN=jp&S?TKlykS~0?{x;zi}LL9u7wl`VThlo$|loYNdtJU6QxnDyn~ zi{rI>NwzeSJ~RzK-|?`W*AS4{qjlKnIu?%sHApp|VH928CgVK5Uv{Gk_5%B4)x=A` zRZw}nk9v0`UZOI%-2ggctU_6*Z3wdhGXC;G|J3+=gY)e#v9)z!|- z!G`U&hZhi?+XOpSWs;YP2|38i>{NCY&alVlJG-zK{KzWq?KmJ5|Bp6Z#dZw^PZW+JTFSqWCgflA%F{>5KoHS1q9(C=2cg@AXusc1k{Ix1GlDZ%dN9;MgxB?vGEjM?E5{wCrfi@>5)!D>IaKgL+laq`tne`Fi&ES zCj)k^98R{zXzQ65V&umhqNGOD=9WkAZ7eEN_ZNqm zA1C#LjSezj*P_CnvTclQo+(QN;9%5!WKJd&R#sBpEONAlv|qy??9d zLzzK0xM42Lp+@EYZZ;!ZFr)4wi_n)=m0Jqe)v$^ZUYb?2dIseODpH?BI&0Y-J{@fT zM+|)6@NCNzY?$aUW<8Bue?Ys(W$Hq~)iWv<7{sd;ak(gz%*I!?I3oKJ7eXS}ow@sp z#oj2$uwJ~#bbjaV#p%fx^lypt%=-cCf<3&Jj9mJy5d3%i&o`;_x+42^5?^`4JUp1` zf!hxGX(v)exBI)Sp;#zozQ_H9;bPVU)HkS~Fo%Xo?Kt7|TVQf2GFB6r+#17$vth&xHnWBBfMmB zOImgC?`y_Z8LjDOvjvsHFm$$bMrcN-9o1v_WIL{XcF*FdOB&wv>5NQJ%<-j|bT%{A z%#PLSXl}?D_Pf3n-Lc4>Q4#+Ovp7O|{TYY+D5_CwMazWApr0<)%4>|!yxVeVG$Q9$ z-x$%~VZ~Nu4{b7~4WZG|H*r1LF=^Yh+mvY3IL_=K+pt_9_UszWD}aCV1L`=HrWZat zb;3gf2jg+PgrcGo-teN}Wvj=xtg7WTC>S=F$`d)Cwj4SROe`T~HdF3&ZLvtPbhhseL4E5FH#{*yiQL)XAeZ1JxPIP{?{U?MN~WGEo=v+tPmyaf_6?RjOEOfFC9SqLzmh@~ zSUi(N25q>MYCAlyDaY>ArvDBIQ?;u;MC^74X2Z~yq2{Dqce~IiMps0N1IDNgK6XoNGlxmu1U1DshzK3n1RjbZmEQ&E( zYA+HPe4ThwRJ2n5j}|I0@^U_;*lxL+?jKZtZc)qPbVqgJHK9p#Y% zOK*_c_j-2Y&t3VklMmE9K%;M#E{oDNFA)@u9bbSHj4#C=k29D;bfYmVL`Zj9T-WJ1 zDj0zygvT);MvI*TKXIhu>_@+w%X2g+EP}>Aw6_hsAJ7OnLNN879!WIIU^)C}`Ttfh z^|;HMOMMiZvy!DSQqRvR8@xL|?-o4db?PN)am~ziF@z|KjzR)&_0ELjQe<6pwuAg1 z`U|9=uwBs|o$on+IEe`&f07!)?R$dUpfO;VKKo5c??%jbwHHK3AGCVt_*r^XrN{k2l|nAxXD2%Q>_m}Bhs&~M^-THx7KM|6w1$}RYY z^E1>xIOMZ6kTGMAj4;j~E@#V^vh4S-%x9kX z%nov-pyjUhac9pP3H+^YDTj<9@uH;&F-&M2YnhuN6sr;?StKJMDewjmU}AaG9X{`M z(4=F>jp*!d8iPA`-C?<@*FB86?(*H z_&RZ~Pz?i8j#LQ2!g4Ad^#iCqPw+If}#wW8`Kn+=Qs z_7ETYEjKw6j;?6q^$x!T-p{qL87NDAe1G0tLw^#>%X-g#49)tSozcM}dzI! zUN6%(b12r=9J*4c2^6G=tfTodDuvfi(HNk|{)@9c5SYz8bYc}$41+wW{H-lWZe0b{ zvs=@|M0&fKjkQ*AlA<5;B^OiFnk!#d7u?h+sk}P|*yN0f{ zZ;RlMJ6$evTHSh`+Q^#Vj&B5|e()%L++*vmO^h#>@vNPTmT}v9zw@pqg~Os~ERjSW z7@{_aHqKxpJ|J4VgF824x5i{w#4pGl%A&;*N=y{WgATDpUoUnUpUJI!zP6^bt58g8 z!k-MbjPit6J9nE<;J19FlF^NQ#SZqfUH{reTj&XfS&p!RVTWhau9vE*RW>g<=R`OA z+&f9>;JaO<%3xW!3SB+9BU$5Spf*IiIamELKHl)tR@5+k^-NytvY*{9cwmnm(q3BJ zC^~EIghSN>I{x8X%6SS6&dRY4`j}WQ>#`mb^W|G9O-weWPMGHgN?YF%hIe# zF_3b%ROZ{=E(_dG z676$Yk$qFAKJAz&6v!+Z$yYYU#Mivko}^4Qc85SI`yiILc(&KBlQ4D;zIe-8-MwOP zZ>n+2v##{5n?pCF$H}Jc8UwBPjm|4lWiVkXvV+&YIerOBMS;DrkDUiSx%ONJkNEF8PfDe(dKMb8-E7sf(!7C{)RGRe-jRtxZRLSo1Kn*RVs%|wr2p@n30ieCN;Ih7 zlTd3BG_G4baR!Vxq&yRxYU<|SJ~WFKl|?C3+BcqE-`IAr}-;RLduQ4 z>uPa{&@^_q`Z7q^nMqc{$7 zucgj!vOlA;%x|nudX+ZRh9)KW>s&pX>y9shti(?vX}8?(?IFOK%v7vKFmeUo?IdLB zgsxeFya^y|?lBfEPSi_E@HUcmj22iR}xyO zp|Ln(O9GWR`LYnX=mfxs93O5Y=sfAv@)X*_Ww?0j^K8Lq78aTho_|lT*zO;|Kh?R& zZ9jmrM>MeulpvLzoMIPa%7B^5Q+iOp9?{68?Um)h($|( zdro@l(GAMH#7II2MRgvZ z7n4`$UW8r>++|2}(%jP&#}ov)BOy8=h|S)Fc3yOCJE(%>@mu)hm>jMUM1+&FH#o4L zYXlt(>++e`yyvr68emnm8Vk}taV#xpPph6mPVMR}{h1i^pLW6d_Y&2617keAN6=7RYblQZ`|oz8ympe(U<&u`sgleAALcBOI!aUK zeD!UjFmCMyRIgM1dw$qkgC+M1;jjWc*M3?K{9v7clC!tNSz-930)+tHtm@+)-EwZu z3n|RNL#QZp?(3FH&%8R=(klt=FA(Tn8zTS}OjEH6wAWI>u)g0UaK}6Wx^pDNI2&k= zW@3kx_J~+Lph`H&zw8Tqf)#C?#862TddLxxpeYte{IG*ujXDAF>R@+NB@d9Er`5Ym zV4Xaf%RqnqbW^Xjvp`B`iH)ir&3}z*F9QulgFJ4_kJ>=8WNo|)cLmM# zk9FM4weu7DL)v-O>Qx`SbJWPoBoHflHz1834Ww(dLZt%f1yDSKKMJ8)z{8DAyo(Lr zGIGsBHyc*PoiqDy7flpWO{|#+40+kqwu4PS$$^qkemB3`PtBQR^u3=!tV!sx}x?F>6gsl_o z_!8g@A&>7H(Vi(90ZQhqS`qZ#Pgo*Fz<-S6*}vG?gCi*^K+$X$?eC%i?2&=Ce}!VR zo#ly|?ZTLDH?d}e)PZ-}!eV|S)_uWCH8{}{|r^E8QrQVX*z(sDd1I(*|%e76Md$Y%0 z%LN$2dYAjF*{|}Zgo5rTClYyJ>|I+ZlXbl@W)n`-P8+|QT9l1go zS>shbzq@^&haKY?ahAc|>I3 zpd>;OI_@|S$5w=Sm?U-SqkpjNgfPVYI3cXaTPkoKyPqN(+k?3`(dC@#Oa4}}Zf$ji zDi&t@{B}w@uhd)^V;$gPxa&9WY!z~EDCmbAJW~M-d@rWMCDvGy*9^jjh`A^K3?MkQ z=;Lc_j}zR=Wf%CE3P2|%xAt#;0E&AOPa29(!l8&$8O`E8%JUx%YTY^WPWQf`YS!s= zV}uTjnAa;<*%pZ{E(bz$i%RYB3huscKoNQfH3xv<;HK52sdFi{dJjM@lGHAFAj-;}I5wdUyC>c-ANA z3&9=_O@xPlI9W~3)N=>-7OIVv*Y4x%&XHqdzcgO4T1*zYcp_y2+6-M4H{{lJey_+s zZ|*o9E>R2uwmd?B$4rT%yXtPK$k?Qz@S18?DItziOfaMw2)?_9>|F;&4*!=* zrY6%9|1%d?QZc`$&^!`yqmY43>JC*yv`TtINyWrTx!n;Qt(41wl-+^B+L|zB&7}#z z5FU8CG&Xwp-taKufm9+=3P7HeTZpP(+*N`S z3eZw7HwH_!y`mS<-8U11>N~OI-r#_K=|-8v)^B0#mSF*BS@bQP#ab3Fjufw{FX!b= zVdF5|g>G_WCxt9<;BqbGNZdG|^?>N7^;o>L;a^(M4);z6$$?Oq{$OY*I|<4+5>eB; zS2R6iqDdeO*g7+mX0v-7$u#}HkT+jbI@FU+2f-zR6C*d$9~1`t)_qCHA5?8NTq%fo zNx~CRXzHi6cs@`6F%o*gI8R@P8r}99kq|S6S|vYxd8#`%vY_Qc8PXl`#Xt4Y3wYg) zvD^#Lo=8SK?mbeGx)*lF+0pQkkhA?ack*J5%i>Yi)@_Txz=mP-y^|k~*L*z1nT??p zKp-7+7+d$K#1fb3W)kvqn?OSAetZat^`SyCTjgo{ziaN_+>-p6)yx1cZE8bf9#50z z7p#yXU#94{*_>KR+}SCr@A#6W;|0d-3HdmriTZ!6oaUPd&g!!jacr%#?m!+`crcw`nCyldSQjZ#Pj4B*M}n(w3w(s;NEgX^HhkFnI3d@8 ztMTFzje@Q6GG2|)9{nS;UO({gd+pQZiJE_8-vme)OEdl}?Hwwmvde$`-_{6|ft87y zCE_2kLSSn%SWBOO(S3=b4gh?)@6Qz9N4Xr%{*bHNb}##M6nitU-6r?=l5T2MZbJ-A@fp*9>qlGdd#H=NTH+pUZ zZmhqLknHOY2;lY>ZEYunYO749ddAq;YKQ52Oy*AWe4Z7m>3F(8HYBcpCldZ%1-^x` zBT%Yc@Y+9(yA*Y%fJAEWX{e-NULOE6fcW;1j)Yl;S7N!TRZO?67q8pFetcRp=kBm*a*X{;4NxvX1 zbe1>ixRPPE8Z`$MBSRQd7WHw)JC84GteKB$)Edx{uqJwP=~s7( zjN2oE?WpShR$d#dk^Sz}g46$Td00f>DDQmy6CrsUYY)i8r0sK^Ax*YV-t%nOWTQ+l zdo>c2kS4HOa7D|=fOu)|ytGz7H%PKa<@w5u`q9}8+K_X5o2+>&U}ayGd>d&(De2AT z|A)VoB6)aI;)Hl^LUb3bV&JTj@7&%;NA9|m;SJsE81_iitNz7PngGMbnotl`XeXu= zcjEMm|7jeldU($RFD~Qt3;n;O`Rpg};eOTF^xJk7H6eqSH->E7GoLEPf*y{i?tEuY z3j8J3)!7P>jL_V|R1l9UQ&Bx8D4Jn*R0-(o$vHTwI(}Z+MNOGRr{tFA_u{4j$A8!u z3x8qufWd)Er!LWd`KEya6hI*R@vA`T^g^PlQ(6bq{JDV2V@9p0f5=?gIhwfBk-ct& z*``pd07Ys6Q{-xi`AND%=<#;0Z1391SDjZJ3t-fPG_0#!`?KL!mQhkKP1-rw>`eTj z%4~Rii)CXSa1qaGz^&~6-QC8t5=Fn8>SvNoOK1U@n76dI3zC-Dc>B_L=!<*uKnbbc_!(+b~Gh`TV zW2vVvBrt7Bf6#ejpQIQ|R}%~Ug4DS`w3|JTF@O4xaHfl=LHm=Gz$vT?yps_b%scI} zEc|rGBE^?0qMa9r5o$&LtlXu`Kpz(oCbIFQ`(f-MjQ;6ZWJ`9RY?f<8>~J-plBo>t zHAEryD*EwR!8Kn>{kj-mKzC==PV$r-oU*WalfrtR3rw)86>>vFM6SaC* zt#~uhT1>T_o76KE-eyCEX$VlPdE=cl{I8Tmpytf_1C5}!0Ihf;RiWiZM_S$mk5qCZhPjm3#0aylt( zGyE3xx&H_&vi|k<+N)dQ&In>BO}*p3yeQQAat5wXl{>;~`+Qd1IwgZnrPc}A>P3cb zBL@zcWQ~%t4|wd}_@Y`HDr%;ohpU%N@qcWl$cq0I92YITk~XF+LtG)mHxF)UjOgH0 zn+4e%Ni29Ma()(}qhwZ;I?fSL&rfyFIloi?G1Km5iB_6k>S|IeX4*>p0aoAGk2DLY z2i$6XPA$b#3ucAHm`hRdRn;Cx1K>N)#npHZxXtVO!QPYGA_`^z2V^!x^fya_Ox zJyIWnm+GoaG%h}?+sP|pekGDtL8vKrh@w{}cz1X{X(xAv8#JTRR40t=ajqmv=^Yk7 zGEHEhzfdRnKD|vRaMPSHZZ(73N{lBsO|zD&coE+!3D&3kH8-)vR zj8ZOf&!foViRO4XukYMDqU4+}P(c|q-E%Q>WT3lG;Qmes*8S3L1eOaB+CRCb5|E5b-HR8eUDYVdUI-4l zN40aR-VYm%WiO*L2{~L-dDgYXcYHf7`TUcXdh4^55x~EU@Yr69(2D*st}fBH$;nP# z)6Q#KA2~vHaKd_AkOnXBTDM$%@R(X28730w3e_1*)*9%rdcy5#9C#f1oa~GB_bg`- z5AJhXPBxe(Yr2FkR&XTBORH!g62JBBw?J%}@yy;BNczhc3zqi*w`f|UWR_n{rk8ME zYxl{o+yo}klKW!~4$5q2;@W#MxC^^_l~kWCVa>NElcPkQHIj0OTSr$n;i)2V`c1U7 z+kDQjU9=by&3=(f(>^72{cN5}6ym=>`mhRnfN#uZRz9iiG33$5sUw!^^Jg%s9pxAu zc#In3O`)!7lBMfbNHCg5yer$NA4u|w?s(|vZ`VgMW?pl~@;>NKVgy?3Dhk-C_X(@XAW69!p#Vu1<>lb^at6{(ysyp> z4YX_?oLX+%JV_~kC87iV^B%kuKk&<7=2NH-6BOiUqXi}$l!t1t<|~xd+(SpO%?{p8 z;eb8cvbw`UKs=*BfKLtVc@BGtHRkp{3DwVwAvW*BaWG|4_ew>|zwB`1osAeBVp&$* zJ{nnT0woyCnW|ze)A@8Me=Ta7-H&B>ivZ*YvHfE|VvnjAZnDb4k^J39C+4$c6Ea-S zX1&p~46{yGz;mf8-)ugQj21z^GlOIt_uiA-E3l;PV@Aax*$1!3EGW zov32aZAp?%7$;~n8BSv8cX>t||Ga!M-NE)g!U}I++U%9S1hzk1+jiyT;bR(!FaGs4 z)T?5B5-De(`C-nvuiMpQsqg2$o>LG)qV_p%v3Z-?p}gdhN*(?3H-32sLzoHPP~T6~ zzg({uf0&{_+_Z&;uIqpqIa&_(WR@joR4#+e=^-qo7+p~TH2VZ#m)Tk&#K-P7DHbUa3C_ypr%-7_SDA}3eZrJB<^7a8Gw6Z=Oe%i`ZnkWvGhn;Cx91avqo%r4%U2~fhivrONsU;@_;1H5~0bF7~n`4@i?qk~) zZ6Cj^Jeq+Gr6f0{4>%FCvDKDFR^U$=)kJG(Ry9FmbY3QIuPAz`_jkj4`zO*S>-XK; z7VKflI(|e!q3ZYG7Zt`p!a&(0Lv=52NA}54|K!zEAEx%A)O@`=X)B7$$7oAzW&3lv3WNn5Y!D; z`GHR+XiX;Dw7c@)sc@wRU-U@Hed`)UK*apJZGNpU>T_!;GdWCI{g%}` zanWoiM2y_)5Otru$uT^^-4r3D`LzTUhkmYfYU?Lue*^}CZ$Lv+s?$Jp?upK zyqM#tLh|2scH;0rY0sj(^qXe)s2KCVLAIzem!G)MkV_!j7nAzkqg>kHG>Y%G`g@0c zqFu$2ISAZ1eajMbkMEW$OCVhd&|qHS-f}J1WNx#*a(U9=n<&?*;)uqB@cAAXTYQ%X z`UP^<26g*$8MFnfhqY$>FxwNzlZfJpauka7Jv?&sU>7inW}+x6B9ki{dxW8(lfl$7 zY|vFXTOC&l;kJo{%qyz5&O`8?iDCU9+ zH+Xiloj_I;%yT^mn$VJ45l$I6sOK9_IM+3PbOSIr^3S3Su50|GE-k1qv30LTLBFxV z*rHgfGQPjS&eV6!!BWIEN6Twj-wR>px?P@RErEJ|@!~YdRn~iA<#cm1V{UJ@E|GpJ z$%&Zto5_Sj!AcW?g*c0-fKHQWx5m0}>%O0?p38)?zpUfYCj&W&ve*T?&PR6~Hcq+I z?*5t!0i41|tf&o!@W!a1Wp6)M@v?hQbYx$fMr1JeMTL`osv$55KgeJkrOy z+a`_CD+pg@Jz>-1_~AG#P9sY&{Lu~V%P=e}jkA;{=|MBW9SL8~xO1}pBJX}eGr?aS zev(a??1CZ{mpKur8)>Rl+orQ{ozY?yxwdsKCa5W~;UBxRGh+91VOi#w+Jtc#m zWu#yH%}MmliqcJLED5<3*wfGe~`R-1nmiL{D!)3@4rwkSnPM)P{&9OP&mblQXV;(Uv^Q#kju+TW!=oamhH2lv9o+PqBsK`_XAxGU>i;`HgF58a@~qe1{OYjm z^^_Hg9UQsUzW>hy#gUDe9|{vsB!1DK{v9t3r)UfcUDW@f}%EesdA)_mlR6 zOCND_5P!TG;ktN-M460o;+J3wblJ(vncDI-wm!mN$Dg*JoBh)H;2lEIJ;OvMkjg%L z$!yiansrEM$$|@(`>bnV4BF-u<2+Wx=sJwh_pL64+0uO&IgBiikgk%^S>Hj&S9qRo z5^&Jfpk8CN)*qp?D~37P$ydzkordR&eu4u=JsP2}-q)9zZBee*l!fWVfH}+p4{=OY zJ@;u}x-cJ7(eTP>Uq;ilSS=JiRWqssUZ)%JJF_YJooM0Q@JdTfaN=>$H4J*Ko6O?L zM;Mu|(o?n>I)W?cz-TFt%X$Rd>WfnuDox374E#=ybEi{IP2Kd*d?TrH!e5OjY;4Tu zBAW3@-qbI}$+f&a-l3fFqLPLXLd`83*mmPVEp{$FbQ<-U(U`;s>I9qlJvO(q@}47o zc6vmIq~Xe_T!h-^Z44NgPSub4?BCPR7C3d3{l3hzF)FU9hEk^Et5z;56nk zeJ7g6eAgTBGaC3%jz5O;|D%1|ktnk-;>+c6p(Js+x&{|&fZXG>sa!6sGF%SM39KcQ zdA?@lVI^h6W*{+4ZV=Pi{`)4y*l8xSisR7f$%&f0K|eX)W5$)W$Z67u7ZM>_pPTN) zCcnZ5bV&V(?{fbSrs=~MU{kJ-&nSBTNs2lCz|acds}JK;P*4=(_;a&6AK^!w8dys|YhAv*^s z0dtm-|4#tv;R~Q)O6mnAH6fiE9{bt?fI6zP9=NX@{^C2(zdr}P=$&ZNE8Dn3(3d-V zp{*1j;@9)lKZ-TruZd#jDuXPh+ZJGSVDM@1XrE<(7DEG9qbg->U*?eX72O_fy>do4wH^2oNl3euuHK{7)3pi=`W~C8N))f3uHXez;BZ zTj^e_Rav~(j7jq~M1OJcub7fX?rQFDJnyqZOUplEvV8#R?sf|uh`;!~i=naF)y4K+ z>+q<>(%l!Sp9Vd2fhNq0`oo%bC|(}?e*r~-r4Z-u;knT8UN8{Fk&3xdQ)}2lijUE|Ai{E{pun%Mv^T@EB9EBlL#$0+t}83JO5d z(A*XLU-+N@?Y~|93WmaB%PWZ&nVUZ9321cuWoMbg}@CG zl&o;6190?7RWM6^V+I6vfu=+BUyVHgZ3BR$RQ^Aya51ld|KIYiRYV3bi|_=Y(Oim4 zaZO(4Zlt$y>dz48#ecE@SjV!pw0I3M zvLenij}k=#AU|O!`(~r>{o5ll4r>J+R3oKGzzcfQw({Xer-y?0T5yNus4nVF zKc)Y8k}L&_5Zjw)cu} z3Ax+;+26lcstT~6Hym8`O`HXdZb(p(Vn$qHtd%tjZUCg8Z?(;3e631sL9o^f5-3Vj zTaFPg$CYSXUbbBKrTCDo%~Qz?pN_aFvOLXC^~>=)Skp{AKPF?m+|w*BXHVk?p^Ris zy}u2l94U8O|K$+HYj8*x->}>qE80hTMrn&|Ncykd@Br(qnIGK&-kC;U9ov%>*C=nA z$VC8k@uQ-MZKKgY7Phy3hIVD@~uUofF9t z!x}ZUU!!I3Tbw|q0t{=<-<$`=ZIWcy_b)(q3xn+3reF9htz8q6NN~f3q;~Fa&Ysb8 zqk*m_rQs_o$(9Ni&7aHFz?bLY4pz25>3M(^=bO-PpKonx$GsxIYBG{JoaZw!;lxw8 z6^^~(cwIAt{k}_`&pdVGbLvs8a;z`j)OPhqb$h-stDG_O6F1T*Z2j^l!OZa6wQsu& znDcqJXk*~uo9l16s4MsoQ>k@g>rxn+?>4mR2kBaWZm^V1AM>WDw^85oD;^etn{cZV z-f@M@Pnqt;cJ(Fj@d-*v8-b8zY*^J|-@faG%T8>f&5G|^prm0dyXSuz@~pn9p)_ED z{PkiUlkM9eJ3HIq`-bKb`n@G1-B0ZEN$V=l@>5B<17yzX0WfLv8(g;n01akch)^+G z{S+1WIn0Hnfg-YLdHo>Fw{N#WJ3hn-#y*I|faH#9Ket{mc6@mI_!($7xWZ{fbZEed zb)2U6m5(YLvRhKF&mE|Y{3jdh2>-v>SVP@^iYgTQ*KO%JY4tTej;{T^?0v3_ zcQ>p)x&O=Ri)(+`dOUc`5})XHjH&Jw7sI4OuJwa%A8pZ*y!JoI4{7oK+PCrhZ7bNo zdM+1OeX8z%Hj0}z|K@E(teF>^kJHdm-=r+OMDA$!@F3sRr%}K1Ez+qb zav)7Jr!}jc_d!RQ`fSj(JFtPDN^$#A)>OTq? zz$AFTCwfyOMZa7ZH+cJ5+27eM^j&^T}* z7^(C^y!*}~2ZzmjiUf){_??;!OvCQc@D)sz80!wO2?lfj-zU*LK;H+rf*x}M9S6V~ z2L#Q3?0Is(wEiEW-ZH8UE?C*mLwP4Gz z*&i1Rf@-EMlN`Ac_d2^>gmyXc$R>iLJ8=4784g!ZUnfj0D#bDUQ1zCl)U8^jjB^9R+I%6MR?tHRwhj zTtdz}OTNwfEA&eBmC{&V!%`Y4`)8J#hAYWi z-}DZPbrNv~pL-Hki-3tdZ6T!AdO97ZSSMk2qs|~%h;a=PV*-5>P&)HO&d*5UgaJG=LXcxA(F2uUG-uVf2(5$ohvgghL z(kR)Z)qfIeCNn^$MS4Rm>RuU2DJ8Kf`QtsyXR7DmF^i2Sxmwj5v$TI4ynb?vCnPZU zbUP-$5vd1os%`nnQ;=BIoEaZWOrX{C&MhQ|#p?wL^T_npP7__J{T7Y`vJ0^9U$aN8 zs%dH5A4Pkqd)KI1NE5O_>X!uS>ZOh~l_ejR#BC_i;2Y76wq^|bf1SSnCbbAS?)*mw zO1v7^>P~}Ue809S*3$yAI)6=eDScd5`gT4g#H)l@=e@g`LBi?tGMfMLle3pUT~~GU zp11e0U7etL1pR|OTI%IlR>ty-k zMvILgPfqy5an;Q(&4~@mpXVf42Y98M8~eHN0VFZ#B~U40wV_UVhCrzQa>0fJsZ1yC zE2P=hx(Byji6Q9W$TE3T)3MIQ{REgsm*pSvQGdPP4>&7d_@y*Qo!TplLP5<+>dx@z zLBrkfxQcZLevr!{()p@$4-3p*FF9?e@*iF5V2RBvv2cUN|G}j;cSqQd7x{{|Zu0v? z%xJh85tT9h$wS5!hQ33ZphW%w$D_CmH~*^=r}kaZ!yuO7^J=(`8qdLKVasJqslp2L zb*k!v@DOnG@(vWwR%IPxGRZJ84h0_1AlX54W@SspLBAIIPLa(A6C?4xF??HnLFt|a z>*sgt>bg}Yi28K`)x0I#d?EOwh9wg9lj6FVS;&saYKe{ATX<5ze3s6Lgk3I37G>vXeAt~X$$x*fsqr6kYuWaH znOiZBZd}a;>s=TmBcXF#`+u>HrY~#vO}M(z4kt!h<7##2SWSEQteOkZRDbwFv5sxW zP4}Yu#lHRy84*(hi>%r;uaUsTPwkNP$TWD$PriN^{WSdXJpDX2)3D2fMTJ_`3p(w1 z-Ru;N!9>EOQ+ECBX`NrL(KDkEVhz`@?}4| zDe2VzBe4~Rbudq+bKGivEN~auvHV7|1%f<|=joJlJs%9ql7vGWOVsY_G^fr~Lu#~? zTcWrTS#sp_kh9YKG*|yg;dOM8`%$k=_{CGdOuARDSy1cQqZuZog5j%?Zs{e9j~x(> z&pwCj06~%guK$6(v?}su`E>1rHfd_o@E6F)<(vMld=(Bu!resFFZ_^%OIDHp1-yCH zBwi!?1jdWF5Zs?R7vNu&^xV~OYDeo%9j+GLs;rvTFr*tS^7nxCgH80sGZNRFHJ_>o8^FUSz@jP@aQT@k=@#Y5fDad)l9k(Z zjXR0GdWDaRNPdOFZW(_|OPq@DQORI!Y5Xcsifu? zA(A>*B-#B~d6m}4#-{*rN_QG=no(VIr0cbFSV5v1d4pPL_i#PU(z!GX&sIaY;>kRy zI;I%ZZgpKZtrPDj&kEDEq^}xIhK`!IOHT*Nico8ooZFxe;x3*$5Z%nZ>Gg0)4d~qi zP)%qsHnDKX|Jy6!YM!vN*7wfJ5Au@|dK@=kW^iJ5K&x|#uuD*wzG+$_btI>qyT^{<|;8w_D`!}WTT!6dHkX%y#{+FATBxQ*a} z&J*kIpr&Z$c^l1xdT}1lk^gB##g`)+j`LT)1b#d+Az`%#{+D5UFeA_BU9n#z_QA>O zOSHL5*mn{Mu6#AwMe0wPm)7%|R0Wm(N2oSyzvuqKZI(9`Yw{zsP>5=!O!owT>;5J` z$KsZR%$J8#LDarHbpEIosgq`4-ZfwH;<+wyYqxMexC^+o0V!K!^henLdCl2e{`VlG zpKy8CQLP0t!n4EC(;|(nKoli~tJuEsFnRB>X};*$y8L+z0-7wx5^it?hYC)J7?Ypn z1D(Ed8iYz3pObXcC5zX_tA0G(75f;5V>=2R9q}s=ud7lgTVGBTNG2;{seI5?K08(A{}*JK)2k(Z%n7oE8Bgv>FhTg4^wN>2#EDtrF~K6 zmnhR~(&mD^)$ku!&**PorPWOtrr!~drC2}(tFbUvK?}C=t6-oJW+ zjx^uZ?&10$PKPVeW>}5CqjO53@w;}W6=W_mUEj`1j4uTDi2ENG>eF24vX!5rp*5A7L#*EO~FGNqGL`+KFcD1qcap z(qtw~`Mx9io<5Y1)10nd3f;-e0qZ*grEL7im4Ex>~S@QPwIf;O6tJ=gI3#jdc&|)cNUe z=6#irh?V)*aYr>%wD~QKh+xm(<|@qDU+}OT0mm~9BgHmc`F919ARJjc9!i%~IKtaR z->^r`6<7uhhvzG9`|vtz#2eoHn8#40!BCrYC$SH>Ay~Aa=Jw25bX2c0wD6O9Mp|m? z?oxsBY4QkQfN8DDU7#O6zbF<{Wma&zDb~@B8%a$)dFiRX7*vk4Npg{ourhE)w!UmK zKMz#D!}Ku(skum&`sXF4&@!72O&59i(3D_4)jE#+2|Eq*w zc9GyA2rLoUw@AKhXJhd8{m5|L4qWe#9Iv|2-o|2;lCIj_=M0^XQhV1`A?OAM`^;kE zcj7yB7FSo?lz&`i$Sn4IK(YEyx5=Udzw~}MX7xLJ1b8DV{qUDhyaFFS^2LJgJgmG1 zY8<+A&GubR_g)Kg6@k;-3^V@YMNJ~P*u(y83W9%?6y1G~M+OWkKb(oV=cjfVO8JR4 zc);@9Uq*Q?rDQif^RW9=k$9Dd=y?dVZ0&qecyt&`*IK*KWe|>xtzwc2#+D0fw}#e| z%sEp9GvLE7B%|C!9Rr!^xF`jPgK~(TOOTCY-JHApLWty(4BLff?Ga1a(^2Pd57sB( zAD%9{ewwoQcg<5-UV0;ap9qha;1^$&oU!rly4L2hfAjY1nyfwtYNSI~!*uIZN|A9g zIXW0$>fngWvXN-hqkR1WBE$2OO~=D{*{rSnC-32j+4;zy2cAZoUtq0mQm6tYqly~10wi3ijdQ;MF2)2=6^H~=x0*hK$Mt$HBUCgHy z{Z}npYIXZa*kJNeY?!!&8sdY%{t3#kSmO6(Byd>(#i8YqGC#t$gHPs4=p-l!+iD)X z4x>?Kffvq;XQv=xftTo4oz)A+K(iTY<=do77wQjWF*e19Rli_qc1-?29zjH_4 zt~fN`5Bp#8+}VW4Uv)H5p< zMf%w@D#7opJdQ-Gb7H2uJFJJn8cln=3us=N$69?)`OhN3Izchj|FtZ*nuF{VhY%hnF>Kc*tCKotTG+ep4 z>`xB&r5+_xI`wsve~Z`%67wG*1Xo5f8$R!t9iI}j#Hu!tCmT&tA-<2o%M*f2=FB@&XUCv{ra5RKJ|gZe;y7f( zsdw*=2uxenvg^&eYYj4pxE$)Wg-yM0&BiN5=_1nGE;zIR|K3s~>iMLQ3t=;{{B ze1ztIz;T}IpcFNS9SVIZlb$$t<9G7MEm=EWJ@Z+AAvk(qK-`P8RG6k5-%az>RB~heWn?n#9S>HbmqpR%OWK z`8Wb1S5)I5rImEje}Iv1hyn6|cm;FY(X994lTv2{jp;H<&^W&ax+Su+U_uB;^JY-i zi3Ep7Sx>>WZX>r*MHRct*au^~Gl^y=JvxVEjegy<`T=0FQrUN!f&VCb5x~PwV&TXu zt*>2bYSuCd)3`->`H?SQKYnL=O7%kfrCYeer?+#i>Xquvz`ZGLGyo0x`k@db&70;n zICdRRj$VL&?C7asG$`K_C^Lyrl1gVnj6;f@eXfu3kNFT=7cUc;1c3*uiw|QU*LXmMmLrr7ApB#bbq?%B1o&szA4ncrj>u@?0Bg%6gm+oncqxZO3L-(No90nNTP*eB&6e~2 zqzp^=4oxi)7DTrABtv<)q4|?mUWM?y?dTYZz`_ls*o42KZP~MoY#e;p}Xb^5J zq+lfTgJ8LtqgObnI3^Q6d#1QW(?Rw748}}Drfsn36Gt@9+KRU(cqFVX$046s z%O8LtxpKQV_+k`jKZg11x2?5>=GzI&-IN#8e`%WDr2V+R$?yL-KfdV9P4=8~23Jl4 zU7zv{k7WEYZJvOis^ToQ)uX%=<&RIz&JWJ|wofD{gh9J3mU!K->(=FAM($x%;Q^V+ zl~2h3MGv|irg7&tI0K<;PUT<82h=pJL zSurzbtP6d%Ei?CVkR2zk!xy8jX`D927b8b|SF@#V`1qgc#rK|Y#xJ=h%oQ$!f|i$MR4adk;eE!zu0!_l*v&u94Bl3Ta|$*a12R+nkL7d=Vvr{ClDnif#pQxlh(}j3gm-WYwj-B!Os3@ z7AB5HojC&SH|qS0S!MhV8R*32yH15?HP&AhlkvwgCsgm3kua67=S4*nQMhtRN- zm4DU`!}Z^t$c-wDG!`T{O6Rh`;!kVm*Y_yoB3uhk{_C$0Ydte_-5zBBbf{SKO)BB4 zO#mR1r&+yDwS~jf$9?_BwepMOz+&t(*tQLx47=c!Oz=aUDZyFPV9vk<#>7^HG zMO;?+#_@V>g3Ktr7xu|E_^{}7IfgpFe;_Dk5X+$A8ft$hSrd&;HHV$y&5gU&{YJWH z$ovlFv?^ZF(sZ?<+8_b~7@b`L{;C1d+ps(0u2taMr+D1hITX26zZj%tAM6S@n4~4? zsW8JnHr1#0h0hP&o~&~lP}!jR`w0S)O?=~?`9HD`YPPyXQ1LP|%2p6pqzZc-za=d9 z91^s4#`LxHbbUub3;{(MMZ?|3bUCqgGBav#e0nA#lSyW)s^vKSqp;b0u`u6djtvZgO%AMZ4NFtJHnK z9<0g_gPe0=hq~SS2rh3#>2Qo{mBIj#R$B5&&#G^5Pi~{yNPKxBy*z`+#Lx%myA~R3 z0tL1V6lcqaR?6|QG(6s^;w5hY-g*f>r*b(h_kJ;h)Ir1XG%j%tb0>fBOW(__`J3!72K|f=d05rfsLr|fgg<1_O!ZSeL zhQ-ohiZ%n=z`AK#?py*#3x!=C<~L%5CTlfuUfNw$1>}iMExUomg&*>X+*^WSuD#;r zAQVkB1q0uorsmPya`=BtX#;l!{%Zd)D0w-wmq{?q4#v#Tf9}_+w05Ffpq39<(R+a) z)422grjbCf)NrRb6i5&8+{zZ8zeAs{MtFqR2$~o^OZ{}l*keZ6k9qtXW{r%1acDp>7-z;JC3aib7P+1qstP*Z8d%e?&Fgw>$8#;^=$hi?wjP_9JKU&sT#>2U$&l+ z4*I-n!RpYK(C;cP7a$!h3a6SKPV%VWNgVq1@s*z&ofH8@8ymDKjM)TD_(Nw&eSmY~Pe6u0Dkxw&zn%+?&e_zAMLjXdfV7YV;%`Dks-Vw7(L-@!ACzMo`xw%BnMonMIW zwE(0jeF30Bhc9eT)h$Odvq9dvsGfpaen0tsRP-3E#140@!XoVGoa0~2qFWeH<8azl zlN24JdAeo2-|-^)$mx(nh7W_;czM?I^kKjb6{|R;9eRgihfYwdSasWsKt zB9r-Z=>A^n#6eLqbphG@CM*~UyrmD~^P;%8!p)T?rGKxpLca4bettC|;G`gg!N)?s zC4oLxu1664CZvU^8_7MuA9rc`wUV#M&_epM;`312AyP82`?TD12U2z~=5(VwX!&=L zKRXEX1Dwwf+3#Vk!K`^A=%sH7*W`Ty^xAMh8l!>6C}iUXxS}>67l4sv8$QVm3g+|~ zIzIGm(#cre^FYHy)$f7lB&2rH>lF7d+N{!2kCC_p26k4TkC^;?Z%)_Gg>MK8=IWJx ziAX02RO7uxxXn#;3HZ|yLWPx!y^w#la?5LH7Q>k$ukdJ8ir?|u?hTpmEgfg!a);wO zijoJjKYk91X-dk74P&N;AddVYWSFbkmz3Ikv0N89)4zIZ7D=Piyj3GxaO^ge#!;gh zyKZzgn*iK_ir76yEx6;(^-Z%DVM8ySed*0cwnV1yM@%(e&?id@RzqX=mBWGF#zKiM zA3U*he=%D~8m!I@#^|U=tE$>zQ8?Afz){IDq=u5l2|`#jfH7dr7%tk&8eAXd zaWh|UVbvaa4)27cb=HM=(yUHm)asXS{x%uoMo6oBO>Dx-=ttPxk$W7x*)GwSj@;z* z57Jv94z5GluADQrU~kpYiv+9m-XqBPLBZ!nJTR?XX*Z)ryH8zll9k2QDm4v!Eqdcl z%qu(hA^~6xwu(a$iB*qF9r2r#$|o99KK)_|_f^+O_CDC^$RQ(PuPO&g_WfuWBedw+ zZ}y#L>o=WIfJx+O%v{sJp})OQ_t6JUob~b(7+z$rC~8%amsZ?Mxeu}Q4upYh&IH$b z-9wy9eqL9?KfVr;_N=r0()W6hWvsV-OHRG?S;nqWk>=4K?Z~wf&5dX6XH} z>MZx5rsX()fdcho!=1Bru`S9Me=GT61aGm367|1bYJE+^MvmO2YoC+EfnMf}KWrJj zTu1Sr+YVXXHkOTZ9OxZ3L+a*+Mw#?K zt~;Y%IcNHEM=2(>4BBre5k#J^Gqu6NVzgxnm2;sV9P6MlHP)t-aOk0oFxS+DOH7QZ zxuYuVOGGqZA*;Ud7#~>vI_6p;| zL4@&bE_!0C<4ZP$jnv>68E574ReWFX9K5Lpezf)9;S&;NmsB}N!kgV!_th5uv2Pjc zfRq-d?{NJ#I<#*2*LYW01y)id3r#dq2Ke1VSGX%KUxagEkU>#c8h5$Dc(9EByp-GR zst^BMCx}J*RvM`c`f-u*L#{m4XXSJMYAd%_;`ZUrj}EULNK==cie zbKcwp^IoXPs34Q~llHJ%jskIc!nEMX|KFyK8$jrsP+i-Z#7J2ce#K2@{KKxRmEIBm zwTM~mTm&8Xha@t+Y3Z5Zv=ekcx*HpU)KaMJ2x)qbqLu+wt9oMK(?pSqn+mmEJiv&oVm^*O)+B zjn(Zj8a;T$XRJCjBk3)hy8ESRH*64_)Erl)GH}RUthv_9=Ml5bm96HQAvf%MdED$f z`iuwajH1Rc8jzG7w93J~E zp0H{PV1>o=WOZr6J#zZ=j~QRXip&wvlmS~(ZQ$Y3+gSEfVek~SEv<_6->~Uz6^8zn zUEUHn9>%F^zDkv5tN%4lWe<6ue`>$vD)WN0KM|Ta8l+w3ySBO31q~_cQ`1&Vc_^TTh5`%Tzhkh+ZnH%?rm7t7iF#G|A(=iS(dI1|Ux z>{|H|;7w7Uyl-_e^=Y)f#&Xzh_>7A2?47?1)Kby$H9fCy1eYjV5DoEz@ZvQGas$v^umoTv1 z`_dDlN{h)UzHWFYiz;_1Y%^1AVJ5^9bbQUdET3nHbo4!yiHJA?_?2au^esXD(f9L- zJfe|^3>X^+4x`BC(f5%E%#;N~y4~*ipn7)jLr8jGcDg5_ZGSo)hZ*a*5KcU`91yuSYI2(J>4wbLjFZzyM%O$w9`l^isNLdV}<)BoEdW3~-B z+$N7}PV+gziz4g-T^kO`@sX$7;w1yWZpK4wvL}bL zwbsmO6e9+cic!y@KOI%fK`Y_>Dj}*5g>2>awll58qC*JQL|9$a5mgh~AP1UpRB{s` z*L1@IhtlGe=JtnvrCSWgiH}bEXi?)^yaR3>Lsw)$0f}nYPd?Mn`!S>G8_++CUeJ{d zeX-Xr%U%%PdLERXyDdCmQVx1Jm+G=l67oIAYQ1rA+oae<7sk+uxS?IB7mu1Y9L+FR zH3BE0&C>gY@zP7dolj^;%5m(aeA?;rZ{(!xu5nbJ2>L!WVNBG9m@)k*6Qn=e0Y&ST zkjI6q&Q+O?oy?`su`sWfZxWfWAG|1`!7Mw$XI~=7nexc}n!2XrSA3GFewhuId?7?l zBYB%x2zT%X_d_HrwgVtiXSM0}osiJ*Nn2$Ck?C@F%qwXJf?s5IZ$0a3h|oTnXEPN! zWAhkH$v zaEAlH7X61ggXI*RsCbNO$uV?dbYIyiN*$Ix{h*jJ>fBzNAFX%^MsD6M9%Xe|X9b9! zbgiaxXzlUZ9&EMQP!@b!V``Jp-X(dP7Z7kBmwGq#W}MEK-n&mOV|e5m`|g}uri*d? zOv3FRbn~u_K&keQZvQ1#OYUdM$VH3SXAWX!)P1g;LyUb(V$Rz`HWqFiG$#g9E)Jl9 z`xFJVmDS0)*QEYmqq7RK>AhpV^M~9sOi_0zBv-vn4(=2g+^)9JoN|y2^H9*xaA79F zcRq`{Pl?b)2$;iH#Sdhptf}lbUXCkv_OX>{8-D`YC*B`l0B$l?mI7!-px?Cy8MKSN zg3pd`gIBnrXVUc<>&)Z9c_8{G5S=g%(D&R=V~h0n^9{kRpfu(u(WyrMRLm##09m8S zF#Wja06JOJWN9gI>gibw^BM+%VQe@AI>3ZNeciY#K(JF-Tt=g96iPNT=5uXes)Ddfvw`lE3qHLSZz2) zx{C9%s&V&-jlrm;Qz88y#NJ9w^Uk>D`Sig!HP!Q)rIfT5IjQktx*mLU*E9Dq zHgMDOYh9;bSI;VY%p~U`pm+Z0jVr1JG()-cTn#8`Fkag`N};Bn9oYx6&1fSr1k;-a(r&1t=-k<7CaPoZBz ztw_0~C~^6@7Xh&Ccfx}l!qSoF#4o9chYfuIi%VU%|pf2A0jAHsS9x2k7 z=lfrd#%+($=j&hMqDCHaewG)E$z&yxKg7vjqD@o8UUZ#_ww8(ai>}rN zY(r1u5aXP^GE`95T!tghX=RMnx-RoY&R6t1!B0wUa&Zes?!cq)ns)Y6O2Cl5+>RM{ zb26JMCWJugdm9b{7b?FB^u_T_g!gR_3(jk&-rzzc*icyfWABYZ0ORS|UJ~psEuH7g zg6}by5~R|En^b4>$co)Y9xfZFd$9l*yxywUo+^#sq!2QAO;P)*+J0?Z*fG+8j5ow~ zz9V0*!5DJ_H0O%(>9Xqy^88+6L_Oa;Ztg>ug4g+N(RYE+v(3}~`_%um67t>%r&3Oh z24Ndp2@HL(c~$|pGJ@~E1q`FVIQpHI?x7Nc4=<;v+n>U|nW{>jSU(Ruw<-8U+LzC@ zdbc|+R1oGPz(#NzhG;{~v7$hApbe4o^Wpt48CljU@QW#cMu@-%L}vf0KkweBI5 zTG!}%4irzaw}QC@z_KCs!&0g{X|q1gA1dO0`m)A(ec-fqzkwVm9DQ$d>X7eq?BIE^ z9+7y)4ZF5$1AtFfA=L#`ZETw1-Aql${AkBC_RoG=Jl#vE3GZ;DUa9h{|cO((=zRJ7g*#ks$ruAJi(w;_iS- zDc$0Vns;iPaf_~jOZkd>u`_a?V4W#4IYz}HG-XS*QKwyw!tVZ^GK8M)saZ=h5#p|O zEos6=iN4nMQX4gP-+uws5T%Gc4bZv6OpK~)nP{~4M4^+|^ZUKozM-7uFeJ?%LKbu% zjzkJCOdLCUJvhz$u|e!v-tE&Yw@kzxosAVW=Q$%o`UBEIggv)=tBphaW}7y7D26mkD34Y)?p)e;$$4YDzvA!FFq>{6>R&y7?;2>6^hJua;pwe|?o zo%XxKFMP18$!%i0Xeu7(%q)U~Q<5QJQ>C}H-R~*PlqIE%ggQiqsHJcH;GR)Jvf)u+ z?--h@wHsRMSBe`o8pYnK?qN7hwOx1ZLd1hSGFkK&AU5l|?b%uE)(C~`Qls?W&W`Rh zACsm!^Kc1myT0E-)8sa-s7#}5&#Spc|K!@JON&N=n!*(H7VZR`6~bouufIa z+e3kBT+w@@;Jr^vGroUIQCGcz`b9KOCPkwUne#d~L?BtRWf9l}>p~#^ zm~~b5^}N9e=;0)gum=dtIi?9uUjv$%Ky4{N zcLjhe&J}m-sUV$eu?vNI&qwLFc;T|#c%y{Ofd&@|ye3yqU6`CEcWBXhT6B$#6-4#XbfJyy zI4UA7ltU^V?&!u-r?+%c6`@8cDKsO*CMg$u&W-=A>~zmWTjBnTWRexe?GJO3##F+< zTiSu$51Jv}NR=~_K>si;m)`n+(I4(HzCjB+DRlIYq6(vd5v-j(APZ!!Gi>o<(*lyP zI?w|&{nK*4)8FJp`raml+2S!(HqzQ2zX=zxzz{wW?S|l6l!3}1NVy_z@sj$gP-xGj z!3TLT8=}o(CYdGbGhYuXwI1h+yzm_R}9P77&sJ<@`l5pQ}UmPRwk zE%LVkr{5TH#8@?B^r#Xj7S8s>=Ffp^<@i6?^jBN~oYS0?Mi#}zo(5P2SCU1bJDuP4 zI3S`Yqy=Sbi!cnJQ|-L18FxFFeF)qWV9hx_LiPnnWrkM2M$hm|&C!>()MyWqz9SR( zZdXRzzc8&(Ggv!2)hWW2AZ4Lh=DW3s|Xh&bK zSl44UpYSQC7_e6rgygdabt{WP%s5bPw2@WknG7$PEryYY+TDNt!T1-jPITz*n<Q0SKL)M@Q{1NE_Y+rNzQNZyjsaR{1b^CMFL5QpV72Dp|vgia}xjlk-S83;T( znTX3f4hz(Aa8<%g&~l>8Er-yN=78Rd9$l!ZeR(reGVDaYaEwG@uQ7(9Dr zeFd?qMc+7-#w1m{_B>MBBd0WNA5U#h)*3IXbcU|4?OdYJ3twRI(ZUB)gI z6OOej^!>qWTJyBJdG0b`FsQ=W|JX0!+ChTizjT(xQcj_zY|?QCqET19IY?n<`yLI> z7-9yj9YhmF0Xw|IfOU>pI0Dg+xY%hS7e3P2TZLg-SN-O)~eC>{Z5-X~DHtqxwNbQOYi;~K~qaV2D z-56wlMBe-zqO2TL!9Msu3$M^b<_K}AKm{XfVmm19G^DE|7u5b;s zH!+?a=eh0^hLN{H9~FjPbx)G(rK$LR9KxAkjCB)DmB-hC(#aKBo5Q~rx~{^6>m~o* zd>}a0HK1hF>1qUvjQn4|*+_>^v(wKkI!WNqpQNd>Keh(p9j4mT;f~2lzJm+U9{jo* zW?aew_{&fl$T+Uue5GY&+$#MKbL!@cWdn`@VXrN6-X)KZUhntEmBN2e)^dK(5IPl8 z;z$yaU2@Yh$M+2*cS^oeiVEVtz>*i4q6*{>TsjrJS|33{`k8bX)PdVO2E^Gd5sK7; z!-nzCHiAID|B?!*Z~P-luuhkyL;A<}J|UCG0S=q)OH=WBKZ=G*+wZ9+u!6!1@Xuf1 zuS)n=*A&K;1K7-kBoy;xH0T+~nZ^eR^1EeN+J2G)xy^XD69x8eYQ)YvNW}C5BlF1o z^iPdO6}^GpXdqw0jyL5ZHvPl_I)4&ePi$mKjJdMEjA1G1hoea{TYlxtV;<7B!67vk z&Ouu))~V$^PrpptC_0k!dmbzOZ5-vOAeeQw)4$l2iYs#8lP%~|Zo zYJd;g^` z*rp9_4QuyZFuc`6)q0y|+Z+v9p%{C}(|^SJ;`i0BI07PdLyu25sMf=4(=!f?1jXZT zXLuopSPMPBKc6VuD?kMnelo%Rw(h^QtyTO0xIy|j`ei)%o>zbl`h=ev<;JOGU8q)_ zHloaB?(v#nLjR1Tw|De-IB4=@eYPT#A2gkx+{Ig0C?lkW<2NqsUv-`|r1OighgX~v z4KpOUMXlQ{C*)VCQa1HJz>~iqESZW=C=3n&8Khq`xNI3v9tS+&Sv-ff7$sQ_OzGA0 zaZ8}If90+-3eq9r*D#?bd45Npjs-bXuxp?I>fjKa_&pBFhq?mHYE$2IJi?xPmD(GU zWP8_AzjBO~+x!j3lRnsydUu-pDO!2Nh7vjpMR1vDS?$=mMX2}Qun2vQ-G+ess5C=bS9N)-MLSH zr0jaC1AtxCy;nyjgz(znSSLd&MWGiQ-tL^*asEkic@;TiYydIu@M}T0oyW%B18X!V zK5Ht&Xm653xzB(Z07qS<$e7;9V_q8c)Icq2OSKxdG*0W7z1;bMEWzC}bP)}Pam^Y{8N3XW1S*{bch z`j9Q4%H`wQg=KIMG@U`+ce}|gesxkK-gBzU+aey}lIoxMRv)mT=368Fa**e%J!q7xasa`Dp{ zHVpy!vNWG!wvk!~Nv<}2DP^hcyYs;)zJ;U&DAd5}5aOq^McdoHC3eJe^d&xoSS*2I z!X7n+Ec)TL@#wnjS=<^8=zO+dWP`a4)?s$KQyMn{B;blj;9j*#Ks2r=E;A{Jo!D2C zphE%S3Hr+=fbhp*@k!vlEu|qQ$zc(TD?Y5}S?+F~DF5*QakV zUJ1|ZDVurqhnwwmOKOp^p@dbH8{zJTiJ%;bNG*>K_4Hn_w1}q5g}iUGA@vo=l_qo` z*o6uYq4&3*H%K7EbPqT~rSrXfaUd%5EmijL`*}=+0z;fV-!!z%B<4me_1!ulJyj37 z+}I@=_HqKUn%#8E;eQHvA+38saCgPM*%J9KQu-q>G&m*(~fS}A5uO6>Y&B$Ni<%z>3GNT0?<>S0sB^6qN(=lwK;`blozKn z?rRhl?8?+>)L<;>%SfKH5=GV>WvV$Q{wcj?{S&K7lM6)pRs6_0JnF9#LyMUz4WH z+$Xb3&Jcyd;*Fy9RS}1p`ryd7f^Z&A&(el-1q1HOQY#(83i2q=`aHLZ&CXI+CTMu! zcs>>6nKbKpoMUZ2wd%DeXW}9;<2IVvrG|gxH<0W{{vclQzl!#HQ~GYvHQ;VVy6!Qi znlPoaeUY~ZRW3S6>d7Gv(EBV2=G=ypJeGk1oA>0!mz2>wGfzu8L(cWdjT@%j69xZG zWLoRppw59P?2%+<rJkjbul(mgyVvNI)8Q3IPgN1Xut5}Cw z7#@5W6Lt<}tls42{@+2|-74{0^$yBw7{YzsY5W#gfP9?950!YN6@=OfN#f3`+Q>}N zY!aysW6h$hB~`u1SErDW zJ7j~Kcqe$=M?$rhvbsj%Zuu*k%rMRb;8#sJ;BO{PrS8e$Xkj}RD}-29Rhbn;;*2yI z^UCeTKXo#&GbbI3YNO;j@Z-Kxowg4<9(<2Qpzcb~;zC=iw*f3i?&rwL+Fdv#Z~Etc z{{ON7&fAod<9z9a+Hl@3flDC!#T&yP6J63d!(`y4lWQjb(ZQDdMxYGj# zSTGhe&mS-sId0I#aceaLjVZQoSCT|(?f*Hrjpxc^8bOF(MlnvTc>X99`C=0vQL(pE zSm&Yi6T!~lb{bwUZD0waXIKB(d$BzM*S`Xsu2W)bnOvyc!^qS!Hz9@5V8r=Jz{$Ae z*2}c?2vrOBjuvWSi&-3tEG6#@j7gWBXC8zw$az#&0G-nTL!(7X^%c=zNZ5XyOA2{> zr*nVKk%=>X^Kz&)N+k$G+_*}s)R+&>?9+SXY90(q|cN}uej3#8E**r#Rr(W$))dy*Yy9T$;?-Y|t(t0gQc(1JLeQE&T%qU!dbT{wA zC|XC=o7>;3MTFzCnxKy{*q^xJ8bIAW_ zkb?R{x(p=zXa0hsXk-am-eUPBKLr}fg9Aa$lf99iD0LhcT@9-PT2!Ub#7B4tjf^Ej zN7L!ZGl~?btxG=UX3g88pFMZ-Z5hp+L5Jb1Ey+YXseY2CnqI;hn*ViFFy% zun$!rHh346$}QLlqSE@Za?PUTmA}nqK}S7OzD}L2UOEsx_X+ogL#yTkWKL5^0zB@X z;`I90!4K&zd~@;-6CmRj8^=I)zLp5UfnT6k?57g9c=KyK`7eM5w_kZ*^k{Y_tY?}~<4Y%`y|%c2*Vs)#@l!vmmDPgA z?;rnkyz+>a?bmctNS;n36UB&V&2}Hevp6E9#VNjQneMU#5-~D!c>~=}6H+swGTZD? z1l;~JyS)gjGr!T%3rr!JewkXM z!~F$bJ)hVugEz?xq}uuX9dP#|L#UvXVr1})I2s1b>!@0>PT~Zon{Tm&#?HF>)kGHS z4MHf=_1{uWM?Pc1{Fj)axIhM2|36r0!c6Z4KEI$JZ8%z9sG-$hDeo>x;oi45y4-(0 z_#R;QOUQsIDc(6u*ZCXf1)as}?1R$#F+%1CP2GJzd;0YsJiES zPgzq;#QgKi^7`=Fa6+t*KMRga#fo#nUf1*rj2*tDNly8FCz~fEdRmfti)-!Z^L}o& zEGRc3CF6&+uZKCH?n@E5idbx~$$H&-(VwHgzs?Bhu`-JE%>Eg|yDY!{>~<)VAw3T; znk_fLW`)cw!lCpiERVB3k`S$ixTcFrut=U6!WKbdWc zorsN7!eH9Z9IHnad@Xca(G7ru-t9CLo}3@w74Qgtm=Maew&yB|isZUSOBq4M2+cem z@T=LA`J!hba`mP>i09Cew}{+2)$y)v9tSXf1y6s$Hw&9E9vX7Xzp_U*^iv7H7oiaE zymlPXX{dJ7m4b7aUlB$dy(7Etct2rw^YFq7HV;5xt#~qaX!4tdA5bltf|R1xX4CUw zNQoXfe}*{@4tt~@px6+PyU>WdSK+g9kHF!s!-)Ak)(^O!l-i=P8uwO8(0~n2Zq%e# z-#4k}d>{V{Hqu#NmsouByNFLO(}snzt1)Ma^o!u{v@_?Nzn_Y>7y34&ro$rLo-57= zZ~hhn*iYj8`2Zs-m9$6LXQ$?mnwIliVVArccc3-ls%voGM%MEe-D2XDkjpV{(RpY9 z04^=&0Y1YTk3{3v@ebha9Uu)L(1$+5dWJmZvZWmgm-WEN&j=k*F2Qkb|` zGz~=i_pGpM!?F9tL`%ZrPLSZn;GUL95s3DLNl=dhehPF^8gTLaf6TpgP+U*fEj+;B z8Z=mN2n2W61ZM~yBuEJE!QCMcED(IK1lQmWg9JiwCpf{v;O=k_$$RhnJkR^9y7&9< ztFD?VriMPJckk1^d+)W@ah>xi%fK9u1NaQi^WcaaZ#3`@5CmNfJ0I`f8pqguDeapnFRn3uj%3l>1lD`&o|I$(3PIe52<7k5P&{2!9z3B3KG^EOJwLPg#%kj{e+kPm|hM$3`8Z!?86G5A>Ngo4^_U zpl$2?BypaQZ;_%kz~2{u69HuDw{xW8>d(0vwW{^|6-Z`6&kfStsSQEzaKm&pZ(-D37<7X8lw zO}~zm;Sy_Iap+T45TDCvGBK-~ zqNAZRQ0|OS^95$~y%*4xv}Q1K2rzU1FAe6|`^P;K0XW2eyXRlm|G$53QvO-;waou} z$xo4fjPw82pzePSnfm|LkPpLlTy**~XtV#H4EknO@MV!L&18+=i_?A%3$55djR|05 zxnEu6Vl#Z|U1y^;?nN|V*J!VuZ1y9&?FRmdjN7g4>a3Y+oYs3-RGHGdYLn`EWa3() z&YEEF8|Q|~<3-&Cm#$Om{-Imzv4Kte{HXC>HyzwX_X2iRz^x}1Z}%CW|735xke+NY zAxhlbGk`bQR7^R4yJ6U#v~lo@!&~PG<)rwZ?ZV>SAJbL*tLdIMIWPC@OczCw@)X8O zT#7pC0zK2#ZhjMjOWa?^Lbkg}n6xHQ#E=TE9h9;mweiKTKajzL=*5q&1uVtneLdDR z+LV(`^(MGx>1Nk)B{FmFv&PoN?(I?yolg_tX(bivKsBrEY8R+t8cMLi#a`rZgkhpe zZ<8d4JGGY0DVSR`F=fmtSeuELI@oBf70H#Z>A8^QEZ#2DZ3`PRdF}Mcnhsl?S6XaA z0qF&(0Gt*$i@n%gJlAfCToqYpIiJsGjNbXoZQj7kI`n{Bx!6+b-23LW5-w1gZ}*Gz zADj}}PH}O1qVOUJmP>+0S*G;uoZ$Snd^qg|$=*e;9DaSAxS~0TiAp)rAMZ~JnKAtN zCd~JIF@HlD{^dhz#Vga(^Cf>&mZQnkikH9%zH;p1E}W-WvleHnRw!Zs0mN34MQIo4 z=6`cofavJHQDCGA1ojh+OZV@g@)R<;FDND29dnx)SC0tJe`!G>nR-i&e({ z@K&{drnr>DGkKP5R9(L6TJ@$w-t|~TcXAsQr}#`Pqc`(867(yV3D01&j-gYkdH>S= zb=K9dehqjpk3`XyvrazQ%gu0s!(x(z@_$%7B!B(&8-aiKn|IlU(dxyokI9;_01hfm zPUtvl;X}#^;{0Q09sYBj1MYmh8jC~_=Blo`)~t$pcT!!US(fjMgcNx9?u?3M(Y3{< zOF1#325OA)0|dF-W|)dgt!R?AdrgTLxd39yrQG+5t-aZlYv~5ZeO{rQ?b}F9aQ)xzA8hPArRm5OQSq$LR$S z;0GrSsjhWxZ34=9)8`^oJVwoLqnZMhg#+) zYlPTy;mCq3o}$~7TldbtZ%|WqTtDuwh?0RjZ-EhgUyWB{pE6wmR*n^JmEV9ToX)Hw z3$oF`m~{{lAihn!YU_$&8;29TITjWTREsmKDK@|+{GTn*U;OU?Z2w~b8!B5$I6X4v zAJhpP6{nMhhk2H2Gi$uL%|;wPR#?&@AIsk}Ht{Q&*FGToe*p8Gp5~z047HxjjT~ad zU;f0;AZ+A(X>mRoR{NtUDf-#=4+TsB45Z&tJN;IhJV|xr=bN3a5gVxKBYbSfG@-WS zCW+zQrc$6>q{d;twE1d}THyAGQT_?zKl#_+K!ZWH^?z?gTUyxB@J|}JagJ->dzmI` z8iz};k_|sM)m9WdX}f3tvyql0EEVOLZkCv4`90F^M%{1LAbNIE*t9vMPZTm{hbmjI~yl?jReCnLkyRIr7{$W#Q_I_q*rf>X=F8xR~lq zuly2Y7dMCI-W5lYa%g4w-qi{poSB>sRAIM)BKx_`G~E|7HKHj-WM97!MZ_lKo913{ zJF9nwuj@$1jC5?@Eu>k-(h^v(YH%K-7}i;m(Z`DLe?!z*~cRCkBv9Cft{@lBBwZaxTa7 zb+t~H^zAjL-?phApLcIEP42v~DPr>>BcAg6xY|=%Y#V{d!f{#FbeV4p$Er=Gqw>$! zE?ro8Ok%!kJ<<%l-F2Vz{_ZlEe#O`So0r?jRp?UlDsgs7uhwAMiT4bRd%y;;U|sZ=LK;y?X64`U36`=EbHE>Qy9X(tpaa zW%2A`KMhq!?wjtjV?n*71Yq&I-$x1HK<=OzAoQYt=qIUcA?aQJqC@F?@8`KRXFb`J z(H$Ozv3m+sQKt0}B%pT+ls5+id{$HMUK>IPG84wCIhcC5ZFG12jj+WRc=kxON4w&BpI#KB_&y1A4jH|S~Z*6E>{E6 z6BRiAE(T=_CskMPdkjZjki0HjDo{!n#_&NfG4Q&D(fGz>C7-oeU1A>>yT{-SrhIpT z&H241-}VWMH7dMKG=Z{foj9EyAh{PQakPHw$>1nb+0Q?sShmdUWqQ(I(o1`?Brap| z+fSoHc8l=VeNJh`FL1=+*_i0TvakC~@4=kA{rfxB;TLm;USgkdbAGI6YJWd>D_)gg zezH+8IU$bIa-75eIxW5C&6L9;dD75p7SM{G9d3UeQ$@Ox!?dE#9Q<3*4vKB^;wWO`~Z1*K@`%gHfDJ=ro6g}l* zx>!C-rsWr#Q?+GoRaWG)3h(@XhPoZeRrxovf)@cu^NZfqyCAoE^DcJR-|`;*PF`DB z$p)Wgv205g`kw%0+)Q#oim{C|Zp7Wtjacu!ffuU-t8f}Ux$kFHHWlq>@vA)}GvnFX zq#4*fnHEWQYpkcxyHkOj+5k#NVaZk5P;S*xs82;^x?gtX3SKmNf<@WO_6!k=JQInC z+9AP=o7fG8c9rB3#?v1fw`P;|$rV5I=P1KH6J{6Pmo(3s2og9VO|{jQ z9t8AMV>t&7}I!e z(Lgp*s^Qo3`*VN)BB${r%auBxHiv#u%5xjUuQ-n$s{z5-nyGJ_*R7KE%}Jj1VQB}; z<{|DV1XGv%UrQTFc=gJxrcZN>Q8**QV(E%xN$inAg)Tk87 zx;e6;L6V`zmSWR^wi1>k%GZY8s;+Q?S*OJe$v&3#tf`Hdi$>8O9w2HZO)Cd6djPp( zJ(d00#sKYScvL0{%9N|EmeORoo^-)z+os@Twz(DCKn;Fg!mUG#YRtM!^YTM|Msn`< zsM7TgmMZ$9wtP@UHUD67^AVYE3vOWie3scymg((sSj98;VfuuLO%Q|dX%;#KjmxHZkR_ydz?p z&&T-A@3ATIAVnd^C<)Ko22CR7ly@xvH)!s$4&9@krxLgIG8Ko~>Yz?JTxLN9&+UOs@oUYhrR3=Z z^ckb3ch!-#887L)t`u~_%clfWO{1%%v#w$qzUCD+lcg}6*^}{ z)G)(*Ro*g~Lmtvf|JmOBf>ji>YkQ%##ZbnpF?=Y7nrU;H5f;b;z)J#Cjb}fhjWV5` z8o8eF7lioMO#O8UA@eR>0EoFvjJSuE1VlH}XI}t_jacpC%`eF_+Lt$cFLvjt9;!*N zI=RshF_UeGHomsJ%ITf>>R0AMb`eO8i+Bg5C9;}g#==ID(euNzw-AE5PHoED)U%YN z%G*AkAc0KwHyX9ch~O?-pg~x$t5R<Td46kTHKceZEn{N^Zj053q!WpEFFh~XDg{>bh$;^?%8_*SWNwxg>_lc^H zllp>;9Y~Kl{-pq(i%gtuW{t;HJPLUHXZ2={w!)sigSt*aenJL4XP}p~FPD_e#xX~m znr?ZcB2w19LK?D8+gF+B%o|oz4g3@*n}QL?hr%YdIUn5$4S`#)DU%Ry!weMxZ@r?< z{&%U)m=Q<4+nuMcdq?cwR81?4Vw6pCwBO~UoLZN=yEqHhggVFvBhNk`iCJ}*zF`4- zNRCG`r=9;2JOhG@{<~=5wJJ%=D4T-}bYB!0W1+(|V=?O`O^15O>T=s!N4f)*x?OX0 zhaJPQQwfz&OsPIU1mUZhH2GB$9DJ)5B=s06Qpdix1!Mys8(_Os`Ph$XPw1d(!qn6~kl=pr;rnI#3us+2A z$VhokhLc@V$s_{_)A@(Y;QYA!aeZ#fNB~0DSc`kI)R>Ea8N@#s@T4yQ7d$yq_07Xm z1mO+z-Xd2`_lpz9Gl`Sepo`z$$`bL!OF;aXbLOTJIY>x0|AZ$txCaaDhzPtp=tQh7 znju;v|8o4whE2lYOL_LkV-bY10~IicqQ>-`ym)wd%lcdAqepXnnq!WyuWpFNl7=(p zncny_Yt;r%aZi#8-DJNGLx45^>FEi+N|6$f|~n9yM62J_u;T~AsVEOW4SiyPXm81xxO zAx)sc?Mt%2P?ei`^CbX=hd^;8$x~#5JfEd(cyHdu5~ia#6DZ0Q-ooqRWZZH!zBoD9 zWyX$wT9=T_$I<`jhLb?}ndf`guyLn#=Ruq#t{vDeKt-zK=BGM7P7w9`?OBKTSpc3( zkvKrLkPXPD5TNYco;>zyMKHiD1pb9m+$;V~*GnB3+A*?J=vV1l=$ zeea*|nss@*Y)kxvS8x&tc)rznCXs3%$B#LPKZPdg{X}kK8aOZ6w=&JjKIqt>4}Bzv zpBtF(^DR4k(1y`(HC3LkbkmzjnJJYyx(MNN>S@T-equTP0!{Q=3R)Esq#?HL$1dVw zhX!$&=}nPleeQ`!2)r(eMo`G+r8psR;rqaUtoe2+kY1&2dgS$`BZ#`5}k z=O^Zx%CB4?M$PpL9&dH3qswHaUUD(dk9yU9$>PZpASn+GgaK3>5_3czJgW4BeCCZ0 z3kr<-W(J-(uq{tSNlA&!JKe-O1jz8fV`Jodg5A)?+tXYp@U9tiEeSslDy;Th$XQS~ ze40h&*jX!M56E*h4dsBK_Jf{Z5+yd~GLZ`OS`hCUv2YQ#(7*>_{b9oT&|I!4;f|S< zsv(q@8KE2WNm+hzB^ttAUc z9U%ZL79!6tdn3~z&SSmRIeMO4XDd3;h6!E`uD;7-`{>Gs=`7G&P+#`#1ivu4oviQp z&Hqdoq)A}tUVMsQ3oF4xRSEX~ban%LL| zNP?VM1bau%;W+UU2>_BHc0bTf=-<;IFiqi0Kh9?>Vbo7U0Xf2J<%x}HqQDf!N0EHb zs2jpS2*E0^EIwpYqdZ9#bH2z4(1iw+6rZ(tNuy7BxlThXM80_kjV(_V|A@i zd-L8!1*#2sjvy7tP!0`NSh9Clj za}ylRkLMHD0Vt7V*CJ^omL?)qLk{SWA~#xhwvKA`DOVeJmfXs?V%l9#2{G{!jM*~* zx}Rq>-N@s&*hCj7Cef7axH0MIdt$3Dm}iL9|<)CRoBD-+{?12nzE9Ltk-P{Dp}3y*Olon%)d+ebvzD9goTkW z(@SBZ*HHWM5~2uNC3yAC=HRDDdLulgL*QA{$nPf5v%%lAZdvxO)1TTn6g?FRA5_cMO2y$bHag_j!b0{ z#3PIpc(Wk>G{Le6&W(e#@7R{Byn~~EYH|;Cx&Lm|{0~wf{B3z|tN^-^U(Qr<7zE*} zWFw+gFeyz&K~nxG1w##rpxsK4BmUx3#KhJSKcW5xhTi<1>KR%2V8{ig0_K`MzFt65 z`TS>h=j{)GFTD(MLqgNj(vmMk)|1SC@1axn`c*j+{Vl8)@*rG6q+E)Cg(TICr1yl{ z(%*%!*`8*`oJU$64f|fkw#x3jt^Rb+KOR9^rGo)vTImM>-l31s1pgL6*&c z%7?}Ua{M<(B)YF6q|Lih_^@$-c)!QSAy%K`wPad)>B^N-o`+D;i73#tf}v;eoGF9Y zQrQmYgTXGK=b$)H-#Z0kl>CuM8Ry8wrHDF$5qGnAD(-;fg)0?proQgitn}O6=#KH( zLEu-ro*h^eH(`O9`mI{g5854a$A-c|U9tL6-7YHd5dD52vx`@HdxBQrFwkX#yi72ecBRlFdl3I}EgCOFrI+tD`~8wj-j=)c1U!gBZYnGaSgfOs@h5(&hW639tk; zM2KaDXdBVz!zYY~JK$Z$DAH_!@AM1I$?M=;_dA13FSw8 z{@Dv$3_?TkM1lk>bZs$GmiNM#bIVTafXykmwx~<)lx^Ur*n8aUSKG>RZkHcVxif3X zbT#x*&XK`vkIPkv=rUh-^>H`^teeFCX>LDxlL} z4!*hF5L=7$&BPg^Mh25WIu!)F!mOUfB}^fOoZ`&}=W54JM8&7k31?q?%>PY&5Q5Ge z$D4}W!6}K%kANC}3UI}9yA*iz@#V*GeQz#Cd*Tq?Bmxpn8dtT!9GpQ23}`w^@wm8X z^r^Y2UDMy8YR!8zUmp!KWP>#VIZe93#_vvljp`v`Y;jRD1k&S>Z=q?tCfarx@1WGboicKYM=P)&oycqjen5aTHG+IEH8|Z<`_<~7RhmFe46sh@oZC>dp z;d$tiA;_Rc_xt9xb{mxxf7Sw*c}ang#ASSt-NnkAgM{%&mo@%pw?Fz0S=4<*V^JKN z=*|a)70?Ck80~P*lqQ?DEtS%TGV8%foQ%XOh_UOw0GQEgcb0RU+xy((ka4QPY8Z7I z1hv*;E~m1aJ8gms47A>J$E`i+_MEidd?Vkko2<|$palDkEprS;fCRPJbzVvQ$#ZCe zAZ_3ioctkr;O7P7Vl{~@r(VD1`q2%H2gT-LBEHJzea4@i#ZqHx0(d@->?pLd;mu(? z{y6{MniQcC6M2VN-RRtBF{RU)MIqrXjDie}+Za0KDLwnlM|^)b$NX$N)99rcS1Q+A zDu{hRf`*>d_5e%a?(-?k0ZZxX35efpsx1MfcPvwa7uBmi!PeN*mr!t@93sSClGXy4 zvo?~gnVe}sZaWW7buBhJ9mh0C+OpGr!{jBB9HTV(W-{;Wk55 zXzCX)K1E$p5p-B-xB?R=GkDx8+XDdtWj}hVmX~qH5$G(U07EiMUWPT9t$xq(A*Mw3 z@oL&zTqQrKmvFo`_Wg= z>k@dnL%R;{T4NXD{lVU;9u680-_ya2mCI)pttH~3?+h@NKZu^bU&pjKDqWu?dAvx9 zC{@FkFE1+7fCL_>+2Yreiy%(<*ybmwN};yMCURa9NM|mB;q)M>BwUFE8LRoFJ6nWZ zh9ZCnLZQa$&IS*C@#W~Q9KQq$x>{+-O%@s`w|6#EQD_~ot;uT0x@*LWxy1UhcGz6V zT94Nhn_+15Ncf!aOg0XOa1uEB^$J?);hC@762*my3@suSS{z| zIwC^HcZi7gd56)r0$dUq9_;(AFIM&Sk5W;B@~3tpT013~a6VLelBE)dwhJq8M*L_) zmus{Xq!Aq;sAB{;sg%#gCH({a*_->GlcH>L(tH<(a^fZtlR+#wcD7Mr&xKI2nQ{-~ zLC~YF=jLD-I^$_PA5{D$fYp)XW=8W#4jAvpA%j4yXdrRIN@{Vr@Gj?e2z~j zk{BFFgLb2#(WQWhXvjF2t4iCfnwOUNp=8L;dizZ^f6xiT$s?iKaDS%!!!F@s#LK6p#keNZ&V1&VI-q1iPZwm4#l3te+8LlHJ1I@C## zhuD~LbMU9uF-oH5o!oJ;aw>NS17;bkrNzUk(+#FjS0ul&lB*zh0WBJD$r=()IWQ*Ev$b zid|0J%}E>Gf`%Zdn?T@xJ;NfY?e6+f~a?) zOG+p=gsJ^lJ6$ElepVDV!6+$*CT}(46$h{^bNQFS)B!43v>Y{w1$_puSi#Y`K-IR` zd#`Eo=*71!*ubLVkyAT|dKePz^$Y?8f1#X|Tr84$b%j$VraFHeO774ywRg6Lu|e-dZwwI~;IUMiBwyxI`S;u_;g0kCBsuKhwQ1> zko1EOyq=mQ$j6S<%^Nx&!VvDLLA6ys$I#hlB6r1KssNkn;ua^t2bvYlnBB z+2u76K)g?(e+zY&12u?_>DU>7=@bI`-X)n2WFk7FIJZ3XzwbYVY&&P_ZZ|mV zrm+TxrBdx8Z&!2M7Bb_2$7Y`<^KM#$jDpVpCPCD3!Zxw{Fkl*T}piZ zaZnq{m`E0=;GtSQNU=olO?&CyQPu_rjv1cyR~adc7kAh9B})5UlZ|G*n=8>x3s>KP zUvI;7A^Xo>tZB1SJ8kRsju6uHlGP(m%3CA|5)q6hj<*Q4-5G=?c^fu-L_yG-kR^oI z^ZaZQ%;RgRadv$bcJUE5wfc4}20{E$w{SFyqn@B$Kv1mE%YB;hNeG$g?aNW=*kYQs z5>#-OU1I!z)9k7j0_3`GXxwhOqWyad3xXqLW(tF3FkzuHT*EKraV{4lS|a;d2z;!L zKe~_R>kZ+g8UPY5qerk^YZR%`H9lFhp!5~g4g7|Fr9?7otj2kdG_~*qset8z|J@e~ z0mBMFRVjx`#uNe|`8f_c&^l*fN?puddC9*WRq-5JXE6~G=&dIkB5^8w1wBEK2Pk>C zvo~&ijhh3sh`sIN4W&-{CFUy&dHE?!pVNnBX^vZb5B5v3OAwNfZv(-A6)c3E^s_2q-v8*FCKM_Ofq#sr@|kg z_upnhxBlH@mRjA*AeUhI9tm(#G&ba_Q+@1-><}aI9!$shyHAS}CzaM?>_2VOS?6lF z7AEO%7t0)4PxnkFtB&O_UqwG2ktJfjc;8mPe|lb{jl~WsBxE7MfAcP+m#Xi}Oe~fp znP@ow%a`%XvVe2>b>`htnd#6P$mi62M; zixn328pk6*{)4kfPJHGHJFDne@lZy?zkN@oMuJgPg4k~iOUno|QV6=cT(Z`#`sYG*}UyCW*ydVHrgkMo5S79oj;g7}q& zZtisY_tyg=0n@wUuO5{K27bD-wRVG=ltg-#$V%a}4EFNIbY!rIelB}?)Wj_QHvz;I zGr9SLt{fF$sIj`L{R|o^qp>;%DdB31<9wsNR~2pn7y;V3ZA&-#(^_{eWyq`*!2LE0 z3|7tRKGXZqBD3*gH^hyY&=KR$*4KC}hGk?zb3kT8dtt8}&G#{bX=C=Ef-LR_|4Nm! zdejL>jdiTQ_Y46s0;-sAHH%RX=%Ut@0X2AA1g@D!52XInbd_vW9=@4fubm4L>;9Nq z3O;*rXf7iHx6Pbgl-F%puy&hZpR>C?AD|GX0bB3L_1} zairFB<ey6q>tD;k(dJ5yN&q zCD#xu5e-)4$5+6N{BKnx{H(f^zfsS8SWB=!C=@c$Q=EK8q?M7NOi3F=>DYPUI5?TZ z<&=)nV;*WYSEtLjOAz6pIGBI|ForWJ$$!fgZeEq4j9i@Yq1MK%D-vfP?&|T`tmth& z0a04w+{T|gxuK@B64-quqIKL^E(TVSva}DHvYmOcp_;XBImI<$RHY6es+xM400|9s zRf)^5Z94+CNwarH+c!_YjdCo92o<%AbjG8E=LU?QzuQL%8;L=uL&g*JjMlOKpFrK)E3XZduI#LO&dbgyf1a*g_)JQ?J1 zdg={;Digq}Iq3*-{^DDr4R8YQVQvyrp$ z(E<=bq?TA6au9@BEu&ILaby~jLbdb``0|SCiDwHhG_C>MY0P3rj_zo1>+Vrlb6mhzPa5cf`)){$>fK*b6ten69*0;Pbj7UreY{*NDBWaBQ;`S(5TkrNfiQI+X6pht*T>rLNK9-}dZ>6^B2jhKi*5u9n0!&Mx?P&%1W1PGs284H8U z6Ea8I;{wBp-~jRfU*!~25Gdo~=u=aMWXn+=hF*(^^0M0(dViI&bnQu>b&tpU?z>{y z$SbiDX}#Q1--k#2!lP1$lX+!%t7=MM^|j>gMF68y&2z7>EK>Be5P;gn6-mb!qatP+ z2^uW8$UMdRZvWT~($k>P8E)Lm#UHu?y}Js$h_1xcw{7 z3&#}qb@3QcgvW1K`<2p7GyUL?#KgbLpSf*3R9zaoELz_QnWZ}7l8b9Q%qZA=9zIDc z6fDCAm{b4}ShK<4*}_KU;kx1x7fMxd@m2mM*FObykpSf-GV-+(CV+}ZaeJrcVsb zF9Qvc8V!J!2)Zcq*$V*KDhiRB(jsdeHWTzA4X}I@LKcb`YTo>=4Q}iSTvKUrk~Is- z0|Atf2IM!$sB^>6(+@BJ#wFd&H)RHkE8PXAb~HP3MXDm7B}osE$GHq$##<6Fe!V z{anUEj;{^RYSvsIZr)u)At6-iZ7N5|JV;$?G=>gD095xX*jqTkhW##=6m}LrO4qFc zkiaS1CzH8Zt0Zmg@M@~OK55Yev+D4~=@G@PDgSt{_1g2b-IO_2{30WQSyQdo*QlMa zrI#Ndbga>$mSx$ooK93-r&8Sg(}I1rg(S;B!IIyK^OBUnU;$`-0`16t6u6Zyv9UgB%Sd&G7B zqw(8FThax&@@#>r{mIAl=31;3yYGU;>plg%B%}`)~jp3i$r`>)t0I zVrruR4Q!yUrLGn3e+xsc349YI-mA*$YW~7aP%0zaUeZ2boFRGSRb3jtZ1>F2pM7T( z5b;=Y8!RFCYB2BIBGZt3Mlo{t)3MEB+}4JGAi$5`BGMx4KM_F>e}CQtP(giTVGK){ zeV3(5>+I(r#0xIE8^mpXd*4=@(mZ25>|?ll5HSRByB`6XmJcU0yHqac6z+0}w1HH! z+6ogmKYb_YHy|99o2g$Lt^C|>q*q0qI`1I` z(BG$ngG7xd->E#xf-iq{NLq9LO(+TPd*4Z>m}&qvUEjTi_K^@>=;n8lbtt!YDB{R+ zIOsx|YFftT%F!biNkh05MRj`lwKW1Hqt8n8W-4H+wLu?S1;6RDxXBnsKFqirBW67{ zdELe}#{z&FIi~R0$Y$eRU?LpW>T;Jrg{rm%6Mqm@`DntD`w(YI+0jKRJ`njSo6$zo zD_HbBr@IK{ryf*#fiwWSA1(~E;}h(i^?;%(Um)B#bFcTBtR3c^@~~>yAS?1?kNbRF zi5rd+XRFmlPbckiMl1BE|BAyn3!RnX-DfyX*aWI}XlNn~sif8E6Efl>mgH0QiIW_T zxU({rJOCOKDcK}DX2}Vh4ZAR*?4y{9*4CHO1Nn`(3!kR~G@UE``6@IYl&4r4#%?BT zk_nFph^KZj2kSekrw%sT~_^ZQpX@8Zho1^ zqq&BdV~(_rPuAqRBKmQ6C-~p?;E>_PlUUMGQHbZusu;XI3|=*6O_SWkAj=m-&7typ zVP|#lyOFnCtel16GCMeoA=a1TewJ0IXe-z0(`t{c&xZlu+q^m2o)~@0DDuUMT6Wcb z2;F2es>apQ)(gMANMf%EC!gTPN+%7H@r$HVHSq4x-C8q-uXNp`Pu}|_4jPS{x&Txq z|LZj(2t>B8@LWn$dK7)2J12(0q3r_x3C?94d3DmQqZfy(QYft|`ss5!jA^z|VK@%u z)!HR9s+AoZQy=&2)iEN;y7-{hjC@> zbpQtyO)Ok5j=}Pw3F`E5E=X;oFSDqlMd=ru^dWGnvWe4)q+J`@nn8d~jax$3S0Oer zm7#ptcQV-c4__(dRW4+k-bopu-95-e$%OdRrhpEKCyXaZLc4KA0xp~-$g7%<%E z>~HDpcKGxj2mcO1uzSc;@WPGm;zJOO0^F{y0@r!@kfUy6H*9>JVjj|#dNN+@L^N3l z5%R6|Lb~iu#XE|i>sqD&>12A_j|bHai{I;E^6Z)f8OY2e0rWBYQi(iqngG@(Ej7uw z``~+SytdD(Hw0+DECRKC00dCcCPN`QWx_)O$WqS8#XLD*Krt3S>}aV^puU6dF^yqm zvL=9`kFmP0=VfMjI9+={F;T0oPjUx8b09noE*h0zMLKFsR<@;?2UycAmbc#&bGQzZ za=AVpo$)c|cQ%m9;M=S1wcHZhk?kLIKy=NK=?;-rxg;xb#c#SXX3Ji`)@n2`@!bUr zI!Okk1Em3(3O%?cJXX&_9GTU*2#%X*hx^t`6l{KqyWc!zx5UgwYfi(jbKH(- zQuADFn0|8r{}z4KzYp)C%W4SP{CK3ay=mFpXxWAC^Q1$-*g971>^vfGXvgZgGo`hK zyS3yY-lP&QAvRFrBTz|wI|Jmu3*IfptN1#@<*);qqCGvWut9i2v**d4sm}iZ+z!P1 zL&RbG!~4ahky5F`VpVXI5n%6!iqR-q0=&@!)nBl?UCa}R*Ulol?41ZS}u0MsRKW9R2CU;sIEtV{-eM6p5&&UDA*Dn~Nk+M8reI0gw?+-#4f}y;WSMFHZiz z-iW6WLy&D5_}Nhbq%i{mUJmjcYs%_n{&vs+%?2k2(g zm~Ir6=Tg1|qV_@Xj{Kh&TbcFxaSOOAifFe3M4+TTZtxX+t-kn8hW$NOermlS2S5~N zYM&&g%f>h5{lp@v+0Kzj3l&-Z^dwI~P1L#TA95#u3suzS4~H}JsXXiFUsgU9??mxc z#%1>c>X}Ew-8>ZUV~`G0g}&qGy>Mhke|Fk+*yX^p%-)%1k)qmgpYQ zrGvtdin;*;?29*Vu_TqS)ZQ{9$|ftk@Vt{4b1aqj?4VbB8V7OvmcQ#&b!ySf)6INH^|Fp7Txn2nYgZ4d7n zDmJQ)`r&oUX9C&FIXzk3%9?<_u$i2V<|ue?VGn?X_)rqmo7F%}|?LQ$6Ox%+S|2vuEWQkkD z_1oU?d)vFSb6krPDGe~5BnaVOKH!gxJBwm`J3=&wt^?5vSlp0;1+4?GlPw0x9d1fJ zueLsz@AS6HNS^PtmHCa_URq=cNZed-6H1dJqG>YVWkyBdI7t(vI=rd={W2`EdCP2u zg8_{?0EGB29}{$VS&qdPP*b|b7Ev87)h7q!5K~!iwoL)(*$>stzrWOEHGJ~!{r#N8F9DdGBGktfA?Rx}sbw{YI07nGyg{OyRM z02bAk8kCQmL*U+ZC8kXAcq=+#d z{jrcBejq6UFR}`zH0Hu|zkwiL=il%D+kAzF0q6z7ZjahmG{57-3L={eIO ze23;OYR~l-;(s>+D3B6^bEQURM_xx+@P(tBj+y=5fAu!IAfC6jqS)m-v;F%KYr%_fq`qAwhtO%U2$x-$%iCqT&qsy-}f!o_UgXc#6i@Z!{^=Xik z3jUv3eqB};-U;Xh8EOT>_yWNvRF5p}u_6klmzw70FMsM6^-TPo8pr2|8^XF(-%?e$ zyJWpGr@iR6JeHrcVC<0ScP=N1U1Mh zD?PddloF!1`-1(ogxcn%xK=(rtM!65gnqt%pE*0nTyNh#)pA)UKBG;ANcq<&FIy$O zqX)>W%{|O#(+>mEF zdVLQ`sHfZ3^|_yJR|~#8$2?SPQW5QDBfag7nwtOI*!U>xT~luXl)n;}l>X1WHz9_O zlccVsngpt(FLKA(wmh9t`RXXzi^$i!?-VGNfcWo|zYM5G6{NRa8*Of%tf7<)^VzL- zsaW3|7-W`gGARo(hr{oLbJ3Y1u6yPR26sg&bT$V9{@(ITwB(A5oUDiJ_wV^C4npyc zuPAnCUkTcZRK8uDaGbfw+bMGMD1|&Zy}8 z;LBAurfjzkoCtVtgSCAP;DHn6{rHWH5?d!^?VB}w_S7N|1C$I!+(=8|sTvp=_-YtC zu6G(ARe>^&irMS@c7ipla%t;I?8N&m<$sK_0qo~>>3e+CTrn`rAECe?P_gEpk;&^s zq=m$_qItS!mA32KsSp%N&U+O*$|qpkJq=IQJ7g}H?w;Om{W;%u>*c(CMoG|1@b^Is zXE81h6-rMgO(UJ!cG4>`j6Z-=pJr3fvwx}SQ6}wT1poW>L4kn*HyQaQCCP({DYi{s zry3%OHHWGKeb{E5R$rU9Sp*BwnH08FgsrTcF|8U!6kK;DWrP3h43c%Q?hhvB)dOFn zM%j~@zf>Q^{aPUs0QAk+{=;?f;t=k#(O%h9{EF$uyh2oIHzr&Q4Z(|7;3O1?Lii-~G=WygL>4 zgsb(NRL!%Vtg-hC8Akju4G?CaPq#l@G3@LHi!`I59=U6V@>F8yRpL(l`9~?WsDBG0 zs2!IPcSGX!$=GdwEdT0M78HBaS@eUl{uZ67&)R;~CCh7Z9=;X$_3y?Ohe%NF9>Ev^ z5Bb$H6|rXL`Ze9yWX`-JZ{f6NIa?w0Ke{GF>=I(sscPJ9ZxGZl_4^T`k#W7p$q3CY zb1z|Pd9{gStohexSZSAE-zXk2q%joJiK#e{D$JIVxo|!G{lCh(@^C2EH+&9FAxET> zq!5lZ#*zp{vS&9WW-P~8vWJ{8mPw86SSDo4SR%`ey|Q)GXza$4bu3YXDMrj0PM9+0 zOy>N4=gRs1{od>O?&p5q`+4s7kN5hzf%Q!>#~xo@uOPlLkv-sCrsDOy&2B|`iij+x zj#_BavfzbghRF$PB&bcKh9|u0V*eExY{02u_9s9}%B0`3eKIOVX}OcWQa4**Z@O3_ ztgR0#sNNHwq`s!6{HD4hOJpN zvSj@_H}>4OX?|W-nFJTQbsS@s5&U>fcn`!3|P0Ue1s(m+_GQ^ZsJzbDMa!gGct*`SHsQrq&f|0Mr z!ParMfGj%B1Sx|xj@PM~Fj0l*m|T)gym-vslAv5;U&(Zv?q9hdZJYRg*t_lVfFYpO z#Bvc$#PZI%p){KE7MQ}r7Hx|j$=^^y$L8!QvxsE9jKC3ba&fUpk)uKoWL`oO88><; z)b2m=1db|`K=dJRJZ9r;=bvoyPjQ_X@_{0~k+4$Pgr4)ZcrX zYfiK-vU*u4PFbE!D4qi#$R+$(_}sj5f62@Ej;^cNtFP-Vilyr8UB<;3onH5KGI_RU z=uZU3xDK|KMnG<`lQYaKMjGwKF?xm#vw-`Ax&A&(X9pI{GfLsMcO2pyB!7vh*(d=E z#gS?uTX@P@C<>|fog-njlqOj>8Fb+W%Sitw#xhvzLPl(Dwp$mw;Uy$5NOtm`(+$z| zs(X@I{%irzCA8^8HdN1ZrwPRQ-nf2-lA?MrVwzF=Ui{dYagjefpZ-&Y1@+2d)IK%s zlK>uR6;*vTeO|{HD5!-M@OXfi!kFTyfcy=w+%*kG8w?+oV{p*=1wY|1*R+4NNJrX{ zwG&DEG7`7mutBHLQ7QbxZRcnFrdSz=In3mymxYCC>6Z=hiU`Ncxk#C|CG+^AJQNh} zdT|}t0$m*8_!Z%zVELw5Q%-4gINn@_y<&i0HkZQ$DUFTvIG?<(K3Sy{=gbu!$Fr!o z&?xU}WK#LA$v>QRoiC+K%Sgq8(`Ucm{okjvJhDE=$Bz~AW6yfTfDdo$-r6yH$!Hl< zV2^lXC2Qrm2V54QZ8V`IGW9d|I_cy+cLp97*5*L&=UUmu5M?xYE0Q0s*H-k3n_&-g zik^4~mHdylHs$yzhEB&~g1xM*({M_P7NrIMfZpeSmBJJSVdwp>x zK2PM8+n+A$-79DGVRpf^URc1aYw(3wyumBIWY9=;3YJ#Qiy_&ti~g@D+OKkb({JFC zpk)?SJU-#u8&+ung8b=kOzhhm&ucv>hCP*=_h<`u6|_jQ0o;6)Z(4(Il|3-|^xm7W zG=PojVVynce80l>%VsQVt$9g+8wCP@2_;9k!J*B{T(qMLHt91aSw*fuA;7Wx>Xh1>xw+AOML zqf1__Nov;zEGYisTy+=vFelycpa}SL72ZpuMOm#cRPn~GVdR*6wG=xKw|KqR21ZgB zY$rsVW1w}9UG5Cd=_?PMOfya;E+GbFGdlR(mM%?aSOHUe502ow?SY4eh7pgo;9EPd z1GT`IoXoMWVp7y=)#KaPTY14wSvgDWU3`M)MB7{<(g+J*>_dH0AFpEJ=Zc@k(<*6? z+WN{(B4;DsUz#zqHdOk2fPKr$Ryt?Gn;1Bio2VAH|~2J^-T;IXXk5(Rch7rpOpD<49S5T8WxfdcMsi@37t@tsW)JL9IJs1cUf~8B3;y7K%WcAn*l(nIRTBOLVK`h^WOgMfJ_>mF4aGU_2?$rV7{t6*C4*x|xQ&th>Xh%lk zHfRtQ4ekqR`Rhk5#`6|?buex&h!0Vouug(mQGzD3WifFR1;+&MsRQ|Hb-y^hML>cX zBXxrF%tq?O^TeH57spNsqH9IT5QYL%QOfRn2~;7vPv6_dole>e+SrYx7DV<_x;CxI z>5I58<1ZKl(ZKMzE3+YA&l7sG1M;Vyy_-Z`&nlYYu4wuiBiO1Wws+I8w)wV)#x-bb z)N(eZGQE)J#fPoh#(s)o-Y7x;ow}B2n(# z{8LkbDRhx+dJX01u$)kn+4|}J-k|8SwBy|+iH7e6=IYhR^5ab%u2-FaX}T^5G-3&Z z+^o~F>QA_=@oDQzsf-PX8KP=ZP?yuPhp|wlcRsz$%)hdT0$B1x!<&#Vt<+mQq~pmp$Hm7-bf}Dai9Gu~>yR8yf8dgt=r^jp0uFQg?$k zS7BL%sjzJv`uTCbEiHM@wc@3x)1upZ##t-3`wWRg&$oL-wusa+^V7sELTSeDxQ95f zz)|_;=xoo8$DCkoH7_DA$*0++dD;I_V#8_-dLU5jsZa#p?T9FDdQV%Dko1S=BYWEVzfR)|^R$V%AwT;L&!Q1&8;s$X zzpeLo6i3i@^WYb6gf>>!8dBUw?ZY8Od7s@UMg7+z`lTr3XF;j~HJ9VRuFYu9y3Xn| e#T>3Nm|}ppMQ6{20>^(~J*I}12DSQb_x=VvW~(~@ literal 0 HcmV?d00001 diff --git a/docs/static/img/console_languages.png b/docs/static/img/console_languages.png new file mode 100644 index 0000000000000000000000000000000000000000..750f970ddd4345a4a0a89f1f7eb5dc5528f2a234 GIT binary patch literal 213256 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 bQ8jKn7N6E(cpay(415k+qW2b9xL*1TqkGw= literal 0 HcmV?d00001 From 1c5ecba42a8ffb5b366db9c5ca28a7170cdd33a1 Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Sat, 4 May 2024 11:55:57 +0200 Subject: [PATCH 4/7] feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst Co-authored-by: Elio Bischof --- docs/docs/apis/actionsv2/execution-local.md | 139 +++ docs/docs/apis/actionsv2/introduction.md | 167 +++ docs/docs/concepts/features/actions.md | 2 +- docs/docs/concepts/features/actions_v2.md | 40 + docs/sidebars.js | 9 + internal/api/grpc/action/v3alpha/execution.go | 111 +- .../v3alpha/execution_integration_test.go | 143 ++- .../execution_target_integration_test.go | 323 +++++ internal/api/grpc/action/v3alpha/query.go | 116 +- .../action/v3alpha/query_integration_test.go | 321 +++-- internal/api/grpc/action/v3alpha/server.go | 2 +- internal/api/grpc/action/v3alpha/target.go | 47 +- .../action/v3alpha/target_integration_test.go | 118 +- .../api/grpc/action/v3alpha/target_test.go | 139 ++- .../middleware/execution_interceptor.go | 179 +++ .../middleware/execution_interceptor_test.go | 778 ++++++++++++ internal/api/grpc/server/server.go | 1 + internal/command/action_v2_execution.go | 48 +- internal/command/action_v2_execution_model.go | 16 +- .../command/action_v2_execution_model_test.go | 209 ++-- internal/command/action_v2_execution_test.go | 1047 +++++++---------- internal/command/action_v2_target.go | 26 +- internal/command/action_v2_target_model.go | 23 +- .../command/action_v2_target_model_test.go | 1 - internal/command/action_v2_target_test.go | 254 ++-- internal/domain/execution.go | 14 + internal/domain/target.go | 3 +- internal/execution/execution.go | 122 ++ internal/execution/execution_test.go | 347 ++++++ internal/integration/assert.go | 8 +- internal/integration/client.go | 59 +- internal/query/execution.go | 384 ++++-- internal/query/execution_targets.sql | 11 + internal/query/execution_test.go | 94 +- internal/query/projection/execution.go | 114 +- internal/query/projection/execution_test.go | 42 +- internal/query/projection/projection.go | 2 +- internal/query/projection/target.go | 22 +- internal/query/projection/target_test.go | 14 +- internal/query/search_query.go | 31 +- internal/query/search_query_test.go | 8 +- internal/query/target.go | 17 +- internal/query/target_test.go | 96 +- internal/query/targets_by_execution_id.sql | 40 + internal/query/targets_by_execution_ids.sql | 47 + internal/repository/execution/aggregate.go | 5 +- internal/repository/execution/eventstore.go | 1 + internal/repository/execution/execution.go | 39 +- internal/repository/target/target.go | 21 +- internal/static/i18n/bg.yaml | 1 + internal/static/i18n/cs.yaml | 1 + internal/static/i18n/de.yaml | 1 + internal/static/i18n/en.yaml | 1 + internal/static/i18n/es.yaml | 1 + internal/static/i18n/fr.yaml | 1 + internal/static/i18n/it.yaml | 1 + internal/static/i18n/ja.yaml | 1 + internal/static/i18n/mk.yaml | 1 + internal/static/i18n/nl.yaml | 1 + internal/static/i18n/pl.yaml | 1 + internal/static/i18n/pt.yaml | 1 + internal/static/i18n/ru.yaml | 1 + internal/static/i18n/zh.yaml | 1 + .../action/v3alpha/action_service.proto | 45 +- proto/zitadel/action/v3alpha/execution.proto | 28 +- proto/zitadel/action/v3alpha/query.proto | 2 +- proto/zitadel/action/v3alpha/target.proto | 46 +- 67 files changed, 4388 insertions(+), 1547 deletions(-) create mode 100644 docs/docs/apis/actionsv2/execution-local.md create mode 100644 docs/docs/apis/actionsv2/introduction.md create mode 100644 docs/docs/concepts/features/actions_v2.md create mode 100644 internal/api/grpc/action/v3alpha/execution_target_integration_test.go create mode 100644 internal/api/grpc/server/middleware/execution_interceptor.go create mode 100644 internal/api/grpc/server/middleware/execution_interceptor_test.go create mode 100644 internal/execution/execution.go create mode 100644 internal/execution/execution_test.go create mode 100644 internal/query/execution_targets.sql create mode 100644 internal/query/targets_by_execution_id.sql create mode 100644 internal/query/targets_by_execution_ids.sql diff --git a/docs/docs/apis/actionsv2/execution-local.md b/docs/docs/apis/actionsv2/execution-local.md new file mode 100644 index 00000000000..3f0ccc0fe0d --- /dev/null +++ b/docs/docs/apis/actionsv2/execution-local.md @@ -0,0 +1,139 @@ +--- +title: Actions v2 example execution locally +--- + +In this guide, you will create a ZITADEL execution and target. After a user is created through the API, the target is called. + +## Prerequisites + +Before you start, make sure you have everything set up correctly. + +- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers) +- Your ZITADEL instance needs to have the actions feature enabled. + +## Start example target + +To start a simple HTTP server locally, which receives the webhook call, the following code example can be used: + +```go +package main + +import ( + "fmt" + "io" + "net/http" +) + +// webhook HandleFunc to read the request body and then print out the contents +func webhook(w http.ResponseWriter, req *http.Request) { + // read the body content + sentBody, err := io.ReadAll(req.Body) + if err != nil { + // if there was an error while reading the body return an error + http.Error(w, "error", http.StatusInternalServerError) + return + } + // print out the read content + fmt.Println(string(sentBody)) +} + +func main() { + // handle the HTTP call under "/webhook" + http.HandleFunc("/webhook", webhook) + + // start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090" + http.ListenAndServe(":8090", nil) +} +``` + +What happens here is only a target which prints out the received request, which could also be handled with a different logic. + +## Create target + +As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows: + +[Create a target](/apis/resources/action_service_v3/action-service-create-target) + +```shell +curl -L -X POST 'https://$CUSTOM-DOMAIN/v3alpha/targets' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' \ +-H 'Authorization: Bearer ' \ +--data-raw '{ + "name": "local webhook", + "restWebhook": { + "interruptOnError": true + }, + "endpoint": "http://localhost:8090/webhook", + "timeout": "10s" +}' +``` + +Save the returned ID to set in the execution. + +## Set execution + +To call the target just created before, with the intention to print the request used for user creation by the user V2 API, we define an execution with a method condition. + +[Set an execution](/apis/resources/action_service_v3/action-service-set-execution) + +```shell +curl -L -X PUT 'https://$CUSTOM-DOMAIN/v3alpha/executions' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' \ +-H 'Authorization: Bearer ' \ +--data-raw '{ + "condition": { + "request": { + "method": "/zitadel.user.v2beta.UserService/AddHumanUser" + } + }, + "targets": [ + { + "target": "" + } + ] +}' +``` + +## Example call + +Now on every call on `/zitadel.user.v2beta.UserService/AddHumanUser` the local server prints out the received body of the request: + +```shell +curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/users/human' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' \ +-H 'Authorization: Bearer ' \ +--data-raw '{ + "profile": { + "givenName": "Example_given", + "familyName": "Example_family" + }, + "email": { + "email": "example@example.com" + } +}' +``` + +Should print out something like, also described under [Sent information Request](./introduction#sent-information-request): +```shell +{ + "fullMethod": "/zitadel.user.v2beta.UserService/AddHumanUser", + "instanceID": "262851882718855632", + "orgID": "262851882718921168", + "projectID": "262851882719052240", + "userID": "262851882718986704", + "request": { + "profile": { + "given_name": "Example_given", + "family_name": "Example_family" + }, + "email": { + "email": "example@example.com" + } + } +} +``` + + diff --git a/docs/docs/apis/actionsv2/introduction.md b/docs/docs/apis/actionsv2/introduction.md new file mode 100644 index 00000000000..16adaac4230 --- /dev/null +++ b/docs/docs/apis/actionsv2/introduction.md @@ -0,0 +1,167 @@ +--- +title: Actions V2 +--- + +This page describes the options you have when defining ZITADEL Actions V2. + +## Endpoints + +ZITADEL sends an HTTP Post request to the endpoint set as Target, the received request than can be edited and send back or custom processes can be handled. + +### Sent information Request + +The information sent to the Endpoint is structured as JSON: + +```json +{ + "fullMethod": "full method of the GRPC call", + "instanceID": "instanceID of the called instance", + "orgID": "ID of the organization related to the calling context", + "projectID": "ID of the project related to the used application", + "userID": "ID of the calling user", + "request": "full request of the call" +} +``` + +### Sent information Response + +The information sent to the Endpoint is structured as JSON: + +```json +{ + "fullMethod": "full method of the GRPC call", + "instanceID": "instanceID of the called instance", + "orgID": "ID of the organization related to the calling context", + "projectID": "ID of the project related to the used application", + "userID": "ID of the calling user", + "request": "full request of the call", + "response": "full response of the call" +} +``` + +## Target + +The Target describes how ZITADEL interacts with the Endpoint. + +There are different types of Targets: + +- `Webhook`, the call handles the status code but response is irrelevant, can be InterruptOnError +- `Call`, the call handles the status code and response, can be InterruptOnError +- `Async`, the call handles neither status code nor response, but can be called in parallel with other Targets + +`InterruptOnError` means that the Execution gets interrupted if any of the calls return with a status code >= 400, and the next Target will not be called anymore. + +The API documentation to create a target can be found [here](/apis/resources/action_service_v3/action-service-create-target) + +## Execution + +ZITADEL decides on specific conditions if one or more Targets have to be called. +The Execution resource contains 2 parts, the condition and the called targets. + +The condition can be defined for 4 types of processes: + +- `Requests`, before a request is processed by ZITADEL +- `Responses`, before a response is sent back to the application +- `Functions`, handling specific functionality in the logic of ZITADEL +- `Events`, after a specific event happened and was stored in ZITADEL + +The API documentation to set an Execution can be found [here](/apis/resources/action_service_v3/action-service-set-execution) + +### Condition Best Match + +As the conditions can be defined on different levels, ZITADEL tries to find out which Execution is the best match. +This means that for example if you have an Execution defined on `all requests`, on the service `zitadel.user.v2beta.UserService` and on `/zitadel.user.v2beta.UserService/AddHumanUser`, +ZITADEL would with a call on the `/zitadel.user.v2beta.UserService/AddHumanUser` use the Executions with the following priority: + +1. `/zitadel.user.v2beta.UserService/AddHumanUser` +2. `zitadel.user.v2beta.UserService` +3. `all` + +If you then have a call on `/zitadel.user.v2beta.UserService/UpdateHumanUser` the following priority would be found: + +1. `zitadel.user.v2beta.UserService` +2. `all` + +And if you use a different service, for example `zitadel.session.v2.SessionService`, then the `all` Execution would still be used. + +### Targets and Includes + +An execution can not only contain a list of Targets, but also Includes. +The Includes can be defined in the Execution directly, which means you include all defined Targets by a before set Execution. + +If you define 2 Executions as follows: + +```json +{ + "condition": { + "request": { + "service": "zitadel.user.v2beta.UserService" + } + }, + "targets": [ + { + "target": "" + } + ] +} +``` + +```json +{ + "condition": { + "request": { + "method": "/zitadel.user.v2beta.UserService/AddHumanUser" + } + }, + "targets": [ + { + "target": "" + }, + { + "include": { + "request": { + "service": "zitadel.user.v2beta.UserService" + } + } + } + ] +} +``` + +The called Targets on "/zitadel.user.v2beta.UserService/AddHumanUser" would be, in order: + +1. `` +2. `` + +### Condition for Requests and Responses + +For Request and Response there are 3 levels the condition can be defined: + +- `Method`, handling a request or response of a specific GRPC full method, which includes the service name and method of the ZITADEL API +- `Service`, handling any request or response under a service of the ZITADEL API +- `All`, handling any request or response under the ZITADEL API + +The available conditions can be found under: +- [All available Methods](/apis/resources/action_service_v3/action-service-list-execution-methods), for example `/zitadel.user.v2beta.UserService/AddHumanUser` +- [All available Services](/apis/resources/action_service_v3/action-service-list-execution-services), for example `zitadel.user.v2beta.UserService` + +### Condition for Functions + +Replace the current Actions with the following flows: + +- [Internal Authentication](../actions/internal-authentication) +- [External Authentication](../actions/external-authentication) +- [Complement Token](../actions/complement-token) +- [Customize SAML Response](../actions/customize-samlresponse) + +The available conditions can be found under [all available Functions](/apis/resources/action_service_v3/action-service-list-execution-functions). + +### Condition for Events + +For event there are 3 levels the condition can be defined: + +- Event, handling a specific event +- Group, handling a specific group of events +- All, handling any event in ZITADEL + +The concept of events can be found under [Events](/concepts/architecture/software#events) \ No newline at end of file diff --git a/docs/docs/concepts/features/actions.md b/docs/docs/concepts/features/actions.md index c3c18b0611c..21626d237c5 100644 --- a/docs/docs/concepts/features/actions.md +++ b/docs/docs/concepts/features/actions.md @@ -7,7 +7,7 @@ By using ZITADEL actions, you can manipulate ZITADELs behavior on specific Event This is useful when you have special business requirements that ZITADEL doesn't support out-of-the-box. :::info -We're working on Actions continuously. In the [roadmap](https://zitadel.com/roadmap), you see how we are planning to expand and improve it. Please tell us about your needs and help us prioritize further fixes and features. +We're working on Actions continuously. In the [roadmap](https://zitadel.com/roadmap), you see how we are planning to expand and improve it. Please tell us about your needs and help us prioritize further fixes and features. ::: ## Why actions? diff --git a/docs/docs/concepts/features/actions_v2.md b/docs/docs/concepts/features/actions_v2.md new file mode 100644 index 00000000000..3c782290450 --- /dev/null +++ b/docs/docs/concepts/features/actions_v2.md @@ -0,0 +1,40 @@ +--- +title: ZITADEL Actions v2 +sidebar_label: Actions v2 +--- + +By using ZITADEL actions V2, you can manipulate ZITADELs behavior on specific API calls, events or functions. +This is useful when you have special business requirements that ZITADEL doesn't support out-of-the-box. + +:::info +We're working on Actions continuously. In the [roadmap](https://zitadel.com/roadmap), you see how we are planning to expand and improve it. Please tell us about your needs and help us prioritize further fixes and features. +::: + +## Why actions? +ZITADEL can't anticipate and solve every possible business rule and integration requirements from all ZITADEL users. Here are some examples: +- A business requires domain specific data validation before a user can be created or authenticated. +- A business needs to automate tasks. Roles should be assigned to users based on their ADFS 2016+ groups. +- A business needs to store metadata on a user that is used for integrating applications. +- A business needs to restrict the users who are allowed to register to a certain organization by their email domains. + +With actions, ZITADEL provides a way to solve such problems. + +## How it works +There are 3 components necessary: +- Endpoint, an external endpoint with the desired logic, can be whatever is necessary as long as it can receive an HTTP Post request. +- Target, a resource in ZITADEL with all necessary information how to trigger an endpoint +- Execution, a resource in ZITADEL with the information when to trigger which targets + +The process is that ZITADEL decides at certain points that with a defined Execution a call to the defined Target(s) is triggered, +so that everybody can implement their custom behaviour for as many processes as possible. + +Possible conditions for the Execution: +- Request, to react to or manipulate requests to ZITADEL, for example add information to newly created users +- Response, to react to or manipulate responses to ZITADEL, for example to provision newly created users to other systems +- Function, to react to different functionality in ZITADEL, replaces [Actions](/concepts/features/actions) +- Event, to create to different events which get created in ZITADEL, for example to inform somebody if a user gets locked + +## Further reading + +- [Actions v2 example execution locally](/apis/actionsv2/execution-local) +- [Actions v2 reference](/apis/actionsv2/introduction#action) \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index ddb73baddef..48eda263dad 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -795,6 +795,15 @@ module.exports = { "apis/actions/objects", ], }, + { + type: "category", + label: "Actions V2", + collapsed: false, + items: [ + "apis/actionsv2/introduction", + "apis/actionsv2/execution-local", + ], + }, { type: "doc", label: "gRPC Status Codes", diff --git a/internal/api/grpc/action/v3alpha/execution.go b/internal/api/grpc/action/v3alpha/execution.go index dde4727c2ee..58a36cff226 100644 --- a/internal/api/grpc/action/v3alpha/execution.go +++ b/internal/api/grpc/action/v3alpha/execution.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/repository/execution" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha" ) @@ -33,46 +34,46 @@ func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionReque return nil, err } + targets := make([]*execution.Target, len(req.Targets)) + for i, target := range req.Targets { + switch t := target.GetType().(type) { + case *action.ExecutionTargetType_Include: + include, err := conditionToInclude(t.Include) + if err != nil { + return nil, err + } + targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeInclude, Target: include} + case *action.ExecutionTargetType_Target: + targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeTarget, Target: t.Target} + } + } set := &command.SetExecution{ - Targets: req.GetTargets(), - Includes: req.GetIncludes(), + Targets: targets, } var err error var details *domain.ObjectDetails switch t := req.GetCondition().GetConditionType().(type) { case *action.Condition_Request: - cond := &command.ExecutionAPICondition{ - Method: t.Request.GetMethod(), - Service: t.Request.GetService(), - All: t.Request.GetAll(), - } + cond := executionConditionFromRequest(t.Request) details, err = s.command.SetExecutionRequest(ctx, cond, set, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Response: - cond := &command.ExecutionAPICondition{ - Method: t.Response.GetMethod(), - Service: t.Response.GetService(), - All: t.Response.GetAll(), - } + cond := executionConditionFromResponse(t.Response) details, err = s.command.SetExecutionResponse(ctx, cond, set, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Event: - cond := &command.ExecutionEventCondition{ - Event: t.Event.GetEvent(), - Group: t.Event.GetGroup(), - All: t.Event.GetAll(), - } + cond := executionConditionFromEvent(t.Event) details, err = s.command.SetExecutionEvent(ctx, cond, set, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Function: - details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), set, authz.GetInstance(ctx).InstanceID()) + details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function.GetName()), set, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } @@ -82,6 +83,36 @@ func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionReque }, nil } +func conditionToInclude(cond *action.Condition) (string, error) { + switch t := cond.GetConditionType().(type) { + case *action.Condition_Request: + cond := executionConditionFromRequest(t.Request) + if err := cond.IsValid(); err != nil { + return "", err + } + return cond.ID(domain.ExecutionTypeRequest), nil + case *action.Condition_Response: + cond := executionConditionFromResponse(t.Response) + if err := cond.IsValid(); err != nil { + return "", err + } + return cond.ID(domain.ExecutionTypeRequest), nil + case *action.Condition_Event: + cond := executionConditionFromEvent(t.Event) + if err := cond.IsValid(); err != nil { + return "", err + } + return cond.ID(), nil + case *action.Condition_Function: + cond := command.ExecutionFunctionCondition(t.Function.GetName()) + if err := cond.IsValid(); err != nil { + return "", err + } + return cond.ID(), nil + } + return "", nil +} + func (s *Server) DeleteExecution(ctx context.Context, req *action.DeleteExecutionRequest) (*action.DeleteExecutionResponse, error) { if err := checkExecutionEnabled(ctx); err != nil { return nil, err @@ -91,37 +122,25 @@ func (s *Server) DeleteExecution(ctx context.Context, req *action.DeleteExecutio var details *domain.ObjectDetails switch t := req.GetCondition().GetConditionType().(type) { case *action.Condition_Request: - cond := &command.ExecutionAPICondition{ - Method: t.Request.GetMethod(), - Service: t.Request.GetService(), - All: t.Request.GetAll(), - } + cond := executionConditionFromRequest(t.Request) details, err = s.command.DeleteExecutionRequest(ctx, cond, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Response: - cond := &command.ExecutionAPICondition{ - Method: t.Response.GetMethod(), - Service: t.Response.GetService(), - All: t.Response.GetAll(), - } + cond := executionConditionFromResponse(t.Response) details, err = s.command.DeleteExecutionResponse(ctx, cond, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Event: - cond := &command.ExecutionEventCondition{ - Event: t.Event.GetEvent(), - Group: t.Event.GetGroup(), - All: t.Event.GetAll(), - } + cond := executionConditionFromEvent(t.Event) details, err = s.command.DeleteExecutionEvent(ctx, cond, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } case *action.Condition_Function: - details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), authz.GetInstance(ctx).InstanceID()) + details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function.GetName()), authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } @@ -130,3 +149,27 @@ func (s *Server) DeleteExecution(ctx context.Context, req *action.DeleteExecutio Details: object.DomainToDetailsPb(details), }, nil } + +func executionConditionFromRequest(request *action.RequestExecution) *command.ExecutionAPICondition { + return &command.ExecutionAPICondition{ + Method: request.GetMethod(), + Service: request.GetService(), + All: request.GetAll(), + } +} + +func executionConditionFromResponse(response *action.ResponseExecution) *command.ExecutionAPICondition { + return &command.ExecutionAPICondition{ + Method: response.GetMethod(), + Service: response.GetService(), + All: response.GetAll(), + } +} + +func executionConditionFromEvent(event *action.EventExecution) *command.ExecutionEventCondition { + return &command.ExecutionEventCondition{ + Event: event.GetEvent(), + Group: event.GetGroup(), + All: event.GetAll(), + } +} diff --git a/internal/api/grpc/action/v3alpha/execution_integration_test.go b/internal/api/grpc/action/v3alpha/execution_integration_test.go index 752e9b546af..4ca1b97d6f3 100644 --- a/internal/api/grpc/action/v3alpha/execution_integration_test.go +++ b/internal/api/grpc/action/v3alpha/execution_integration_test.go @@ -9,14 +9,23 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/integration" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" ) +func executionTargetsSingleTarget(id string) []*action.ExecutionTargetType { + return []*action.ExecutionTargetType{{Type: &action.ExecutionTargetType_Target{Target: id}}} +} + +func executionTargetsSingleInclude(include *action.Condition) []*action.ExecutionTargetType { + return []*action.ExecutionTargetType{{Type: &action.ExecutionTargetType_Include{Include: include}}} +} + func TestServer_SetExecution_Request(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -48,7 +57,7 @@ func TestServer_SetExecution_Request(t *testing.T) { Request: &action.RequestExecution{}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -65,7 +74,7 @@ func TestServer_SetExecution_Request(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -82,7 +91,7 @@ func TestServer_SetExecution_Request(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -104,7 +113,7 @@ func TestServer_SetExecution_Request(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -121,7 +130,7 @@ func TestServer_SetExecution_Request(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -143,7 +152,7 @@ func TestServer_SetExecution_Request(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -163,27 +172,28 @@ func TestServer_SetExecution_Request(t *testing.T) { require.NoError(t, err) integration.AssertDetails(t, tt.want, got) + + // cleanup to not impact other requests + Tester.DeleteExecution(tt.ctx, t, tt.req.GetCondition()) }) } } func TestServer_SetExecution_Request_Include(t *testing.T) { ensureFeatureEnabled(t) - - targetResp := Tester.CreateTarget(CTX, t) - executionCond := "request" - Tester.SetExecution(CTX, t, - &action.Condition{ - ConditionType: &action.Condition_Request{ - Request: &action.RequestExecution{ - Condition: &action.RequestExecution_All{ - All: true, - }, + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) + executionCond := &action.Condition{ + ConditionType: &action.Condition_Request{ + Request: &action.RequestExecution{ + Condition: &action.RequestExecution_All{ + All: true, }, }, }, - []string{targetResp.GetId()}, - []string{}, + } + Tester.SetExecution(CTX, t, + executionCond, + executionTargetsSingleTarget(targetResp.GetId()), ) tests := []struct { @@ -206,7 +216,7 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { }, }, }, - Includes: []string{executionCond}, + Targets: executionTargetsSingleInclude(executionCond), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -228,7 +238,7 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { }, }, }, - Includes: []string{executionCond}, + Targets: executionTargetsSingleInclude(executionCond), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -237,6 +247,7 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { }, }, }, + /* circular { name: "all, ok", ctx: CTX, @@ -250,7 +261,7 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { }, }, }, - Includes: []string{executionCond}, + Targets: executionTargetsSingleInclude(executionCond), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -259,6 +270,7 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { }, }, }, + */ } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -270,13 +282,16 @@ func TestServer_SetExecution_Request_Include(t *testing.T) { require.NoError(t, err) integration.AssertDetails(t, tt.want, got) + + // cleanup to not impact other requests + Tester.DeleteExecution(tt.ctx, t, tt.req.GetCondition()) }) } } func TestServer_DeleteExecution_Request(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -332,7 +347,7 @@ func TestServer_DeleteExecution_Request(t *testing.T) { name: "method, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -373,7 +388,7 @@ func TestServer_DeleteExecution_Request(t *testing.T) { name: "service, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -398,7 +413,7 @@ func TestServer_DeleteExecution_Request(t *testing.T) { name: "all, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -441,7 +456,7 @@ func TestServer_DeleteExecution_Request(t *testing.T) { func TestServer_SetExecution_Response(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -473,7 +488,7 @@ func TestServer_SetExecution_Response(t *testing.T) { Response: &action.ResponseExecution{}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -490,7 +505,7 @@ func TestServer_SetExecution_Response(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -507,7 +522,7 @@ func TestServer_SetExecution_Response(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -529,7 +544,7 @@ func TestServer_SetExecution_Response(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -546,7 +561,7 @@ func TestServer_SetExecution_Response(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -568,7 +583,7 @@ func TestServer_SetExecution_Response(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -588,13 +603,16 @@ func TestServer_SetExecution_Response(t *testing.T) { require.NoError(t, err) integration.AssertDetails(t, tt.want, got) + + // cleanup to not impact other requests + Tester.DeleteExecution(tt.ctx, t, tt.req.GetCondition()) }) } } func TestServer_DeleteExecution_Response(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -652,7 +670,7 @@ func TestServer_DeleteExecution_Response(t *testing.T) { name: "method, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -693,7 +711,7 @@ func TestServer_DeleteExecution_Response(t *testing.T) { name: "service, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -718,7 +736,7 @@ func TestServer_DeleteExecution_Response(t *testing.T) { name: "all, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -761,7 +779,7 @@ func TestServer_DeleteExecution_Response(t *testing.T) { func TestServer_SetExecution_Event(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -795,7 +813,7 @@ func TestServer_SetExecution_Event(t *testing.T) { Event: &action.EventExecution{}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -833,7 +851,7 @@ func TestServer_SetExecution_Event(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -876,7 +894,7 @@ func TestServer_SetExecution_Event(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -898,7 +916,7 @@ func TestServer_SetExecution_Event(t *testing.T) { }, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -918,13 +936,16 @@ func TestServer_SetExecution_Event(t *testing.T) { require.NoError(t, err) integration.AssertDetails(t, tt.want, got) + + // cleanup to not impact other requests + Tester.DeleteExecution(tt.ctx, t, tt.req.GetCondition()) }) } } func TestServer_DeleteExecution_Event(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -985,7 +1006,7 @@ func TestServer_DeleteExecution_Event(t *testing.T) { name: "event, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -1026,7 +1047,7 @@ func TestServer_DeleteExecution_Event(t *testing.T) { name: "group, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -1061,18 +1082,13 @@ func TestServer_DeleteExecution_Event(t *testing.T) { }, }, }, - want: &action.DeleteExecutionResponse{ - Details: &object.Details{ - ChangeDate: timestamppb.Now(), - ResourceOwner: Tester.Instance.InstanceID(), - }, - }, + wantErr: true, }, { name: "all, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ @@ -1115,7 +1131,7 @@ func TestServer_DeleteExecution_Event(t *testing.T) { func TestServer_SetExecution_Function(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -1147,7 +1163,7 @@ func TestServer_SetExecution_Function(t *testing.T) { Response: &action.ResponseExecution{}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -1157,10 +1173,10 @@ func TestServer_SetExecution_Function(t *testing.T) { req: &action.SetExecutionRequest{ Condition: &action.Condition{ ConditionType: &action.Condition_Function{ - Function: "xxx", + Function: &action.FunctionExecution{Name: "xxx"}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, wantErr: true, }, @@ -1170,10 +1186,10 @@ func TestServer_SetExecution_Function(t *testing.T) { req: &action.SetExecutionRequest{ Condition: &action.Condition{ ConditionType: &action.Condition_Function{ - Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication", + Function: &action.FunctionExecution{Name: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication"}, }, }, - Targets: []string{targetResp.GetId()}, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, want: &action.SetExecutionResponse{ Details: &object.Details{ @@ -1193,13 +1209,16 @@ func TestServer_SetExecution_Function(t *testing.T) { require.NoError(t, err) integration.AssertDetails(t, tt.want, got) + + // cleanup to not impact other requests + Tester.DeleteExecution(tt.ctx, t, tt.req.GetCondition()) }) } } func TestServer_DeleteExecution_Function(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://notexisting", domain.TargetTypeWebhook, false) tests := []struct { name string @@ -1243,7 +1262,7 @@ func TestServer_DeleteExecution_Function(t *testing.T) { req: &action.DeleteExecutionRequest{ Condition: &action.Condition{ ConditionType: &action.Condition_Function{ - Function: "xxx", + Function: &action.FunctionExecution{Name: "xxx"}, }, }, }, @@ -1253,13 +1272,13 @@ func TestServer_DeleteExecution_Function(t *testing.T) { name: "function, ok", ctx: CTX, dep: func(ctx context.Context, request *action.DeleteExecutionRequest) error { - Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{}) + Tester.SetExecution(ctx, t, request.GetCondition(), executionTargetsSingleTarget(targetResp.GetId())) return nil }, req: &action.DeleteExecutionRequest{ Condition: &action.Condition{ ConditionType: &action.Condition_Function{ - Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication", + Function: &action.FunctionExecution{Name: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication"}, }, }, }, diff --git a/internal/api/grpc/action/v3alpha/execution_target_integration_test.go b/internal/api/grpc/action/v3alpha/execution_target_integration_test.go new file mode 100644 index 00000000000..30afb1af6ff --- /dev/null +++ b/internal/api/grpc/action/v3alpha/execution_target_integration_test.go @@ -0,0 +1,323 @@ +//go:build integration + +package action_test + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/durationpb" + + "github.com/zitadel/zitadel/internal/api/grpc/server/middleware" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/integration" + action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha" +) + +func TestServer_ExecutionTarget(t *testing.T) { + ensureFeatureEnabled(t) + + fullMethod := "/zitadel.action.v3alpha.ActionService/GetTargetByID" + + tests := []struct { + name string + ctx context.Context + dep func(context.Context, *action.GetTargetByIDRequest, *action.GetTargetByIDResponse) (func(), error) + clean func(context.Context) + req *action.GetTargetByIDRequest + want *action.GetTargetByIDResponse + wantErr bool + }{ + { + name: "GetTargetByID, request and response, ok", + ctx: CTX, + dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) (func(), error) { + + instanceID := Tester.Instance.InstanceID() + orgID := Tester.Organisation.ID + projectID := "" + userID := Tester.Users.Get(integration.FirstInstanceUsersKey, integration.IAMOwner).ID + + // create target for target changes + targetCreatedName := fmt.Sprint("GetTargetByID", time.Now().UnixNano()+1) + targetCreatedURL := "https://nonexistent" + + targetCreated := Tester.CreateTarget(ctx, t, targetCreatedName, targetCreatedURL, domain.TargetTypeCall, false) + + // request received by target + wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instanceID, OrgID: orgID, ProjectID: projectID, UserID: userID, Request: request} + changedRequest := &action.GetTargetByIDRequest{TargetId: targetCreated.GetId()} + // replace original request with different targetID + urlRequest, closeRequest := testServerCall(wantRequest, 0, http.StatusOK, changedRequest) + targetRequest := Tester.CreateTarget(ctx, t, "", urlRequest, domain.TargetTypeCall, false) + Tester.SetExecution(ctx, t, conditionRequestFullMethod(fullMethod), executionTargetsSingleTarget(targetRequest.GetId())) + // GetTargetByID with used target + request.TargetId = targetRequest.GetId() + + // expected response from the GetTargetByID + expectedResponse := &action.GetTargetByIDResponse{ + Target: &action.Target{ + TargetId: targetCreated.GetId(), + Details: targetCreated.GetDetails(), + Name: targetCreatedName, + Endpoint: targetCreatedURL, + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: false, + }, + }, + Timeout: durationpb.New(10 * time.Second), + }, + } + // has to be set separately because of the pointers + response.Target = &action.Target{ + TargetId: targetCreated.GetId(), + Details: targetCreated.GetDetails(), + Name: targetCreatedName, + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: false, + }, + }, + Timeout: durationpb.New(10 * time.Second), + } + + // content for partial update + changedResponse := &action.GetTargetByIDResponse{ + Target: &action.Target{ + TargetId: "changed", + }, + } + // change partial updated content on returned response + response.Target.TargetId = changedResponse.Target.TargetId + + // response received by target + wantResponse := &middleware.ContextInfoResponse{ + FullMethod: fullMethod, + InstanceID: instanceID, + OrgID: orgID, + ProjectID: projectID, + UserID: userID, + Request: changedRequest, + Response: expectedResponse, + } + // after request with different targetID, return changed response + targetResponseURL, closeResponse := testServerCall(wantResponse, 0, http.StatusOK, changedResponse) + targetResponse := Tester.CreateTarget(ctx, t, "", targetResponseURL, domain.TargetTypeCall, false) + Tester.SetExecution(ctx, t, conditionResponseFullMethod(fullMethod), executionTargetsSingleTarget(targetResponse.GetId())) + + return func() { + closeRequest() + closeResponse() + }, nil + }, + clean: func(ctx context.Context) { + Tester.DeleteExecution(ctx, t, conditionRequestFullMethod(fullMethod)) + Tester.DeleteExecution(ctx, t, conditionResponseFullMethod(fullMethod)) + }, + req: &action.GetTargetByIDRequest{}, + want: &action.GetTargetByIDResponse{}, + }, + /*{ + name: "GetTargetByID, request, interrupt", + ctx: CTX, + dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) (func(), error) { + + fullMethod := "/zitadel.action.v3alpha.ActionService/GetTargetByID" + instanceID := Tester.Instance.InstanceID() + orgID := Tester.Organisation.ID + projectID := "" + userID := Tester.Users.Get(integration.FirstInstanceUsersKey, integration.IAMOwner).ID + + // request received by target + wantRequest := &middleware.ContextInfoRequest{FullMethod: fullMethod, InstanceID: instanceID, OrgID: orgID, ProjectID: projectID, UserID: userID, Request: request} + urlRequest, closeRequest := testServerCall(wantRequest, 0, http.StatusInternalServerError, &action.GetTargetByIDRequest{TargetId: "notchanged"}) + + targetRequest := Tester.CreateTarget(ctx, t, "", urlRequest, domain.TargetTypeCall, true) + Tester.SetExecution(ctx, t, conditionRequestFullMethod(fullMethod), executionTargetsSingleTarget(targetRequest.GetId())) + // GetTargetByID with used target + request.TargetId = targetRequest.GetId() + + return func() { + closeRequest() + }, nil + }, + clean: func(ctx context.Context) { + Tester.DeleteExecution(ctx, t, conditionRequestFullMethod(fullMethod)) + }, + req: &action.GetTargetByIDRequest{}, + wantErr: true, + }, + { + name: "GetTargetByID, response, interrupt", + ctx: CTX, + dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) (func(), error) { + + fullMethod := "/zitadel.action.v3alpha.ActionService/GetTargetByID" + instanceID := Tester.Instance.InstanceID() + orgID := Tester.Organisation.ID + projectID := "" + userID := Tester.Users.Get(integration.FirstInstanceUsersKey, integration.IAMOwner).ID + + // create target for target changes + targetCreatedName := fmt.Sprint("GetTargetByID", time.Now().UnixNano()+1) + targetCreatedURL := "https://nonexistent" + + targetCreated := Tester.CreateTarget(ctx, t, targetCreatedName, targetCreatedURL, domain.TargetTypeCall, false) + + // GetTargetByID with used target + request.TargetId = targetCreated.GetId() + + // expected response from the GetTargetByID + expectedResponse := &action.GetTargetByIDResponse{ + Target: &action.Target{ + TargetId: targetCreated.GetId(), + Details: targetCreated.GetDetails(), + Name: targetCreatedName, + Endpoint: targetCreatedURL, + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: false, + }, + }, + Timeout: durationpb.New(10 * time.Second), + }, + } + + // content for partial update + changedResponse := &action.GetTargetByIDResponse{ + Target: &action.Target{ + TargetId: "changed", + }, + } + + // response received by target + wantResponse := &middleware.ContextInfoResponse{ + FullMethod: fullMethod, + InstanceID: instanceID, + OrgID: orgID, + ProjectID: projectID, + UserID: userID, + Request: request, + Response: expectedResponse, + } + // after request with different targetID, return changed response + targetResponseURL, closeResponse := testServerCall(wantResponse, 0, http.StatusInternalServerError, changedResponse) + targetResponse := Tester.CreateTarget(ctx, t, "", targetResponseURL, domain.TargetTypeCall, true) + Tester.SetExecution(ctx, t, conditionResponseFullMethod(fullMethod), executionTargetsSingleTarget(targetResponse.GetId())) + + return func() { + closeResponse() + }, nil + }, + clean: func(ctx context.Context) { + Tester.DeleteExecution(ctx, t, conditionResponseFullMethod(fullMethod)) + }, + req: &action.GetTargetByIDRequest{}, + wantErr: true, + },*/ + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.dep != nil { + close, err := tt.dep(tt.ctx, tt.req, tt.want) + require.NoError(t, err) + defer close() + } + + got, err := Client.GetTargetByID(tt.ctx, tt.req) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + integration.AssertDetails(t, tt.want.GetTarget(), got.GetTarget()) + + assert.Equal(t, tt.want.Target.TargetId, got.Target.TargetId) + + if tt.clean != nil { + tt.clean(tt.ctx) + } + }) + } +} + +func conditionRequestFullMethod(fullMethod string) *action.Condition { + return &action.Condition{ + ConditionType: &action.Condition_Request{ + Request: &action.RequestExecution{ + Condition: &action.RequestExecution_Method{ + Method: fullMethod, + }, + }, + }, + } +} + +func conditionResponseFullMethod(fullMethod string) *action.Condition { + return &action.Condition{ + ConditionType: &action.Condition_Response{ + Response: &action.ResponseExecution{ + Condition: &action.ResponseExecution_Method{ + Method: fullMethod, + }, + }, + }, + } +} + +func testServerCall( + reqBody interface{}, + sleep time.Duration, + statusCode int, + respBody interface{}, +) (string, func()) { + handler := func(w http.ResponseWriter, r *http.Request) { + data, err := json.Marshal(reqBody) + if err != nil { + http.Error(w, "error, marshall: "+err.Error(), http.StatusInternalServerError) + return + } + + sentBody, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "error, read body: "+err.Error(), http.StatusInternalServerError) + return + } + if !reflect.DeepEqual(data, sentBody) { + http.Error(w, "error, equal:\n"+string(data)+"\nsent:\n"+string(sentBody), http.StatusInternalServerError) + return + } + if statusCode != http.StatusOK { + http.Error(w, "error, statusCode", statusCode) + return + } + + time.Sleep(sleep) + + w.Header().Set("Content-Type", "application/json") + resp, err := json.Marshal(respBody) + if err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + if _, err := io.WriteString(w, string(resp)); err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + } + + server := httptest.NewServer(http.HandlerFunc(handler)) + + return server.URL, server.Close +} diff --git a/internal/api/grpc/action/v3alpha/query.go b/internal/api/grpc/action/v3alpha/query.go index 582510b0bf3..095eaa7973d 100644 --- a/internal/api/grpc/action/v3alpha/query.go +++ b/internal/api/grpc/action/v3alpha/query.go @@ -2,6 +2,7 @@ package action import ( "context" + "strings" "google.golang.org/protobuf/types/known/durationpb" @@ -67,8 +68,6 @@ func targetFieldNameToSortingColumn(field action.TargetFieldName) query.Column { return query.TargetColumnURL case action.TargetFieldName_FIELD_NAME_TIMEOUT: return query.TargetColumnTimeout - case action.TargetFieldName_FIELD_NAME_ASYNC: - return query.TargetColumnAsync case action.TargetFieldName_FIELD_NAME_INTERRUPT_ON_ERROR: return query.TargetColumnInterruptOnError default: @@ -134,19 +133,16 @@ func targetToPb(t *query.Target) *action.Target { TargetId: t.ID, Name: t.Name, Timeout: durationpb.New(t.Timeout), - } - if t.Async { - target.ExecutionType = &action.Target_IsAsync{IsAsync: t.Async} - } - if t.InterruptOnError { - target.ExecutionType = &action.Target_InterruptOnError{InterruptOnError: t.InterruptOnError} + Endpoint: t.Endpoint, } switch t.TargetType { case domain.TargetTypeWebhook: - target.TargetType = &action.Target_RestWebhook{RestWebhook: &action.SetRESTWebhook{Url: t.URL}} - case domain.TargetTypeRequestResponse: - target.TargetType = &action.Target_RestRequestResponse{RestRequestResponse: &action.SetRESTRequestResponse{Url: t.URL}} + target.TargetType = &action.Target_RestWebhook{RestWebhook: &action.SetRESTWebhook{InterruptOnError: t.InterruptOnError}} + case domain.TargetTypeCall: + target.TargetType = &action.Target_RestCall{RestCall: &action.SetRESTCall{InterruptOnError: t.InterruptOnError}} + case domain.TargetTypeAsync: + target.TargetType = &action.Target_RestAsync{RestAsync: &action.SetRESTAsync{}} default: target.TargetType = nil } @@ -205,10 +201,14 @@ func executionQueryToQuery(searchQuery *action.SearchQuery) (query.SearchQuery, return inConditionsQueryToQuery(q.InConditionsQuery) case *action.SearchQuery_ExecutionTypeQuery: return executionTypeToQuery(q.ExecutionTypeQuery) - case *action.SearchQuery_TargetQuery: - return query.NewExecutionTargetSearchQuery(q.TargetQuery.GetTargetId()) case *action.SearchQuery_IncludeQuery: - return query.NewExecutionIncludeSearchQuery(q.IncludeQuery.GetInclude()) + include, err := conditionToInclude(q.IncludeQuery.GetInclude()) + if err != nil { + return nil, err + } + return query.NewIncludeSearchQuery(include) + case *action.SearchQuery_TargetQuery: + return query.NewTargetSearchQuery(q.TargetQuery.GetTargetId()) default: return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") } @@ -267,7 +267,7 @@ func conditionToID(q *action.Condition) (string, error) { } return cond.ID(), nil case *action.Condition_Function: - return t.Function, nil + return command.ExecutionFunctionCondition(t.Function.GetName()).ID(), nil default: return "", zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") } @@ -282,17 +282,83 @@ func executionsToPb(executions []*query.Execution) []*action.Execution { } func executionToPb(e *query.Execution) *action.Execution { - var targets, includes []string - if len(e.Targets) > 0 { - targets = e.Targets - } - if len(e.Includes) > 0 { - includes = e.Includes + targets := make([]*action.ExecutionTargetType, len(e.Targets)) + for i := range e.Targets { + switch e.Targets[i].Type { + case domain.ExecutionTargetTypeInclude: + targets[i] = &action.ExecutionTargetType{Type: &action.ExecutionTargetType_Include{Include: executionIDToCondition(e.Targets[i].Target)}} + case domain.ExecutionTargetTypeTarget: + targets[i] = &action.ExecutionTargetType{Type: &action.ExecutionTargetType_Target{Target: e.Targets[i].Target}} + case domain.ExecutionTargetTypeUnspecified: + continue + default: + continue + } } + return &action.Execution{ - Details: object.DomainToDetailsPb(&e.ObjectDetails), - ExecutionId: e.ID, - Targets: targets, - Includes: includes, + Details: object.DomainToDetailsPb(&e.ObjectDetails), + Condition: executionIDToCondition(e.ID), + Targets: targets, + } +} + +func executionIDToCondition(include string) *action.Condition { + if strings.HasPrefix(include, domain.ExecutionTypeRequest.String()) { + return includeRequestToCondition(strings.TrimPrefix(include, domain.ExecutionTypeRequest.String())) + } + if strings.HasPrefix(include, domain.ExecutionTypeResponse.String()) { + return includeResponseToCondition(strings.TrimPrefix(include, domain.ExecutionTypeResponse.String())) + } + if strings.HasPrefix(include, domain.ExecutionTypeEvent.String()) { + return includeEventToCondition(strings.TrimPrefix(include, domain.ExecutionTypeEvent.String())) } + if strings.HasPrefix(include, domain.ExecutionTypeFunction.String()) { + return includeFunctionToCondition(strings.TrimPrefix(include, domain.ExecutionTypeFunction.String())) + } + return nil +} + +func includeRequestToCondition(id string) *action.Condition { + switch strings.Count(id, "/") { + case 2: + return &action.Condition{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Method{Method: id}}}} + case 1: + return &action.Condition{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Service{Service: strings.TrimPrefix(id, "/")}}}} + case 0: + return &action.Condition{ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_All{All: true}}}} + default: + return nil + } +} +func includeResponseToCondition(id string) *action.Condition { + switch strings.Count(id, "/") { + case 2: + return &action.Condition{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Method{Method: id}}}} + case 1: + return &action.Condition{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Service{Service: strings.TrimPrefix(id, "/")}}}} + case 0: + return &action.Condition{ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_All{All: true}}}} + default: + return nil + } +} + +func includeEventToCondition(id string) *action.Condition { + switch strings.Count(id, "/") { + case 1: + if strings.HasSuffix(id, command.EventGroupSuffix) { + return &action.Condition{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Group{Group: strings.TrimSuffix(strings.TrimPrefix(id, "/"), command.EventGroupSuffix)}}}} + } else { + return &action.Condition{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Event{Event: strings.TrimPrefix(id, "/")}}}} + } + case 0: + return &action.Condition{ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_All{All: true}}}} + default: + return nil + } +} + +func includeFunctionToCondition(id string) *action.Condition { + return &action.Condition{ConditionType: &action.Condition_Function{Function: &action.FunctionExecution{Name: strings.TrimPrefix(id, "/")}}} } diff --git a/internal/api/grpc/action/v3alpha/query_integration_test.go b/internal/api/grpc/action/v3alpha/query_integration_test.go index 31b5a8025a8..b083eda5a46 100644 --- a/internal/api/grpc/action/v3alpha/query_integration_test.go +++ b/internal/api/grpc/action/v3alpha/query_integration_test.go @@ -5,6 +5,7 @@ package action_test import ( "context" "fmt" + "reflect" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/durationpb" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/integration" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" @@ -52,7 +54,7 @@ func TestServer_GetTargetByID(t *testing.T) { ctx: CTX, dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error { name := fmt.Sprint(time.Now().UnixNano() + 1) - resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeWebhook, false) request.TargetId = resp.GetId() response.Target.TargetId = resp.GetId() @@ -69,10 +71,9 @@ func TestServer_GetTargetByID(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, + Endpoint: "https://example.com", TargetType: &action.Target_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", - }, + RestWebhook: &action.SetRESTWebhook{}, }, Timeout: durationpb.New(10 * time.Second), }, @@ -84,7 +85,7 @@ func TestServer_GetTargetByID(t *testing.T) { ctx: CTX, dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error { name := fmt.Sprint(time.Now().UnixNano() + 1) - resp := Tester.CreateTargetWithNameAndType(ctx, t, name, true, false) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeAsync, false) request.TargetId = resp.GetId() response.Target.TargetId = resp.GetId() @@ -101,23 +102,54 @@ func TestServer_GetTargetByID(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, + Endpoint: "https://example.com", + TargetType: &action.Target_RestAsync{ + RestAsync: &action.SetRESTAsync{}, + }, + Timeout: durationpb.New(10 * time.Second), + }, + }, + }, + { + name: "get, webhook interruptOnError, ok", + args: args{ + ctx: CTX, + dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error { + name := fmt.Sprint(time.Now().UnixNano() + 1) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeWebhook, true) + request.TargetId = resp.GetId() + + response.Target.TargetId = resp.GetId() + response.Target.Name = name + response.Target.Details.ResourceOwner = resp.GetDetails().GetResourceOwner() + response.Target.Details.ChangeDate = resp.GetDetails().GetChangeDate() + response.Target.Details.Sequence = resp.GetDetails().GetSequence() + return nil + }, + req: &action.GetTargetByIDRequest{}, + }, + want: &action.GetTargetByIDResponse{ + Target: &action.Target{ + Details: &object.Details{ + ResourceOwner: Tester.Instance.InstanceID(), + }, + Endpoint: "https://example.com", TargetType: &action.Target_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: true, }, }, - Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.Target_IsAsync{IsAsync: true}, + Timeout: durationpb.New(10 * time.Second), }, }, }, { - name: "get, interruptOnError, ok", + name: "get, call, ok", args: args{ ctx: CTX, dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error { name := fmt.Sprint(time.Now().UnixNano() + 1) - resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, true) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeCall, false) request.TargetId = resp.GetId() response.Target.TargetId = resp.GetId() @@ -134,13 +166,46 @@ func TestServer_GetTargetByID(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - TargetType: &action.Target_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + Endpoint: "https://example.com", + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: false, }, }, - Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.Target_InterruptOnError{InterruptOnError: true}, + Timeout: durationpb.New(10 * time.Second), + }, + }, + }, + { + name: "get, call interruptOnError, ok", + args: args{ + ctx: CTX, + dep: func(ctx context.Context, request *action.GetTargetByIDRequest, response *action.GetTargetByIDResponse) error { + name := fmt.Sprint(time.Now().UnixNano() + 1) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeCall, true) + request.TargetId = resp.GetId() + + response.Target.TargetId = resp.GetId() + response.Target.Name = name + response.Target.Details.ResourceOwner = resp.GetDetails().GetResourceOwner() + response.Target.Details.ChangeDate = resp.GetDetails().GetChangeDate() + response.Target.Details.Sequence = resp.GetDetails().GetSequence() + return nil + }, + req: &action.GetTargetByIDRequest{}, + }, + want: &action.GetTargetByIDResponse{ + Target: &action.Target{ + Details: &object.Details{ + ResourceOwner: Tester.Instance.InstanceID(), + }, + Endpoint: "https://example.com", + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, + }, + }, + Timeout: durationpb.New(10 * time.Second), }, }, }, @@ -163,15 +228,11 @@ func TestServer_GetTargetByID(t *testing.T) { assert.Error(ttt, getErr, "Error: "+getErr.Error()) } else { assert.NoError(ttt, getErr) - } - if getErr != nil { - fmt.Println("Error: " + getErr.Error()) - return - } - integration.AssertDetails(t, tt.want.GetTarget(), got.GetTarget()) + integration.AssertDetails(t, tt.want.GetTarget(), got.GetTarget()) - assert.Equal(t, tt.want.Target, got.Target) + assert.Equal(t, tt.want.Target, got.Target) + } }, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result") }) @@ -227,14 +288,14 @@ func TestServer_ListTargets(t *testing.T) { ctx: CTX, dep: func(ctx context.Context, request *action.ListTargetsRequest, response *action.ListTargetsResponse) error { name := fmt.Sprint(time.Now().UnixNano() + 1) - resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeWebhook, false) request.Queries[0].Query = &action.TargetSearchQuery_InTargetIdsQuery{ InTargetIdsQuery: &action.InTargetIDsQuery{ TargetIds: []string{resp.GetId()}, }, } response.Details.Timestamp = resp.GetDetails().GetChangeDate() - response.Details.ProcessedSequence = resp.GetDetails().GetSequence() + //response.Details.ProcessedSequence = resp.GetDetails().GetSequence() response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate() response.Result[0].Details.Sequence = resp.GetDetails().GetSequence() @@ -255,9 +316,10 @@ func TestServer_ListTargets(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, + Endpoint: "https://example.com", TargetType: &action.Target_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: false, }, }, Timeout: durationpb.New(10 * time.Second), @@ -270,7 +332,7 @@ func TestServer_ListTargets(t *testing.T) { ctx: CTX, dep: func(ctx context.Context, request *action.ListTargetsRequest, response *action.ListTargetsResponse) error { name := fmt.Sprint(time.Now().UnixNano() + 1) - resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false) + resp := Tester.CreateTarget(ctx, t, name, "https://example.com", domain.TargetTypeWebhook, false) request.Queries[0].Query = &action.TargetSearchQuery_TargetNameQuery{ TargetNameQuery: &action.TargetNameQuery{ TargetName: name, @@ -298,9 +360,10 @@ func TestServer_ListTargets(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, + Endpoint: "https://example.com", TargetType: &action.Target_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: false, }, }, Timeout: durationpb.New(10 * time.Second), @@ -316,9 +379,9 @@ func TestServer_ListTargets(t *testing.T) { name1 := fmt.Sprint(time.Now().UnixNano() + 1) name2 := fmt.Sprint(time.Now().UnixNano() + 3) name3 := fmt.Sprint(time.Now().UnixNano() + 5) - resp1 := Tester.CreateTargetWithNameAndType(ctx, t, name1, false, false) - resp2 := Tester.CreateTargetWithNameAndType(ctx, t, name2, true, false) - resp3 := Tester.CreateTargetWithNameAndType(ctx, t, name3, false, true) + resp1 := Tester.CreateTarget(ctx, t, name1, "https://example.com", domain.TargetTypeWebhook, false) + resp2 := Tester.CreateTarget(ctx, t, name2, "https://example.com", domain.TargetTypeCall, true) + resp3 := Tester.CreateTarget(ctx, t, name3, "https://example.com", domain.TargetTypeAsync, false) request.Queries[0].Query = &action.TargetSearchQuery_InTargetIdsQuery{ InTargetIdsQuery: &action.InTargetIDsQuery{ TargetIds: []string{resp1.GetId(), resp2.GetId(), resp3.GetId()}, @@ -354,9 +417,10 @@ func TestServer_ListTargets(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, + Endpoint: "https://example.com", TargetType: &action.Target_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: false, }, }, Timeout: durationpb.New(10 * time.Second), @@ -365,25 +429,23 @@ func TestServer_ListTargets(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - TargetType: &action.Target_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + Endpoint: "https://example.com", + TargetType: &action.Target_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, }, }, - Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.Target_IsAsync{IsAsync: true}, + Timeout: durationpb.New(10 * time.Second), }, { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - TargetType: &action.Target_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", - }, + Endpoint: "https://example.com", + TargetType: &action.Target_RestAsync{ + RestAsync: &action.SetRESTAsync{}, }, - Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.Target_InterruptOnError{InterruptOnError: true}, + Timeout: durationpb.New(10 * time.Second), }, }, }, @@ -422,9 +484,9 @@ func TestServer_ListTargets(t *testing.T) { } } -func TestServer_ListExecutions_Request(t *testing.T) { +func TestServer_ListExecutions(t *testing.T) { ensureFeatureEnabled(t) - targetResp := Tester.CreateTarget(CTX, t) + targetResp := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false) type args struct { ctx context.Context @@ -446,17 +508,20 @@ func TestServer_ListExecutions_Request(t *testing.T) { wantErr: true, }, { - name: "list single condition", + name: "list request single condition", args: args{ ctx: CTX, dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error { - resp := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{}) + cond := request.Queries[0].GetInConditionsQuery().GetConditions()[0] + resp := Tester.SetExecution(ctx, t, cond, executionTargetsSingleTarget(targetResp.GetId())) response.Details.Timestamp = resp.GetDetails().GetChangeDate() - response.Details.ProcessedSequence = resp.GetDetails().GetSequence() + // response.Details.ProcessedSequence = resp.GetDetails().GetSequence() + // Set expected response with used values for SetExecution response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate() response.Result[0].Details.Sequence = resp.GetDetails().GetSequence() + response.Result[0].Condition = cond return nil }, req: &action.ListExecutionsRequest{ @@ -471,8 +536,7 @@ func TestServer_ListExecutions_Request(t *testing.T) { }, }, }, - }, - }, + }}, }, }, }}, @@ -487,18 +551,26 @@ func TestServer_ListExecutions_Request(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.session.v2beta.SessionService/GetSession", - Targets: []string{targetResp.GetId()}, + Condition: &action.Condition{ + ConditionType: &action.Condition_Request{ + Request: &action.RequestExecution{ + Condition: &action.RequestExecution_Method{ + Method: "/zitadel.session.v2beta.SessionService/GetSession", + }, + }, + }, + }, + Targets: executionTargetsSingleTarget(targetResp.GetId()), }, }, }, }, { - name: "list single target", + name: "list request single target", args: args{ ctx: CTX, dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error { - target := Tester.CreateTarget(ctx, t) + target := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false) // add target as query to the request request.Queries[0] = &action.SearchQuery{ Query: &action.SearchQuery_TargetQuery{ @@ -507,7 +579,7 @@ func TestServer_ListExecutions_Request(t *testing.T) { }, }, } - resp := Tester.SetExecution(ctx, t, &action.Condition{ + cond := &action.Condition{ ConditionType: &action.Condition_Request{ Request: &action.RequestExecution{ Condition: &action.RequestExecution_Method{ @@ -515,14 +587,17 @@ func TestServer_ListExecutions_Request(t *testing.T) { }, }, }, - }, []string{target.GetId()}, []string{}) + } + targets := executionTargetsSingleTarget(target.GetId()) + resp := Tester.SetExecution(ctx, t, cond, targets) response.Details.Timestamp = resp.GetDetails().GetChangeDate() response.Details.ProcessedSequence = resp.GetDetails().GetSequence() response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate() response.Result[0].Details.Sequence = resp.GetDetails().GetSequence() - response.Result[0].Targets[0] = target.GetId() + response.Result[0].Condition = cond + response.Result[0].Targets = targets return nil }, req: &action.ListExecutionsRequest{ @@ -538,17 +613,17 @@ func TestServer_ListExecutions_Request(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.management.v1.ManagementService/UpdateAction", - Targets: []string{""}, + Condition: &action.Condition{}, + Targets: executionTargetsSingleTarget(""), }, }, }, }, { - name: "list single include", + name: "list request single include", args: args{ ctx: CTX, dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error { - Tester.SetExecution(ctx, t, &action.Condition{ + cond := &action.Condition{ ConditionType: &action.Condition_Request{ Request: &action.RequestExecution{ Condition: &action.RequestExecution_Method{ @@ -556,8 +631,11 @@ func TestServer_ListExecutions_Request(t *testing.T) { }, }, }, - }, []string{targetResp.GetId()}, []string{}) - resp2 := Tester.SetExecution(ctx, t, &action.Condition{ + } + Tester.SetExecution(ctx, t, cond, executionTargetsSingleTarget(targetResp.GetId())) + request.Queries[0].GetIncludeQuery().Include = cond + + includeCond := &action.Condition{ ConditionType: &action.Condition_Request{ Request: &action.RequestExecution{ Condition: &action.RequestExecution_Method{ @@ -565,19 +643,23 @@ func TestServer_ListExecutions_Request(t *testing.T) { }, }, }, - }, []string{}, []string{"request./zitadel.management.v1.ManagementService/GetAction"}) + } + includeTargets := executionTargetsSingleInclude(cond) + resp2 := Tester.SetExecution(ctx, t, includeCond, includeTargets) response.Details.Timestamp = resp2.GetDetails().GetChangeDate() response.Details.ProcessedSequence = resp2.GetDetails().GetSequence() response.Result[0].Details.ChangeDate = resp2.GetDetails().GetChangeDate() response.Result[0].Details.Sequence = resp2.GetDetails().GetSequence() + response.Result[0].Condition = includeCond + response.Result[0].Targets = includeTargets return nil }, req: &action.ListExecutionsRequest{ Queries: []*action.SearchQuery{{ Query: &action.SearchQuery_IncludeQuery{ - IncludeQuery: &action.IncludeQuery{Include: "request./zitadel.management.v1.ManagementService/GetAction"}, + IncludeQuery: &action.IncludeQuery{}, }, }}, }, @@ -591,8 +673,6 @@ func TestServer_ListExecutions_Request(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.management.v1.ManagementService/ListActions", - Includes: []string{"request./zitadel.management.v1.ManagementService/GetAction"}, }, }, }, @@ -603,19 +683,32 @@ func TestServer_ListExecutions_Request(t *testing.T) { ctx: CTX, dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error { - resp1 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{}) + cond1 := request.Queries[0].GetInConditionsQuery().GetConditions()[0] + targets1 := executionTargetsSingleTarget(targetResp.GetId()) + resp1 := Tester.SetExecution(ctx, t, cond1, targets1) response.Result[0].Details.ChangeDate = resp1.GetDetails().GetChangeDate() response.Result[0].Details.Sequence = resp1.GetDetails().GetSequence() + response.Result[0].Condition = cond1 + response.Result[0].Targets = targets1 - resp2 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[1], []string{targetResp.GetId()}, []string{}) + cond2 := request.Queries[0].GetInConditionsQuery().GetConditions()[1] + targets2 := executionTargetsSingleTarget(targetResp.GetId()) + resp2 := Tester.SetExecution(ctx, t, cond2, targets2) response.Result[1].Details.ChangeDate = resp2.GetDetails().GetChangeDate() response.Result[1].Details.Sequence = resp2.GetDetails().GetSequence() + response.Result[1].Condition = cond2 + response.Result[1].Targets = targets2 - resp3 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[2], []string{targetResp.GetId()}, []string{}) - response.Details.Timestamp = resp3.GetDetails().GetChangeDate() - response.Details.ProcessedSequence = resp3.GetDetails().GetSequence() + cond3 := request.Queries[0].GetInConditionsQuery().GetConditions()[2] + targets3 := executionTargetsSingleTarget(targetResp.GetId()) + resp3 := Tester.SetExecution(ctx, t, cond3, targets3) response.Result[2].Details.ChangeDate = resp3.GetDetails().GetChangeDate() response.Result[2].Details.Sequence = resp3.GetDetails().GetSequence() + response.Result[2].Condition = cond3 + response.Result[2].Targets = targets3 + + response.Details.Timestamp = resp3.GetDetails().GetChangeDate() + response.Details.ProcessedSequence = resp3.GetDetails().GetSequence() return nil }, req: &action.ListExecutionsRequest{ @@ -665,24 +758,77 @@ func TestServer_ListExecutions_Request(t *testing.T) { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.session.v2beta.SessionService/GetSession", - Targets: []string{targetResp.GetId()}, }, { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.session.v2beta.SessionService/CreateSession", - Targets: []string{targetResp.GetId()}, }, { Details: &object.Details{ ResourceOwner: Tester.Instance.InstanceID(), }, - ExecutionId: "request./zitadel.session.v2beta.SessionService/SetSession", - Targets: []string{targetResp.GetId()}, }, }, }, }, + { + name: "list multiple conditions all types", + args: args{ + ctx: CTX, + dep: func(ctx context.Context, request *action.ListExecutionsRequest, response *action.ListExecutionsResponse) error { + targets := executionTargetsSingleTarget(targetResp.GetId()) + for i, cond := range request.Queries[0].GetInConditionsQuery().GetConditions() { + resp := Tester.SetExecution(ctx, t, cond, targets) + response.Result[i].Details.ChangeDate = resp.GetDetails().GetChangeDate() + response.Result[i].Details.Sequence = resp.GetDetails().GetSequence() + response.Result[i].Condition = cond + response.Result[i].Targets = targets + + // filled with info of last sequence + response.Details.Timestamp = resp.GetDetails().GetChangeDate() + response.Details.ProcessedSequence = resp.GetDetails().GetSequence() + } + + return nil + }, + req: &action.ListExecutionsRequest{ + Queries: []*action.SearchQuery{{ + Query: &action.SearchQuery_InConditionsQuery{ + InConditionsQuery: &action.InConditionsQuery{ + Conditions: []*action.Condition{ + {ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Method{Method: "/zitadel.session.v2beta.SessionService/GetSession"}}}}, + {ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_Service{Service: "zitadel.session.v2beta.SessionService"}}}}, + {ConditionType: &action.Condition_Request{Request: &action.RequestExecution{Condition: &action.RequestExecution_All{All: true}}}}, + {ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Method{Method: "/zitadel.session.v2beta.SessionService/GetSession"}}}}, + {ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_Service{Service: "zitadel.session.v2beta.SessionService"}}}}, + {ConditionType: &action.Condition_Response{Response: &action.ResponseExecution{Condition: &action.ResponseExecution_All{All: true}}}}, + {ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Event{Event: "user.added"}}}}, + {ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_Group{Group: "user"}}}}, + {ConditionType: &action.Condition_Event{Event: &action.EventExecution{Condition: &action.EventExecution_All{All: true}}}}, + {ConditionType: &action.Condition_Function{Function: &action.FunctionExecution{Name: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication"}}}, + }, + }, + }, + }}, + }, + }, + want: &action.ListExecutionsResponse{ + Details: &object.ListDetails{ + TotalResult: 10, + }, + Result: []*action.Execution{ + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + {Details: &object.Details{ResourceOwner: Tester.Instance.InstanceID()}}, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -699,20 +845,33 @@ func TestServer_ListExecutions_Request(t *testing.T) { require.EventuallyWithT(t, func(ttt *assert.CollectT) { got, listErr := Client.ListExecutions(tt.args.ctx, tt.args.req) if tt.wantErr { - assert.Error(ttt, listErr, "Error: "+listErr.Error()) + assert.Error(t, listErr, "Error: "+listErr.Error()) } else { - assert.NoError(ttt, listErr) + assert.NoError(t, listErr) } if listErr != nil { return } // always first check length, otherwise its failed anyway - assert.Len(ttt, got.Result, len(tt.want.Result)) + assert.Len(t, got.Result, len(tt.want.Result)) for i := range tt.want.Result { - assert.Contains(ttt, got.Result, tt.want.Result[i]) + // as not sorted, all elements have to be checked + // workaround as oneof elements can only be checked with assert.EqualExportedValues() + if j, found := containExecution(got.Result, tt.want.Result[i]); found { + assert.EqualExportedValues(t, tt.want.Result[i], got.Result[j]) + } } integration.AssertListDetails(t, tt.want, got) }, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result") }) } } + +func containExecution(executionList []*action.Execution, execution *action.Execution) (int, bool) { + for i, exec := range executionList { + if reflect.DeepEqual(exec.Details, execution.Details) { + return i, true + } + } + return 0, false +} diff --git a/internal/api/grpc/action/v3alpha/server.go b/internal/api/grpc/action/v3alpha/server.go index dfd813a5ad5..952a555d24f 100644 --- a/internal/api/grpc/action/v3alpha/server.go +++ b/internal/api/grpc/action/v3alpha/server.go @@ -66,5 +66,5 @@ func checkExecutionEnabled(ctx context.Context) error { if authz.GetInstance(ctx).Features().Actions { return nil } - return zerrors.ThrowPreconditionFailed(nil, "SCHEMA-141bwx3lef", "Errors.action.NotEnabled") + return zerrors.ThrowPreconditionFailed(nil, "ACTION-8o6pvqfjhs", "Errors.Action.NotEnabled") } diff --git a/internal/api/grpc/action/v3alpha/target.go b/internal/api/grpc/action/v3alpha/target.go index 1a01ad22606..c57d5b607f4 100644 --- a/internal/api/grpc/action/v3alpha/target.go +++ b/internal/api/grpc/action/v3alpha/target.go @@ -58,23 +58,26 @@ func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetReque } func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget { - var targetType domain.TargetType - var url string + var ( + targetType domain.TargetType + interruptOnError bool + ) switch t := req.GetTargetType().(type) { case *action.CreateTargetRequest_RestWebhook: targetType = domain.TargetTypeWebhook - url = t.RestWebhook.GetUrl() - case *action.CreateTargetRequest_RestRequestResponse: - targetType = domain.TargetTypeRequestResponse - url = t.RestRequestResponse.GetUrl() + interruptOnError = t.RestWebhook.InterruptOnError + case *action.CreateTargetRequest_RestCall: + targetType = domain.TargetTypeCall + interruptOnError = t.RestCall.InterruptOnError + case *action.CreateTargetRequest_RestAsync: + targetType = domain.TargetTypeAsync } return &command.AddTarget{ Name: req.GetName(), TargetType: targetType, - URL: url, + Endpoint: req.GetEndpoint(), Timeout: req.GetTimeout().AsDuration(), - Async: req.GetIsAsync(), - InterruptOnError: req.GetInterruptOnError(), + InterruptOnError: interruptOnError, } } @@ -86,22 +89,24 @@ func updateTargetToCommand(req *action.UpdateTargetRequest) *command.ChangeTarge ObjectRoot: models.ObjectRoot{ AggregateID: req.GetTargetId(), }, - Name: req.Name, + Name: req.Name, + Endpoint: req.Endpoint, } - switch t := req.GetTargetType().(type) { - case *action.UpdateTargetRequest_RestWebhook: - target.TargetType = gu.Ptr(domain.TargetTypeWebhook) - target.URL = gu.Ptr(t.RestWebhook.GetUrl()) - case *action.UpdateTargetRequest_RestRequestResponse: - target.TargetType = gu.Ptr(domain.TargetTypeRequestResponse) - target.URL = gu.Ptr(t.RestRequestResponse.GetUrl()) + if req.TargetType != nil { + switch t := req.GetTargetType().(type) { + case *action.UpdateTargetRequest_RestWebhook: + target.TargetType = gu.Ptr(domain.TargetTypeWebhook) + target.InterruptOnError = gu.Ptr(t.RestWebhook.InterruptOnError) + case *action.UpdateTargetRequest_RestCall: + target.TargetType = gu.Ptr(domain.TargetTypeCall) + target.InterruptOnError = gu.Ptr(t.RestCall.InterruptOnError) + case *action.UpdateTargetRequest_RestAsync: + target.TargetType = gu.Ptr(domain.TargetTypeAsync) + target.InterruptOnError = gu.Ptr(false) + } } if req.Timeout != nil { target.Timeout = gu.Ptr(req.GetTimeout().AsDuration()) } - if req.ExecutionType != nil { - target.Async = gu.Ptr(req.GetIsAsync()) - target.InterruptOnError = gu.Ptr(req.GetInterruptOnError()) - } return target } diff --git a/internal/api/grpc/action/v3alpha/target_integration_test.go b/internal/api/grpc/action/v3alpha/target_integration_test.go index 2d45bed6d84..8b143fddb80 100644 --- a/internal/api/grpc/action/v3alpha/target_integration_test.go +++ b/internal/api/grpc/action/v3alpha/target_integration_test.go @@ -14,6 +14,7 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/integration" action "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" @@ -69,8 +70,8 @@ func TestServer_CreateTarget(t *testing.T) { ctx: CTX, req: &action.CreateTargetRequest{ Name: fmt.Sprint(time.Now().UnixNano() + 1), - TargetType: &action.CreateTargetRequest_RestRequestResponse{ - RestRequestResponse: &action.SetRESTRequestResponse{}, + TargetType: &action.CreateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{}, }, }, wantErr: true, @@ -79,29 +80,45 @@ func TestServer_CreateTarget(t *testing.T) { name: "empty timeout", ctx: CTX, req: &action.CreateTargetRequest{ - Name: fmt.Sprint(time.Now().UnixNano() + 1), + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", TargetType: &action.CreateTargetRequest_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", - }, + RestWebhook: &action.SetRESTWebhook{}, }, - Timeout: nil, - ExecutionType: nil, + Timeout: nil, }, wantErr: true, }, { - name: "empty execution type, ok", + name: "async, ok", ctx: CTX, req: &action.CreateTargetRequest{ - Name: fmt.Sprint(time.Now().UnixNano() + 1), + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", + TargetType: &action.CreateTargetRequest_RestAsync{ + RestAsync: &action.SetRESTAsync{}, + }, + Timeout: durationpb.New(10 * time.Second), + }, + want: &action.CreateTargetResponse{ + Details: &object.Details{ + ChangeDate: timestamppb.Now(), + ResourceOwner: Tester.Instance.InstanceID(), + }, + }, + }, + { + name: "webhook, ok", + ctx: CTX, + req: &action.CreateTargetRequest{ + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", TargetType: &action.CreateTargetRequest_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: false, }, }, - Timeout: durationpb.New(10 * time.Second), - ExecutionType: nil, + Timeout: durationpb.New(10 * time.Second), }, want: &action.CreateTargetResponse{ Details: &object.Details{ @@ -111,19 +128,17 @@ func TestServer_CreateTarget(t *testing.T) { }, }, { - name: "async execution, ok", + name: "webhook, interrupt on error, ok", ctx: CTX, req: &action.CreateTargetRequest{ - Name: fmt.Sprint(time.Now().UnixNano() + 1), + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", TargetType: &action.CreateTargetRequest_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: true, }, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.CreateTargetRequest_IsAsync{ - IsAsync: true, - }, }, want: &action.CreateTargetResponse{ Details: &object.Details{ @@ -133,19 +148,38 @@ func TestServer_CreateTarget(t *testing.T) { }, }, { - name: "interrupt on error execution, ok", + name: "call, ok", ctx: CTX, req: &action.CreateTargetRequest{ - Name: fmt.Sprint(time.Now().UnixNano() + 1), - TargetType: &action.CreateTargetRequest_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", + TargetType: &action.CreateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: false, }, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.CreateTargetRequest_InterruptOnError{ - InterruptOnError: true, + }, + want: &action.CreateTargetResponse{ + Details: &object.Details{ + ChangeDate: timestamppb.Now(), + ResourceOwner: Tester.Instance.InstanceID(), + }, + }, + }, + + { + name: "call, interruptOnError, ok", + ctx: CTX, + req: &action.CreateTargetRequest{ + Name: fmt.Sprint(time.Now().UnixNano() + 1), + Endpoint: "https://example.com", + TargetType: &action.CreateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, + }, }, + Timeout: durationpb.New(10 * time.Second), }, want: &action.CreateTargetResponse{ Details: &object.Details{ @@ -186,7 +220,7 @@ func TestServer_UpdateTarget(t *testing.T) { { name: "missing permission", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false).GetId() request.TargetId = targetID return nil }, @@ -215,7 +249,7 @@ func TestServer_UpdateTarget(t *testing.T) { { name: "change name, ok", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false).GetId() request.TargetId = targetID return nil }, @@ -235,16 +269,16 @@ func TestServer_UpdateTarget(t *testing.T) { { name: "change type, ok", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false).GetId() request.TargetId = targetID return nil }, args: args{ ctx: CTX, req: &action.UpdateTargetRequest{ - TargetType: &action.UpdateTargetRequest_RestRequestResponse{ - RestRequestResponse: &action.SetRESTRequestResponse{ - Url: "https://example.com", + TargetType: &action.UpdateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, }, }, }, @@ -259,18 +293,14 @@ func TestServer_UpdateTarget(t *testing.T) { { name: "change url, ok", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false).GetId() request.TargetId = targetID return nil }, args: args{ ctx: CTX, req: &action.UpdateTargetRequest{ - TargetType: &action.UpdateTargetRequest_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com/hooks/new", - }, - }, + Endpoint: gu.Ptr("https://example.com/hooks/new"), }, }, want: &action.UpdateTargetResponse{ @@ -283,7 +313,7 @@ func TestServer_UpdateTarget(t *testing.T) { { name: "change timeout, ok", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false).GetId() request.TargetId = targetID return nil }, @@ -301,17 +331,17 @@ func TestServer_UpdateTarget(t *testing.T) { }, }, { - name: "change execution type, ok", + name: "change type async, ok", prepare: func(request *action.UpdateTargetRequest) error { - targetID := Tester.CreateTarget(CTX, t).GetId() + targetID := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeAsync, false).GetId() request.TargetId = targetID return nil }, args: args{ ctx: CTX, req: &action.UpdateTargetRequest{ - ExecutionType: &action.UpdateTargetRequest_IsAsync{ - IsAsync: true, + TargetType: &action.UpdateTargetRequest_RestAsync{ + RestAsync: &action.SetRESTAsync{}, }, }, }, @@ -341,7 +371,7 @@ func TestServer_UpdateTarget(t *testing.T) { func TestServer_DeleteTarget(t *testing.T) { ensureFeatureEnabled(t) - target := Tester.CreateTarget(CTX, t) + target := Tester.CreateTarget(CTX, t, "", "https://example.com", domain.TargetTypeWebhook, false) tests := []struct { name string ctx context.Context diff --git a/internal/api/grpc/action/v3alpha/target_test.go b/internal/api/grpc/action/v3alpha/target_test.go index f630a6c7157..23e33ad9be9 100644 --- a/internal/api/grpc/action/v3alpha/target_test.go +++ b/internal/api/grpc/action/v3alpha/target_test.go @@ -27,55 +27,64 @@ func Test_createTargetToCommand(t *testing.T) { args: args{nil}, want: &command.AddTarget{ Name: "", - URL: "", + Endpoint: "", Timeout: 0, - Async: false, InterruptOnError: false, }, }, { - name: "all fields (async webhook)", + name: "all fields (webhook)", args: args{&action.CreateTargetRequest{ - Name: "target 1", + Name: "target 1", + Endpoint: "https://example.com/hooks/1", TargetType: &action.CreateTargetRequest_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com/hooks/1", - }, + RestWebhook: &action.SetRESTWebhook{}, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.CreateTargetRequest_IsAsync{ - IsAsync: true, - }, }}, want: &command.AddTarget{ Name: "target 1", TargetType: domain.TargetTypeWebhook, - URL: "https://example.com/hooks/1", + Endpoint: "https://example.com/hooks/1", + Timeout: 10 * time.Second, + InterruptOnError: false, + }, + }, + { + name: "all fields (async)", + args: args{&action.CreateTargetRequest{ + Name: "target 1", + Endpoint: "https://example.com/hooks/1", + TargetType: &action.CreateTargetRequest_RestAsync{ + RestAsync: &action.SetRESTAsync{}, + }, + Timeout: durationpb.New(10 * time.Second), + }}, + want: &command.AddTarget{ + Name: "target 1", + TargetType: domain.TargetTypeAsync, + Endpoint: "https://example.com/hooks/1", Timeout: 10 * time.Second, - Async: true, InterruptOnError: false, }, }, { name: "all fields (interrupting response)", args: args{&action.CreateTargetRequest{ - Name: "target 1", - TargetType: &action.CreateTargetRequest_RestRequestResponse{ - RestRequestResponse: &action.SetRESTRequestResponse{ - Url: "https://example.com/hooks/1", + Name: "target 1", + Endpoint: "https://example.com/hooks/1", + TargetType: &action.CreateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, }, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.CreateTargetRequest_InterruptOnError{ - InterruptOnError: true, - }, }}, want: &command.AddTarget{ Name: "target 1", - TargetType: domain.TargetTypeRequestResponse, - URL: "https://example.com/hooks/1", + TargetType: domain.TargetTypeCall, + Endpoint: "https://example.com/hooks/1", Timeout: 10 * time.Second, - Async: false, InterruptOnError: true, }, }, @@ -105,80 +114,108 @@ func Test_updateTargetToCommand(t *testing.T) { { name: "all fields nil", args: args{&action.UpdateTargetRequest{ - Name: nil, - TargetType: nil, - Timeout: nil, - ExecutionType: nil, + Name: nil, + TargetType: nil, + Timeout: nil, }}, want: &command.ChangeTarget{ Name: nil, TargetType: nil, - URL: nil, + Endpoint: nil, Timeout: nil, - Async: nil, InterruptOnError: nil, }, }, { name: "all fields empty", args: args{&action.UpdateTargetRequest{ - Name: gu.Ptr(""), - TargetType: nil, - Timeout: durationpb.New(0), - ExecutionType: nil, + Name: gu.Ptr(""), + TargetType: nil, + Timeout: durationpb.New(0), }}, want: &command.ChangeTarget{ Name: gu.Ptr(""), TargetType: nil, - URL: nil, + Endpoint: nil, Timeout: gu.Ptr(0 * time.Second), - Async: nil, InterruptOnError: nil, }, }, { - name: "all fields (async webhook)", + name: "all fields (webhook)", args: args{&action.UpdateTargetRequest{ - Name: gu.Ptr("target 1"), + Name: gu.Ptr("target 1"), + Endpoint: gu.Ptr("https://example.com/hooks/1"), TargetType: &action.UpdateTargetRequest_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com/hooks/1", + InterruptOnError: false, }, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.UpdateTargetRequest_IsAsync{ - IsAsync: true, + }}, + want: &command.ChangeTarget{ + Name: gu.Ptr("target 1"), + TargetType: gu.Ptr(domain.TargetTypeWebhook), + Endpoint: gu.Ptr("https://example.com/hooks/1"), + Timeout: gu.Ptr(10 * time.Second), + InterruptOnError: gu.Ptr(false), + }, + }, + { + name: "all fields (webhook interrupt)", + args: args{&action.UpdateTargetRequest{ + Name: gu.Ptr("target 1"), + Endpoint: gu.Ptr("https://example.com/hooks/1"), + TargetType: &action.UpdateTargetRequest_RestWebhook{ + RestWebhook: &action.SetRESTWebhook{ + InterruptOnError: true, + }, }, + Timeout: durationpb.New(10 * time.Second), }}, want: &command.ChangeTarget{ Name: gu.Ptr("target 1"), TargetType: gu.Ptr(domain.TargetTypeWebhook), - URL: gu.Ptr("https://example.com/hooks/1"), + Endpoint: gu.Ptr("https://example.com/hooks/1"), + Timeout: gu.Ptr(10 * time.Second), + InterruptOnError: gu.Ptr(true), + }, + }, + { + name: "all fields (async)", + args: args{&action.UpdateTargetRequest{ + Name: gu.Ptr("target 1"), + Endpoint: gu.Ptr("https://example.com/hooks/1"), + TargetType: &action.UpdateTargetRequest_RestAsync{ + RestAsync: &action.SetRESTAsync{}, + }, + Timeout: durationpb.New(10 * time.Second), + }}, + want: &command.ChangeTarget{ + Name: gu.Ptr("target 1"), + TargetType: gu.Ptr(domain.TargetTypeAsync), + Endpoint: gu.Ptr("https://example.com/hooks/1"), Timeout: gu.Ptr(10 * time.Second), - Async: gu.Ptr(true), InterruptOnError: gu.Ptr(false), }, }, { name: "all fields (interrupting response)", args: args{&action.UpdateTargetRequest{ - Name: gu.Ptr("target 1"), - TargetType: &action.UpdateTargetRequest_RestRequestResponse{ - RestRequestResponse: &action.SetRESTRequestResponse{ - Url: "https://example.com/hooks/1", + Name: gu.Ptr("target 1"), + Endpoint: gu.Ptr("https://example.com/hooks/1"), + TargetType: &action.UpdateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: true, }, }, Timeout: durationpb.New(10 * time.Second), - ExecutionType: &action.UpdateTargetRequest_InterruptOnError{ - InterruptOnError: true, - }, }}, want: &command.ChangeTarget{ Name: gu.Ptr("target 1"), - TargetType: gu.Ptr(domain.TargetTypeRequestResponse), - URL: gu.Ptr("https://example.com/hooks/1"), + TargetType: gu.Ptr(domain.TargetTypeCall), + Endpoint: gu.Ptr("https://example.com/hooks/1"), Timeout: gu.Ptr(10 * time.Second), - Async: gu.Ptr(false), InterruptOnError: gu.Ptr(true), }, }, diff --git a/internal/api/grpc/server/middleware/execution_interceptor.go b/internal/api/grpc/server/middleware/execution_interceptor.go new file mode 100644 index 00000000000..ec4eee17d2b --- /dev/null +++ b/internal/api/grpc/server/middleware/execution_interceptor.go @@ -0,0 +1,179 @@ +package middleware + +import ( + "context" + "encoding/json" + "strings" + + "github.com/zitadel/logging" + "google.golang.org/grpc" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/execution" + "github.com/zitadel/zitadel/internal/query" + exec_repo "github.com/zitadel/zitadel/internal/repository/execution" + "github.com/zitadel/zitadel/internal/telemetry/tracing" +) + +func ExecutionHandler(queries *query.Queries) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + requestTargets, responseTargets := queryTargets(ctx, queries, info.FullMethod) + + // call targets otherwise return req + handledReq, err := executeTargetsForRequest(ctx, requestTargets, info.FullMethod, req) + if err != nil { + return nil, err + } + + response, err := handler(ctx, handledReq) + if err != nil { + return nil, err + } + + return executeTargetsForResponse(ctx, responseTargets, info.FullMethod, handledReq, response) + } +} + +func executeTargetsForRequest(ctx context.Context, targets []execution.Target, fullMethod string, req interface{}) (_ interface{}, err error) { + ctx, span := tracing.NewSpan(ctx) + defer span.EndWithError(err) + + // if no targets are found, return without any calls + if len(targets) == 0 { + return req, nil + } + + ctxData := authz.GetCtxData(ctx) + info := &ContextInfoRequest{ + FullMethod: fullMethod, + InstanceID: authz.GetInstance(ctx).InstanceID(), + ProjectID: ctxData.ProjectID, + OrgID: ctxData.OrgID, + UserID: ctxData.UserID, + Request: req, + } + + return execution.CallTargets(ctx, targets, info) +} + +func executeTargetsForResponse(ctx context.Context, targets []execution.Target, fullMethod string, req, resp interface{}) (_ interface{}, err error) { + ctx, span := tracing.NewSpan(ctx) + defer span.EndWithError(err) + + // if no targets are found, return without any calls + if len(targets) == 0 { + return resp, nil + } + + ctxData := authz.GetCtxData(ctx) + info := &ContextInfoResponse{ + FullMethod: fullMethod, + InstanceID: authz.GetInstance(ctx).InstanceID(), + ProjectID: ctxData.ProjectID, + OrgID: ctxData.OrgID, + UserID: ctxData.UserID, + Request: req, + Response: resp, + } + + return execution.CallTargets(ctx, targets, info) +} + +type ExecutionQueries interface { + TargetsByExecutionIDs(ctx context.Context, ids1, ids2 []string) (execution []*query.ExecutionTarget, err error) +} + +func queryTargets( + ctx context.Context, + queries ExecutionQueries, + fullMethod string, +) ([]execution.Target, []execution.Target) { + ctx, span := tracing.NewSpan(ctx) + defer span.End() + + targets, err := queries.TargetsByExecutionIDs(ctx, + idsForFullMethod(fullMethod, domain.ExecutionTypeRequest), + idsForFullMethod(fullMethod, domain.ExecutionTypeResponse), + ) + requestTargets := make([]execution.Target, 0, len(targets)) + responseTargets := make([]execution.Target, 0, len(targets)) + if err != nil { + logging.WithFields("fullMethod", fullMethod).WithError(err).Info("unable to query targets") + return requestTargets, responseTargets + } + + for _, target := range targets { + if strings.HasPrefix(target.GetExecutionID(), exec_repo.IDAll(domain.ExecutionTypeRequest)) { + requestTargets = append(requestTargets, target) + } else if strings.HasPrefix(target.GetExecutionID(), exec_repo.IDAll(domain.ExecutionTypeResponse)) { + responseTargets = append(responseTargets, target) + } + } + + return requestTargets, responseTargets +} + +func idsForFullMethod(fullMethod string, executionType domain.ExecutionType) []string { + return []string{exec_repo.ID(executionType, fullMethod), exec_repo.ID(executionType, serviceFromFullMethod(fullMethod)), exec_repo.IDAll(executionType)} +} + +func serviceFromFullMethod(s string) string { + parts := strings.Split(s, "/") + return parts[1] +} + +var _ execution.ContextInfo = &ContextInfoRequest{} + +type ContextInfoRequest struct { + FullMethod string `json:"fullMethod,omitempty"` + InstanceID string `json:"instanceID,omitempty"` + OrgID string `json:"orgID,omitempty"` + ProjectID string `json:"projectID,omitempty"` + UserID string `json:"userID,omitempty"` + Request interface{} `json:"request,omitempty"` +} + +func (c *ContextInfoRequest) GetHTTPRequestBody() []byte { + data, err := json.Marshal(c) + if err != nil { + return nil + } + return data +} + +func (c *ContextInfoRequest) SetHTTPResponseBody(resp []byte) error { + return json.Unmarshal(resp, c.Request) +} + +func (c *ContextInfoRequest) GetContent() interface{} { + return c.Request +} + +var _ execution.ContextInfo = &ContextInfoResponse{} + +type ContextInfoResponse struct { + FullMethod string `json:"fullMethod,omitempty"` + InstanceID string `json:"instanceID,omitempty"` + OrgID string `json:"orgID,omitempty"` + ProjectID string `json:"projectID,omitempty"` + UserID string `json:"userID,omitempty"` + Request interface{} `json:"request,omitempty"` + Response interface{} `json:"response,omitempty"` +} + +func (c *ContextInfoResponse) GetHTTPRequestBody() []byte { + data, err := json.Marshal(c) + if err != nil { + return nil + } + return data +} + +func (c *ContextInfoResponse) SetHTTPResponseBody(resp []byte) error { + return json.Unmarshal(resp, c.Response) +} + +func (c *ContextInfoResponse) GetContent() interface{} { + return c.Response +} diff --git a/internal/api/grpc/server/middleware/execution_interceptor_test.go b/internal/api/grpc/server/middleware/execution_interceptor_test.go new file mode 100644 index 00000000000..bbc87c374fb --- /dev/null +++ b/internal/api/grpc/server/middleware/execution_interceptor_test.go @@ -0,0 +1,778 @@ +package middleware + +import ( + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/execution" +) + +var _ execution.Target = &mockExecutionTarget{} + +type mockExecutionTarget struct { + InstanceID string + ExecutionID string + TargetID string + TargetType domain.TargetType + Endpoint string + Timeout time.Duration + InterruptOnError bool +} + +func (e *mockExecutionTarget) SetEndpoint(endpoint string) { + e.Endpoint = endpoint +} +func (e *mockExecutionTarget) IsInterruptOnError() bool { + return e.InterruptOnError +} +func (e *mockExecutionTarget) GetEndpoint() string { + return e.Endpoint +} +func (e *mockExecutionTarget) GetTargetType() domain.TargetType { + return e.TargetType +} +func (e *mockExecutionTarget) GetTimeout() time.Duration { + return e.Timeout +} +func (e *mockExecutionTarget) GetTargetID() string { + return e.TargetID +} +func (e *mockExecutionTarget) GetExecutionID() string { + return e.ExecutionID +} + +type mockContentRequest struct { + Content string +} + +func newMockContentRequest(content string) *mockContentRequest { + return &mockContentRequest{ + Content: content, + } +} + +func newMockContextInfoRequest(fullMethod, request string) *ContextInfoRequest { + return &ContextInfoRequest{ + FullMethod: fullMethod, + Request: newMockContentRequest(request), + } +} + +func newMockContextInfoResponse(fullMethod, request, response string) *ContextInfoResponse { + return &ContextInfoResponse{ + FullMethod: fullMethod, + Request: newMockContentRequest(request), + Response: newMockContentRequest(response), + } +} + +func Test_executeTargetsForGRPCFullMethod_request(t *testing.T) { + type target struct { + reqBody execution.ContextInfo + sleep time.Duration + statusCode int + respBody interface{} + } + type args struct { + ctx context.Context + + executionTargets []execution.Target + targets []target + fullMethod string + req interface{} + } + type res struct { + want interface{} + wantErr bool + } + tests := []struct { + name string + args args + res res + }{ + { + "target, executionTargets nil", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: nil, + req: newMockContentRequest("request"), + }, + res{ + want: newMockContentRequest("request"), + }, + }, + { + "target, executionTargets empty", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{}, + req: newMockContentRequest("request"), + }, + res{ + want: newMockContentRequest("request"), + }, + }, + { + "target, not reachable", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{}, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "target, error without interrupt", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusBadRequest, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + want: newMockContentRequest("content"), + }, + }, + { + "target, interruptOnError", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusBadRequest, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "target, timeout", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Second, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 5 * time.Second, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "target, wrong request", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Second, + InterruptOnError: true, + }, + }, + targets: []target{ + {reqBody: newMockContextInfoRequest("/service/method", "wrong")}, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "target, ok", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + want: newMockContentRequest("content1"), + }, + }, + { + "target async, timeout", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeAsync, + Timeout: time.Second, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 5 * time.Second, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + want: newMockContentRequest("content"), + }, + }, + { + "target async, ok", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeAsync, + Timeout: time.Minute, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + want: newMockContentRequest("content"), + }, + }, + { + "webhook, error", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeWebhook, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + sleep: 0, + statusCode: http.StatusInternalServerError, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "webhook, timeout", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeWebhook, + Timeout: time.Second, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 5 * time.Second, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "webhook, ok", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeWebhook, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + want: newMockContentRequest("content"), + }, + }, + { + "with includes, interruptOnError", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target1", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target2", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target3", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusOK, + }, + { + reqBody: newMockContextInfoRequest("/service/method", "content1"), + respBody: newMockContentRequest("content2"), + sleep: 0, + statusCode: http.StatusBadRequest, + }, + { + reqBody: newMockContextInfoRequest("/service/method", "content2"), + respBody: newMockContentRequest("content3"), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + { + "with includes, timeout", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target1", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target2", + TargetType: domain.TargetTypeCall, + Timeout: time.Second, + InterruptOnError: true, + }, + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target3", + TargetType: domain.TargetTypeCall, + Timeout: time.Second, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest("content1"), + sleep: 0, + statusCode: http.StatusOK, + }, + { + reqBody: newMockContextInfoRequest("/service/method", "content1"), + respBody: newMockContentRequest("content2"), + sleep: 5 * time.Second, + statusCode: http.StatusBadRequest, + }, + { + reqBody: newMockContextInfoRequest("/service/method", "content2"), + respBody: newMockContentRequest("content3"), + sleep: 5 * time.Second, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("content"), + }, + res{ + wantErr: true, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + closeFuncs := make([]func(), len(tt.args.targets)) + for i, target := range tt.args.targets { + url, closeF := testServerCall( + target.reqBody, + target.sleep, + target.statusCode, + target.respBody, + ) + + et := tt.args.executionTargets[i].(*mockExecutionTarget) + et.SetEndpoint(url) + closeFuncs[i] = closeF + } + + resp, err := executeTargetsForRequest( + tt.args.ctx, + tt.args.executionTargets, + tt.args.fullMethod, + tt.args.req, + ) + + if tt.res.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tt.res.want, resp) + + for _, closeF := range closeFuncs { + closeF() + } + }) + } +} + +func testServerCall( + reqBody interface{}, + sleep time.Duration, + statusCode int, + respBody interface{}, +) (string, func()) { + handler := func(w http.ResponseWriter, r *http.Request) { + data, err := json.Marshal(reqBody) + if err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + + sentBody, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + + if !reflect.DeepEqual(data, sentBody) { + http.Error(w, "error", http.StatusInternalServerError) + return + } + + if statusCode != http.StatusOK { + http.Error(w, "error", statusCode) + return + } + + time.Sleep(sleep) + + w.Header().Set("Content-Type", "application/json") + resp, err := json.Marshal(respBody) + if err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + if _, err := io.WriteString(w, string(resp)); err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + } + + server := httptest.NewServer(http.HandlerFunc(handler)) + + return server.URL, server.Close +} + +func Test_executeTargetsForGRPCFullMethod_response(t *testing.T) { + type target struct { + reqBody execution.ContextInfo + sleep time.Duration + statusCode int + respBody interface{} + } + type args struct { + ctx context.Context + + executionTargets []execution.Target + targets []target + fullMethod string + req interface{} + resp interface{} + } + type res struct { + want interface{} + wantErr bool + } + tests := []struct { + name string + args args + res res + }{ + { + "target, executionTargets nil", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: nil, + req: newMockContentRequest("request"), + resp: newMockContentRequest("response"), + }, + res{ + want: newMockContentRequest("response"), + }, + }, + { + "target, executionTargets empty", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{}, + req: newMockContentRequest("request"), + resp: newMockContentRequest("response"), + }, + res{ + want: newMockContentRequest("response"), + }, + }, + { + "target, empty response", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "request./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoRequest("/service/method", "content"), + respBody: newMockContentRequest(""), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: []byte{}, + }, + res{ + wantErr: true, + }, + }, + { + "target, ok", + args{ + ctx: context.Background(), + fullMethod: "/service/method", + executionTargets: []execution.Target{ + &mockExecutionTarget{ + InstanceID: "instance", + ExecutionID: "response./zitadel.session.v2beta.SessionService/SetSession", + TargetID: "target", + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + InterruptOnError: true, + }, + }, + targets: []target{ + { + reqBody: newMockContextInfoResponse("/service/method", "request", "response"), + respBody: newMockContentRequest("response1"), + sleep: 0, + statusCode: http.StatusOK, + }, + }, + req: newMockContentRequest("request"), + resp: newMockContentRequest("response"), + }, + res{ + want: newMockContentRequest("response1"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + closeFuncs := make([]func(), len(tt.args.targets)) + for i, target := range tt.args.targets { + url, closeF := testServerCall( + target.reqBody, + target.sleep, + target.statusCode, + target.respBody, + ) + + et := tt.args.executionTargets[i].(*mockExecutionTarget) + et.SetEndpoint(url) + closeFuncs[i] = closeF + } + + resp, err := executeTargetsForResponse( + tt.args.ctx, + tt.args.executionTargets, + tt.args.fullMethod, + tt.args.req, + tt.args.resp, + ) + + if tt.res.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tt.res.want, resp) + + for _, closeF := range closeFuncs { + closeF() + } + }) + } +} diff --git a/internal/api/grpc/server/server.go b/internal/api/grpc/server/server.go index 4f0a6140bc0..ef4c271bf5b 100644 --- a/internal/api/grpc/server/server.go +++ b/internal/api/grpc/server/server.go @@ -58,6 +58,7 @@ func CreateServer( middleware.AuthorizationInterceptor(verifier, authConfig), middleware.TranslationHandler(), middleware.QuotaExhaustedInterceptor(accessSvc, system_pb.SystemService_ServiceDesc.ServiceName), + middleware.ExecutionHandler(queries), middleware.ValidationHandler(), middleware.ServiceHandler(), middleware.ActivityInterceptor(), diff --git a/internal/command/action_v2_execution.go b/internal/command/action_v2_execution.go index 164830d6e51..422e053daff 100644 --- a/internal/command/action_v2_execution.go +++ b/internal/command/action_v2_execution.go @@ -2,6 +2,7 @@ package command import ( "context" + "strings" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore/v1/models" @@ -9,6 +10,10 @@ import ( "github.com/zitadel/zitadel/internal/zerrors" ) +const ( + EventGroupSuffix = ".*" +) + type ExecutionAPICondition struct { Method string Service string @@ -134,7 +139,11 @@ func (e *ExecutionEventCondition) ID() string { return execution.ID(domain.ExecutionTypeEvent, e.Event) } if e.Group != "" { - return execution.ID(domain.ExecutionTypeEvent, e.Group) + group := e.Group + if !strings.HasSuffix(e.Group, EventGroupSuffix) { + group += EventGroupSuffix + } + return execution.ID(domain.ExecutionTypeEvent, group) } if e.All { return execution.IDAll(domain.ExecutionTypeEvent) @@ -168,25 +177,43 @@ func (c *Commands) SetExecutionEvent(ctx context.Context, cond *ExecutionEventCo type SetExecution struct { models.ObjectRoot - Targets []string - Includes []string + Targets []*execution.Target +} + +func (t SetExecution) GetIncludes() []string { + includes := make([]string, 0) + for i := range t.Targets { + if t.Targets[i].Type == domain.ExecutionTargetTypeInclude { + includes = append(includes, t.Targets[i].Target) + } + } + return includes +} + +func (t SetExecution) GetTargets() []string { + targets := make([]string, 0) + for i := range t.Targets { + if t.Targets[i].Type == domain.ExecutionTargetTypeTarget { + targets = append(targets, t.Targets[i].Target) + } + } + return targets } func (e *SetExecution) IsValid() error { - if len(e.Targets) == 0 && len(e.Includes) == 0 { + if len(e.Targets) == 0 { return zerrors.ThrowInvalidArgument(nil, "COMMAND-56bteot2uj", "Errors.Execution.NoTargets") } - if len(e.Targets) > 0 && len(e.Includes) > 0 { - return zerrors.ThrowInvalidArgument(nil, "COMMAND-5zleae34r1", "Errors.Execution.Invalid") - } return nil } func (e *SetExecution) Existing(c *Commands, ctx context.Context, resourceOwner string) error { - if len(e.Targets) > 0 && !c.existsTargetsByIDs(ctx, e.Targets, resourceOwner) { + targets := e.GetTargets() + if len(targets) > 0 && !c.existsTargetsByIDs(ctx, targets, resourceOwner) { return zerrors.ThrowNotFound(nil, "COMMAND-17e8fq1ggk", "Errors.Target.NotFound") } - if len(e.Includes) > 0 && !c.existsExecutionsByIDs(ctx, e.Includes, resourceOwner) { + includes := e.GetIncludes() + if len(includes) > 0 && !c.existsExecutionsByIDs(ctx, includes, resourceOwner) { return zerrors.ThrowNotFound(nil, "COMMAND-slgj0l4cdz", "Errors.Execution.IncludeNotFound") } return nil @@ -206,11 +233,10 @@ func (c *Commands) setExecution(ctx context.Context, set *SetExecution, resource return nil, err } - if err := c.pushAppendAndReduce(ctx, wm, execution.NewSetEvent( + if err := c.pushAppendAndReduce(ctx, wm, execution.NewSetEventV2( ctx, ExecutionAggregateFromWriteModel(&wm.WriteModel), set.Targets, - set.Includes, )); err != nil { return nil, err } diff --git a/internal/command/action_v2_execution_model.go b/internal/command/action_v2_execution_model.go index 0dbeb3d8740..c53992856e1 100644 --- a/internal/command/action_v2_execution_model.go +++ b/internal/command/action_v2_execution_model.go @@ -10,12 +10,13 @@ import ( type ExecutionWriteModel struct { eventstore.WriteModel - Targets []string - Includes []string + Targets []string + Includes []string + ExecutionTargets []*execution.Target } func (e *ExecutionWriteModel) Exists() bool { - return len(e.Targets) > 0 || len(e.Includes) > 0 + return len(e.ExecutionTargets) > 0 || len(e.Includes) > 0 || len(e.Targets) > 0 } func NewExecutionWriteModel(id string, resourceOwner string) *ExecutionWriteModel { @@ -34,9 +35,12 @@ func (wm *ExecutionWriteModel) Reduce() error { case *execution.SetEvent: wm.Targets = e.Targets wm.Includes = e.Includes + case *execution.SetEventV2: + wm.ExecutionTargets = e.Targets case *execution.RemovedEvent: wm.Targets = nil wm.Includes = nil + wm.ExecutionTargets = nil } } return wm.WriteModel.Reduce() @@ -49,6 +53,7 @@ func (wm *ExecutionWriteModel) Query() *eventstore.SearchQueryBuilder { AggregateTypes(execution.AggregateType). AggregateIDs(wm.AggregateID). EventTypes(execution.SetEventType, + execution.SetEventV2Type, execution.RemovedEventType). Builder() } @@ -91,6 +96,10 @@ func (wm *ExecutionsExistWriteModel) Reduce() error { if !slices.Contains(wm.existingIDs, e.Aggregate().ID) { wm.existingIDs = append(wm.existingIDs, e.Aggregate().ID) } + case *execution.SetEventV2: + if !slices.Contains(wm.existingIDs, e.Aggregate().ID) { + wm.existingIDs = append(wm.existingIDs, e.Aggregate().ID) + } case *execution.RemovedEvent: i := slices.Index(wm.existingIDs, e.Aggregate().ID) if i >= 0 { @@ -108,6 +117,7 @@ func (wm *ExecutionsExistWriteModel) Query() *eventstore.SearchQueryBuilder { AggregateTypes(execution.AggregateType). AggregateIDs(wm.ids...). EventTypes(execution.SetEventType, + execution.SetEventV2Type, execution.RemovedEventType). Builder() } diff --git a/internal/command/action_v2_execution_model_test.go b/internal/command/action_v2_execution_model_test.go index 4c74a146e80..1c0f535d094 100644 --- a/internal/command/action_v2_execution_model_test.go +++ b/internal/command/action_v2_execution_model_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/execution" ) @@ -32,10 +33,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -53,10 +56,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -65,10 +70,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -91,10 +98,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -112,10 +121,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -138,24 +149,30 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -174,17 +191,21 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -193,10 +214,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -214,17 +237,21 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -233,10 +260,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -254,24 +283,30 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -299,24 +334,30 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), ), @@ -334,10 +375,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -346,17 +389,21 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -385,10 +432,12 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution1", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( @@ -397,17 +446,21 @@ func TestCommandSide_executionsExistsWriteModel(t *testing.T) { ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution2", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( - execution.NewSetEvent(context.Background(), + execution.NewSetEventV2(context.Background(), execution.NewAggregate("execution3", "org1"), - []string{"target"}, - []string{"include"}, + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, ), ), eventFromEventPusher( diff --git a/internal/command/action_v2_execution_test.go b/internal/command/action_v2_execution_test.go index 6a40eadf5e4..c8f91f49b20 100644 --- a/internal/command/action_v2_execution_test.go +++ b/internal/command/action_v2_execution_test.go @@ -19,10 +19,9 @@ func existsMock(exists bool) func(method string) bool { return exists } } - func TestCommands_SetExecutionRequest(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore grpcMethodExists func(method string) bool grpcServiceExists func(method string) bool } @@ -45,7 +44,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -60,13 +59,13 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionAPICondition{}, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -75,7 +74,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "no valid cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -85,7 +84,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -94,7 +93,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "empty executionType, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(true), }, args{ @@ -105,7 +104,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -114,7 +113,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "empty target, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(true), }, args{ @@ -125,83 +124,16 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", - }, - res{ - err: zerrors.IsErrorInvalidArgument, - }, - }, - { - "target and include, error", - fields{ - eventstore: eventstoreExpect(t), - grpcMethodExists: existsMock(true), - }, - args{ - ctx: context.Background(), - cond: &ExecutionAPICondition{ - "notvalid", - "", - false, - }, - set: &SetExecution{ - Targets: []string{"invalid"}, - Includes: []string{"invalid"}, - }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, }, }, - { - "push failed, error", - fields{ - eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), - ), - expectPushFailed( - zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.valid", "org1"), - []string{"target"}, - nil, - ), - ), - ), - grpcMethodExists: existsMock(true), - }, - args{ - ctx: context.Background(), - cond: &ExecutionAPICondition{ - "valid", - "", - false, - }, - set: &SetExecution{ - Targets: []string{"target"}, - }, - resourceOwner: "org1", - }, - res{ - err: zerrors.IsPreconditionFailed, - }, - }, { "method not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(false), }, args{ @@ -212,9 +144,11 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -223,7 +157,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "service not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcServiceExists: existsMock(false), }, args{ @@ -234,9 +168,11 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -245,25 +181,25 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "push ok, method target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), + target.NewAggregate("target", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, true, - true, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.method", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/method", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -277,38 +213,40 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, service target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), + target.NewAggregate("target", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, true, - true, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.service", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/service", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -322,38 +260,40 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, all target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), + target.NewAggregate("target", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, true, - true, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -366,20 +306,22 @@ func TestCommands_SetExecutionRequest(t *testing.T) { true, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push not found, method include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), grpcMethodExists: existsMock(true), @@ -392,9 +334,11 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -403,21 +347,23 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "push ok, method include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.include", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/include", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.method", "org1"), - nil, - []string{"request.include"}, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/method", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, ), ), ), @@ -431,20 +377,22 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push not found, service include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), grpcServiceExists: existsMock(true), @@ -457,9 +405,11 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -468,21 +418,23 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "push ok, service include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.include", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/include", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.service", "org1"), - nil, - []string{"request.include"}, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/service", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, ), ), ), @@ -496,20 +448,22 @@ func TestCommands_SetExecutionRequest(t *testing.T) { false, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push not found, all include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -521,9 +475,11 @@ func TestCommands_SetExecutionRequest(t *testing.T) { true, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -532,21 +488,23 @@ func TestCommands_SetExecutionRequest(t *testing.T) { { "push ok, all include", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.include", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/include", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request", "org1"), - nil, - []string{"request.include"}, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, ), ), ), @@ -559,13 +517,15 @@ func TestCommands_SetExecutionRequest(t *testing.T) { true, }, set: &SetExecution{ - Includes: []string{"request.include"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "request/include"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -573,7 +533,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), GrpcMethodExisting: tt.fields.grpcMethodExists, GrpcServiceExisting: tt.fields.grpcServiceExists, } @@ -593,7 +553,7 @@ func TestCommands_SetExecutionRequest(t *testing.T) { func TestCommands_SetExecutionResponse(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore grpcMethodExists func(method string) bool grpcServiceExists func(method string) bool } @@ -616,7 +576,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -631,13 +591,13 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionAPICondition{}, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -646,7 +606,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "no valid cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -656,7 +616,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -665,7 +625,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "empty executionType, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(true), }, args{ @@ -676,7 +636,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -685,7 +645,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "empty target, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(true), }, args{ @@ -696,30 +656,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", - }, - res{ - err: zerrors.IsErrorInvalidArgument, - }, - }, - { - "target and include, error", - fields{ - eventstore: eventstoreExpect(t), - grpcMethodExists: existsMock(true), - }, - args{ - ctx: context.Background(), - cond: &ExecutionAPICondition{ - "notvalid", - "", - false, - }, - set: &SetExecution{ - Targets: []string{"invalid"}, - Includes: []string{"invalid"}, - }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -728,24 +665,24 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), + target.NewAggregate("target", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, true, - true, ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -759,9 +696,11 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -770,7 +709,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "method not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcMethodExists: existsMock(false), }, args{ @@ -781,9 +720,11 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -792,7 +733,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "service not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), grpcServiceExists: existsMock(false), }, args{ @@ -803,9 +744,11 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -814,25 +757,25 @@ func TestCommands_SetExecutionResponse(t *testing.T) { { "push ok, method target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), + target.NewAggregate("target", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, true, - true, ), ), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.method", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/method", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -846,38 +789,31 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, service target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.service", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/service", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -891,38 +827,31 @@ func TestCommands_SetExecutionResponse(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, all target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -935,13 +864,15 @@ func TestCommands_SetExecutionResponse(t *testing.T) { true, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -949,7 +880,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), GrpcMethodExisting: tt.fields.grpcMethodExists, GrpcServiceExisting: tt.fields.grpcServiceExists, } @@ -969,7 +900,7 @@ func TestCommands_SetExecutionResponse(t *testing.T) { func TestCommands_SetExecutionEvent(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore eventExists func(string) bool eventGroupExists func(string) bool } @@ -992,7 +923,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1007,13 +938,13 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionEventCondition{}, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1022,7 +953,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "no valid cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1032,7 +963,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1041,7 +972,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "empty executionType, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), eventExists: existsMock(true), }, args{ @@ -1052,7 +983,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1061,7 +992,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "empty target, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), eventExists: existsMock(true), }, args{ @@ -1072,30 +1003,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{}, - resourceOwner: "org1", - }, - res{ - err: zerrors.IsErrorInvalidArgument, - }, - }, - { - "target and include, error", - fields{ - eventstore: eventstoreExpect(t), - eventExists: existsMock(true), - }, - args{ - ctx: context.Background(), - cond: &ExecutionEventCondition{ - "notvalid", - "", - false, - }, - set: &SetExecution{ - Targets: []string{"invalid"}, - Includes: []string{"invalid"}, - }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1104,26 +1012,17 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1137,9 +1036,11 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -1148,7 +1049,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "event not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), eventExists: existsMock(false), }, args{ @@ -1159,9 +1060,11 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1170,7 +1073,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "group not found, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), eventGroupExists: existsMock(false), }, args{ @@ -1181,9 +1084,11 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1192,25 +1097,16 @@ func TestCommands_SetExecutionEvent(t *testing.T) { { "push ok, event target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.event", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/event", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1224,38 +1120,31 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, group target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.group", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/group.*", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1269,38 +1158,31 @@ func TestCommands_SetExecutionEvent(t *testing.T) { false, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, all target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1313,13 +1195,15 @@ func TestCommands_SetExecutionEvent(t *testing.T) { true, }, set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -1327,7 +1211,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), EventExisting: tt.fields.eventExists, EventGroupExisting: tt.fields.eventGroupExists, } @@ -1347,7 +1231,7 @@ func TestCommands_SetExecutionEvent(t *testing.T) { func TestCommands_SetExecutionFunction(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore actionFunctionExists func(string) bool } type args struct { @@ -1369,7 +1253,7 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), actionFunctionExists: existsMock(true), }, args{ @@ -1385,13 +1269,13 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: "", set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1400,14 +1284,14 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "empty executionType, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), actionFunctionExists: existsMock(true), }, args{ ctx: context.Background(), cond: "function", set: &SetExecution{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1416,33 +1300,14 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "empty target, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), actionFunctionExists: existsMock(true), }, args{ ctx: context.Background(), cond: "function", set: &SetExecution{}, - resourceOwner: "org1", - }, - res{ - err: zerrors.IsErrorInvalidArgument, - }, - }, - { - "target and include, error", - fields{ - eventstore: eventstoreExpect(t), - actionFunctionExists: existsMock(true), - }, - args{ - ctx: context.Background(), - cond: "function", - set: &SetExecution{ - Targets: []string{"invalid"}, - Includes: []string{"invalid"}, - }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1451,26 +1316,17 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), - execution.NewSetEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("function/function", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1480,9 +1336,11 @@ func TestCommands_SetExecutionFunction(t *testing.T) { ctx: context.Background(), cond: "function", set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -1490,7 +1348,7 @@ func TestCommands_SetExecutionFunction(t *testing.T) { }, { "push error, function target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), actionFunctionExists: existsMock(true), @@ -1499,9 +1357,11 @@ func TestCommands_SetExecutionFunction(t *testing.T) { ctx: context.Background(), cond: "function", set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1510,16 +1370,18 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "push error, function not existing", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), actionFunctionExists: existsMock(false), }, args{ ctx: context.Background(), cond: "function", set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1528,25 +1390,16 @@ func TestCommands_SetExecutionFunction(t *testing.T) { { "push ok, function target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("target", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), - ), + targetAddEvent("target", "instance"), ), expectPush( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("function/function", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), @@ -1556,13 +1409,15 @@ func TestCommands_SetExecutionFunction(t *testing.T) { ctx: context.Background(), cond: "function", set: &SetExecution{ - Targets: []string{"target"}, + Targets: []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -1570,7 +1425,7 @@ func TestCommands_SetExecutionFunction(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), ActionFunctionExisting: tt.fields.actionFunctionExists, } details, err := c.SetExecutionFunction(tt.args.ctx, tt.args.cond, tt.args.set, tt.args.resourceOwner) @@ -1589,7 +1444,7 @@ func TestCommands_SetExecutionFunction(t *testing.T) { func TestCommands_DeleteExecutionRequest(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -1609,7 +1464,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1623,12 +1478,12 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionAPICondition{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1637,7 +1492,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "no valid cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1646,7 +1501,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "notvalid", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1655,20 +1510,21 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("request.valid", "org1"), + execution.NewAggregate("request/valid", "instance"), ), ), ), @@ -1680,7 +1536,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -1689,7 +1545,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "not found, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1700,7 +1556,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1709,19 +1565,20 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { { "push ok, method target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.method", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/method", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("request.method", "org1"), + execution.NewAggregate("request/method", "instance"), ), ), ), @@ -1733,30 +1590,31 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, service target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request.service", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request/service", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("request.service", "org1"), + execution.NewAggregate("request/service", "instance"), ), ), ), @@ -1768,30 +1626,31 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "service", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, all target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("request", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("request", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("request", "org1"), + execution.NewAggregate("request", "instance"), ), ), ), @@ -1803,11 +1662,11 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { "", true, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -1815,7 +1674,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.DeleteExecutionRequest(tt.args.ctx, tt.args.cond, tt.args.resourceOwner) if tt.res.err == nil { @@ -1833,7 +1692,7 @@ func TestCommands_DeleteExecutionRequest(t *testing.T) { func TestCommands_DeleteExecutionResponse(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -1853,7 +1712,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1867,12 +1726,12 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionAPICondition{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1881,7 +1740,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "no valid cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1890,7 +1749,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "notvalid", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -1899,20 +1758,21 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("response.valid", "org1"), + execution.NewAggregate("response/valid", "instance"), ), ), ), @@ -1924,7 +1784,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -1933,7 +1793,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "not found, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1944,7 +1804,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -1953,19 +1813,20 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { { "push ok, method target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.method", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/method", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("response.method", "org1"), + execution.NewAggregate("response/method", "instance"), ), ), ), @@ -1977,30 +1838,31 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, service target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response.service", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response/service", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("response.service", "org1"), + execution.NewAggregate("response/service", "instance"), ), ), ), @@ -2012,30 +1874,31 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "service", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push ok, all target", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("response", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("response", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("response", "org1"), + execution.NewAggregate("response", "instance"), ), ), ), @@ -2047,11 +1910,11 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { "", true, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -2059,7 +1922,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.DeleteExecutionResponse(tt.args.ctx, tt.args.cond, tt.args.resourceOwner) if tt.res.err == nil { @@ -2077,7 +1940,7 @@ func TestCommands_DeleteExecutionResponse(t *testing.T) { func TestCommands_DeleteExecutionEvent(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -2097,7 +1960,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2111,12 +1974,12 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: &ExecutionEventCondition{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -2125,20 +1988,21 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("event.valid", "org1"), + execution.NewAggregate("event/valid", "instance"), ), ), ), @@ -2150,7 +2014,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -2159,7 +2023,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push error, not existing", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2170,7 +2034,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -2179,7 +2043,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push error, event", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2190,7 +2054,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -2199,19 +2063,20 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push ok, event", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.valid", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/valid", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("event.valid", "org1"), + execution.NewAggregate("event/valid", "instance"), ), ), ), @@ -2223,18 +2088,18 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push error, group", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2245,7 +2110,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "valid", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -2254,19 +2119,20 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push ok, group", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event.group", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event/group", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("event.group", "org1"), + execution.NewAggregate("event/group.*", "instance"), ), ), ), @@ -2278,18 +2144,18 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "group", false, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push error, all", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2300,7 +2166,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", true, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -2309,19 +2175,20 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { { "push ok, all", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("event", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("event", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("event", "org1"), + execution.NewAggregate("event", "instance"), ), ), ), @@ -2333,11 +2200,11 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { "", true, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -2345,7 +2212,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.DeleteExecutionEvent(tt.args.ctx, tt.args.cond, tt.args.resourceOwner) if tt.res.err == nil { @@ -2363,7 +2230,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) { func TestCommands_DeleteExecutionFunction(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -2383,7 +2250,7 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2397,12 +2264,12 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { { "no cond, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), cond: "", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -2411,20 +2278,21 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { { "push failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("function/function", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), + execution.NewAggregate("function/function", "instance"), ), ), ), @@ -2432,7 +2300,7 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { args{ ctx: context.Background(), cond: "function", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -2441,14 +2309,14 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { { "push error, not existing", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, args{ ctx: context.Background(), cond: "function", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -2457,19 +2325,20 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { { "push ok, function", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - execution.NewSetEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), - []string{"target"}, - nil, + execution.NewSetEventV2(context.Background(), + execution.NewAggregate("function/function", "instance"), + []*execution.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, ), ), ), expectPush( execution.NewRemovedEvent(context.Background(), - execution.NewAggregate("function.function", "org1"), + execution.NewAggregate("function/function", "instance"), ), ), ), @@ -2477,11 +2346,11 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { args{ ctx: context.Background(), cond: "function", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -2489,7 +2358,7 @@ func TestCommands_DeleteExecutionFunction(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.DeleteExecutionFunction(tt.args.ctx, tt.args.cond, tt.args.resourceOwner) if tt.res.err == nil { diff --git a/internal/command/action_v2_target.go b/internal/command/action_v2_target.go index 1bd2a620708..913bfb2299a 100644 --- a/internal/command/action_v2_target.go +++ b/internal/command/action_v2_target.go @@ -16,9 +16,8 @@ type AddTarget struct { Name string TargetType domain.TargetType - URL string + Endpoint string Timeout time.Duration - Async bool InterruptOnError bool } @@ -29,9 +28,9 @@ func (a *AddTarget) IsValid() error { if a.Timeout == 0 { return zerrors.ThrowInvalidArgument(nil, "COMMAND-39f35d8uri", "Errors.Target.NoTimeout") } - _, err := url.Parse(a.URL) - if err != nil || a.URL == "" { - return zerrors.ThrowInvalidArgument(nil, "COMMAND-1r2k6qo6wg", "Errors.Target.InvalidURL") + _, err := url.Parse(a.Endpoint) + if err != nil || a.Endpoint == "" { + return zerrors.ThrowInvalidArgument(err, "COMMAND-1r2k6qo6wg", "Errors.Target.InvalidURL") } return nil @@ -65,9 +64,8 @@ func (c *Commands) AddTarget(ctx context.Context, add *AddTarget, resourceOwner TargetAggregateFromWriteModel(&wm.WriteModel), add.Name, add.TargetType, - add.URL, + add.Endpoint, add.Timeout, - add.Async, add.InterruptOnError, )) if err != nil { @@ -84,9 +82,8 @@ type ChangeTarget struct { Name *string TargetType *domain.TargetType - URL *string + Endpoint *string Timeout *time.Duration - Async *bool InterruptOnError *bool } @@ -100,10 +97,10 @@ func (a *ChangeTarget) IsValid() error { if a.Timeout != nil && *a.Timeout == 0 { return zerrors.ThrowInvalidArgument(nil, "COMMAND-08b39vdi57", "Errors.Target.NoTimeout") } - if a.URL != nil { - _, err := url.Parse(*a.URL) - if err != nil || *a.URL == "" { - return zerrors.ThrowInvalidArgument(nil, "COMMAND-jsbaera7b6", "Errors.Target.InvalidURL") + if a.Endpoint != nil { + _, err := url.Parse(*a.Endpoint) + if err != nil || *a.Endpoint == "" { + return zerrors.ThrowInvalidArgument(err, "COMMAND-jsbaera7b6", "Errors.Target.InvalidURL") } } return nil @@ -130,9 +127,8 @@ func (c *Commands) ChangeTarget(ctx context.Context, change *ChangeTarget, resou TargetAggregateFromWriteModel(&existing.WriteModel), change.Name, change.TargetType, - change.URL, + change.Endpoint, change.Timeout, - change.Async, change.InterruptOnError) if changedEvent == nil { return writeModelToObjectDetails(&existing.WriteModel), nil diff --git a/internal/command/action_v2_target_model.go b/internal/command/action_v2_target_model.go index 60f70c40e0e..24dd76c80a9 100644 --- a/internal/command/action_v2_target_model.go +++ b/internal/command/action_v2_target_model.go @@ -15,9 +15,8 @@ type TargetWriteModel struct { Name string TargetType domain.TargetType - URL string + Endpoint string Timeout time.Duration - Async bool InterruptOnError bool State domain.TargetState @@ -39,9 +38,8 @@ func (wm *TargetWriteModel) Reduce() error { case *target.AddedEvent: wm.Name = e.Name wm.TargetType = e.TargetType - wm.URL = e.URL + wm.Endpoint = e.Endpoint wm.Timeout = e.Timeout - wm.Async = e.Async wm.State = domain.TargetActive case *target.ChangedEvent: if e.Name != nil { @@ -50,15 +48,12 @@ func (wm *TargetWriteModel) Reduce() error { if e.TargetType != nil { wm.TargetType = *e.TargetType } - if e.URL != nil { - wm.URL = *e.URL + if e.Endpoint != nil { + wm.Endpoint = *e.Endpoint } if e.Timeout != nil { wm.Timeout = *e.Timeout } - if e.Async != nil { - wm.Async = *e.Async - } if e.InterruptOnError != nil { wm.InterruptOnError = *e.InterruptOnError } @@ -86,9 +81,8 @@ func (wm *TargetWriteModel) NewChangedEvent( agg *eventstore.Aggregate, name *string, targetType *domain.TargetType, - url *string, + endpoint *string, timeout *time.Duration, - async *bool, interruptOnError *bool, ) *target.ChangedEvent { changes := make([]target.Changes, 0) @@ -98,15 +92,12 @@ func (wm *TargetWriteModel) NewChangedEvent( if targetType != nil && wm.TargetType != *targetType { changes = append(changes, target.ChangeTargetType(*targetType)) } - if url != nil && wm.URL != *url { - changes = append(changes, target.ChangeURL(*url)) + if endpoint != nil && wm.Endpoint != *endpoint { + changes = append(changes, target.ChangeEndpoint(*endpoint)) } if timeout != nil && wm.Timeout != *timeout { changes = append(changes, target.ChangeTimeout(*timeout)) } - if async != nil && wm.Async != *async { - changes = append(changes, target.ChangeAsync(*async)) - } if interruptOnError != nil && wm.InterruptOnError != *interruptOnError { changes = append(changes, target.ChangeInterruptOnError(*interruptOnError)) } diff --git a/internal/command/action_v2_target_model_test.go b/internal/command/action_v2_target_model_test.go index 4c0f31c8e0b..8042da23b19 100644 --- a/internal/command/action_v2_target_model_test.go +++ b/internal/command/action_v2_target_model_test.go @@ -20,7 +20,6 @@ func targetAddEvent(aggID, resourceOwner string) *target.AddedEvent { "https://example.com", time.Second, false, - false, ) } diff --git a/internal/command/action_v2_target_test.go b/internal/command/action_v2_target_test.go index 8600ffabf10..ef60baae490 100644 --- a/internal/command/action_v2_target_test.go +++ b/internal/command/action_v2_target_test.go @@ -19,7 +19,7 @@ import ( func TestCommands_AddTarget(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore idGenerator id.Generator } type args struct { @@ -41,7 +41,7 @@ func TestCommands_AddTarget(t *testing.T) { { "no resourceowner, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -55,12 +55,12 @@ func TestCommands_AddTarget(t *testing.T) { { "no name, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), add: &AddTarget{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -69,50 +69,50 @@ func TestCommands_AddTarget(t *testing.T) { { "no timeout, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), add: &AddTarget{ Name: "name", }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, }, }, { - "no url, error", + "no Endpoint, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), add: &AddTarget{ - Name: "name", - Timeout: time.Second, - URL: "", + Name: "name", + Timeout: time.Second, + Endpoint: "", }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, }, }, { - "no parsable url, error", + "no parsable Endpoint, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), add: &AddTarget{ - Name: "name", - Timeout: time.Second, - URL: "://", + Name: "name", + Timeout: time.Second, + Endpoint: "://", }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -121,18 +121,17 @@ func TestCommands_AddTarget(t *testing.T) { { "unique constraint failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), + target.NewAggregate("id1", "instance"), "name", domain.TargetTypeWebhook, "https://example.com", time.Second, false, - false, ), ), ), @@ -142,11 +141,11 @@ func TestCommands_AddTarget(t *testing.T) { ctx: context.Background(), add: &AddTarget{ Name: "name", - URL: "https://example.com", + Endpoint: "https://example.com", Timeout: time.Second, TargetType: domain.TargetTypeWebhook, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -155,16 +154,10 @@ func TestCommands_AddTarget(t *testing.T) { { "already existing", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - false, - false, + eventFromEventPusher( + targetAddEvent("target", "instance"), ), ), ), @@ -176,9 +169,9 @@ func TestCommands_AddTarget(t *testing.T) { Name: "name", TargetType: domain.TargetTypeWebhook, Timeout: time.Second, - URL: "https://example.com", + Endpoint: "https://example.com", }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorAlreadyExists, @@ -187,18 +180,10 @@ func TestCommands_AddTarget(t *testing.T) { { "push ok", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - false, - false, - ), + targetAddEvent("id1", "instance"), ), ), idGenerator: mock.ExpectID(t, "id1"), @@ -209,32 +194,28 @@ func TestCommands_AddTarget(t *testing.T) { Name: "name", TargetType: domain.TargetTypeWebhook, Timeout: time.Second, - URL: "https://example.com", + Endpoint: "https://example.com", }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ id: "id1", details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push full ok", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - time.Second, - true, - true, - ), + func() eventstore.Command { + event := targetAddEvent("id1", "instance") + event.InterruptOnError = true + return event + }(), ), ), idGenerator: mock.ExpectID(t, "id1"), @@ -244,17 +225,16 @@ func TestCommands_AddTarget(t *testing.T) { add: &AddTarget{ Name: "name", TargetType: domain.TargetTypeWebhook, - URL: "https://example.com", + Endpoint: "https://example.com", Timeout: time.Second, - Async: true, InterruptOnError: true, }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ id: "id1", details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -262,7 +242,7 @@ func TestCommands_AddTarget(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, } details, err := c.AddTarget(tt.args.ctx, tt.args.add, tt.args.resourceOwner) @@ -282,7 +262,7 @@ func TestCommands_AddTarget(t *testing.T) { func TestCommands_ChangeTarget(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -302,7 +282,7 @@ func TestCommands_ChangeTarget(t *testing.T) { { "resourceowner missing, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -316,12 +296,12 @@ func TestCommands_ChangeTarget(t *testing.T) { { "id missing, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), change: &ChangeTarget{}, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -330,14 +310,14 @@ func TestCommands_ChangeTarget(t *testing.T) { { "name empty, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), change: &ChangeTarget{ Name: gu.Ptr(""), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -346,46 +326,46 @@ func TestCommands_ChangeTarget(t *testing.T) { { "timeout empty, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), change: &ChangeTarget{ Timeout: gu.Ptr(time.Duration(0)), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, }, }, { - "url empty, error", + "Endpoint empty, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), change: &ChangeTarget{ - URL: gu.Ptr(""), + Endpoint: gu.Ptr(""), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, }, }, { - "url not parsable, error", + "Endpoint not parsable, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), change: &ChangeTarget{ - URL: gu.Ptr("://"), + Endpoint: gu.Ptr("://"), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -394,7 +374,7 @@ func TestCommands_ChangeTarget(t *testing.T) { { "not found, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -406,7 +386,7 @@ func TestCommands_ChangeTarget(t *testing.T) { }, Name: gu.Ptr("name"), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -415,18 +395,10 @@ func TestCommands_ChangeTarget(t *testing.T) { { "no changes", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - 0, - false, - false, - ), + targetAddEvent("target", "instance"), ), ), ), @@ -439,35 +411,27 @@ func TestCommands_ChangeTarget(t *testing.T) { }, TargetType: gu.Ptr(domain.TargetTypeWebhook), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "unique constraint failed, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - 0, - false, - false, - ), + targetAddEvent("target", "instance"), ), ), expectPushFailed( zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"), target.NewChangedEvent(context.Background(), - target.NewAggregate("id1", "org1"), + target.NewAggregate("id1", "instance"), []target.Changes{ target.ChangeName("name", "name2"), }, @@ -483,7 +447,7 @@ func TestCommands_ChangeTarget(t *testing.T) { }, Name: gu.Ptr("name2"), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsPreconditionFailed, @@ -492,23 +456,15 @@ func TestCommands_ChangeTarget(t *testing.T) { { "push ok", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - 0, - false, - false, - ), + targetAddEvent("id1", "instance"), ), ), expectPush( target.NewChangedEvent(context.Background(), - target.NewAggregate("id1", "org1"), + target.NewAggregate("id1", "instance"), []target.Changes{ target.ChangeName("name", "name2"), }, @@ -524,40 +480,31 @@ func TestCommands_ChangeTarget(t *testing.T) { }, Name: gu.Ptr("name2"), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, { "push full ok", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - 0, - false, - false, - ), + targetAddEvent("id1", "instance"), ), ), expectPush( target.NewChangedEvent(context.Background(), - target.NewAggregate("id1", "org1"), + target.NewAggregate("id1", "instance"), []target.Changes{ target.ChangeName("name", "name2"), - target.ChangeURL("https://example2.com"), - target.ChangeTargetType(domain.TargetTypeRequestResponse), - target.ChangeTimeout(time.Second), - target.ChangeAsync(true), + target.ChangeEndpoint("https://example2.com"), + target.ChangeTargetType(domain.TargetTypeCall), + target.ChangeTimeout(10 * time.Second), target.ChangeInterruptOnError(true), }, ), @@ -571,17 +518,16 @@ func TestCommands_ChangeTarget(t *testing.T) { AggregateID: "id1", }, Name: gu.Ptr("name2"), - URL: gu.Ptr("https://example2.com"), - TargetType: gu.Ptr(domain.TargetTypeRequestResponse), - Timeout: gu.Ptr(time.Second), - Async: gu.Ptr(true), + Endpoint: gu.Ptr("https://example2.com"), + TargetType: gu.Ptr(domain.TargetTypeCall), + Timeout: gu.Ptr(10 * time.Second), InterruptOnError: gu.Ptr(true), }, - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -589,7 +535,7 @@ func TestCommands_ChangeTarget(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.ChangeTarget(tt.args.ctx, tt.args.change, tt.args.resourceOwner) if tt.res.err == nil { @@ -607,7 +553,7 @@ func TestCommands_ChangeTarget(t *testing.T) { func TestCommands_DeleteTarget(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore } type args struct { ctx context.Context @@ -627,12 +573,12 @@ func TestCommands_DeleteTarget(t *testing.T) { { "id missing, error", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), id: "", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsErrorInvalidArgument, @@ -641,14 +587,14 @@ func TestCommands_DeleteTarget(t *testing.T) { { "not found, error", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, args{ ctx: context.Background(), id: "id1", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ err: zerrors.IsNotFound, @@ -657,23 +603,15 @@ func TestCommands_DeleteTarget(t *testing.T) { { "remove ok", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - target.NewAddedEvent(context.Background(), - target.NewAggregate("id1", "org1"), - "name", - domain.TargetTypeWebhook, - "https://example.com", - 0, - false, - false, - ), + targetAddEvent("id1", "instance"), ), ), expectPush( target.NewRemovedEvent(context.Background(), - target.NewAggregate("id1", "org1"), + target.NewAggregate("id1", "instance"), "name", ), ), @@ -682,11 +620,11 @@ func TestCommands_DeleteTarget(t *testing.T) { args{ ctx: context.Background(), id: "id1", - resourceOwner: "org1", + resourceOwner: "instance", }, res{ details: &domain.ObjectDetails{ - ResourceOwner: "org1", + ResourceOwner: "instance", }, }, }, @@ -694,7 +632,7 @@ func TestCommands_DeleteTarget(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), } details, err := c.DeleteTarget(tt.args.ctx, tt.args.id, tt.args.resourceOwner) if tt.res.err == nil { diff --git a/internal/domain/execution.go b/internal/domain/execution.go index 08f215bf080..eb83a0578c8 100644 --- a/internal/domain/execution.go +++ b/internal/domain/execution.go @@ -31,3 +31,17 @@ func (e ExecutionType) String() string { } return "" } + +type ExecutionTargetType uint + +func (s ExecutionTargetType) Valid() bool { + return s < executionTargetTypeStateCount +} + +const ( + ExecutionTargetTypeUnspecified ExecutionTargetType = iota + ExecutionTargetTypeInclude + ExecutionTargetTypeTarget + + executionTargetTypeStateCount +) diff --git a/internal/domain/target.go b/internal/domain/target.go index 83ab85478ee..1e08f91cf04 100644 --- a/internal/domain/target.go +++ b/internal/domain/target.go @@ -4,7 +4,8 @@ type TargetType uint const ( TargetTypeWebhook TargetType = iota - TargetTypeRequestResponse + TargetTypeCall + TargetTypeAsync ) type TargetState int32 diff --git a/internal/execution/execution.go b/internal/execution/execution.go new file mode 100644 index 00000000000..abb2153fc2a --- /dev/null +++ b/internal/execution/execution.go @@ -0,0 +1,122 @@ +package execution + +import ( + "bytes" + "context" + "io" + "net/http" + "time" + + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/telemetry/tracing" + "github.com/zitadel/zitadel/internal/zerrors" +) + +type ContextInfo interface { + GetHTTPRequestBody() []byte + GetContent() interface{} + SetHTTPResponseBody([]byte) error +} + +type Target interface { + GetTargetID() string + IsInterruptOnError() bool + GetEndpoint() string + GetTargetType() domain.TargetType + GetTimeout() time.Duration +} + +// CallTargets call a list of targets in order with handling of error and responses +func CallTargets( + ctx context.Context, + targets []Target, + info ContextInfo, +) (_ interface{}, err error) { + ctx, span := tracing.NewSpan(ctx) + defer span.EndWithError(err) + + for _, target := range targets { + // call the type of target + resp, err := CallTarget(ctx, target, info) + // handle error if interrupt is set + if err != nil && target.IsInterruptOnError() { + return nil, err + } + if len(resp) > 0 { + // error in unmarshalling + if err := info.SetHTTPResponseBody(resp); err != nil { + return nil, err + } + } + } + return info.GetContent(), nil +} + +type ContextInfoRequest interface { + GetHTTPRequestBody() []byte +} + +// CallTarget call the desired type of target with handling of responses +func CallTarget( + ctx context.Context, + target Target, + info ContextInfoRequest, +) (res []byte, err error) { + ctx, span := tracing.NewSpan(ctx) + defer span.EndWithError(err) + + switch target.GetTargetType() { + // get request, ignore response and return request and error for handling in list of targets + case domain.TargetTypeWebhook: + return nil, webhook(ctx, target.GetEndpoint(), target.GetTimeout(), info.GetHTTPRequestBody()) + // get request, return response and error + case domain.TargetTypeCall: + return call(ctx, target.GetEndpoint(), target.GetTimeout(), info.GetHTTPRequestBody()) + case domain.TargetTypeAsync: + go func(target Target, info ContextInfoRequest) { + if _, err := call(ctx, target.GetEndpoint(), target.GetTimeout(), info.GetHTTPRequestBody()); err != nil { + logging.WithFields("target", target.GetTargetID()).OnError(err).Info(err) + } + }(target, info) + return nil, nil + default: + return nil, zerrors.ThrowInternal(nil, "EXEC-auqnansr2m", "Errors.Execution.Unknown") + } +} + +// webhook call a webhook, ignore the response but return the errror +func webhook(ctx context.Context, url string, timeout time.Duration, body []byte) error { + _, err := call(ctx, url, timeout, body) + return err +} + +// call function to do a post HTTP request to a desired url with timeout +func call(ctx context.Context, url string, timeout time.Duration, body []byte) (_ []byte, err error) { + ctx, cancel := context.WithTimeout(ctx, timeout) + ctx, span := tracing.NewSpan(ctx) + defer func() { + cancel() + span.EndWithError(err) + }() + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + client := http.DefaultClient + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + // Check for success between 200 and 299, redirect 300 to 399 is handled by the client, return error with statusCode >= 400 + if resp.StatusCode >= 200 && resp.StatusCode <= 299 { + return io.ReadAll(resp.Body) + } + return nil, zerrors.ThrowUnknown(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed") +} diff --git a/internal/execution/execution_test.go b/internal/execution/execution_test.go new file mode 100644 index 00000000000..2d891148df7 --- /dev/null +++ b/internal/execution/execution_test.go @@ -0,0 +1,347 @@ +package execution + +import ( + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/zitadel/zitadel/internal/domain" +) + +var _ Target = &mockTarget{} + +type mockTarget struct { + InstanceID string + ExecutionID string + TargetID string + TargetType domain.TargetType + Endpoint string + Timeout time.Duration + InterruptOnError bool +} + +func (e *mockTarget) GetTargetID() string { + return e.TargetID +} +func (e *mockTarget) IsInterruptOnError() bool { + return e.InterruptOnError +} +func (e *mockTarget) GetEndpoint() string { + return e.Endpoint +} +func (e *mockTarget) GetTargetType() domain.TargetType { + return e.TargetType +} +func (e *mockTarget) GetTimeout() time.Duration { + return e.Timeout +} + +func Test_Call(t *testing.T) { + type args struct { + ctx context.Context + timeout time.Duration + sleep time.Duration + method string + body []byte + respBody []byte + statusCode int + } + type res struct { + body []byte + wantErr bool + } + tests := []struct { + name string + args args + res res + }{ + { + "not ok status", + args{ + ctx: context.Background(), + timeout: time.Minute, + sleep: time.Second, + method: http.MethodPost, + body: []byte("{\"request\": \"values\"}"), + respBody: []byte("{\"response\": \"values\"}"), + statusCode: http.StatusBadRequest, + }, + res{ + wantErr: true, + }, + }, + { + "timeout", + args{ + ctx: context.Background(), + timeout: time.Second, + sleep: time.Second, + method: http.MethodPost, + body: []byte("{\"request\": \"values\"}"), + respBody: []byte("{\"response\": \"values\"}"), + statusCode: http.StatusOK, + }, + res{ + wantErr: true, + }, + }, + { + "ok", + args{ + ctx: context.Background(), + timeout: time.Minute, + sleep: time.Second, + method: http.MethodPost, + body: []byte("{\"request\": \"values\"}"), + respBody: []byte("{\"response\": \"values\"}"), + statusCode: http.StatusOK, + }, + res{ + body: []byte("{\"response\": \"values\"}"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + respBody, err := testServerCall(t, + tt.args.method, + tt.args.body, + tt.args.sleep, + tt.args.statusCode, + tt.args.respBody, + testCall(tt.args.ctx, tt.args.timeout, tt.args.body), + ) + if tt.res.wantErr { + assert.Error(t, err) + assert.Nil(t, respBody) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.res.body, respBody) + } + }) + } +} + +func testCall(ctx context.Context, timeout time.Duration, body []byte) func(string) ([]byte, error) { + return func(url string) ([]byte, error) { + return call(ctx, url, timeout, body) + } +} + +func testCallTarget(ctx context.Context, + target *mockTarget, + info ContextInfoRequest, +) func(string) ([]byte, error) { + return func(url string) (r []byte, err error) { + target.Endpoint = url + return CallTarget(ctx, target, info) + } +} + +func testServerCall( + t *testing.T, + method string, + body []byte, + timeout time.Duration, + statusCode int, + respBody []byte, + call func(string) ([]byte, error), +) ([]byte, error) { + handler := func(w http.ResponseWriter, r *http.Request) { + checkRequest(t, r, method, body) + + if statusCode != http.StatusOK { + http.Error(w, "error", statusCode) + return + } + + time.Sleep(timeout) + + w.Header().Set("Content-Type", "application/json") + if _, err := io.WriteString(w, string(respBody)); err != nil { + http.Error(w, "error", http.StatusInternalServerError) + return + } + } + + server := httptest.NewServer(http.HandlerFunc(handler)) + defer server.Close() + + return call(server.URL) +} + +func checkRequest(t *testing.T, sent *http.Request, method string, expectedBody []byte) { + sentBody, err := io.ReadAll(sent.Body) + require.NoError(t, err) + require.Equal(t, expectedBody, sentBody) + require.Equal(t, method, sent.Method) +} + +var _ ContextInfoRequest = &mockContextInfoRequest{} + +type request struct { + Request string `json:"request"` +} + +type mockContextInfoRequest struct { + Request *request `json:"request"` +} + +func newMockContextInfoRequest(s string) *mockContextInfoRequest { + return &mockContextInfoRequest{&request{s}} +} + +func (c *mockContextInfoRequest) GetHTTPRequestBody() []byte { + data, _ := json.Marshal(c) + return data +} + +func (c *mockContextInfoRequest) GetContent() []byte { + data, _ := json.Marshal(c.Request) + return data +} + +func Test_CallTarget(t *testing.T) { + type args struct { + ctx context.Context + target *mockTarget + sleep time.Duration + + info ContextInfoRequest + + method string + body []byte + + respBody []byte + statusCode int + } + type res struct { + body []byte + wantErr bool + } + tests := []struct { + name string + args args + res res + }{ + { + "unknown targettype, error", + args{ + ctx: context.Background(), + sleep: time.Second, + method: http.MethodPost, + info: newMockContextInfoRequest("content1"), + target: &mockTarget{ + TargetType: 4, + }, + body: []byte("{\"request\":{\"request\":\"content1\"}}"), + respBody: []byte("{\"request\":\"content2\"}"), + statusCode: http.StatusInternalServerError, + }, + res{ + wantErr: true, + }, + }, + { + "webhook, error", + args{ + ctx: context.Background(), + sleep: time.Second, + method: http.MethodPost, + info: newMockContextInfoRequest("content1"), + target: &mockTarget{ + TargetType: domain.TargetTypeWebhook, + Timeout: time.Minute, + }, + body: []byte("{\"request\":{\"request\":\"content1\"}}"), + respBody: []byte("{\"request\":\"content2\"}"), + statusCode: http.StatusInternalServerError, + }, + res{ + wantErr: true, + }, + }, + { + "webhook, ok", + args{ + ctx: context.Background(), + sleep: time.Second, + method: http.MethodPost, + info: newMockContextInfoRequest("content1"), + target: &mockTarget{ + TargetType: domain.TargetTypeWebhook, + Timeout: time.Minute, + }, + body: []byte("{\"request\":{\"request\":\"content1\"}}"), + respBody: []byte("{\"request\":\"content2\"}"), + statusCode: http.StatusOK, + }, + res{ + body: nil, + }, + }, + { + "request response, error", + args{ + ctx: context.Background(), + sleep: time.Second, + method: http.MethodPost, + info: newMockContextInfoRequest("content1"), + target: &mockTarget{ + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + }, + body: []byte("{\"request\":{\"request\":\"content1\"}}"), + respBody: []byte("{\"request\":\"content2\"}"), + statusCode: http.StatusInternalServerError, + }, + res{ + wantErr: true, + }, + }, + { + "request response, ok", + args{ + ctx: context.Background(), + sleep: time.Second, + method: http.MethodPost, + info: newMockContextInfoRequest("content1"), + target: &mockTarget{ + TargetType: domain.TargetTypeCall, + Timeout: time.Minute, + }, + body: []byte("{\"request\":{\"request\":\"content1\"}}"), + respBody: []byte("{\"request\":\"content2\"}"), + statusCode: http.StatusOK, + }, + res{ + body: []byte("{\"request\":\"content2\"}"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + respBody, err := testServerCall(t, + tt.args.method, + tt.args.body, + tt.args.sleep, + tt.args.statusCode, + tt.args.respBody, + testCallTarget(tt.args.ctx, tt.args.target, tt.args.info), + ) + if tt.res.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tt.res.body, respBody) + }) + } +} diff --git a/internal/integration/assert.go b/internal/integration/assert.go index d5b7353aa26..225b3399b42 100644 --- a/internal/integration/assert.go +++ b/internal/integration/assert.go @@ -65,7 +65,9 @@ func AssertListDetails[D ListDetailsMsg](t testing.TB, expected, actual D) { assert.Equal(t, wantDetails.GetTotalResult(), gotDetails.GetTotalResult()) - gotCD := gotDetails.GetTimestamp().AsTime() - wantCD := time.Now() - assert.WithinRange(t, gotCD, wantCD.Add(-time.Minute), wantCD.Add(time.Minute)) + if wantDetails.GetTimestamp() != nil { + gotCD := gotDetails.GetTimestamp().AsTime() + wantCD := time.Now() + assert.WithinRange(t, gotCD, wantCD.Add(-time.Minute), wantCD.Add(time.Minute)) + } } diff --git a/internal/integration/client.go b/internal/integration/client.go index eb95134bc38..cb22e5d5529 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -522,39 +522,32 @@ func (s *Tester) CreateProjectMembership(t *testing.T, ctx context.Context, proj require.NoError(t, err) } -func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *action.CreateTargetResponse { - req := &action.CreateTargetRequest{ - Name: fmt.Sprint(time.Now().UnixNano() + 1), - TargetType: &action.CreateTargetRequest_RestWebhook{ - RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", - }, - }, - Timeout: durationpb.New(10 * time.Second), +func (s *Tester) CreateTarget(ctx context.Context, t *testing.T, name, endpoint string, ty domain.TargetType, interrupt bool) *action.CreateTargetResponse { + nameSet := fmt.Sprint(time.Now().UnixNano() + 1) + if name != "" { + nameSet = name } - target, err := s.Client.ActionV3.CreateTarget(ctx, req) - require.NoError(t, err) - return target -} - -func (s *Tester) CreateTargetWithNameAndType(ctx context.Context, t *testing.T, name string, async bool, interrupt bool) *action.CreateTargetResponse { req := &action.CreateTargetRequest{ - Name: name, - TargetType: &action.CreateTargetRequest_RestWebhook{ + Name: nameSet, + Endpoint: endpoint, + Timeout: durationpb.New(10 * time.Second), + } + switch ty { + case domain.TargetTypeWebhook: + req.TargetType = &action.CreateTargetRequest_RestWebhook{ RestWebhook: &action.SetRESTWebhook{ - Url: "https://example.com", + InterruptOnError: interrupt, }, - }, - Timeout: durationpb.New(10 * time.Second), - } - if async { - req.ExecutionType = &action.CreateTargetRequest_IsAsync{ - IsAsync: true, } - } - if interrupt { - req.ExecutionType = &action.CreateTargetRequest_InterruptOnError{ - InterruptOnError: true, + case domain.TargetTypeCall: + req.TargetType = &action.CreateTargetRequest_RestCall{ + RestCall: &action.SetRESTCall{ + InterruptOnError: interrupt, + }, + } + case domain.TargetTypeAsync: + req.TargetType = &action.CreateTargetRequest_RestAsync{ + RestAsync: &action.SetRESTAsync{}, } } target, err := s.Client.ActionV3.CreateTarget(ctx, req) @@ -562,16 +555,22 @@ func (s *Tester) CreateTargetWithNameAndType(ctx context.Context, t *testing.T, return target } -func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *action.Condition, targets []string, includes []string) *action.SetExecutionResponse { +func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *action.Condition, targets []*action.ExecutionTargetType) *action.SetExecutionResponse { target, err := s.Client.ActionV3.SetExecution(ctx, &action.SetExecutionRequest{ Condition: cond, Targets: targets, - Includes: includes, }) require.NoError(t, err) return target } +func (s *Tester) DeleteExecution(ctx context.Context, t *testing.T, cond *action.Condition) { + _, err := s.Client.ActionV3.DeleteExecution(ctx, &action.DeleteExecutionRequest{ + Condition: cond, + }) + require.NoError(t, err) +} + func (s *Tester) CreateUserSchema(ctx context.Context, t *testing.T) *schema.CreateUserSchemaResponse { return s.CreateUserSchemaWithType(ctx, t, fmt.Sprint(time.Now().UnixNano()+1)) } diff --git a/internal/query/execution.go b/internal/query/execution.go index 5a8a7e0f799..ff501f8201a 100644 --- a/internal/query/execution.go +++ b/internal/query/execution.go @@ -3,7 +3,10 @@ package query import ( "context" "database/sql" + _ "embed" + "encoding/json" "errors" + "time" sq "github.com/Masterminds/squirrel" @@ -11,6 +14,8 @@ import ( "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/query/projection" + exec "github.com/zitadel/zitadel/internal/repository/execution" + "github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -23,18 +28,10 @@ var ( name: projection.ExecutionIDCol, table: executionTable, } - ExecutionColumnCreationDate = Column{ - name: projection.ExecutionCreationDateCol, - table: executionTable, - } ExecutionColumnChangeDate = Column{ name: projection.ExecutionChangeDateCol, table: executionTable, } - ExecutionColumnResourceOwner = Column{ - name: projection.ExecutionResourceOwnerCol, - table: executionTable, - } ExecutionColumnInstanceID = Column{ name: projection.ExecutionInstanceIDCol, table: executionTable, @@ -43,16 +40,35 @@ var ( name: projection.ExecutionSequenceCol, table: executionTable, } - ExecutionColumnTargets = Column{ - name: projection.ExecutionTargetsCol, - table: executionTable, + + executionTargetsTable = table{ + name: projection.ExecutionTable + "_" + projection.ExecutionTargetSuffix, + instanceIDCol: projection.ExecutionTargetInstanceIDCol, } - ExecutionColumnIncludes = Column{ - name: projection.ExecutionIncludesCol, - table: executionTable, + executionTargetsTableAlias = executionTargetsTable.setAlias("execution_targets") + ExecutionTargetsColumnInstanceID = Column{ + name: projection.ExecutionTargetInstanceIDCol, + table: executionTargetsTableAlias, + } + ExecutionTargetsColumnExecutionID = Column{ + name: projection.ExecutionTargetExecutionIDCol, + table: executionTargetsTableAlias, + } + executionTargetsListCol = Column{ + name: "targets", + table: executionTargetsTableAlias, } ) +var ( + //go:embed execution_targets.sql + executionTargetsQuery string + //go:embed targets_by_execution_id.sql + TargetsByExecutionIDQuery string + //go:embed targets_by_execution_ids.sql + TargetsByExecutionIDsQuery string +) + type Executions struct { SearchResponse Executions []*Execution @@ -66,8 +82,7 @@ type Execution struct { ID string domain.ObjectDetails - Targets database.TextArray[string] - Includes database.TextArray[string] + Targets []*exec.Target } type ExecutionSearchQueries struct { @@ -108,84 +123,301 @@ func NewExecutionTypeSearchQuery(t domain.ExecutionType) (SearchQuery, error) { return NewTextQuery(ExecutionColumnID, t.String(), TextStartsWith) } -func NewExecutionTargetSearchQuery(value string) (SearchQuery, error) { - return NewTextQuery(ExecutionColumnTargets, value, TextListContains) +func NewTargetSearchQuery(target string) (SearchQuery, error) { + data, err := targetItemJSONB(domain.ExecutionTargetTypeTarget, target) + if err != nil { + return nil, err + } + return NewListContains(executionTargetsListCol, data) } -func NewExecutionIncludeSearchQuery(value string) (SearchQuery, error) { - return NewTextQuery(ExecutionColumnIncludes, value, TextListContains) +func NewIncludeSearchQuery(include string) (SearchQuery, error) { + data, err := targetItemJSONB(domain.ExecutionTargetTypeInclude, include) + if err != nil { + return nil, err + } + return NewListContains(executionTargetsListCol, data) } -func prepareExecutionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*Executions, error)) { +// marshall executionTargets into the same JSONB structure as in the SQL queries +func targetItemJSONB(t domain.ExecutionTargetType, targetItem string) ([]byte, error) { + var target *executionTarget + switch t { + case domain.ExecutionTargetTypeTarget: + target = &executionTarget{Target: targetItem} + case domain.ExecutionTargetTypeInclude: + target = &executionTarget{Include: targetItem} + case domain.ExecutionTargetTypeUnspecified: + return nil, nil + default: + return nil, nil + } + return json.Marshal([]*executionTarget{target}) +} + +// TargetsByExecutionID query list of targets for best match of a list of IDs, for example: +// [ "request/zitadel.action.v3alpha.ActionService/GetTargetByID", +// "request/zitadel.action.v3alpha.ActionService", +// "request" ] +func (q *Queries) TargetsByExecutionID(ctx context.Context, ids []string) (execution []*ExecutionTarget, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.End() }() + + instanceID := authz.GetInstance(ctx).InstanceID() + if instanceID == "" { + return nil, nil + } + + err = q.client.QueryContext(ctx, + func(rows *sql.Rows) error { + execution, err = scanExecutionTargets(rows) + return err + }, + TargetsByExecutionIDQuery, + instanceID, + database.TextArray[string](ids), + ) + return execution, err +} + +// TargetsByExecutionIDs query list of targets for best matches of 2 separate lists of IDs, combined for performance, for example: +// [ "request/zitadel.action.v3alpha.ActionService/GetTargetByID", +// "request/zitadel.action.v3alpha.ActionService", +// "request" ] +// and +// [ "response/zitadel.action.v3alpha.ActionService/GetTargetByID", +// "response/zitadel.action.v3alpha.ActionService", +// "response" ] +func (q *Queries) TargetsByExecutionIDs(ctx context.Context, ids1, ids2 []string) (execution []*ExecutionTarget, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.End() }() + + instanceID := authz.GetInstance(ctx).InstanceID() + if instanceID == "" { + return nil, nil + } + + err = q.client.QueryContext(ctx, + func(rows *sql.Rows) error { + execution, err = scanExecutionTargets(rows) + return err + }, + TargetsByExecutionIDsQuery, + instanceID, + database.TextArray[string](ids1), + database.TextArray[string](ids2), + ) + return execution, err +} + +func prepareExecutionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*Execution, error)) { return sq.Select( + ExecutionColumnInstanceID.identifier(), ExecutionColumnID.identifier(), ExecutionColumnChangeDate.identifier(), - ExecutionColumnResourceOwner.identifier(), ExecutionColumnSequence.identifier(), - ExecutionColumnTargets.identifier(), - ExecutionColumnIncludes.identifier(), - countColumn.identifier(), + executionTargetsListCol.identifier(), ).From(executionTable.identifier()). + Join("(" + executionTargetsQuery + ") AS " + executionTargetsTableAlias.alias + " ON " + + ExecutionTargetsColumnInstanceID.identifier() + " = " + ExecutionColumnInstanceID.identifier() + " AND " + + ExecutionTargetsColumnExecutionID.identifier() + " = " + ExecutionColumnID.identifier(), + ). PlaceholderFormat(sq.Dollar), - func(rows *sql.Rows) (*Executions, error) { - executions := make([]*Execution, 0) - var count uint64 - for rows.Next() { - execution := new(Execution) - err := rows.Scan( - &execution.ID, - &execution.EventDate, - &execution.ResourceOwner, - &execution.Sequence, - &execution.Targets, - &execution.Includes, - &count, - ) - if err != nil { - return nil, err - } - executions = append(executions, execution) - } - - if err := rows.Close(); err != nil { - return nil, zerrors.ThrowInternal(err, "QUERY-72xfx5jlj7", "Errors.Query.CloseRows") - } - - return &Executions{ - Executions: executions, - SearchResponse: SearchResponse{ - Count: count, - }, - }, nil - } + scanExecution } -func prepareExecutionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*Execution, error)) { +func prepareExecutionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*Executions, error)) { return sq.Select( + ExecutionColumnInstanceID.identifier(), ExecutionColumnID.identifier(), ExecutionColumnChangeDate.identifier(), - ExecutionColumnResourceOwner.identifier(), ExecutionColumnSequence.identifier(), - ExecutionColumnTargets.identifier(), - ExecutionColumnIncludes.identifier(), + executionTargetsListCol.identifier(), + countColumn.identifier(), ).From(executionTable.identifier()). + Join("(" + executionTargetsQuery + ") AS " + executionTargetsTableAlias.alias + " ON " + + ExecutionTargetsColumnInstanceID.identifier() + " = " + ExecutionColumnInstanceID.identifier() + " AND " + + ExecutionTargetsColumnExecutionID.identifier() + " = " + ExecutionColumnID.identifier(), + ). PlaceholderFormat(sq.Dollar), - func(row *sql.Row) (*Execution, error) { - execution := new(Execution) - err := row.Scan( - &execution.ID, - &execution.EventDate, - &execution.ResourceOwner, - &execution.Sequence, - &execution.Targets, - &execution.Includes, - ) - if err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, zerrors.ThrowNotFound(err, "QUERY-qzn1xycesh", "Errors.Execution.NotFound") - } - return nil, zerrors.ThrowInternal(err, "QUERY-f8sjvm4tb8", "Errors.Internal") + scanExecutions +} + +type executionTarget struct { + Position int `json:"position,omitempty"` + Include string `json:"include,omitempty"` + Target string `json:"target,omitempty"` +} + +func scanExecution(row *sql.Row) (*Execution, error) { + execution := new(Execution) + targets := make([]byte, 0) + + err := row.Scan( + &execution.ResourceOwner, + &execution.ID, + &execution.EventDate, + &execution.Sequence, + &targets, + ) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, zerrors.ThrowNotFound(err, "QUERY-qzn1xycesh", "Errors.Execution.NotFound") + } + return nil, zerrors.ThrowInternal(err, "QUERY-f8sjvm4tb8", "Errors.Internal") + } + + executionTargets := make([]*executionTarget, 0) + if err := json.Unmarshal(targets, &executionTargets); err != nil { + return nil, err + } + + execution.Targets = make([]*exec.Target, len(executionTargets)) + for i := range executionTargets { + if executionTargets[i].Target != "" { + execution.Targets[i] = &exec.Target{Type: domain.ExecutionTargetTypeTarget, Target: executionTargets[i].Target} + } + if executionTargets[i].Include != "" { + execution.Targets[i] = &exec.Target{Type: domain.ExecutionTargetTypeInclude, Target: executionTargets[i].Include} + } + } + + return execution, nil +} + +func executionTargetsUnmarshal(data []byte) ([]*exec.Target, error) { + executionTargets := make([]*executionTarget, 0) + if err := json.Unmarshal(data, &executionTargets); err != nil { + return nil, err + } + + targets := make([]*exec.Target, len(executionTargets)) + // position starts with 1 + for _, item := range executionTargets { + if item.Target != "" { + targets[item.Position-1] = &exec.Target{Type: domain.ExecutionTargetTypeTarget, Target: item.Target} + } + if item.Include != "" { + targets[item.Position-1] = &exec.Target{Type: domain.ExecutionTargetTypeInclude, Target: item.Include} + } + } + return targets, nil +} + +func scanExecutions(rows *sql.Rows) (*Executions, error) { + executions := make([]*Execution, 0) + var count uint64 + + for rows.Next() { + execution := new(Execution) + targets := make([]byte, 0) + + err := rows.Scan( + &execution.ResourceOwner, + &execution.ID, + &execution.EventDate, + &execution.Sequence, + &targets, + &count, + ) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, zerrors.ThrowNotFound(err, "QUERY-tbrmno85vp", "Errors.Execution.NotFound") } - return execution, nil + return nil, zerrors.ThrowInternal(err, "QUERY-tyw2ydsj84", "Errors.Internal") } + + execution.Targets, err = executionTargetsUnmarshal(targets) + if err != nil { + return nil, err + } + executions = append(executions, execution) + } + + if err := rows.Close(); err != nil { + return nil, zerrors.ThrowInternal(err, "QUERY-yhka3fs3mw", "Errors.Query.CloseRows") + } + + return &Executions{ + Executions: executions, + SearchResponse: SearchResponse{ + Count: count, + }, + }, nil +} + +type ExecutionTarget struct { + InstanceID string + ExecutionID string + TargetID string + TargetType domain.TargetType + Endpoint string + Timeout time.Duration + InterruptOnError bool +} + +func (e *ExecutionTarget) GetExecutionID() string { + return e.ExecutionID +} +func (e *ExecutionTarget) GetTargetID() string { + return e.TargetID +} +func (e *ExecutionTarget) IsInterruptOnError() bool { + return e.InterruptOnError +} +func (e *ExecutionTarget) GetEndpoint() string { + return e.Endpoint +} +func (e *ExecutionTarget) GetTargetType() domain.TargetType { + return e.TargetType +} +func (e *ExecutionTarget) GetTimeout() time.Duration { + return e.Timeout +} + +func scanExecutionTargets(rows *sql.Rows) ([]*ExecutionTarget, error) { + targets := make([]*ExecutionTarget, 0) + for rows.Next() { + target := new(ExecutionTarget) + + var ( + instanceID = &sql.NullString{} + executionID = &sql.NullString{} + targetID = &sql.NullString{} + targetType = &sql.NullInt32{} + endpoint = &sql.NullString{} + timeout = &sql.NullInt64{} + interruptOnError = &sql.NullBool{} + ) + + err := rows.Scan( + executionID, + instanceID, + targetID, + targetType, + endpoint, + timeout, + interruptOnError, + ) + + if err != nil { + return nil, err + } + + target.InstanceID = instanceID.String + target.ExecutionID = executionID.String + target.TargetID = targetID.String + target.TargetType = domain.TargetType(targetType.Int32) + target.Endpoint = endpoint.String + target.Timeout = time.Duration(timeout.Int64) + target.InterruptOnError = interruptOnError.Bool + + targets = append(targets, target) + } + + if err := rows.Close(); err != nil { + return nil, zerrors.ThrowInternal(err, "QUERY-37ardr0pki", "Errors.Query.CloseRows") + } + + return targets, nil } diff --git a/internal/query/execution_targets.sql b/internal/query/execution_targets.sql new file mode 100644 index 00000000000..32257f4a1fb --- /dev/null +++ b/internal/query/execution_targets.sql @@ -0,0 +1,11 @@ +SELECT instance_id, + execution_id, + JSONB_AGG( + JSON_OBJECT( + 'position' : position, + 'include' : include, + 'target' : target_id + ) + ) as targets +FROM projections.executions1_targets +GROUP BY instance_id, execution_id \ No newline at end of file diff --git a/internal/query/execution_test.go b/internal/query/execution_test.go index 20058b1ae00..b989d539a05 100644 --- a/internal/query/execution_test.go +++ b/internal/query/execution_test.go @@ -8,44 +8,56 @@ import ( "regexp" "testing" - "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/domain" + exec "github.com/zitadel/zitadel/internal/repository/execution" "github.com/zitadel/zitadel/internal/zerrors" ) var ( - prepareExecutionsStmt = `SELECT projections.executions.id,` + - ` projections.executions.change_date,` + - ` projections.executions.resource_owner,` + - ` projections.executions.sequence,` + - ` projections.executions.targets,` + - ` projections.executions.includes,` + + prepareExecutionsStmt = `SELECT projections.executions1.instance_id,` + + ` projections.executions1.id,` + + ` projections.executions1.change_date,` + + ` projections.executions1.sequence,` + + ` execution_targets.targets,` + ` COUNT(*) OVER ()` + - ` FROM projections.executions` + ` FROM projections.executions1` + + ` JOIN (` + + `SELECT instance_id, execution_id, JSONB_AGG( JSON_OBJECT( 'position' : position, 'include' : include, 'target' : target_id ) ) as targets` + + ` FROM projections.executions1_targets` + + ` GROUP BY instance_id, execution_id` + + `)` + + ` AS execution_targets` + + ` ON execution_targets.instance_id = projections.executions1.instance_id` + + ` AND execution_targets.execution_id = projections.executions1.id` prepareExecutionsCols = []string{ + "instance_id", "id", "change_date", - "resource_owner", "sequence", "targets", - "includes", "count", } - prepareExecutionStmt = `SELECT projections.executions.id,` + - ` projections.executions.change_date,` + - ` projections.executions.resource_owner,` + - ` projections.executions.sequence,` + - ` projections.executions.targets,` + - ` projections.executions.includes` + - ` FROM projections.executions` + prepareExecutionStmt = `SELECT projections.executions1.instance_id,` + + ` projections.executions1.id,` + + ` projections.executions1.change_date,` + + ` projections.executions1.sequence,` + + ` execution_targets.targets` + + ` FROM projections.executions1` + + ` JOIN (` + + `SELECT instance_id, execution_id, JSONB_AGG( JSON_OBJECT( 'position' : position, 'include' : include, 'target' : target_id ) ) as targets` + + ` FROM projections.executions1_targets` + + ` GROUP BY instance_id, execution_id` + + `)` + + ` AS execution_targets` + + ` ON execution_targets.instance_id = projections.executions1.instance_id` + + ` AND execution_targets.execution_id = projections.executions1.id` prepareExecutionCols = []string{ + "instance_id", "id", "change_date", - "resource_owner", "sequence", "targets", - "includes", } ) @@ -81,12 +93,11 @@ func Test_ExecutionPrepares(t *testing.T) { prepareExecutionsCols, [][]driver.Value{ { + "ro", "id", testNow, - "ro", uint64(20211109), - database.TextArray[string]{"target"}, - database.TextArray[string]{"include"}, + []byte(`[{"position" : 1, "target" : "target"}, {"position" : 2, "include" : "include"}]`), }, }, ), @@ -103,8 +114,10 @@ func Test_ExecutionPrepares(t *testing.T) { ResourceOwner: "ro", Sequence: 20211109, }, - Targets: database.TextArray[string]{"target"}, - Includes: database.TextArray[string]{"include"}, + Targets: []*exec.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, }, }, }, @@ -118,20 +131,18 @@ func Test_ExecutionPrepares(t *testing.T) { prepareExecutionsCols, [][]driver.Value{ { + "ro", "id-1", testNow, - "ro", uint64(20211109), - database.TextArray[string]{"target1"}, - database.TextArray[string]{"include1"}, + []byte(`[{"position" : 1, "target" : "target"}, {"position" : 2, "include" : "include"}]`), }, { + "ro", "id-2", testNow, - "ro", uint64(20211110), - database.TextArray[string]{"target2"}, - database.TextArray[string]{"include2"}, + []byte(`[{"position" : 2, "target" : "target"}, {"position" : 1, "include" : "include"}]`), }, }, ), @@ -148,8 +159,10 @@ func Test_ExecutionPrepares(t *testing.T) { ResourceOwner: "ro", Sequence: 20211109, }, - Targets: database.TextArray[string]{"target1"}, - Includes: database.TextArray[string]{"include1"}, + Targets: []*exec.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, }, { ID: "id-2", @@ -158,8 +171,10 @@ func Test_ExecutionPrepares(t *testing.T) { ResourceOwner: "ro", Sequence: 20211110, }, - Targets: database.TextArray[string]{"target2"}, - Includes: database.TextArray[string]{"include2"}, + Targets: []*exec.Target{ + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + }, }, }, }, @@ -207,12 +222,11 @@ func Test_ExecutionPrepares(t *testing.T) { regexp.QuoteMeta(prepareExecutionStmt), prepareExecutionCols, []driver.Value{ + "ro", "id", testNow, - "ro", uint64(20211109), - database.TextArray[string]{"target"}, - database.TextArray[string]{"include"}, + []byte(`[{"position" : 1, "target" : "target"}, {"position" : 2, "include" : "include"}]`), }, ), }, @@ -223,8 +237,10 @@ func Test_ExecutionPrepares(t *testing.T) { ResourceOwner: "ro", Sequence: 20211109, }, - Targets: database.TextArray[string]{"target"}, - Includes: database.TextArray[string]{"include"}, + Targets: []*exec.Target{ + {Type: domain.ExecutionTargetTypeTarget, Target: "target"}, + {Type: domain.ExecutionTargetTypeInclude, Target: "include"}, + }, }, }, { diff --git a/internal/query/projection/execution.go b/internal/query/projection/execution.go index 350a27ec27a..9001fcd3ba2 100644 --- a/internal/query/projection/execution.go +++ b/internal/query/projection/execution.go @@ -3,6 +3,7 @@ package projection import ( "context" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" old_handler "github.com/zitadel/zitadel/internal/eventstore/handler" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" @@ -11,15 +12,19 @@ import ( ) const ( - ExecutionTable = "projections.executions" - ExecutionIDCol = "id" - ExecutionCreationDateCol = "creation_date" - ExecutionChangeDateCol = "change_date" - ExecutionResourceOwnerCol = "resource_owner" - ExecutionInstanceIDCol = "instance_id" - ExecutionSequenceCol = "sequence" - ExecutionTargetsCol = "targets" - ExecutionIncludesCol = "includes" + ExecutionTable = "projections.executions1" + ExecutionIDCol = "id" + ExecutionCreationDateCol = "creation_date" + ExecutionChangeDateCol = "change_date" + ExecutionInstanceIDCol = "instance_id" + ExecutionSequenceCol = "sequence" + + ExecutionTargetSuffix = "targets" + ExecutionTargetExecutionIDCol = "execution_id" + ExecutionTargetInstanceIDCol = "instance_id" + ExecutionTargetPositionCol = "position" + ExecutionTargetTargetIDCol = "target_id" + ExecutionTargetIncludeCol = "include" ) type executionProjection struct{} @@ -33,19 +38,28 @@ func (*executionProjection) Name() string { } func (*executionProjection) Init() *old_handler.Check { - return handler.NewTableCheck( + return handler.NewMultiTableCheck( handler.NewTable([]*handler.InitColumn{ handler.NewColumn(ExecutionIDCol, handler.ColumnTypeText), handler.NewColumn(ExecutionCreationDateCol, handler.ColumnTypeTimestamp), handler.NewColumn(ExecutionChangeDateCol, handler.ColumnTypeTimestamp), - handler.NewColumn(ExecutionResourceOwnerCol, handler.ColumnTypeText), - handler.NewColumn(ExecutionInstanceIDCol, handler.ColumnTypeText), handler.NewColumn(ExecutionSequenceCol, handler.ColumnTypeInt64), - handler.NewColumn(ExecutionTargetsCol, handler.ColumnTypeTextArray, handler.Nullable()), - handler.NewColumn(ExecutionIncludesCol, handler.ColumnTypeTextArray, handler.Nullable()), + handler.NewColumn(ExecutionInstanceIDCol, handler.ColumnTypeText), }, handler.NewPrimaryKey(ExecutionInstanceIDCol, ExecutionIDCol), ), + handler.NewSuffixedTable([]*handler.InitColumn{ + handler.NewColumn(ExecutionTargetInstanceIDCol, handler.ColumnTypeText), + handler.NewColumn(ExecutionTargetExecutionIDCol, handler.ColumnTypeText), + handler.NewColumn(ExecutionTargetPositionCol, handler.ColumnTypeInt64), + handler.NewColumn(ExecutionTargetIncludeCol, handler.ColumnTypeText, handler.Nullable()), + handler.NewColumn(ExecutionTargetTargetIDCol, handler.ColumnTypeText, handler.Nullable()), + }, + handler.NewPrimaryKey(ExecutionTargetInstanceIDCol, ExecutionTargetExecutionIDCol, ExecutionTargetPositionCol), + ExecutionTargetSuffix, + handler.WithForeignKey(handler.NewForeignKey("execution", []string{ExecutionTargetInstanceIDCol, ExecutionTargetExecutionIDCol}, []string{ExecutionInstanceIDCol, ExecutionIDCol})), + handler.WithIndex(handler.NewIndex("execution", []string{ExecutionTargetInstanceIDCol, ExecutionTargetExecutionIDCol})), + ), ) } @@ -55,7 +69,7 @@ func (p *executionProjection) Reducers() []handler.AggregateReducer { Aggregate: exec.AggregateType, EventReducers: []handler.EventReducer{ { - Event: exec.SetEventType, + Event: exec.SetEventV2Type, Reduce: p.reduceExecutionSet, }, { @@ -77,21 +91,65 @@ func (p *executionProjection) Reducers() []handler.AggregateReducer { } func (p *executionProjection) reduceExecutionSet(event eventstore.Event) (*handler.Statement, error) { - e, err := assertEvent[*exec.SetEvent](event) + e, err := assertEvent[*exec.SetEventV2](event) if err != nil { return nil, err } - columns := []handler.Column{ - handler.NewCol(ExecutionInstanceIDCol, e.Aggregate().InstanceID), - handler.NewCol(ExecutionIDCol, e.Aggregate().ID), - handler.NewCol(ExecutionResourceOwnerCol, e.Aggregate().ResourceOwner), - handler.NewCol(ExecutionCreationDateCol, handler.OnlySetValueOnInsert(ExecutionTable, e.CreationDate())), - handler.NewCol(ExecutionChangeDateCol, e.CreationDate()), - handler.NewCol(ExecutionSequenceCol, e.Sequence()), - handler.NewCol(ExecutionTargetsCol, e.Targets), - handler.NewCol(ExecutionIncludesCol, e.Includes), + + stmts := []func(eventstore.Event) handler.Exec{ + handler.AddUpsertStatement( + []handler.Column{ + handler.NewCol(ExecutionInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCol(ExecutionIDCol, e.Aggregate().ID), + }, + []handler.Column{ + handler.NewCol(ExecutionInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCol(ExecutionIDCol, e.Aggregate().ID), + handler.NewCol(ExecutionCreationDateCol, handler.OnlySetValueOnInsert(ExecutionTable, e.CreationDate())), + handler.NewCol(ExecutionChangeDateCol, e.CreationDate()), + handler.NewCol(ExecutionSequenceCol, e.Sequence()), + }, + ), + // cleanup execution targets to re-insert them + handler.AddDeleteStatement( + []handler.Condition{ + handler.NewCond(ExecutionTargetInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(ExecutionTargetExecutionIDCol, e.Aggregate().ID), + }, + handler.WithTableSuffix(ExecutionTargetSuffix), + ), + } + + if len(e.Targets) > 0 { + for i, target := range e.Targets { + var targetStr, includeStr string + switch target.Type { + case domain.ExecutionTargetTypeTarget: + targetStr = target.Target + case domain.ExecutionTargetTypeInclude: + includeStr = target.Target + case domain.ExecutionTargetTypeUnspecified: + continue + default: + continue + } + + stmts = append(stmts, + handler.AddCreateStatement( + []handler.Column{ + handler.NewCol(ExecutionTargetInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCol(ExecutionTargetExecutionIDCol, e.Aggregate().ID), + handler.NewCol(ExecutionTargetPositionCol, i+1), + handler.NewCol(ExecutionTargetIncludeCol, includeStr), + handler.NewCol(ExecutionTargetTargetIDCol, targetStr), + }, + handler.WithTableSuffix(ExecutionTargetSuffix), + ), + ) + } } - return handler.NewUpsertStatement(e, columns[0:2], columns), nil + + return handler.NewMultiStatement(e, stmts...), nil } func (p *executionProjection) reduceExecutionRemoved(event eventstore.Event) (*handler.Statement, error) { @@ -99,8 +157,8 @@ func (p *executionProjection) reduceExecutionRemoved(event eventstore.Event) (*h if err != nil { return nil, err } - return handler.NewDeleteStatement( - e, + + return handler.NewDeleteStatement(e, []handler.Condition{ handler.NewCond(ExecutionInstanceIDCol, e.Aggregate().InstanceID), handler.NewCond(ExecutionIDCol, e.Aggregate().ID), diff --git a/internal/query/projection/execution_test.go b/internal/query/projection/execution_test.go index 537e8e0586e..27d6e892581 100644 --- a/internal/query/projection/execution_test.go +++ b/internal/query/projection/execution_test.go @@ -25,11 +25,11 @@ func TestExecutionProjection_reduces(t *testing.T) { args: args{ event: getEvent( testEvent( - exec.SetEventType, + exec.SetEventV2Type, exec.AggregateType, - []byte(`{"targets": ["target"], "includes": ["include"]}`), + []byte(`{"targets": [{"type":2,"target":"target"},{"type":1,"target":"include"}]}`), ), - eventstore.GenericEventMapper[exec.SetEvent], + eventstore.GenericEventMapper[exec.SetEventV2], ), }, reduce: (&executionProjection{}).reduceExecutionSet, @@ -39,16 +39,40 @@ func TestExecutionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.executions (instance_id, id, resource_owner, creation_date, change_date, sequence, targets, includes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, id) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, targets, includes) = (EXCLUDED.resource_owner, projections.executions.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.targets, EXCLUDED.includes)", + expectedStmt: "INSERT INTO projections.executions1 (instance_id, id, creation_date, change_date, sequence) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (instance_id, id) DO UPDATE SET (creation_date, change_date, sequence) = (projections.executions1.creation_date, EXCLUDED.change_date, EXCLUDED.sequence)", expectedArgs: []interface{}{ "instance-id", "agg-id", - "ro-id", anyArg{}, anyArg{}, uint64(15), - []string{"target"}, - []string{"include"}, + }, + }, + { + expectedStmt: "DELETE FROM projections.executions1_targets WHERE (instance_id = $1) AND (execution_id = $2)", + expectedArgs: []interface{}{ + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "INSERT INTO projections.executions1_targets (instance_id, execution_id, position, include, target_id) VALUES ($1, $2, $3, $4, $5)", + expectedArgs: []interface{}{ + "instance-id", + "agg-id", + 1, + "", + "target", + }, + }, + { + expectedStmt: "INSERT INTO projections.executions1_targets (instance_id, execution_id, position, include, target_id) VALUES ($1, $2, $3, $4, $5)", + expectedArgs: []interface{}{ + "instance-id", + "agg-id", + 2, + "include", + "", }, }, }, @@ -74,7 +98,7 @@ func TestExecutionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.executions WHERE (instance_id = $1) AND (id = $2)", + expectedStmt: "DELETE FROM projections.executions1 WHERE (instance_id = $1) AND (id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -103,7 +127,7 @@ func TestExecutionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.executions WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.executions1 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go index 0f8b2518a6a..de7b6135bd2 100644 --- a/internal/query/projection/projection.go +++ b/internal/query/projection/projection.go @@ -269,8 +269,8 @@ func newProjectionsList() { RestrictionsProjection, SystemFeatureProjection, InstanceFeatureProjection, - ExecutionProjection, TargetProjection, + ExecutionProjection, UserSchemaProjection, } } diff --git a/internal/query/projection/target.go b/internal/query/projection/target.go index af801002a96..7b7c46d2574 100644 --- a/internal/query/projection/target.go +++ b/internal/query/projection/target.go @@ -11,7 +11,7 @@ import ( ) const ( - TargetTable = "projections.targets" + TargetTable = "projections.targets1" TargetIDCol = "id" TargetCreationDateCol = "creation_date" TargetChangeDateCol = "change_date" @@ -20,9 +20,8 @@ const ( TargetSequenceCol = "sequence" TargetNameCol = "name" TargetTargetType = "target_type" - TargetURLCol = "url" + TargetEndpointCol = "endpoint" TargetTimeoutCol = "timeout" - TargetAsyncCol = "async" TargetInterruptOnErrorCol = "interrupt_on_error" ) @@ -47,10 +46,9 @@ func (*targetProjection) Init() *old_handler.Check { handler.NewColumn(TargetTargetType, handler.ColumnTypeEnum), handler.NewColumn(TargetSequenceCol, handler.ColumnTypeInt64), handler.NewColumn(TargetNameCol, handler.ColumnTypeText), - handler.NewColumn(TargetURLCol, handler.ColumnTypeText, handler.Default("")), - handler.NewColumn(TargetTimeoutCol, handler.ColumnTypeInt64, handler.Default(0)), - handler.NewColumn(TargetAsyncCol, handler.ColumnTypeBool, handler.Default(false)), - handler.NewColumn(TargetInterruptOnErrorCol, handler.ColumnTypeBool, handler.Default(false)), + handler.NewColumn(TargetEndpointCol, handler.ColumnTypeText), + handler.NewColumn(TargetTimeoutCol, handler.ColumnTypeInt64), + handler.NewColumn(TargetInterruptOnErrorCol, handler.ColumnTypeBool), }, handler.NewPrimaryKey(TargetInstanceIDCol, TargetIDCol), ), @@ -103,10 +101,9 @@ func (p *targetProjection) reduceTargetAdded(event eventstore.Event) (*handler.S handler.NewCol(TargetChangeDateCol, e.CreationDate()), handler.NewCol(TargetSequenceCol, e.Sequence()), handler.NewCol(TargetNameCol, e.Name), - handler.NewCol(TargetURLCol, e.URL), + handler.NewCol(TargetEndpointCol, e.Endpoint), handler.NewCol(TargetTargetType, e.TargetType), handler.NewCol(TargetTimeoutCol, e.Timeout), - handler.NewCol(TargetAsyncCol, e.Async), handler.NewCol(TargetInterruptOnErrorCol, e.InterruptOnError), }, ), nil @@ -128,15 +125,12 @@ func (p *targetProjection) reduceTargetChanged(event eventstore.Event) (*handler if e.TargetType != nil { values = append(values, handler.NewCol(TargetTargetType, *e.TargetType)) } - if e.URL != nil { - values = append(values, handler.NewCol(TargetURLCol, *e.URL)) + if e.Endpoint != nil { + values = append(values, handler.NewCol(TargetEndpointCol, *e.Endpoint)) } if e.Timeout != nil { values = append(values, handler.NewCol(TargetTimeoutCol, *e.Timeout)) } - if e.Async != nil { - values = append(values, handler.NewCol(TargetAsyncCol, *e.Async)) - } if e.InterruptOnError != nil { values = append(values, handler.NewCol(TargetInterruptOnErrorCol, *e.InterruptOnError)) } diff --git a/internal/query/projection/target_test.go b/internal/query/projection/target_test.go index 1ba0c9379dc..30067c6640c 100644 --- a/internal/query/projection/target_test.go +++ b/internal/query/projection/target_test.go @@ -29,7 +29,7 @@ func TestTargetProjection_reduces(t *testing.T) { testEvent( target.AddedEventType, target.AggregateType, - []byte(`{"name": "name", "targetType":0, "url":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`), + []byte(`{"name": "name", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`), ), eventstore.GenericEventMapper[target.AddedEvent], ), @@ -41,7 +41,7 @@ func TestTargetProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.targets (instance_id, resource_owner, id, creation_date, change_date, sequence, name, url, target_type, timeout, async, interrupt_on_error) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", + expectedStmt: "INSERT INTO projections.targets1 (instance_id, resource_owner, id, creation_date, change_date, sequence, name, endpoint, target_type, timeout, interrupt_on_error) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "instance-id", "ro-id", @@ -54,7 +54,6 @@ func TestTargetProjection_reduces(t *testing.T) { domain.TargetTypeWebhook, 3 * time.Second, true, - true, }, }, }, @@ -68,7 +67,7 @@ func TestTargetProjection_reduces(t *testing.T) { testEvent( target.ChangedEventType, target.AggregateType, - []byte(`{"name": "name2", "targetType":0, "url":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`), + []byte(`{"name": "name2", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`), ), eventstore.GenericEventMapper[target.ChangedEvent], ), @@ -80,7 +79,7 @@ func TestTargetProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.targets SET (change_date, sequence, resource_owner, name, target_type, url, timeout, async, interrupt_on_error) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (instance_id = $10) AND (id = $11)", + expectedStmt: "UPDATE projections.targets1 SET (change_date, sequence, resource_owner, name, target_type, endpoint, timeout, interrupt_on_error) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (instance_id = $9) AND (id = $10)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -90,7 +89,6 @@ func TestTargetProjection_reduces(t *testing.T) { "https://example.com", 3 * time.Second, true, - true, "instance-id", "agg-id", }, @@ -118,7 +116,7 @@ func TestTargetProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.targets WHERE (instance_id = $1) AND (id = $2)", + expectedStmt: "DELETE FROM projections.targets1 WHERE (instance_id = $1) AND (id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -147,7 +145,7 @@ func TestTargetProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.targets WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.targets1 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/search_query.go b/internal/query/search_query.go index b4944a8f2d6..868df84fe9c 100644 --- a/internal/query/search_query.go +++ b/internal/query/search_query.go @@ -478,31 +478,31 @@ func (q *SubSelect) comp() sq.Sqlizer { return selectQuery } -type ListQuery struct { +type listQuery struct { Column Column Data interface{} Compare ListComparison } -func NewListQuery(column Column, value interface{}, compare ListComparison) (*ListQuery, error) { +func NewListQuery(column Column, value interface{}, compare ListComparison) (*listQuery, error) { if compare < 0 || compare >= listCompareMax { return nil, ErrInvalidCompare } if column.isZero() { return nil, ErrMissingColumn } - return &ListQuery{ + return &listQuery{ Column: column, Data: value, Compare: compare, }, nil } -func (q *ListQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { +func (q *listQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { return query.Where(q.comp()) } -func (q *ListQuery) comp() sq.Sqlizer { +func (q *listQuery) comp() sq.Sqlizer { if q.Compare != ListIn { return nil } @@ -517,7 +517,7 @@ func (q *ListQuery) comp() sq.Sqlizer { return sq.Eq{q.Column.identifier(): q.Data} } -func (q *ListQuery) Col() Column { +func (q *listQuery) Col() Column { return q.Column } @@ -720,6 +720,25 @@ type listContains struct { args interface{} } +func NewListContains(c Column, value interface{}) (*listContains, error) { + return &listContains{ + col: c, + args: value, + }, nil +} + +func (q *listContains) Col() Column { + return q.col +} + +func (q *listContains) toQuery(query sq.SelectBuilder) sq.SelectBuilder { + return query.Where(q.comp()) +} + func (q *listContains) ToSql() (string, []interface{}, error) { return q.col.identifier() + " @> ? ", []interface{}{q.args}, nil } + +func (q *listContains) comp() sq.Sqlizer { + return q +} diff --git a/internal/query/search_query_test.go b/internal/query/search_query_test.go index c64b2c131c5..19c1dbcf41b 100644 --- a/internal/query/search_query_test.go +++ b/internal/query/search_query_test.go @@ -521,7 +521,7 @@ func TestNewListQuery(t *testing.T) { tests := []struct { name string args args - want *ListQuery + want *listQuery wantErr func(error) bool }{ { @@ -575,7 +575,7 @@ func TestNewListQuery(t *testing.T) { data: []interface{}{"hurst"}, compare: ListIn, }, - want: &ListQuery{ + want: &listQuery{ Column: testCol, Data: []interface{}{"hurst"}, Compare: ListIn, @@ -588,7 +588,7 @@ func TestNewListQuery(t *testing.T) { data: &SubSelect{Column: testCol, Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}}}, compare: ListIn, }, - want: &ListQuery{ + want: &listQuery{ Column: testCol, Data: &SubSelect{Column: testCol, Queries: []SearchQuery{&textQuery{testCol, "horst1", TextEquals}}}, Compare: ListIn, @@ -751,7 +751,7 @@ func TestListQuery_comp(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := &ListQuery{ + s := &listQuery{ Column: tt.fields.Column, Data: tt.fields.Data, Compare: tt.fields.Compare, diff --git a/internal/query/target.go b/internal/query/target.go index ecb60dca792..c5d8f893ade 100644 --- a/internal/query/target.go +++ b/internal/query/target.go @@ -52,17 +52,13 @@ var ( table: targetTable, } TargetColumnURL = Column{ - name: projection.TargetURLCol, + name: projection.TargetEndpointCol, table: targetTable, } TargetColumnTimeout = Column{ name: projection.TargetTimeoutCol, table: targetTable, } - TargetColumnAsync = Column{ - name: projection.TargetAsyncCol, - table: targetTable, - } TargetColumnInterruptOnError = Column{ name: projection.TargetInterruptOnErrorCol, table: targetTable, @@ -84,9 +80,8 @@ type Target struct { Name string TargetType domain.TargetType - URL string + Endpoint string Timeout time.Duration - Async bool InterruptOnError bool } @@ -138,7 +133,6 @@ func prepareTargetsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil TargetColumnTargetType.identifier(), TargetColumnTimeout.identifier(), TargetColumnURL.identifier(), - TargetColumnAsync.identifier(), TargetColumnInterruptOnError.identifier(), countColumn.identifier(), ).From(targetTable.identifier()). @@ -156,8 +150,7 @@ func prepareTargetsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil &target.Name, &target.TargetType, &target.Timeout, - &target.URL, - &target.Async, + &target.Endpoint, &target.InterruptOnError, &count, ) @@ -190,7 +183,6 @@ func prepareTargetQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuild TargetColumnTargetType.identifier(), TargetColumnTimeout.identifier(), TargetColumnURL.identifier(), - TargetColumnAsync.identifier(), TargetColumnInterruptOnError.identifier(), ).From(targetTable.identifier()). PlaceholderFormat(sq.Dollar), @@ -204,8 +196,7 @@ func prepareTargetQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuild &target.Name, &target.TargetType, &target.Timeout, - &target.URL, - &target.Async, + &target.Endpoint, &target.InterruptOnError, ) if err != nil { diff --git a/internal/query/target_test.go b/internal/query/target_test.go index d1003fc8d85..61a61e9e45f 100644 --- a/internal/query/target_test.go +++ b/internal/query/target_test.go @@ -14,18 +14,17 @@ import ( ) var ( - prepareTargetsStmt = `SELECT projections.targets.id,` + - ` projections.targets.change_date,` + - ` projections.targets.resource_owner,` + - ` projections.targets.sequence,` + - ` projections.targets.name,` + - ` projections.targets.target_type,` + - ` projections.targets.timeout,` + - ` projections.targets.url,` + - ` projections.targets.async,` + - ` projections.targets.interrupt_on_error,` + + prepareTargetsStmt = `SELECT projections.targets1.id,` + + ` projections.targets1.change_date,` + + ` projections.targets1.resource_owner,` + + ` projections.targets1.sequence,` + + ` projections.targets1.name,` + + ` projections.targets1.target_type,` + + ` projections.targets1.timeout,` + + ` projections.targets1.endpoint,` + + ` projections.targets1.interrupt_on_error,` + ` COUNT(*) OVER ()` + - ` FROM projections.targets` + ` FROM projections.targets1` prepareTargetsCols = []string{ "id", "change_date", @@ -34,23 +33,21 @@ var ( "name", "target_type", "timeout", - "url", - "async", + "endpoint", "interrupt_on_error", "count", } - prepareTargetStmt = `SELECT projections.targets.id,` + - ` projections.targets.change_date,` + - ` projections.targets.resource_owner,` + - ` projections.targets.sequence,` + - ` projections.targets.name,` + - ` projections.targets.target_type,` + - ` projections.targets.timeout,` + - ` projections.targets.url,` + - ` projections.targets.async,` + - ` projections.targets.interrupt_on_error` + - ` FROM projections.targets` + prepareTargetStmt = `SELECT projections.targets1.id,` + + ` projections.targets1.change_date,` + + ` projections.targets1.resource_owner,` + + ` projections.targets1.sequence,` + + ` projections.targets1.name,` + + ` projections.targets1.target_type,` + + ` projections.targets1.timeout,` + + ` projections.targets1.endpoint,` + + ` projections.targets1.interrupt_on_error` + + ` FROM projections.targets1` prepareTargetCols = []string{ "id", "change_date", @@ -59,8 +56,7 @@ var ( "name", "target_type", "timeout", - "url", - "async", + "endpoint", "interrupt_on_error", } ) @@ -106,7 +102,6 @@ func Test_TargetPrepares(t *testing.T) { 1 * time.Second, "https://example.com", true, - true, }, }, ), @@ -126,8 +121,7 @@ func Test_TargetPrepares(t *testing.T) { Name: "target-name", TargetType: domain.TargetTypeWebhook, Timeout: 1 * time.Second, - URL: "https://example.com", - Async: true, + Endpoint: "https://example.com", InterruptOnError: true, }, }, @@ -151,7 +145,6 @@ func Test_TargetPrepares(t *testing.T) { 1 * time.Second, "https://example.com", true, - false, }, { "id-2", @@ -163,14 +156,24 @@ func Test_TargetPrepares(t *testing.T) { 1 * time.Second, "https://example.com", false, - true, + }, + { + "id-3", + testNow, + "ro", + uint64(20211110), + "target-name3", + domain.TargetTypeAsync, + 1 * time.Second, + "https://example.com", + false, }, }, ), }, object: &Targets{ SearchResponse: SearchResponse{ - Count: 2, + Count: 3, }, Targets: []*Target{ { @@ -183,9 +186,8 @@ func Test_TargetPrepares(t *testing.T) { Name: "target-name1", TargetType: domain.TargetTypeWebhook, Timeout: 1 * time.Second, - URL: "https://example.com", - Async: true, - InterruptOnError: false, + Endpoint: "https://example.com", + InterruptOnError: true, }, { ID: "id-2", @@ -197,9 +199,21 @@ func Test_TargetPrepares(t *testing.T) { Name: "target-name2", TargetType: domain.TargetTypeWebhook, Timeout: 1 * time.Second, - URL: "https://example.com", - Async: false, - InterruptOnError: true, + Endpoint: "https://example.com", + InterruptOnError: false, + }, + { + ID: "id-3", + ObjectDetails: domain.ObjectDetails{ + EventDate: testNow, + ResourceOwner: "ro", + Sequence: 20211110, + }, + Name: "target-name3", + TargetType: domain.TargetTypeAsync, + Timeout: 1 * time.Second, + Endpoint: "https://example.com", + InterruptOnError: false, }, }, }, @@ -256,7 +270,6 @@ func Test_TargetPrepares(t *testing.T) { 1 * time.Second, "https://example.com", true, - false, }, ), }, @@ -270,9 +283,8 @@ func Test_TargetPrepares(t *testing.T) { Name: "target-name", TargetType: domain.TargetTypeWebhook, Timeout: 1 * time.Second, - URL: "https://example.com", - Async: true, - InterruptOnError: false, + Endpoint: "https://example.com", + InterruptOnError: true, }, }, { diff --git a/internal/query/targets_by_execution_id.sql b/internal/query/targets_by_execution_id.sql new file mode 100644 index 00000000000..6b564104e5d --- /dev/null +++ b/internal/query/targets_by_execution_id.sql @@ -0,0 +1,40 @@ +WITH RECURSIVE + dissolved_execution_targets(execution_id, instance_id, position, "include", "target_id") + AS (SELECT execution_id + , instance_id + , ARRAY [position] + , "include" + , "target_id" + FROM matched_targets_and_includes + UNION ALL + SELECT e.execution_id + , p.instance_id + , e.position || p.position + , p."include" + , p."target_id" + FROM dissolved_execution_targets e + JOIN projections.executions1_targets p + ON e.instance_id = p.instance_id + AND e.include IS NOT NULL + AND e.include = p.execution_id), + matched AS (SELECT * + FROM projections.executions1 + WHERE instance_id = $1 + AND id = ANY($2) + ORDER BY id DESC + LIMIT 1), + matched_targets_and_includes AS (SELECT pos.* + FROM matched m + JOIN + projections.executions1_targets pos + ON m.id = pos.execution_id + AND m.instance_id = pos.instance_id + ORDER BY execution_id, + position) +select e.execution_id, e.instance_id, e.target_id, t.target_type, t.endpoint, t.timeout, t.interrupt_on_error +FROM dissolved_execution_targets e + JOIN projections.targets1 t + ON e.instance_id = t.instance_id + AND e.target_id = t.id +WHERE "include" = '' +ORDER BY position DESC; diff --git a/internal/query/targets_by_execution_ids.sql b/internal/query/targets_by_execution_ids.sql new file mode 100644 index 00000000000..c1361d9320b --- /dev/null +++ b/internal/query/targets_by_execution_ids.sql @@ -0,0 +1,47 @@ +WITH RECURSIVE + dissolved_execution_targets(execution_id, instance_id, position, "include", "target_id") + AS (SELECT execution_id + , instance_id + , ARRAY [position] + , "include" + , "target_id" + FROM matched_targets_and_includes + UNION ALL + SELECT e.execution_id + , p.instance_id + , e.position || p.position + , p."include" + , p."target_id" + FROM dissolved_execution_targets e + JOIN projections.executions1_targets p + ON e.instance_id = p.instance_id + AND e.include IS NOT NULL + AND e.include = p.execution_id), + matched AS ((SELECT * + FROM projections.executions1 + WHERE instance_id = $1 + AND id = ANY($2) + ORDER BY id DESC + LIMIT 1) + UNION ALL + (SELECT * + FROM projections.executions1 + WHERE instance_id = $1 + AND id = ANY($3) + ORDER BY id DESC + LIMIT 1)), + matched_targets_and_includes AS (SELECT pos.* + FROM matched m + JOIN + projections.executions1_targets pos + ON m.id = pos.execution_id + AND m.instance_id = pos.instance_id + ORDER BY execution_id, + position) +select e.execution_id, e.instance_id, e.target_id, t.target_type, t.endpoint, t.timeout, t.interrupt_on_error +FROM dissolved_execution_targets e + JOIN projections.targets1 t + ON e.instance_id = t.instance_id + AND e.target_id = t.id +WHERE "include" = '' +ORDER BY position DESC; diff --git a/internal/repository/execution/aggregate.go b/internal/repository/execution/aggregate.go index 973bb178541..eea14f8468d 100644 --- a/internal/repository/execution/aggregate.go +++ b/internal/repository/execution/aggregate.go @@ -23,7 +23,10 @@ func NewAggregate(aggrID, instanceID string) *eventstore.Aggregate { } func ID(executionType domain.ExecutionType, value string) string { - return strings.Join([]string{executionType.String(), value}, ".") + if strings.HasPrefix(value, "/") { + return strings.Join([]string{executionType.String(), value}, "") + } + return strings.Join([]string{executionType.String(), value}, "/") } func IDAll(executionType domain.ExecutionType) string { diff --git a/internal/repository/execution/eventstore.go b/internal/repository/execution/eventstore.go index bf4e7bc79f0..2d930002178 100644 --- a/internal/repository/execution/eventstore.go +++ b/internal/repository/execution/eventstore.go @@ -4,5 +4,6 @@ import "github.com/zitadel/zitadel/internal/eventstore" func init() { eventstore.RegisterFilterEventMapper(AggregateType, SetEventType, eventstore.GenericEventMapper[SetEvent]) + eventstore.RegisterFilterEventMapper(AggregateType, SetEventV2Type, eventstore.GenericEventMapper[SetEventV2]) eventstore.RegisterFilterEventMapper(AggregateType, RemovedEventType, eventstore.GenericEventMapper[RemovedEvent]) } diff --git a/internal/repository/execution/execution.go b/internal/repository/execution/execution.go index 4c1a85a6b62..a6851b44954 100644 --- a/internal/repository/execution/execution.go +++ b/internal/repository/execution/execution.go @@ -3,12 +3,14 @@ package execution import ( "context" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" ) const ( eventTypePrefix eventstore.EventType = "execution." SetEventType = eventTypePrefix + "set" + SetEventV2Type = eventTypePrefix + "v2.set" RemovedEventType = eventTypePrefix + "removed" ) @@ -31,18 +33,39 @@ func (e *SetEvent) UniqueConstraints() []*eventstore.UniqueConstraint { return nil } -func NewSetEvent( +type SetEventV2 struct { + *eventstore.BaseEvent `json:"-"` + + Targets []*Target `json:"targets"` +} + +func (e *SetEventV2) SetBaseEvent(b *eventstore.BaseEvent) { + e.BaseEvent = b +} + +func (e *SetEventV2) Payload() any { + return e +} + +func (e *SetEventV2) UniqueConstraints() []*eventstore.UniqueConstraint { + return nil +} + +type Target struct { + Type domain.ExecutionTargetType `json:"type"` + Target string `json:"target"` +} + +func NewSetEventV2( ctx context.Context, aggregate *eventstore.Aggregate, - targets []string, - includes []string, -) *SetEvent { - return &SetEvent{ + targets []*Target, +) *SetEventV2 { + return &SetEventV2{ BaseEvent: eventstore.NewBaseEventForPush( - ctx, aggregate, SetEventType, + ctx, aggregate, SetEventV2Type, ), - Targets: targets, - Includes: includes, + Targets: targets, } } diff --git a/internal/repository/target/target.go b/internal/repository/target/target.go index 2d50857cba8..85e3ae70230 100644 --- a/internal/repository/target/target.go +++ b/internal/repository/target/target.go @@ -20,9 +20,8 @@ type AddedEvent struct { Name string `json:"name"` TargetType domain.TargetType `json:"targetType"` - URL string `json:"url"` + Endpoint string `json:"endpoint"` Timeout time.Duration `json:"timeout"` - Async bool `json:"async"` InterruptOnError bool `json:"interruptOnError"` } @@ -43,16 +42,15 @@ func NewAddedEvent( aggregate *eventstore.Aggregate, name string, targetType domain.TargetType, - url string, + endpoint string, timeout time.Duration, - async bool, interruptOnError bool, ) *AddedEvent { return &AddedEvent{ *eventstore.NewBaseEventForPush( ctx, aggregate, AddedEventType, ), - name, targetType, url, timeout, async, interruptOnError} + name, targetType, endpoint, timeout, interruptOnError} } type ChangedEvent struct { @@ -60,9 +58,8 @@ type ChangedEvent struct { Name *string `json:"name,omitempty"` TargetType *domain.TargetType `json:"targetType,omitempty"` - URL *string `json:"url,omitempty"` + Endpoint *string `json:"endpoint,omitempty"` Timeout *time.Duration `json:"timeout,omitempty"` - Async *bool `json:"async,omitempty"` InterruptOnError *bool `json:"interruptOnError,omitempty"` oldName string @@ -119,9 +116,9 @@ func ChangeTargetType(targetType domain.TargetType) func(event *ChangedEvent) { } } -func ChangeURL(url string) func(event *ChangedEvent) { +func ChangeEndpoint(endpoint string) func(event *ChangedEvent) { return func(e *ChangedEvent) { - e.URL = &url + e.Endpoint = &endpoint } } @@ -131,12 +128,6 @@ func ChangeTimeout(timeout time.Duration) func(event *ChangedEvent) { } } -func ChangeAsync(async bool) func(event *ChangedEvent) { - return func(e *ChangedEvent) { - e.Async = &async - } -} - func ChangeInterruptOnError(interruptOnError bool) func(event *ChangedEvent) { return func(e *ChangedEvent) { e.InterruptOnError = &interruptOnError diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index aa6223fd051..b1ba504c26d 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -484,6 +484,7 @@ Errors: NotActive: Действието не е активно NotInactive: Действието не е неактивно MaxAllowed: Не са разрешени допълнителни активни действия + NotEnabled: Функцията „Действие“ не е активирана Flow: FlowTypeMissing: Липсва FlowType Empty: Потокът вече е празен diff --git a/internal/static/i18n/cs.yaml b/internal/static/i18n/cs.yaml index cc35a3165ab..ab303086b5b 100644 --- a/internal/static/i18n/cs.yaml +++ b/internal/static/i18n/cs.yaml @@ -470,6 +470,7 @@ Errors: NotActive: Akce není aktivní NotInactive: Akce není neaktivní MaxAllowed: Není dovoleno více aktivních akcí + NotEnabled: Funkce "Akce" není povolena Flow: FlowTypeMissing: Chybí typ toku Empty: Tok je již prázdný diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index c36ea20c46d..a5cfd521cdb 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -470,6 +470,7 @@ Errors: NotActive: Action ist nicht aktiv NotInactive: Action ist nicht inaktiv MaxAllowed: Keine weitere aktiven Actions mehr erlaubt + NotEnabled: Function "Action" ist nicht aktiviert Flow: FlowTypeMissing: FlowType fehlt Empty: Flow ist bereits leer diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index bec1ac2a72a..fc1ef19ac06 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -470,6 +470,7 @@ Errors: NotActive: Action is not active NotInactive: Action is not inactive MaxAllowed: No additional active Actions allowed + NotEnabled: Feature "Action" is not enabled Flow: FlowTypeMissing: FlowType missing Empty: Flow is already empty diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index 89eca6f58ea..fff4bf468d1 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -470,6 +470,7 @@ Errors: NotActive: La acción no está activa NotInactive: La acción no está inactiva MaxAllowed: No hay acciones adicionales activas permitidas + NotEnabled: La función "Acción" no está habilitada Flow: FlowTypeMissing: Falta el tipo de flujo Empty: El flujo ya está vacío diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 308dea53af7..500d3f32251 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -470,6 +470,7 @@ Errors: NotActive: L'action n'est pas active NotInactive: L'action n'est pas inactive MaxAllowed: Aucune action active supplémentaire n'est autorisée + NotEnabled: La fonctionnalité "Action" n'est pas activée Flow: FlowTypeMissing: FlowType missing Empty: Le flux est déjà vide diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 9537a5b7900..ce1b04b9827 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -470,6 +470,7 @@ Errors: NotActive: L'azione non è attiva NotInactive: L'azione non è inattiva MaxAllowed: Non sono permesse altre azioni attive + NotEnabled: La funzione "Azione" non è abilitata Flow: FlowTypeMissing: FlowType mancante Empty: Flow è già vuoto diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index 130e89d55f8..2e980e49255 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -459,6 +459,7 @@ Errors: NotActive: アクションはアクティブではありません NotInactive: アクションは非アクティブではありません MaxAllowed: 追加のアクティブアクションは許可されていません + NotEnabled: 機能「アクション」が有効になっていません Flow: FlowTypeMissing: フロータイプがありません Empty: フローはすでに空です diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml index 293afdd8436..eceb252c710 100644 --- a/internal/static/i18n/mk.yaml +++ b/internal/static/i18n/mk.yaml @@ -469,6 +469,7 @@ Errors: NotActive: Акцијата не е активна NotInactive: Акцијата не е неактивна MaxAllowed: Не се дозволени дополнителни активни акции + NotEnabled: Функцијата „Акција“ не е овозможена Flow: FlowTypeMissing: FlowType не е наведен Empty: Flow е веќе празен diff --git a/internal/static/i18n/nl.yaml b/internal/static/i18n/nl.yaml index d0afcfc0724..a03d9e177a9 100644 --- a/internal/static/i18n/nl.yaml +++ b/internal/static/i18n/nl.yaml @@ -469,6 +469,7 @@ Errors: NotActive: Actie is niet actief NotInactive: Actie is niet inactief MaxAllowed: Geen extra actieve acties toegestaan + NotEnabled: Functie "Actie" is niet ingeschakeld Flow: FlowTypeMissing: FlowType ontbreekt Empty: Flow is al leeg diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index 381ab9f6ad1..7d54595a2f7 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -470,6 +470,7 @@ Errors: NotActive: Działanie nie jest aktywne NotInactive: Działanie nie jest dezaktywowane MaxAllowed: Nie dopuszcza się dodatkowych aktywnych działań. + NotEnabled: Funkcja „Akcja” nie jest włączona Flow: FlowTypeMissing: Typ przepływu brakuje Empty: Przepływ jest już pusty diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml index 9f0d94d9c40..4e160363951 100644 --- a/internal/static/i18n/pt.yaml +++ b/internal/static/i18n/pt.yaml @@ -469,6 +469,7 @@ Errors: NotActive: A ação não está ativa NotInactive: A ação não está inativa MaxAllowed: Não são permitidas ações adicionais ativas + NotEnabled: O recurso "Ação" não está ativado Flow: FlowTypeMissing: O tipo de fluxo está faltando Empty: O fluxo já está vazio diff --git a/internal/static/i18n/ru.yaml b/internal/static/i18n/ru.yaml index 172f2bee017..5b3e46e6bd3 100644 --- a/internal/static/i18n/ru.yaml +++ b/internal/static/i18n/ru.yaml @@ -463,6 +463,7 @@ Errors: NotActive: Действие не активно NotInactive: Действие не является неактивным MaxAllowed: Дополнительные активные действия запрещены + NotEnabled: Функция «Действие» не включена Flow: FlowTypeMissing: Тип процесса отсутствует Empty: Процесс уже пуст diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index 171807a1a80..9b6b30b14f3 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -470,6 +470,7 @@ Errors: NotActive: 动作不是启用状态 NotInactive: 动作不是停用状态 MaxAllowed: 不允许额外的动作 + NotEnabled: 未启用“操作”功能 Flow: FlowTypeMissing: 缺少身份认证流程类型 Empty: 身份认证流程为空 diff --git a/proto/zitadel/action/v3alpha/action_service.proto b/proto/zitadel/action/v3alpha/action_service.proto index 4c372763266..da174b45d0b 100644 --- a/proto/zitadel/action/v3alpha/action_service.proto +++ b/proto/zitadel/action/v3alpha/action_service.proto @@ -423,22 +423,26 @@ message CreateTargetRequest { option (validate.required) = true; SetRESTWebhook rest_webhook = 2; - SetRESTRequestResponse rest_request_response = 3; + SetRESTCall rest_call = 3; + SetRESTAsync rest_async = 4; } // Timeout defines the duration until ZITADEL cancels the execution. - google.protobuf.Duration timeout = 4 [ + google.protobuf.Duration timeout = 5 [ (validate.rules).duration = {gt: {seconds: 0}, required: true}, (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"10s\""; } ]; - oneof execution_type { - // Set the execution to run asynchronously. - bool is_async = 5; - // Define if any error stops the whole execution. By default the process continues as normal. - bool interrupt_on_error = 6; - } + string endpoint = 6 [ + (validate.rules).string = {min_len: 1, max_len: 1000, uri: true}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1, + max_length: 1000, + example: "\"https://example.com/hooks/ip_check\""; + } + ]; } message CreateTargetResponse { @@ -472,21 +476,24 @@ message UpdateTargetRequest { // or its target URL. oneof target_type { SetRESTWebhook rest_webhook = 3; - SetRESTRequestResponse rest_request_response = 4; + SetRESTCall rest_call = 4; + SetRESTAsync rest_async = 5; } // Optionally change the timeout, which defines the duration until ZITADEL cancels the execution. - optional google.protobuf.Duration timeout = 5 [ + optional google.protobuf.Duration timeout = 6 [ (validate.rules).duration = {gt: {seconds: 0}}, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"10s\""; } ]; - oneof execution_type { - // Set the execution to run asynchronously. - bool is_async = 6; - // Define if any error stops the whole execution. By default the process continues as normal. - bool interrupt_on_error = 7; - } + + optional string endpoint = 7 [ + (validate.rules).string = {max_len: 1000, uri: true}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + max_length: 1000, + example: "\"https://example.com/hooks/ip_check\""; + } + ]; } message UpdateTargetResponse { @@ -554,10 +561,8 @@ message GetTargetByIDResponse { message SetExecutionRequest { // Defines the condition type and content of the condition for execution. Condition condition = 1; - // Defines the execution targets which are defined as a different resource, which are called in the defined conditions. - repeated string targets = 2; - // Defines other executions as included with the same condition-types. - repeated string includes = 3; + // Ordered list of targets/includes called during the execution. + repeated zitadel.action.v3alpha.ExecutionTargetType targets = 2; } message SetExecutionResponse { diff --git a/proto/zitadel/action/v3alpha/execution.proto b/proto/zitadel/action/v3alpha/execution.proto index c8b85f50a03..6f244711854 100644 --- a/proto/zitadel/action/v3alpha/execution.proto +++ b/proto/zitadel/action/v3alpha/execution.proto @@ -14,17 +14,20 @@ import "zitadel/protoc_gen_zitadel/v2/options.proto"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action"; message Execution { - string execution_id = 1 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"request.zitadel.session.v2beta.SessionService\""; - } - ]; + Condition Condition = 1; // Details provide some base information (such as the last change date) of the target. zitadel.object.v2beta.Details details = 2; - // Targets which are called in the defined conditions. - repeated string targets = 3; - // Included executions with the same condition-types. - repeated string includes = 4; + // List of ordered list of targets/includes called during the execution. + repeated ExecutionTargetType targets = 3; +} + +message ExecutionTargetType { + oneof type { + // Unique identifier of existing target to call. + string target = 1; + // Unique identifier of existing execution to include targets of. + Condition include = 2; + } } message Condition { @@ -37,7 +40,7 @@ message Condition { // Condition-type to execute on response if a request on the defined API point happens. ResponseExecution response = 2; // Condition-type to execute if function is used, replaces actions v1. - string function = 3; + FunctionExecution function = 3; // Condition-type to execute if an event is created in the system. EventExecution event = 4; } @@ -95,6 +98,11 @@ message ResponseExecution { } } +// Executed on the specified function +message FunctionExecution { + string name = 1 [(validate.rules).string = {min_len: 1, max_len: 1000}]; +} + message EventExecution{ // Condition for the event execution, only one possible. oneof condition{ diff --git a/proto/zitadel/action/v3alpha/query.proto b/proto/zitadel/action/v3alpha/query.proto index 26093305bcc..a32caacfbaa 100644 --- a/proto/zitadel/action/v3alpha/query.proto +++ b/proto/zitadel/action/v3alpha/query.proto @@ -43,7 +43,7 @@ message TargetQuery { message IncludeQuery { // Defines the include to query for. - string include = 1 [ + Condition include = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "the id of the include" example: "\"request.zitadel.session.v2beta.SessionService\""; diff --git a/proto/zitadel/action/v3alpha/target.proto b/proto/zitadel/action/v3alpha/target.proto index a034c58acee..92dda32bbb7 100644 --- a/proto/zitadel/action/v3alpha/target.proto +++ b/proto/zitadel/action/v3alpha/target.proto @@ -13,30 +13,21 @@ import "zitadel/protoc_gen_zitadel/v2/options.proto"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/action/v3alpha;action"; +// Wait for response but response body is ignored, status is checked, call is sent as post. message SetRESTWebhook { - string url = 1 [ - (validate.rules).string = {min_len: 1, max_len: 1000, uri: true}, - (google.api.field_behavior) = REQUIRED, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - min_length: 1, - max_length: 1000, - example: "\"https://example.com/hooks/ip_check\""; - } - ]; + // Define if any error stops the whole execution. By default the process continues as normal. + bool interrupt_on_error = 1; } -message SetRESTRequestResponse { - string url = 1 [ - (validate.rules).string = {min_len: 1, max_len: 1000, uri: true}, - (google.api.field_behavior) = REQUIRED, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - min_length: 1, - max_length: 1000, - example: "\"https://example.com/hooks/ip_check\""; - } - ]; +// Wait for response and response body is used, status is checked, call is sent as post. +message SetRESTCall { + // Define if any error stops the whole execution. By default the process continues as normal. + bool interrupt_on_error = 1; } +// Call is executed in parallel to others, ZITADEL does not wait until the call is finished. The state is ignored, call is sent as post. +message SetRESTAsync {} + message Target { // ID is the read-only unique identifier of the target. string target_id = 1 [ @@ -56,18 +47,19 @@ message Target { // Defines the target type and how the response of the target is treated. oneof target_type { SetRESTWebhook rest_webhook = 4; - SetRESTRequestResponse rest_request_response = 5; + SetRESTCall rest_call = 5; + SetRESTAsync rest_async = 6; } // Timeout defines the duration until ZITADEL cancels the execution. - google.protobuf.Duration timeout = 6 [ + google.protobuf.Duration timeout = 7 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"10s\""; } ]; - oneof execution_type { - // Set the execution to run asynchronously. - bool is_async = 7; - // Define if any error stops the whole execution. By default the process continues as normal. - bool interrupt_on_error = 8; - } + + string endpoint = 8 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"https://example.com/hooks/ip_check\""; + } + ]; } \ No newline at end of file From 016e5e5da1680f776aac07576969157658513dd5 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 6 May 2024 15:15:35 +0200 Subject: [PATCH 5/7] fix(console): password reset hidden texts (#7915) fix(console): password reset hidden --- .../policies/login-policy/login-policy.component.html | 4 ++-- console/src/assets/i18n/bg.json | 6 +++--- console/src/assets/i18n/cs.json | 6 +++--- console/src/assets/i18n/de.json | 6 +++--- console/src/assets/i18n/en.json | 6 +++--- console/src/assets/i18n/es.json | 6 +++--- console/src/assets/i18n/fr.json | 6 +++--- console/src/assets/i18n/it.json | 6 +++--- console/src/assets/i18n/ja.json | 6 +++--- console/src/assets/i18n/mk.json | 6 +++--- console/src/assets/i18n/nl.json | 6 +++--- console/src/assets/i18n/pl.json | 6 +++--- console/src/assets/i18n/pt.json | 6 +++--- console/src/assets/i18n/ru.json | 6 +++--- console/src/assets/i18n/zh.json | 6 +++--- 15 files changed, 44 insertions(+), 44 deletions(-) diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html index 2171d0d3631..6a2da2bd383 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.html +++ b/console/src/app/modules/policies/login-policy/login-policy.component.html @@ -297,7 +297,7 @@

{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.TITLE' | translate }}

class="login-policy-toggle" color="primary" ngDefaultControl - matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.PASSWORD_RESET_ALLOWED.DESCRIPTION' | translate }}" + matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.DESCRIPTION' | translate }}" [(ngModel)]="loginData.hidePasswordReset" [disabled]=" ([ @@ -311,7 +311,7 @@

{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.TITLE' | translate }}

| async) === false " > - {{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.PASSWORD_RESET_ALLOWED.TITLE' | translate }} + {{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.TITLE' | translate }}