From 7ccc46a571cd59269830b00f17e6dc127274e842 Mon Sep 17 00:00:00 2001 From: Tyler Britten <1933680+tybritten@users.noreply.github.com> Date: Fri, 20 Nov 2020 08:46:46 -0500 Subject: [PATCH 001/630] limit migrations --- .../contacts/migrations/0110_populate_last_seen_on.py | 2 +- .../migrations/0111_populate_last_seen_on_2.py | 2 +- temba/contacts/migrations/0113_contact_status.py | 11 +---------- .../migrations/0114_populate_contact_status.py | 4 ++-- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/temba/contacts/migrations/0110_populate_last_seen_on.py b/temba/contacts/migrations/0110_populate_last_seen_on.py index 524c2f7c885..b953bc3ba8b 100644 --- a/temba/contacts/migrations/0110_populate_last_seen_on.py +++ b/temba/contacts/migrations/0110_populate_last_seen_on.py @@ -116,4 +116,4 @@ class Migration(migrations.Migration): ("contacts", "0109_contact_last_seen_on"), ] - operations = [migrations.RunPython(populate_last_seen_on, reverse)] + operations = [] diff --git a/temba/contacts/migrations/0111_populate_last_seen_on_2.py b/temba/contacts/migrations/0111_populate_last_seen_on_2.py index 14a82a25f99..5b8419d86eb 100644 --- a/temba/contacts/migrations/0111_populate_last_seen_on_2.py +++ b/temba/contacts/migrations/0111_populate_last_seen_on_2.py @@ -120,4 +120,4 @@ class Migration(migrations.Migration): ("contacts", "0110_populate_last_seen_on"), ] - operations = [migrations.RunPython(populate_last_seen_on, reverse)] + operations = [] diff --git a/temba/contacts/migrations/0113_contact_status.py b/temba/contacts/migrations/0113_contact_status.py index 35cb9a34b17..af08600771c 100644 --- a/temba/contacts/migrations/0113_contact_status.py +++ b/temba/contacts/migrations/0113_contact_status.py @@ -11,15 +11,6 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="contact", - name="status", - field=models.CharField( - choices=[("A", "Active"), ("B", "Blocked"), ("S", "Stopped"), ("V", "Archived")], - max_length=1, - null=True, - ), - ), - migrations.AlterField( model_name="contact", name="status", field=models.CharField( @@ -28,5 +19,5 @@ class Migration(migrations.Migration): max_length=1, null=True, ), - ), + ) ] diff --git a/temba/contacts/migrations/0114_populate_contact_status.py b/temba/contacts/migrations/0114_populate_contact_status.py index 157845a8c48..6c2f65924ac 100644 --- a/temba/contacts/migrations/0114_populate_contact_status.py +++ b/temba/contacts/migrations/0114_populate_contact_status.py @@ -63,5 +63,5 @@ class Migration(migrations.Migration): dependencies = [ ("contacts", "0113_contact_status"), ] - - operations = [migrations.RunPython(populate_contact_status, reverse)] + sql = "UPDATE contacts_contact SET status = CASE WHEN is_stopped = true THEN 'S' WHEN is_stopped = false AND is_blocked = true THEN 'B' END" + operations = [migrations.RunSQL(sql)] From 23f6322de36b4167504115581d9e048ecd751c88 Mon Sep 17 00:00:00 2001 From: Tyler Britten <1933680+tybritten@users.noreply.github.com> Date: Fri, 20 Nov 2020 14:20:23 -0500 Subject: [PATCH 002/630] skip updating contact status --- temba/contacts/migrations/0114_populate_contact_status.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/temba/contacts/migrations/0114_populate_contact_status.py b/temba/contacts/migrations/0114_populate_contact_status.py index 6c2f65924ac..561ed95c410 100644 --- a/temba/contacts/migrations/0114_populate_contact_status.py +++ b/temba/contacts/migrations/0114_populate_contact_status.py @@ -63,5 +63,6 @@ class Migration(migrations.Migration): dependencies = [ ("contacts", "0113_contact_status"), ] - sql = "UPDATE contacts_contact SET status = CASE WHEN is_stopped = true THEN 'S' WHEN is_stopped = false AND is_blocked = true THEN 'B' END" - operations = [migrations.RunSQL(sql)] + + operations = [] + From bb621d4bb935f49a88e90dbab97d093b766dfa8c Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 1 Jun 2022 19:53:03 -0300 Subject: [PATCH 003/630] add slack channel --- static/fonts/icons/Read Me.txt | 14 +- static/fonts/icons/demo.html | 16 +- static/fonts/icons/fonts/temba.eot | Bin 67984 -> 68312 bytes static/fonts/icons/fonts/temba.svg | 521 ++++++++++----------- static/fonts/icons/fonts/temba.ttf | Bin 67828 -> 68156 bytes static/fonts/icons/fonts/temba.woff | Bin 67904 -> 68232 bytes static/fonts/icons/selection.json | 2 +- static/fonts/icons/style.css | 13 +- temba/channels/types/slack/__init__.py | 1 + temba/channels/types/slack/tests.py | 115 +++++ temba/channels/types/slack/type.py | 31 ++ temba/channels/types/slack/views.py | 97 ++++ temba/contacts/models.py | 2 + temba/settings_common.py | 1 + templates/channels/types/slack/claim.haml | 24 + templates/channels/types/slack/config.haml | 11 + 16 files changed, 566 insertions(+), 282 deletions(-) create mode 100644 temba/channels/types/slack/__init__.py create mode 100644 temba/channels/types/slack/tests.py create mode 100644 temba/channels/types/slack/type.py create mode 100644 temba/channels/types/slack/views.py create mode 100644 templates/channels/types/slack/claim.haml create mode 100644 templates/channels/types/slack/config.haml diff --git a/static/fonts/icons/Read Me.txt b/static/fonts/icons/Read Me.txt index e39b5440ee0..8491652f880 100644 --- a/static/fonts/icons/Read Me.txt +++ b/static/fonts/icons/Read Me.txt @@ -1,7 +1,7 @@ -Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. - -To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts - -You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. - -You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. +Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. + +To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts + +You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. + +You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. diff --git a/static/fonts/icons/demo.html b/static/fonts/icons/demo.html index 86027e317e2..f66f7cdfb10 100644 --- a/static/fonts/icons/demo.html +++ b/static/fonts/icons/demo.html @@ -9,10 +9,24 @@
-

Font Name: temba (Glyphs: 251)

+

Font Name: temba (Glyphs: 252)

Grid Size: Unknown

+
+
+ + icon-slack +
+
+ + +
+
+ liga: + +
+
diff --git a/static/fonts/icons/fonts/temba.eot b/static/fonts/icons/fonts/temba.eot index d6974c8e5c53d4324594136cca3fb06ec6516682..e677a7ceb25920ee80d81d29449d2a4a7309e343 100644 GIT binary patch delta 1243 zcma)6ZA@EL7(VCT%cYb;TUu^QY47a?1`ICHZwfM6J_JS(upo9FGT2~2`6{JAWkMH2 z3}Rhmo$Es8oX#JNHH2&i=hiKCL0lHIG}}~S79`7pie{p72{FjLrSZ>x7=NAj`8scM z&U?;#UTpb&3}5C#P{f_W4H%tq*Ewabg6gTawb&tMl%5L8-RDKy*8o5T06dj;cC@uK z3)f@-BAEaHLnlj!u8Rg)+{)s#&K{>r*pYdT#p3{ASa;u{Hp@qz8vx=H03cXTo68Qp zyb%C79@ekyZR_bcx3_MB#eM)_uf1=;2~bvnTzOarDCXS{-$8)Ny9P_VyOF$bX+_Gs zA0XMCPwy$Cl$a8wo=|^MkE!3O4eA%_XKIalNUc&oP~TG_>MC`CIzV=i&7_nRD}Gb# zlb@H*B)=jH$gaw+NCT3alCLCRN){!TC4R{TNd~b*d_lAmbmF^-f<#2rBYHt(6vTK{ z=;xQdL3uyAIqV?>F@OdE7m#2#*aNCS6KDf{0EonRYD&6ZXLt@ubOx=4NEAjGmA(k- zb)p@Or4=xm)mVv+Fe+^!)M}z45iy<(Ga@lzgh3I};oQ z%g_v$;Wko_V(44wEcR(sZPW}d#ar>y`2A>Ev?clhXN)t$*@|(*+~OkKChkJ4IQDSt zTwg^Xrv%-+@uY}x$_5@dgMIPY!i?uE<+%UI_2(|-;dxbgr}7@C%&MR|SG}mQX*xCI znul7O4$&EPO?sZ*sz0Xx+K_7~HN0sE=Iip08yVw4Oytv z^?1GG#ZpVLWxfGvkT>`n&or*Q6nHt!I$^!DZ_>uKyBpV!c z5C8!E+-PNCWGh32J^%p#>;M1&HfU&NVH3U+a{vJWBme*aBxr4PcnM`FqW}Q`NB{r> z{A_PyVF+(b4gdiKL;wH+0BvD-Z~>7FdH?|jL;wH)AZ}r8Wur(>hX4TwWB>pGZg6jN zbN~YY00039)BpegAOHgdlUo6cljs3K0U?tp0x*+W0z&~Klbix9Xdnb210Vt)^dIvd z@*nUY?;q+P=pW@D;~(E2-XGZ?&mX!Usvlk+WFA`{7akKG?j2Yhs2ryoTpGI?x*E9{ zyBEh7#uvpG!xzFAwil`wsTU;{#1_96Viq42ixmzP026ByOA|H_2a_-ZxwHKP_~x@6 z?5!3a006d?M0Z~gJoNwz1ONa4007<;pUMCL007<;pURi$0s%Gx0RNXD0|7g?UjqSb z1DDSR0bqZ20L}q60nP#R0!9M*1AGIZ1gZr@1)c^D237`=2GR!*2S^9l2y_UZ2=WPN z3BU>X3QP*D3knNd3#1Fy3`h*149X1j4KNLm4k8YW4#p1>4_ptH54;c%5U>$c5pWTp z5ylbl5+o8@5^fTL69yAv6TTEe6p9rb748-u7C3(vP!?boa2A#pycY-`ZZXJRhq#ev1{vHw@CLS~%LLPP=m>$L+^dBN0 zP#=IFvLECh`XC}8N+4_?pdj2J{vjM8WFd?pwjtmmA|u8l<|K+GFeUORvMW?9dM&&y z=q`VvF1#-MFFr4hFW4|PFt#xyF}gBPGF~!zGTJjxGx#(vG)y%DHBL2zHNrL|HaIqT zHnuk^H;6bQI9NDzIJ7wiIY>FiI&M5@K8`;8K<+_0LGD6SLjXfAL##vwL_|b_MH)sL zMu0}ZM&?IAM}$bINw`W1O0G;gOvp~sPY{1k#!ui+{7`67I8roHrc(G*5>uj7lvLDJ zvR4{deptv^fLZ`ra$2HWPFx6FR&1<{9 diff --git a/static/fonts/icons/fonts/temba.svg b/static/fonts/icons/fonts/temba.svg index 2b25390116c..96b68457086 100644 --- a/static/fonts/icons/fonts/temba.svg +++ b/static/fonts/icons/fonts/temba.svg @@ -1,277 +1,262 @@ - - - -{ - "fontFamily": "temba", - "majorVersion": 1, - "minorVersion": 0, - "version": "Version 1.0", - "fontId": "temba", - "psName": "temba", - "subFamily": "Regular", - "fullName": "temba", - "description": "Font generated by IcoMoon." -} - - - +Generated by IcoMoon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/fonts/icons/fonts/temba.ttf b/static/fonts/icons/fonts/temba.ttf index 3079de929f120bd2973e1e3d5944a40c24efa4ee..e3343cd387b8458893f317272463785e1140f045 100644 GIT binary patch delta 1219 zcma)5ZA?>F7(VB=lu`=)zAdG_w*`a_E^R4oDTuU`4v{cmrDNDJq)L&EQc7E(;-JQm zg^+3{C1Qv%I`;#S5TXksT1{shGiEW3Gn-iqW5%!zjbl?2vM|`~n*H&|vL7e!d7kHe z&im$^^S(SqjZ9KMkp&MC!*T$igj~-KJA57h02=@bos9Iut|Oh7c-uEfOmaJ-E~le| zSiB(y5K)l2zKbMyH+lUeZYOb0SC2oyaVjp7coYCC)zy2*VZ9K#1t4t<0EF7(2zX$a zIRqd*MCQxfj-CwX#eEH9Br!)e;P&+T{D4AAkRds>G=TthxE5B1Pe4_C8-Z0}h!nVX z9>|hpR2c<-g}=mK;J@P=_*48>d<}nsui`)AKj1O^I(`{HfH|>NOoZ{Jze)E?E=guG z-xo*3*TvUF5#b%-*TS!aw}nf>IpJkt9=eQviFTlJ!3hCdfbe>FZ}AN56tWW-zJPRv z7m$>23dM4@l*0TuNZ!m&lnN+OzyKI{1MC4cpcyzoF919~Ejue$r`7LH%_r3)FTj1)j+uWiy(v^%G6UT>JMAp(QL;GMn*5kPLZ6{;rFc{BG7v^HV=GT*&!s=w5XDzeE>}#Ah&Jbso6XX2JRdPGH0d9!L=DB!x z_;vhAL9SpERRmEpYDYgrhtTurvXCpXiSCKEGRzq>Vw%_{p3lt99LU_19F$B*<|V&K z`O<(iB%POjhtV+!rp79;I_wzsDHg-FaRRsF<9GyrPX1RyW|IxbW@T$~x;$6zmYa zw^cE!3{{I3wx!+@dNZdwr+U2lZuQ3A+Px=huI#&2%dcIkv((+Me-vyGH^ds&8)=Q+ zx6RfH>p~OKBx#znowKdH6L~kMWvu1?{&73Q{*is|y_QyPYrAXFZF8^mMm%bd#}n;i z_nqx~<~`?q?o;>zzR&yy|FnOt-_t)jfDS|k`Ge(y(SRwid8B2?FtmCUIodj$H5?hK s9+@AB1VaGE=MGNQCc~eEMdWBXffx9|2jqacfeaJ@B`BIQ)8UoB0bXQWc>n+a delta 930 zcmXw&ZA@Er6vog0wv@iDuk>Ch?fu`DvMg?t^41kx$biafZD?hP$eOv%vej5hp|y0) zMv*jeL9z^rtJw!cMidF^!c3iv;Id&|7M%$p%Ul**bdp7vx?oMnQa7(3{BZK*_dGet z^WmK3Np5bOdzOj&?s^IUkcOQ{$33AS0LTD1d{+6#{U?syt{DA+W!C%Wp0CH_-QALC z1O$)R-0Wiw<%%){2pL#5_xWEZf+fyua@a55LbL0aRcGAfVS14We;z3{WA< zzyv(KB|R5x&UabE%N7U(`$A#huo2>~k6)fhI#3hRCC88{xq@0y*#xo2&u|$IL*N|# z3vc1a_)q*heu#g=zv7?q2L1{Eh?np@K1_S*Lo`JzwOMVKW=``-sat(Ty`=uS_zLwM zm7%_+u2a{jG&N6sN|lqVG!RJuS@s+4I(aE7GR_3!<+wW%0VDA0nbti0zLoLbprW0sTv+S5|6+w zWJb48j%X#Ga87cjx$_0qf+?Pa*U6jUtrf}&ZH0IEVg3|JL~!Ud5~z4y7jr!9I*mnCfZvYuCOtIsq9_W2smH0Jkbn;M$3 z%^fY!Vr*Hk@~l?t$P4OLb?b2J)z-}e`wt{+b1z=D3+eKW^VXs5m&&G1;;H%Hpf)uA#0QuMKxY_dxf|p*A<)-RWNl*aPc*i@}}2W5IMk zuYaQdmx0NF2O&BX2%Qh*!?y5Rc=PROgpNcaQ-k`!nP_)(>BRY1bIcoCIhi;`pPCzz z4bekc_FDj+i3L#@|L;bCV9!dK`ht&EDHC);4-7yE-h@5~00UKE1XF5MfEND+s`)2y diff --git a/static/fonts/icons/fonts/temba.woff b/static/fonts/icons/fonts/temba.woff index 035f480a778641d2438522b2469c1a41cb496b1e..7fb01611cd469fcd93911c2cb6e9cbf707703629 100644 GIT binary patch delta 1289 zcmX>wiKSyIi$uAmS~>ulRAl>rn4imd_iRX|vHpKxhL zZb=1D>;eM=3kwJfrfMwC$xjBVW4pq@zyuUyVhLKdtXqXGysPUfk~ zOUz9Liv0k(I1hvud-``2Tk;p=cgwGqkC#i8i;sl`hS3hf%yOf7lRywCW9@52SXS`B11j{gRlsjvXYvqiJ3K{xQUsu zk(j6;M8v?U=onT5HHc@@hRRzKDi zY!YkttTYipW;T z_QNEo0w0s(6LCesI%B-DPS37dBLi} zrpRuFJ)6T1M;FH*PI1m$&KAzwTm)SFTzXtp+*I7U+)lZDaQAZW^VsBh$Ve3JOw}>9O0|3H-0IfV?Wykp7F)awjEp=L3=_d=gb7%N2~Xe5&Ui%J f5SaB+8HyN+88U$xFb`Oo7&7QF7*6lwVB7=%s%dE2 delta 938 zcmeB}%5q>5i&(k8n;Qco0|Nsirvn2wi01ghz&QCMlh{NZmHLcZiLB{~#RUuu%ppKI z4k#8#oUip4N6{JjIh*L1tiW~3&jFfcM&0M(d*u(orHT?SAPCb4+{A8dy)(H#@Oh9E!3>^7Be7T7gx&;i3>_9;V1rTPO$WxV< zn41a|+W>TD9tbb?@NX~3FD?N(Ut!{(S(9flIx;FwzQJfPnTyGpQF*ctlTL;LivqI( zll&L?&+?z-KghqAe00DVs&Ai$HvDN#x{xV61xDq2m1|< z5{`KspExr(4{-kA^5I&;&BYzVy@dN3j|a~Jo>M$ucnx?b@G0^2@Ezk9;*a5<#=l2E zKwyJlh+u)>0>NW~AB0qdqJ;8>1gAazb)yawc+4 za%FNezPImx7XlmqL!h0);yY{}g2uQxtm?w<$hQQc^yq{7j`w z)j;)=#wP6$ohscux-azV7wPTM`=f8C-=}}Wz|3Hqp^D)yqX45gqbj3Y#sS7ZO!Q2A zOqopmOj}G3nW>mrm{pi$NV4o{|U$l zvly(#G~X=$+OamGP$y{vU%l7<%=q!Dt1-Qs&cAIsoGc5 mQY%-xqE4VruI?Q;6aMF!exHN!0i(h61DuSaK[a-z0-9\-]+)/receive$" + + claim_blurb = _("Add a %(link)s bot to send and receive messages to Slack users, on your slack workspace.") % { + "link": 'Slack' + } + + claim_view = ClaimView diff --git a/temba/channels/types/slack/views.py b/temba/channels/types/slack/views.py new file mode 100644 index 00000000000..a906b435045 --- /dev/null +++ b/temba/channels/types/slack/views.py @@ -0,0 +1,97 @@ +import slack_sdk +from smartmin.views import SmartFormView + +from django import forms +from django.core.exceptions import ValidationError +from django.utils.translation import gettext_lazy as _ + +from ...models import Channel +from ...views import ClaimViewMixin + + +class ClaimView(ClaimViewMixin, SmartFormView): + class Form(ClaimViewMixin.Form): + user_token = forms.CharField( + label=_("User OAuth Token"), + help_text=_( + "In https://api.slack.com/apps select your bot app and go to Features / OAuth & Permissions to see this information." + ), + ) + bot_token = forms.CharField( + label=_("Bot User OAuth Token"), + help_text=_( + "In https://api.slack.com/apps select your bot app and go to Features / OAuth & Permissions to see this information." + ), + ) + verification_token = forms.CharField( + label=_("Verification Token"), + help_text=_( + "In https://api.slack.com/apps go to Settings / Basic information, find in App Credentials and paste here." + ), + ) + + def clean_user_token(self): + org = self.request.user.get_org() + value = self.cleaned_data["user_token"] + + for channel in Channel.objects.filter(org=org, is_active=True, channel_type=self.channel_type.code): + if channel.config["user_token"] == value: + raise ValidationError(_("A slack channel for this bot already exists on your account.")) + + try: + client = slack_sdk.WebClient(token=value) + client.api_call(api_method="auth.test") + except slack_sdk.errors.SlackApiError: + raise ValidationError(_("Your user token is invalid, please check and try again")) + + return value + + def clean_bot_token(self): + org = self.request.user.get_org() + value = self.cleaned_data["bot_token"] + + for channel in Channel.objects.filter(org=org, is_active=True, channel_type=self.channel_type.code): + if channel.config["bot_token"] == value: + raise ValidationError(_("A slack channel for this bot already exists on your account.")) + + try: + client = slack_sdk.WebClient(token=value) + client.api_call(api_method="auth.test") + except slack_sdk.errors.SlackApiError: + raise ValidationError(_("Your bot user token is invalid, please check and try again")) + + return value + + def form_valid(self, form): + from .type import SlackType + + user_token = form.cleaned_data["user_token"] + bot_token = form.cleaned_data["bot_token"] + verification_token = form.cleaned_data["verification_token"] + + client = slack_sdk.WebClient(token=bot_token) + + auth_test = client.api_call( + api_method="auth.test", + ) + + config = { + SlackType.CONFIG_BOT_TOKEN: bot_token, + SlackType.CONFIG_USER_TOKEN: user_token, + SlackType.CONFIG_VERIFICATION_TOKEN: verification_token, + } + + self.object = Channel.create( + org=self.org, + user=self.request.user, + country=None, + channel_type=self.channel_type, + name=auth_test["user"], + address=auth_test["user"], + config=config, + ) + + return super().form_valid(form) + + form_class = Form + success_url = "uuid@channels.channel_configuration" diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 33138a3af58..ce905606c8a 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -61,6 +61,7 @@ class URN: JIOCHAT_SCHEME = "jiochat" LINE_SCHEME = "line" ROCKETCHAT_SCHEME = "rocketchat" + SLACK_SCHEME = "slack" TELEGRAM_SCHEME = "telegram" TEL_SCHEME = "tel" TWITTERID_SCHEME = "twitterid" @@ -91,6 +92,7 @@ class URN: (WECHAT_SCHEME, _("WeChat Identifier")), (WEBCHAT_SCHEME, _("Webchat Identifier")), (WHATSAPP_SCHEME, _("WhatsApp Identifier")), + (SLACK_SCHEME, _("Slack Identifier")), ) VALID_SCHEMES = {s[0] for s in SCHEME_CHOICES} diff --git a/temba/settings_common.py b/temba/settings_common.py index 376df94e1b0..7570d29e6e0 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -1190,6 +1190,7 @@ "temba.channels.types.discord.DiscordType", "temba.channels.types.rocketchat.RocketChatType", "temba.channels.types.instagram.InstagramType", + "temba.channels.types.slack.SlackType", ] ANALYTICS_TYPES = [ diff --git a/templates/channels/types/slack/claim.haml b/templates/channels/types/slack/claim.haml new file mode 100644 index 00000000000..c040fb8dc86 --- /dev/null +++ b/templates/channels/types/slack/claim.haml @@ -0,0 +1,24 @@ +-extends "channels/channel_claim_form.html" +-load i18n compress temba + +-block pre-form + -blocktrans trimmed with name=brand.name + You can connect a Slack Bot to your {{name}} workspace to automate sending and receiving messages. + + -blocktrans trimmed + To do it, you will need to create a new slack app and configure it. + + %ol.steps.card + %li + -blocktrans trimmed + You'll need to create a Slack App if you haven't already. + %li + -blocktrans trimmed + Setup a bot to your Slack App, add the needed scopes for Bot Token (chat:write, files:read, files:write, users:read), User Token (files:read and files:write) and install app on your slack workspace. + %li + -blocktrans trimmed + Fill this form, submit and go redirected to config page. + %li + -blocktrans trimmed + Copy Request URL from channel config page, go to slack Event Subscriptions page, enable Events, paste Request URL into input field and subscribe to bot events (file_created, message.channels, message.im). + If you need help how to do all this steps, read this guide here please. diff --git a/templates/channels/types/slack/config.haml b/templates/channels/types/slack/config.haml new file mode 100644 index 00000000000..53f9e061a48 --- /dev/null +++ b/templates/channels/types/slack/config.haml @@ -0,0 +1,11 @@ +-load i18n + +-blocktrans trimmed + To finish configuring your connection you'll need to set the following callback URL on your app + Event Subscription Request URL.More info. + +.card.mt-6 + .title + -trans "Request URL" + .code.inline-block.m-0 + https://{{ channel.callback_domain }}/c/sl/{{ channel.uuid }}/receive/ \ No newline at end of file From 9748210362fc9d9d550058be5cb0b12ff5000643 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Tue, 14 Jun 2022 10:14:39 -0300 Subject: [PATCH 004/630] add slack channel dependency --- poetry.lock | 18 +++++++++++++++++- pyproject.toml | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index d8d6e1c367f..c838ed7a341 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1174,6 +1174,18 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "slack-sdk" +version = "3.17.0" +description = "The Slack API Platform SDK for Python" +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=10,<11)", "websocket-client (>=1,<2)"] +testing = ["pytest (>=6.2.5,<7)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "itsdangerous (==1.1.0)", "Jinja2 (==3.0.3)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=4,<5)", "black (==22.3.0)", "click (==8.0.4)", "psutil (>=5,<6)", "databases (>=0.5)", "boto3 (<=2)", "moto (>=3,<4)"] + [[package]] name = "smartmin" version = "4.1.0" @@ -1367,7 +1379,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "724895289cfcb6eba0b73cba4f9bc84044fc99a76182af649b9f642ff677d235" +content-hash = "865b8b348a08881a569d768babcf5fd2863024fd2de5fdd7dbe024c1e2f90e20" [metadata.files] amqp = [ @@ -2036,6 +2048,10 @@ six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +slack-sdk = [ + {file = "slack_sdk-3.17.0-py2.py3-none-any.whl", hash = "sha256:0816efc43d1d2db8286e8dbcbb2e86fd0f71c206c01c521c2cb054ecb40f9ced"}, + {file = "slack_sdk-3.17.0.tar.gz", hash = "sha256:860cd0e50c454b955f14321c8c5486a47cc1e0e84116acdb009107f836752feb"}, +] smartmin = [ {file = "smartmin-4.1.0-py3-none-any.whl", hash = "sha256:3667eaf2b2c9a6d7b4ccccc58efd36a6eef8cd1c17bcf43ab2c76defb25abe92"}, {file = "smartmin-4.1.0.tar.gz", hash = "sha256:8a8fae03da769b72f301e5bf28b13b3de0d6e316522fabeae19b6eac2073436b"}, diff --git a/pyproject.toml b/pyproject.toml index 9ac253e5c34..afdffb193dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ packaging = "^20.9" requests-toolbelt = "^0.9.1" chardet = "^4.0.0" openpyxl = "^3.0.9" +slack-sdk = "3.17.0" [tool.poetry.dev-dependencies] black = "^22.1.0" From 5895f4cff9b8eca07e6927a5518c3756e703ef0c Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Wed, 22 Jun 2022 16:54:36 -0300 Subject: [PATCH 005/630] tweaks in slack views and test --- temba/channels/types/slack/tests.py | 19 +++++++++++++++++-- temba/channels/types/slack/views.py | 20 +++++++++++--------- templates/channels/types/slack/claim.haml | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/temba/channels/types/slack/tests.py b/temba/channels/types/slack/tests.py index ecf6376768c..cbdc37a931a 100644 --- a/temba/channels/types/slack/tests.py +++ b/temba/channels/types/slack/tests.py @@ -38,6 +38,20 @@ def test_claim(self, mock_api_call): response = self.client.get(url) self.assertContains(response, "Connect Slack") + # claim with already used user_token and bot_token + response = self.client.post(url, {"user_token": "123456789:ABCDEFabcdef-1a2b3c4d"}) + print(response) + self.assertEqual( + "A slack channel for this bot already exists.", + response.context["form"].errors["user_token"][0], + ) + response = self.client.post(url, {"bot_token": "123456789:ABCDEFabcdef-1a2b3c4d"}) + print(response) + self.assertEqual( + "A slack channel for this bot already exists.", + response.context["form"].errors["bot_token"][0], + ) + # claim with invalid token mock_api_call.side_effect = slack_sdk.errors.SlackApiError("", "") response = self.client.post(url, {"user_token": "invalid"}) @@ -62,6 +76,7 @@ def test_claim(self, mock_api_call): "user": "dummy", "team_id": "T0DUMMY", "user_id": "U0DUMMY", + "bot_id": "B0TDUMMY", "is_enterprise_install": False, } @@ -76,7 +91,7 @@ def test_claim(self, mock_api_call): "verification_token": "VTK0123456789ABCDEFabcdef-1a2b3c4d", }, ) - channel = Channel.objects.get(address="dummy") + channel = Channel.objects.get(address="B0TDUMMY") self.assertEqual(channel.channel_type, "SL") self.assertEqual( channel.config, @@ -102,7 +117,7 @@ def test_claim(self, mock_api_call): }, ) self.assertEqual( - "A slack channel for this bot already exists on your account.", + "A slack channel for this bot already exists.", response.context["form"].errors["user_token"][0], ) diff --git a/temba/channels/types/slack/views.py b/temba/channels/types/slack/views.py index a906b435045..5cc9bad955a 100644 --- a/temba/channels/types/slack/views.py +++ b/temba/channels/types/slack/views.py @@ -31,12 +31,13 @@ class Form(ClaimViewMixin.Form): ) def clean_user_token(self): - org = self.request.user.get_org() value = self.cleaned_data["user_token"] - for channel in Channel.objects.filter(org=org, is_active=True, channel_type=self.channel_type.code): - if channel.config["user_token"] == value: - raise ValidationError(_("A slack channel for this bot already exists on your account.")) + existing = Channel.objects.filter( + is_active=True, channel_type=self.channel_type.code, config__contains=value + ).first() + if existing: + raise ValidationError(_("A slack channel for this bot already exists.")) try: client = slack_sdk.WebClient(token=value) @@ -47,12 +48,13 @@ def clean_user_token(self): return value def clean_bot_token(self): - org = self.request.user.get_org() value = self.cleaned_data["bot_token"] - for channel in Channel.objects.filter(org=org, is_active=True, channel_type=self.channel_type.code): - if channel.config["bot_token"] == value: - raise ValidationError(_("A slack channel for this bot already exists on your account.")) + existing = Channel.objects.filter( + is_active=True, channel_type=self.channel_type.code, config__contains=value + ).first() + if existing: + raise ValidationError(_("A slack channel for this bot already exists.")) try: client = slack_sdk.WebClient(token=value) @@ -87,7 +89,7 @@ def form_valid(self, form): country=None, channel_type=self.channel_type, name=auth_test["user"], - address=auth_test["user"], + address=auth_test["bot_id"], config=config, ) diff --git a/templates/channels/types/slack/claim.haml b/templates/channels/types/slack/claim.haml index c040fb8dc86..ff6f8c04566 100644 --- a/templates/channels/types/slack/claim.haml +++ b/templates/channels/types/slack/claim.haml @@ -20,5 +20,5 @@ Fill this form, submit and go redirected to config page. %li -blocktrans trimmed - Copy Request URL from channel config page, go to slack Event Subscriptions page, enable Events, paste Request URL into input field and subscribe to bot events (file_created, message.channels, message.im). + Copy Request URL from channel config page, go to slack Event Subscriptions page, enable Events, paste Request URL into input field and subscribe to bot events (file_created, message.im). If you need help how to do all this steps, read this guide here please. From 41ae996b814570ba720b5ca2de212381bd200e68 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Mon, 11 Jul 2022 14:14:59 -0700 Subject: [PATCH 006/630] Scroll main content pane up on page replacement --- templates/spa_frame.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/spa_frame.haml b/templates/spa_frame.haml index 2db9313afd2..7398dadf391 100644 --- a/templates/spa_frame.haml +++ b/templates/spa_frame.haml @@ -593,6 +593,10 @@ if (container) { container.classList.remove("loading"); } + + // scroll our content to the top if needed + var content = document.querySelector(".spa-content"); + content.scrollTo(0, 0); updatePageTitle(); var menu = document.querySelector("temba-menu"); From 0f8be159af6198626a6acb352640245ab8ba8ee2 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 12 Jul 2022 11:04:13 +0100 Subject: [PATCH 007/630] Add data migration to fix non-waiting sessions with no ended_on --- .../flows/migrations/0289_fail_ghost_runs.py | 4 +- .../0292_ensure_session_ended_on.py | 32 +++++++++ temba/flows/tests.py | 66 +++++++++---------- 3 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 temba/flows/migrations/0292_ensure_session_ended_on.py diff --git a/temba/flows/migrations/0289_fail_ghost_runs.py b/temba/flows/migrations/0289_fail_ghost_runs.py index ee12287175a..e53859917da 100644 --- a/temba/flows/migrations/0289_fail_ghost_runs.py +++ b/temba/flows/migrations/0289_fail_ghost_runs.py @@ -8,7 +8,7 @@ STATUS_FAILED = "F" -def fail_ghost_runs(apps, schema_editor): +def fail_ghost_runs(apps, schema_editor): # pragma: no cover FlowRun = apps.get_model("flows", "FlowRun") num_failed = 0 @@ -26,7 +26,7 @@ def fail_ghost_runs(apps, schema_editor): print(f"Failed {num_failed} active/waiting runs without a session") -def reverse(apps, schema_editor): +def reverse(apps, schema_editor): # pragma: no cover pass diff --git a/temba/flows/migrations/0292_ensure_session_ended_on.py b/temba/flows/migrations/0292_ensure_session_ended_on.py new file mode 100644 index 00000000000..05e533dac15 --- /dev/null +++ b/temba/flows/migrations/0292_ensure_session_ended_on.py @@ -0,0 +1,32 @@ +# Generated by Django 4.0.6 on 2022-07-12 09:37 + +from django.db import migrations +from django.utils import timezone + + +def ensure_session_ended_on(apps, schema_editor): + FlowSession = apps.get_model("flows", "FlowSession") + + num_updated = 0 + while True: + batch = list(FlowSession.objects.filter(ended_on=None).exclude(status="W").only("id", "ended_on")[:100]) + if not batch: + break + + FlowSession.objects.filter(id__in=[r.id for r in batch]).update(ended_on=timezone.now()) + + num_updated += len(batch) + print(f"Updated {num_updated} non-waiting sessions without an ended_on") + + +def reverse(apps, schema_editor): + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ("flows", "0291_flowrun_flows_run_active_or_waiting_has_session"), + ] + + operations = [migrations.RunPython(ensure_session_ended_on, reverse)] diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 14437c60d5e..5fe558a872f 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -5636,61 +5636,55 @@ def test_trim_revisions(self): self.assertEqual(31, FlowRevision.objects.filter(flow=color).count()) -class FailGhostRunsMigrationTest(MigrationTest): +class EnsureSessionEndedOnMigrationTest(MigrationTest): app = "flows" - migrate_from = "0288_flowlabel_is_system" - migrate_to = "0289_fail_ghost_runs" + migrate_from = "0291_flowrun_flows_run_active_or_waiting_has_session" + migrate_to = "0292_ensure_session_ended_on" def setUpBeforeMigration(self, apps): contact = self.create_contact("Bob", phone="+1234567890") - flow = self.create_flow("Flow") - def create_session(status: str): + def create_session(status: str, ended_on): + uuid = uuid4() return FlowSession.objects.create( - uuid=uuid4(), + uuid=uuid, org=self.org, contact=contact, status=status, created_on=timezone.now(), + ended_on=ended_on, wait_started_on=timezone.now(), wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, + output={"uuid": str(uuid)}, ) - def create_run(session, status: str): - return FlowRun.objects.create( - uuid=uuid4(), - org=self.org, - session=session, - flow=flow, - contact=contact, - status=status, - created_on=timezone.now(), - modified_on=timezone.now(), - ) + self.session1 = create_session(status=FlowSession.STATUS_WAITING, ended_on=None) + self.session2 = create_session(status=FlowSession.STATUS_COMPLETED, ended_on=None) + self.session3 = create_session(status=FlowSession.STATUS_INTERRUPTED, ended_on=None) + self.session4 = create_session(status=FlowSession.STATUS_EXPIRED, ended_on=None) + self.session5 = create_session(status=FlowSession.STATUS_FAILED, ended_on=None) - self.run1 = create_run(create_session(FlowSession.STATUS_WAITING), FlowRun.STATUS_WAITING) - self.run2 = create_run(create_session(FlowSession.STATUS_WAITING), FlowRun.STATUS_ACTIVE) - self.run3 = create_run(None, FlowRun.STATUS_ACTIVE) - self.run4 = create_run(None, FlowRun.STATUS_WAITING) - self.run5 = create_run(None, FlowRun.STATUS_COMPLETED) + # a non-waiting session with an ended_on shouldn't be changed + self.session6 = create_session( + status=FlowSession.STATUS_FAILED, ended_on=datetime(2022, 7, 12, 11, 0, 0, 0, timezone.utc) + ) def test_migration(self): - self.run1.refresh_from_db() - self.assertEqual(FlowRun.STATUS_WAITING, self.run1.status) # unchanged - self.assertIsNone(self.run1.exited_on) + self.session1.refresh_from_db() + self.assertIsNone(self.session1.ended_on) + + self.session2.refresh_from_db() + self.assertIsNotNone(self.session2.ended_on) - self.run2.refresh_from_db() - self.assertEqual(FlowRun.STATUS_ACTIVE, self.run2.status) # unchanged - self.assertIsNone(self.run2.exited_on) + self.session3.refresh_from_db() + self.assertIsNotNone(self.session3.ended_on) - self.run3.refresh_from_db() - self.assertEqual(FlowRun.STATUS_FAILED, self.run3.status) - self.assertIsNotNone(self.run3.exited_on) + self.session4.refresh_from_db() + self.assertIsNotNone(self.session4.ended_on) - self.run4.refresh_from_db() - self.assertEqual(FlowRun.STATUS_FAILED, self.run4.status) - self.assertIsNotNone(self.run4.exited_on) + self.session5.refresh_from_db() + self.assertIsNotNone(self.session5.ended_on) - self.run5.refresh_from_db() - self.assertEqual(FlowRun.STATUS_COMPLETED, self.run5.status) # unchanged + self.session6.refresh_from_db() + self.assertEqual(datetime(2022, 7, 12, 11, 0, 0, 0, timezone.utc), self.session6.ended_on) # unchanged From f3b29d7c2dd164efb5959cdfa6c33f92a0bebf8f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 12 Jul 2022 11:15:42 +0100 Subject: [PATCH 008/630] Add constraint to ensure non-waiting sessions have an ended_on --- ..._flows_session_non_waiting_has_ended_on.py | 20 +++++++++++++++++ temba/flows/models.py | 4 ++++ temba/flows/tests.py | 22 ++++++++++++++++--- temba/tests/base.py | 1 + temba/tests/engine.py | 6 ++++- 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py diff --git a/temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py b/temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py new file mode 100644 index 00000000000..c5909b27fe5 --- /dev/null +++ b/temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.6 on 2022-07-12 10:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("flows", "0292_ensure_session_ended_on"), + ] + + operations = [ + migrations.AddConstraint( + model_name="flowsession", + constraint=models.CheckConstraint( + check=models.Q(("status", "W"), ("ended_on__isnull", False), _connector="OR"), + name="flows_session_non_waiting_has_ended_on", + ), + ), + ] diff --git a/temba/flows/models.py b/temba/flows/models.py index 3608ab66734..cb72dd67623 100644 --- a/temba/flows/models.py +++ b/temba/flows/models.py @@ -1154,6 +1154,10 @@ class Meta: check=~Q(status="W") | Q(wait_started_on__isnull=False, wait_expires_on__isnull=False), name="flows_session_waiting_has_started_and_expires", ), + # ensure that non-waiting sessions have an ended_on + models.CheckConstraint( + check=Q(status="W") | Q(ended_on__isnull=False), name="flows_session_non_waiting_has_ended_on" + ), # ensure that all sessions have output or output_url models.CheckConstraint( check=Q(output__isnull=False) | Q(output_url__isnull=False), diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 5fe558a872f..824c47ae705 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -1690,6 +1690,7 @@ def test_update_expiration_task(self): wait_started_on=datetime(2022, 1, 1, 0, 0, 0, 0, pytz.UTC), wait_expires_on=None, wait_resume_on_expire=False, + ended_on=timezone.now(), ) # create waiting session for flow 2 @@ -3861,6 +3862,9 @@ def test_trim(self): org=self.org, contact=contact, output_url="http://sessions.com/123.json", + status=FlowSession.STATUS_WAITING, + wait_started_on=timezone.now(), + wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) session2 = FlowSession.objects.create( @@ -3868,6 +3872,9 @@ def test_trim(self): org=self.org, contact=contact, output_url="http://sessions.com/234.json", + status=FlowSession.STATUS_WAITING, + wait_started_on=timezone.now(), + wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) session3 = FlowSession.objects.create( @@ -3875,6 +3882,9 @@ def test_trim(self): org=self.org, contact=contact, output_url="http://sessions.com/345.json", + status=FlowSession.STATUS_WAITING, + wait_started_on=timezone.now(), + wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) run1 = FlowRun.objects.create(org=self.org, flow=flow, contact=contact, session=session1) @@ -3891,14 +3901,17 @@ def test_trim(self): self.assertIsNotNone(run4.session) # end run1 and run4's sessions in the past + run1.session.status = FlowSession.STATUS_COMPLETED run1.session.ended_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) - run1.session.save(update_fields=("ended_on",)) + run1.session.save(update_fields=("status", "ended_on")) + run4.session.status = FlowSession.STATUS_INTERRUPTED run4.session.ended_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) - run4.session.save(update_fields=("ended_on",)) + run4.session.save(update_fields=("status", "ended_on")) # end run2's session now + run4.session.status = FlowSession.STATUS_EXPIRED run2.session.ended_on = timezone.now() - run2.session.save(update_fields=("ended_on",)) + run2.session.save(update_fields=("status", "ended_on")) trim_flow_sessions_and_starts() @@ -3930,6 +3943,9 @@ def create_start(user, start_type, status, modified_on, **kwargs): org=self.org, contact=contact, output_url="http://sessions.com/123.json", + status=FlowSession.STATUS_WAITING, + wait_started_on=timezone.now(), + wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) FlowRun.objects.create(org=self.org, contact=contact, flow=flow, session=session, start=start) diff --git a/temba/tests/base.py b/temba/tests/base.py index 6b2114e9202..240441aee05 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -512,6 +512,7 @@ def create_incoming_call(self, flow, contact, status=IVRCall.STATUS_COMPLETED): output_url="http://sessions.com/123.json", connection=call, wait_resume_on_expire=False, + ended_on=timezone.now(), ) FlowRun.objects.create( org=self.org, flow=flow, contact=contact, status=FlowRun.STATUS_COMPLETED, session=session diff --git a/temba/tests/engine.py b/temba/tests/engine.py index d8185fd2652..6d2de1c04b8 100644 --- a/temba/tests/engine.py +++ b/temba/tests/engine.py @@ -279,10 +279,12 @@ def save(self): wait_started_on = timezone.now() wait_expires_on = iso8601.parse_date(wait_event["expires_on"]) if wait_event["expires_on"] else None wait_resume_on_expire = False # this doesn't support sub-flows + ended_on = None else: wait_started_on = None wait_expires_on = None wait_resume_on_expire = False + ended_on = timezone.now() # create or update session object itself if self.session: @@ -290,7 +292,8 @@ def save(self): self.session.status = SESSION_STATUSES[self.output["status"]] self.session.wait_started_on = wait_started_on self.session.wait_expires_on = wait_expires_on - self.session.save(update_fields=("output", "status", "wait_started_on", "wait_expires_on")) + self.session.ended_on = ended_on + self.session.save(update_fields=("output", "status", "wait_started_on", "wait_expires_on", "ended_on")) else: self.session = FlowSession.objects.create( uuid=self.output["uuid"], @@ -302,6 +305,7 @@ def save(self): wait_started_on=wait_started_on, wait_expires_on=wait_expires_on, wait_resume_on_expire=wait_resume_on_expire, + ended_on=ended_on, ) current_flow = None From 9acb734aa3bca9f57daf986736f4992687765fd0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 12 Jul 2022 13:55:20 +0100 Subject: [PATCH 009/630] Add constraint to ensure non-waiting/active runs have exited_on set --- ...ws_run_inactive_has_exited_on_and_more.py} | 9 ++- temba/flows/models.py | 8 +- temba/flows/tests.py | 73 +++++++++++++++---- temba/tests/base.py | 7 +- 4 files changed, 80 insertions(+), 17 deletions(-) rename temba/flows/migrations/{0293_flowsession_flows_session_non_waiting_has_ended_on.py => 0293_flowrun_flows_run_inactive_has_exited_on_and_more.py} (58%) diff --git a/temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py b/temba/flows/migrations/0293_flowrun_flows_run_inactive_has_exited_on_and_more.py similarity index 58% rename from temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py rename to temba/flows/migrations/0293_flowrun_flows_run_inactive_has_exited_on_and_more.py index c5909b27fe5..7c8bcbb2e78 100644 --- a/temba/flows/migrations/0293_flowsession_flows_session_non_waiting_has_ended_on.py +++ b/temba/flows/migrations/0293_flowrun_flows_run_inactive_has_exited_on_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0.6 on 2022-07-12 10:15 +# Generated by Django 4.0.6 on 2022-07-12 11:36 from django.db import migrations, models @@ -10,6 +10,13 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AddConstraint( + model_name="flowrun", + constraint=models.CheckConstraint( + check=models.Q(("status__in", ("A", "W")), ("exited_on__isnull", False), _connector="OR"), + name="flows_run_inactive_has_exited_on", + ), + ), migrations.AddConstraint( model_name="flowsession", constraint=models.CheckConstraint( diff --git a/temba/flows/models.py b/temba/flows/models.py index cb72dd67623..299d65427bc 100644 --- a/temba/flows/models.py +++ b/temba/flows/models.py @@ -1310,10 +1310,16 @@ class Meta: models.Index(name="flows_flowrun_contact_inc_flow", fields=("contact",), include=("flow",)), ] constraints = [ + # all active/waiting runs must have a session models.CheckConstraint( check=~Q(status__in=("A", "W")) | Q(session__isnull=False), name="flows_run_active_or_waiting_has_session", - ) + ), + # all non-active/waiting runs must have an exited_on + models.CheckConstraint( + check=Q(status__in=("A", "W")) | Q(exited_on__isnull=False), + name="flows_run_inactive_has_exited_on", + ), ] diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 824c47ae705..0517dfe8377 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -1080,24 +1080,37 @@ def test_category_counts_with_null_categories(self): FlowCategoryCount.objects.get(category_name="Blue", result_name="Color", result_key="color", count=-1) def test_flow_start_counts(self): - flow = self.get_flow("color") - # create start for 10 contacts + flow = self.create_flow("Test") start = FlowStart.objects.create(org=self.org, flow=flow, created_by=self.admin) for i in range(10): - contact = self.create_contact("Bob", urns=[f"twitter:bobby{i}"]) - start.contacts.add(contact) + start.contacts.add(self.create_contact("Bob", urns=[f"twitter:bobby{i}"])) + + def create_run(contact): + session = FlowSession.objects.create( + uuid=uuid4(), + org=self.org, + contact=contact, + status=FlowSession.STATUS_WAITING, + output_url="http://sessions.com/123.json", + wait_started_on=timezone.now(), + wait_expires_on=timezone.now() + timedelta(days=7), + wait_resume_on_expire=False, + ) + FlowRun.objects.create( + org=self.org, flow=flow, contact=contact, session=session, start=start, status=FlowRun.STATUS_WAITING + ) # create runs for first 5 - for contact in start.contacts.order_by("id")[:5]: - FlowRun.objects.create(org=self.org, flow=flow, contact=contact, start=start) + for c in start.contacts.order_by("id")[:5]: + create_run(c) # check our count self.assertEqual(FlowStartCount.get_count(start), 5) # create runs for last 5 - for contact in start.contacts.order_by("id")[5:]: - FlowRun.objects.create(org=self.org, flow=flow, contact=contact, start=start) + for c in start.contacts.order_by("id")[5:]: + create_run(c) # check our count self.assertEqual(FlowStartCount.get_count(start), 10) @@ -3259,7 +3272,14 @@ def test_results(self): with patch("temba.flows.views.FlowCRUDL.RunTable.paginate_by", 1): # create one empty run - FlowRun.objects.create(org=self.org, flow=flow, contact=pete, responded=True) + FlowRun.objects.create( + org=self.org, + flow=flow, + contact=pete, + responded=True, + status=FlowRun.STATUS_COMPLETED, + exited_on=timezone.now(), + ) # fetch our intercooler rows for the run table response = self.client.get(reverse("flows.flow_run_table", args=[flow.id])) @@ -3268,7 +3288,14 @@ def test_results(self): with patch("temba.flows.views.FlowCRUDL.RunTable.paginate_by", 1): # create one empty run - FlowRun.objects.create(org=self.org, flow=flow, contact=pete, responded=False) + FlowRun.objects.create( + org=self.org, + flow=flow, + contact=pete, + responded=False, + status=FlowRun.STATUS_COMPLETED, + exited_on=timezone.now(), + ) # fetch our intercooler rows for the run table response = self.client.get("%s?responded=bla" % reverse("flows.flow_run_table", args=[flow.id])) @@ -3887,9 +3914,15 @@ def test_trim(self): wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) - run1 = FlowRun.objects.create(org=self.org, flow=flow, contact=contact, session=session1) - run2 = FlowRun.objects.create(org=self.org, flow=flow, contact=contact, session=session2) - run3 = FlowRun.objects.create(org=self.org, flow=flow, contact=contact, session=session3) + run1 = FlowRun.objects.create( + org=self.org, flow=flow, contact=contact, session=session1, status=FlowRun.STATUS_WAITING + ) + run2 = FlowRun.objects.create( + org=self.org, flow=flow, contact=contact, session=session2, status=FlowRun.STATUS_WAITING + ) + run3 = FlowRun.objects.create( + org=self.org, flow=flow, contact=contact, session=session3, status=FlowRun.STATUS_WAITING + ) # create an IVR call with session call = self.create_incoming_call(flow, contact) @@ -3901,14 +3934,24 @@ def test_trim(self): self.assertIsNotNone(run4.session) # end run1 and run4's sessions in the past + run1.status = FlowRun.STATUS_COMPLETED + run1.exited_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) + run1.save(update_fields=("status", "exited_on")) run1.session.status = FlowSession.STATUS_COMPLETED run1.session.ended_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) run1.session.save(update_fields=("status", "ended_on")) + + run4.status = FlowRun.STATUS_INTERRUPTED + run4.exited_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) + run4.save(update_fields=("status", "exited_on")) run4.session.status = FlowSession.STATUS_INTERRUPTED run4.session.ended_on = datetime(2015, 9, 15, 0, 0, 0, 0, pytz.UTC) run4.session.save(update_fields=("status", "ended_on")) # end run2's session now + run2.status = FlowRun.STATUS_EXPIRED + run2.exited_on = timezone.now() + run2.save(update_fields=("status", "exited_on")) run4.session.status = FlowSession.STATUS_EXPIRED run2.session.ended_on = timezone.now() run2.session.save(update_fields=("status", "ended_on")) @@ -3948,7 +3991,9 @@ def create_start(user, start_type, status, modified_on, **kwargs): wait_expires_on=timezone.now() + timedelta(days=7), wait_resume_on_expire=False, ) - FlowRun.objects.create(org=self.org, contact=contact, flow=flow, session=session, start=start) + FlowRun.objects.create( + org=self.org, contact=contact, flow=flow, session=session, start=start, status=FlowRun.STATUS_WAITING + ) FlowStartCount.objects.create(start=start, count=1, is_squashed=False) diff --git a/temba/tests/base.py b/temba/tests/base.py index 240441aee05..1259c9739cc 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -515,7 +515,12 @@ def create_incoming_call(self, flow, contact, status=IVRCall.STATUS_COMPLETED): ended_on=timezone.now(), ) FlowRun.objects.create( - org=self.org, flow=flow, contact=contact, status=FlowRun.STATUS_COMPLETED, session=session + org=self.org, + flow=flow, + contact=contact, + status=FlowRun.STATUS_COMPLETED, + session=session, + exited_on=timezone.now(), ) Msg.objects.create( org=self.org, From 72acd7d5f163d3ef9b99fd97656e8ee8f2693f18 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 12 Jul 2022 14:55:09 +0100 Subject: [PATCH 010/630] Fix tests --- temba/api/v2/tests.py | 50 ++++++++++++++++++++++++------------------- temba/flows/tests.py | 19 ++-------------- temba/orgs/tests.py | 8 ++++++- 3 files changed, 37 insertions(+), 40 deletions(-) diff --git a/temba/api/v2/tests.py b/temba/api/v2/tests.py index 38d1dbd2ef0..ee508eff65d 100644 --- a/temba/api/v2/tests.py +++ b/temba/api/v2/tests.py @@ -543,7 +543,10 @@ def test_pagination(self): # create 1255 test runs (5 full pages of 250 items + 1 partial with 5 items) flow = self.create_flow("Test") - FlowRun.objects.bulk_create([FlowRun(org=self.org, flow=flow, contact=self.joe) for r in range(1255)]) + runs = [] + for r in range(1255): + runs.append(FlowRun(org=self.org, flow=flow, contact=self.joe, status="C", exited_on=timezone.now())) + FlowRun.objects.bulk_create(runs) actual_ids = list(FlowRun.objects.order_by("-pk").values_list("pk", flat=True)) # give them all the same modified_on @@ -2277,11 +2280,11 @@ def test_contact_actions(self, mr_mocks): self.create_group("Developers", query="isdeveloper = YES") other_org_group = self.create_group("Testers", org=self.org2) - # create some "active" runs for some of the contacts - flow = self.get_flow("favorites_v13") - FlowRun.objects.create(org=self.org, flow=flow, contact=contact1) - FlowRun.objects.create(org=self.org, flow=flow, contact=contact2) - FlowRun.objects.create(org=self.org, flow=flow, contact=contact3) + # create some waiting runs for some of the contacts + flow = self.create_flow("Favorites") + MockSessionWriter(contact1, flow).wait().save() + MockSessionWriter(contact2, flow).wait().save() + MockSessionWriter(contact3, flow).wait().save() self.create_incoming_msg(contact1, "Hello") self.create_incoming_msg(contact2, "Hello") @@ -2643,10 +2646,9 @@ def test_flows(self): color.labels.add(reporting) # make it look like joe completed the color flow - run = FlowRun.objects.create(org=self.org, flow=color, contact=self.joe) - run.status = FlowRun.STATUS_COMPLETED - run.exited_on = timezone.now() - run.save(update_fields=("status", "exited_on", "modified_on")) + FlowRun.objects.create( + org=self.org, flow=color, contact=self.joe, status=FlowRun.STATUS_COMPLETED, exited_on=timezone.now() + ) # flow belong to other org self.create_flow("Other", org=self.org2) @@ -3759,18 +3761,22 @@ def test_runs_with_action_results(self): url = reverse("api.v2.runs") self.assertEndpointAccess(url) - flow = self.get_flow("color") - run = FlowRun.objects.create(org=self.org, flow=flow, contact=self.frank) - run.results = { - "manual": { - "created_on": "2019-06-28T06:37:02.628152471Z", - "name": "Manual", - "node_uuid": "6edeb849-1f65-4038-95dc-4d99d7dde6b8", - "value": "", - } - } - run.save(update_fields=("results",)) - + flow = self.create_flow("Test") + FlowRun.objects.create( + org=self.org, + flow=flow, + contact=self.frank, + status=FlowRun.STATUS_COMPLETED, + exited_on=timezone.now(), + results={ + "manual": { + "created_on": "2019-06-28T06:37:02.628152471Z", + "name": "Manual", + "node_uuid": "6edeb849-1f65-4038-95dc-4d99d7dde6b8", + "value": "", + } + }, + ) response = self.fetchJSON(url) resp_json = response.json() diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 0517dfe8377..4fc940b1739 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -1086,31 +1086,16 @@ def test_flow_start_counts(self): for i in range(10): start.contacts.add(self.create_contact("Bob", urns=[f"twitter:bobby{i}"])) - def create_run(contact): - session = FlowSession.objects.create( - uuid=uuid4(), - org=self.org, - contact=contact, - status=FlowSession.STATUS_WAITING, - output_url="http://sessions.com/123.json", - wait_started_on=timezone.now(), - wait_expires_on=timezone.now() + timedelta(days=7), - wait_resume_on_expire=False, - ) - FlowRun.objects.create( - org=self.org, flow=flow, contact=contact, session=session, start=start, status=FlowRun.STATUS_WAITING - ) - # create runs for first 5 for c in start.contacts.order_by("id")[:5]: - create_run(c) + MockSessionWriter(contact=c, flow=flow, start=start).wait().save() # check our count self.assertEqual(FlowStartCount.get_count(start), 5) # create runs for last 5 for c in start.contacts.order_by("id")[5:]: - create_run(c) + MockSessionWriter(contact=c, flow=flow, start=start).wait().save() # check our count self.assertEqual(FlowStartCount.get_count(start), 10) diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 75dcfa6666f..c11dcb4739e 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -831,7 +831,13 @@ def setUp(self): self.org = self.child_org child_flow = self.get_flow("color") - FlowRun.objects.create(org=self.org, flow=child_flow, contact=child_contact) + FlowRun.objects.create( + org=self.org, + flow=child_flow, + contact=child_contact, + status=FlowRun.STATUS_COMPLETED, + exited_on=timezone.now(), + ) # labels for our flows flow_label1 = FlowLabel.create(self.parent_org, self.admin, "Cool Parent Flows") From 61a2168a1705792f5804c6391a9658258f362edd Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 12 Jul 2022 18:14:51 -0700 Subject: [PATCH 011/630] Add workspace selection to account page --- package-lock.json | 14 +++++++------- package.json | 2 +- static/js/urls.js | 1 + temba/orgs/views.py | 6 +++--- templates/orgs/user_account.haml | 29 ++++++++++++++++++++++++++--- templates/spa_frame.haml | 7 ++++++- 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66aea28dc3d..8b429708b72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "license": "AGPL-3.0", "dependencies": { "@nyaruka/flow-editor": "1.17.1", - "@nyaruka/temba-components": "0.28.2", + "@nyaruka/temba-components": "0.29.0", "colorette": "1.2.2", "fa-icons": "0.2.0", "is-core-module": "2.4.0", @@ -89,9 +89,9 @@ } }, "node_modules/@nyaruka/temba-components": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@nyaruka/temba-components/-/temba-components-0.28.2.tgz", - "integrity": "sha512-e1tDTTVhQYWlRasIUp4zbO4YtQhyFmmm2mUqC3xfW2oetuH+LiEKIh4Vzv7hpRBhsAj4BcAI5dJB4oRgSPODAA==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@nyaruka/temba-components/-/temba-components-0.29.0.tgz", + "integrity": "sha512-kiAXeQ1jAgaZAqb3MfTNGsR4GGLMX3QjiFvxSiyQHjxVwYFVpNOmbKoXq3Zvx9NaOvyOSnw7DM1Zi80U5ZOB6A==", "dependencies": { "geojson": "^0.5.0", "highlight.js": "^10.7.1", @@ -2488,9 +2488,9 @@ } }, "@nyaruka/temba-components": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@nyaruka/temba-components/-/temba-components-0.28.2.tgz", - "integrity": "sha512-e1tDTTVhQYWlRasIUp4zbO4YtQhyFmmm2mUqC3xfW2oetuH+LiEKIh4Vzv7hpRBhsAj4BcAI5dJB4oRgSPODAA==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@nyaruka/temba-components/-/temba-components-0.29.0.tgz", + "integrity": "sha512-kiAXeQ1jAgaZAqb3MfTNGsR4GGLMX3QjiFvxSiyQHjxVwYFVpNOmbKoXq3Zvx9NaOvyOSnw7DM1Zi80U5ZOB6A==", "requires": { "geojson": "^0.5.0", "highlight.js": "^10.7.1", diff --git a/package.json b/package.json index 76ab8e30e4a..76a8daedee6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@nyaruka/flow-editor": "1.17.1", - "@nyaruka/temba-components": "0.28.2", + "@nyaruka/temba-components": "0.29.0", "colorette": "1.2.2", "fa-icons": "0.2.0", "is-core-module": "2.4.0", diff --git a/static/js/urls.js b/static/js/urls.js index ded50a6ecf6..71af93abca1 100644 --- a/static/js/urls.js +++ b/static/js/urls.js @@ -22,6 +22,7 @@ window.urls = [ { old: /\/channels\/channel\/read\/(.*)/, new: /\/settings\/channels\/(.*)/ }, { old: /\/channels\/types\/(.*)\/claim/, new: /\/settings\/channel\/(.*)/ }, { old: /\/org\/manage_accounts\/(.*)/, new: /\/settings\/logins/ }, + { old: /\/user\/account\//, new: /\/settings\/account/ }, { old: /\/user\/two_factor_disable\//, new: /\/settings\/authentication\/2fa-disable/ } ] diff --git a/temba/orgs/views.py b/temba/orgs/views.py index 8ed5c4f62e4..fe631e7cb47 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -1233,13 +1233,13 @@ def derive_menu(self): if self.has_org_perm("orgs.org_account"): menu.append( - self.create_menu_item(name=_("Account"), icon="user", href=reverse("orgs.user_account")) + self.create_menu_item(menu_id="account", name=_("Account"), icon="user", href=reverse("orgs.user_account")) ) if self.request.user.settings.two_factor_enabled: menu.append( self.create_menu_item( - name=_("Security"), icon="shield", href=reverse("orgs.user_two_factor_tokens") + menu_id="security", name=_("Security"), icon="shield", href=reverse("orgs.user_two_factor_tokens") ) ) else: @@ -2641,7 +2641,7 @@ def form_valid(self, form): else: # pragma: no cover return self.render_modal_response() - class Choose(SmartFormView): + class Choose(SpaMixin, SmartFormView): class Form(forms.Form): organization = forms.ModelChoiceField(queryset=Org.objects.none(), empty_label=None) diff --git a/templates/orgs/user_account.haml b/templates/orgs/user_account.haml index 8b7a049cac7..9c538023136 100644 --- a/templates/orgs/user_account.haml +++ b/templates/orgs/user_account.haml @@ -1,12 +1,35 @@ {% extends "smartmin/read.html" %} -load temba compress smartmin i18n --block page-title - -trans "User Account" +-block extra-script + {{block.super}} + :javascript + var currentOrg = {{user_org.id}}; + function handleWorkspaceChanged(evt) { + var orgId = evt.target.value.value; + if (orgId != currentOrg) { + showLoading(); + var store = document.querySelector("temba-store"); + store.postUrl("/org/choose/", "organization=" + orgId, {}, 'application/x-www-form-urlencoded').then(function(response) { + var menu = document.querySelector("temba-menu"); + menu.setSelectionPath("settings/account"); + menu.refresh(); + }) + } + } + +-block page-header + .text-xl.w-full.mb-4 + %temba-select.w-full(onchange="handleWorkspaceChanged(event)") + -for org in user_orgs + -if org.id == user_org.id + %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}" selected="true") + -else + %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}") -block content -if not two_factor_enabled - %temba-alert.mb-4(level="error") + %temba-alert.mb-4(level="info") {% url "orgs.user_two_factor_enable" as otp_url %} -blocktrans with brand=brand.name {{brand}} recommends that you enable two factor authentication. diff --git a/templates/spa_frame.haml b/templates/spa_frame.haml index 2db9313afd2..ea73be42def 100644 --- a/templates/spa_frame.haml +++ b/templates/spa_frame.haml @@ -485,6 +485,12 @@ } if (a && a.href) { + if (a.classList.contains("posterize")) { + evt.stopPropagation(); + evt.preventDefault(); + return; + } + evt.stopPropagation(); evt.preventDefault(); @@ -742,7 +748,6 @@ -block page-container -include "includes/frame_top.html" - %temba-modax#shared-modax .ajax-scripts From 2998539a927dc400bdc04f11c4d3ae1907695a37 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 12 Jul 2022 18:14:58 -0700 Subject: [PATCH 012/630] formatting --- temba/orgs/views.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index fe631e7cb47..ddf4bfc0900 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -1233,13 +1233,18 @@ def derive_menu(self): if self.has_org_perm("orgs.org_account"): menu.append( - self.create_menu_item(menu_id="account", name=_("Account"), icon="user", href=reverse("orgs.user_account")) + self.create_menu_item( + menu_id="account", name=_("Account"), icon="user", href=reverse("orgs.user_account") + ) ) if self.request.user.settings.two_factor_enabled: menu.append( self.create_menu_item( - menu_id="security", name=_("Security"), icon="shield", href=reverse("orgs.user_two_factor_tokens") + menu_id="security", + name=_("Security"), + icon="shield", + href=reverse("orgs.user_two_factor_tokens"), ) ) else: From c8f4ed96c6f5f9f420d34021018e62caef5ae28f Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 12 Jul 2022 18:19:36 -0700 Subject: [PATCH 013/630] Only show dropdown if they have access to more than one org --- templates/orgs/user_account.haml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/templates/orgs/user_account.haml b/templates/orgs/user_account.haml index 9c538023136..67287b89e2b 100644 --- a/templates/orgs/user_account.haml +++ b/templates/orgs/user_account.haml @@ -19,13 +19,18 @@ } -block page-header - .text-xl.w-full.mb-4 - %temba-select.w-full(onchange="handleWorkspaceChanged(event)") - -for org in user_orgs - -if org.id == user_org.id - %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}" selected="true") - -else - %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}") + + -if user_orgs|length > 1 + .text-xl.w-full.mb-4 + %temba-select.w-full(onchange="handleWorkspaceChanged(event)") + -for org in user_orgs + -if org.id == user_org.id + %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}" selected="true") + -else + %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}") + - else + {{block.super}} + -block content -if not two_factor_enabled From f37fd1d7e3099818002769964c41a6abe3a8ad47 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 12 Jul 2022 18:28:43 -0700 Subject: [PATCH 014/630] Show zeros in menu items --- temba/orgs/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index 8ed5c4f62e4..14d37eed09d 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -1139,7 +1139,7 @@ def create_menu_item( if icon: menu_item["icon"] = icon - if count: # pragma: no cover + if count is not None: menu_item["count"] = count if endpoint: From bd8f0bf1d0f5d085e2f6a9168a43d8c4a7c61ca6 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Wed, 13 Jul 2022 14:15:27 -0700 Subject: [PATCH 015/630] Add start flow bulk action in new interface --- templates/contacts/contact_list.haml | 20 ++++++++++++-------- templates/frame.haml | 1 + templates/includes/short_pagination.haml | 7 ++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/templates/contacts/contact_list.haml b/templates/contacts/contact_list.haml index aa8c2e34dfe..44ed08a6615 100644 --- a/templates/contacts/contact_list.haml +++ b/templates/contacts/contact_list.haml @@ -188,11 +188,9 @@ -trans "Send" -if org_perms.flows.flow_broadcast - %temba-modax#start-flow(header='{{_("Start Flow")|escapejs}}' endpoint="{% url 'flows.flow_broadcast' %}") - .button-action.no-loading(onclick="handleStartFlowClicked()") - .mr-2.glyph.icon-flow(style="font-size:14px") - -trans "Start Flow" - + .button-action.no-loading(onclick="handleStartFlowClicked(event)") + .mr-2.glyph.icon-flow(style="font-size:14px") + -trans "Start Flow" .flex-grow.ml-1.self-end.items-end .flex.flex-col.pr-12 @@ -293,16 +291,22 @@ {% endif %} } - function handleStartFlowClicked() { - // when we click send, include any clicked messages in our modax request + function handleStartFlowClicked(evt) { + var sendEndpoint = "{% url 'flows.flow_broadcast' %}"; - var startModal = document.querySelector("#start-flow"); + var startModal = document.querySelector("#shared-modax, #start-modal"); + + startModal.header = '{{_("Start Flow")|escapejs}}'; var ids = getCheckedUuids(); if (ids.length > 0) { startModal.setAttribute("endpoint", sendEndpoint + '?c=' + ids); } else { startModal.setAttribute("endpoint", sendEndpoint); } + startModal.open = true; + + evt.preventDefault(); + evt.stopPropagation(); } function handleSendMessageClicked() { diff --git a/templates/frame.haml b/templates/frame.haml index 4a80fc2008e..e50126ceed5 100644 --- a/templates/frame.haml +++ b/templates/frame.haml @@ -237,6 +237,7 @@ -block post-header -block page-container + %temba-modax#shared-modax .flex-grow .page-content -block suspension diff --git a/templates/includes/short_pagination.haml b/templates/includes/short_pagination.haml index 49279ee7358..abe319de50b 100644 --- a/templates/includes/short_pagination.haml +++ b/templates/includes/short_pagination.haml @@ -77,7 +77,12 @@ .linked.ml-4(onclick='runActionOnObjectRows("block")') %temba-tip(position="top" text='{{_("Block")|escapejs}}') %temba-icon.show-loading(name="slash" clickable="true") - + + -if org_perms.flows.flow_broadcast + .linked.ml-4(onclick='handleStartFlowClicked(event)') + %temba-tip(position="top" text='{{_("Start Flow")|escapejs}}') + %temba-icon.show-loading(name="flow" clickable="true") + .paging-range.mr-4 -blocktrans trimmed with start=page_obj.start_index|intcomma end=page_obj.end_index|intcomma total=paginator.count|intcomma {{ start }} - {{ end }} of {{ total }} From 58fa799162d0a28853ac69dd23616e142c82d8bc Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Wed, 13 Jul 2022 14:20:51 -0700 Subject: [PATCH 016/630] Switch field label to name --- templates/contacts/contact_list_spa.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/contacts/contact_list_spa.haml b/templates/contacts/contact_list_spa.haml index 85d45671789..7eea6d8e9ed 100644 --- a/templates/contacts/contact_list_spa.haml +++ b/templates/contacts/contact_list_spa.haml @@ -54,17 +54,17 @@ -if sort_direction == 'desc' %a(href="{{request.path}}?sort_on={{ field.key }}{% if search %}&search={{ search|escape }}{% endif %}") %div - {{ field.label }} + {{ field.name }} %span.sort.icon.icon-arrow-down-2.sort-asc.visible -else %a(href="{{request.path}}?sort_on=-{{ field.key }}{% if search %}&search={{ search|escape }}{% endif %}") %div - {{ field.label }} + {{ field.name }} %span.sort.icon.icon-arrow-up51.sort-desc.visible -else %a(href="{{request.path}}?sort_on=-{{ field.key }}{% if search %}&search={{ search|escape }}{% endif %}") %div - {{ field.label }} + {{ field.name }} %span.sort.icon.icon-arrow-down-2.sort-desc %th.px-6.py-3.pt-4.border-b.border-gray-200.bg-gray-100.text-left.font-medium.uppercase.text-xs.tracking-wider - if object_list From e0dc082bf1b2969373741511e889437eb61ad2df Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Fri, 1 Jul 2022 15:07:24 -0300 Subject: [PATCH 017/630] tweaks in slack config, tests and validation --- temba/channels/types/slack/tests.py | 56 ++++++++++++++-------- temba/channels/types/slack/views.py | 23 ++++----- templates/channels/types/slack/claim.haml | 13 +++-- templates/channels/types/slack/config.haml | 41 ++++++++++++++-- 4 files changed, 91 insertions(+), 42 deletions(-) diff --git a/temba/channels/types/slack/tests.py b/temba/channels/types/slack/tests.py index cbdc37a931a..95b9325708d 100644 --- a/temba/channels/types/slack/tests.py +++ b/temba/channels/types/slack/tests.py @@ -13,10 +13,11 @@ class SlackTypeTest(TembaTest): def setUp(self): super().setUp() - self.channel = self.create_channel( + self.create_channel( "SL", - "Slack", - "12345", + "Slack12345", + "B0T12345", + org=self.org2, config={ "user_token": "123456789:ABCDEFabcdef-1a2b3c4d", "bot_token": "123456789:ABCDEFabcdef-1a2b3c4d", @@ -38,20 +39,6 @@ def test_claim(self, mock_api_call): response = self.client.get(url) self.assertContains(response, "Connect Slack") - # claim with already used user_token and bot_token - response = self.client.post(url, {"user_token": "123456789:ABCDEFabcdef-1a2b3c4d"}) - print(response) - self.assertEqual( - "A slack channel for this bot already exists.", - response.context["form"].errors["user_token"][0], - ) - response = self.client.post(url, {"bot_token": "123456789:ABCDEFabcdef-1a2b3c4d"}) - print(response) - self.assertEqual( - "A slack channel for this bot already exists.", - response.context["form"].errors["bot_token"][0], - ) - # claim with invalid token mock_api_call.side_effect = slack_sdk.errors.SlackApiError("", "") response = self.client.post(url, {"user_token": "invalid"}) @@ -69,6 +56,35 @@ def test_claim(self, mock_api_call): response.context["form"].errors["bot_token"][0], ), + # test to claim a channel with a bot token that already exists for another organization + auth_test = { + "ok": True, + "url": "https://12345-team-group.slack.com/", + "team": "12345-team", + "user": "dummy", + "team_id": "T012345", + "user_id": "U012345", + "bot_id": "B0T12345", + "is_enterprise_install": False, + } + + mock_api_call.side_effect = None + mock_api_call.return_value = auth_test + + response = self.client.post( + url, + { + "user_token": "123456789:ABCDEFabcdef-1a2b3c4d", + "bot_token": "123456789:ABCDEFabcdef-1a2b3c4d", + "verification_token": "123456789:ABCDEFabcdef-1a2b3c4d", + }, + ) + self.assertEqual( + "A slack channel for this bot already exists in another organization.", + response.context["form"].errors["bot_token"][0], + ) + + # test claim a channel with success auth_test = { "ok": True, "url": "https://dummy-team-group.slack.com/", @@ -102,12 +118,14 @@ def test_claim(self, mock_api_call): }, ), + # test access config page config_url = reverse("channels.channel_configuration", args=[channel.uuid]) self.assertRedirect(response, config_url) response = self.client.get(config_url) self.assertEqual(response.status_code, 200) + # test to claim a channel with a bot token that already exists in this organization response = self.client.post( url, { @@ -117,8 +135,8 @@ def test_claim(self, mock_api_call): }, ) self.assertEqual( - "A slack channel for this bot already exists.", - response.context["form"].errors["user_token"][0], + "A slack channel for this bot already exists in this organization.", + response.context["form"].errors["bot_token"][0], ) contact = self.create_contact("Slack User", urns=["slack:1234"]) diff --git a/temba/channels/types/slack/views.py b/temba/channels/types/slack/views.py index 5cc9bad955a..f7148befc71 100644 --- a/temba/channels/types/slack/views.py +++ b/temba/channels/types/slack/views.py @@ -33,12 +33,6 @@ class Form(ClaimViewMixin.Form): def clean_user_token(self): value = self.cleaned_data["user_token"] - existing = Channel.objects.filter( - is_active=True, channel_type=self.channel_type.code, config__contains=value - ).first() - if existing: - raise ValidationError(_("A slack channel for this bot already exists.")) - try: client = slack_sdk.WebClient(token=value) client.api_call(api_method="auth.test") @@ -50,18 +44,21 @@ def clean_user_token(self): def clean_bot_token(self): value = self.cleaned_data["bot_token"] - existing = Channel.objects.filter( - is_active=True, channel_type=self.channel_type.code, config__contains=value - ).first() - if existing: - raise ValidationError(_("A slack channel for this bot already exists.")) - try: client = slack_sdk.WebClient(token=value) - client.api_call(api_method="auth.test") + appAuthTest = client.api_call(api_method="auth.test") except slack_sdk.errors.SlackApiError: raise ValidationError(_("Your bot user token is invalid, please check and try again")) + existing = Channel.objects.filter( + is_active=True, channel_type=self.channel_type.code, address=appAuthTest["bot_id"] + ).first() + + if existing: + if existing.org_id == self.request.user.get_org().id: + raise ValidationError(_("A slack channel for this bot already exists in this organization.")) + raise ValidationError(_("A slack channel for this bot already exists in another organization.")) + return value def form_valid(self, form): diff --git a/templates/channels/types/slack/claim.haml b/templates/channels/types/slack/claim.haml index ff6f8c04566..35d7a201279 100644 --- a/templates/channels/types/slack/claim.haml +++ b/templates/channels/types/slack/claim.haml @@ -3,22 +3,21 @@ -block pre-form -blocktrans trimmed with name=brand.name - You can connect a Slack Bot to your {{name}} workspace to automate sending and receiving messages. + You can connect a Slack Bot to your {{name}} workspace to automate sending and receiving messages. -blocktrans trimmed To do it, you will need to create a new slack app and configure it. + -blocktrans trimmed + If you want to better understand these steps, read this guide here please. + %ol.steps.card %li -blocktrans trimmed - You'll need to create a Slack App if you haven't already. + You'll need to create a Slack App if you haven't already. %li -blocktrans trimmed Setup a bot to your Slack App, add the needed scopes for Bot Token (chat:write, files:read, files:write, users:read), User Token (files:read and files:write) and install app on your slack workspace. %li -blocktrans trimmed - Fill this form, submit and go redirected to config page. - %li - -blocktrans trimmed - Copy Request URL from channel config page, go to slack Event Subscriptions page, enable Events, paste Request URL into input field and subscribe to bot events (file_created, message.im). - If you need help how to do all this steps, read this guide here please. + Fill this form, submit and go redirected to new channel's configuration to finish connection. diff --git a/templates/channels/types/slack/config.haml b/templates/channels/types/slack/config.haml index 53f9e061a48..599b08779b3 100644 --- a/templates/channels/types/slack/config.haml +++ b/templates/channels/types/slack/config.haml @@ -1,11 +1,46 @@ -load i18n -blocktrans trimmed - To finish configuring your connection you'll need to set the following callback URL on your app - Event Subscription Request URL.More info. + To finish configuring your connection, you'll need to set the following callback URL on your app + Event Subscription Request URL and enable users to send messages to bot. + More info. .card.mt-6 .title -trans "Request URL" .code.inline-block.m-0 - https://{{ channel.callback_domain }}/c/sl/{{ channel.uuid }}/receive/ \ No newline at end of file + https://{{ channel.callback_domain }}/c/sl/{{ channel.uuid }}/receive/ + + +%h3 + -blocktrans trimmed + How to setup Request URL and subscribe to events: + +%ol.steps.card + %li + -blocktrans trimmed + Copy Request URL, access https://api.slack.com/apps and select your bot app. + %li + -blocktrans trimmed + From left side menu Features, access Event Subscriptions page, enable Events and paste Request URL into input field. + %li + -blocktrans trimmed + On Events Subscriptions page, Subscribe to bot events (file_created, message.im). + %li + -blocktrans trimmed + Save the changes and then you will be asked to reinstall the app to your slack workspace to complete events subscription. + +%h3 + -blocktrans trimmed + How to enable users to send messages to bot on slack workspace: + +%ol.steps.card + %li + -blocktrans trimmed + Access https://api.slack.com/apps, select your bot app. + %li + -blocktrans trimmed + From left side menu Features, access App Home, in "Show Tabs" card section, turn on "Messages Tab". + %li + -blocktrans trimmed + When Messages Tab is activated, will appear a checkbox, so check it to (Allow users to send Slash commands and messages from the messages tab). From 444899137b2710595d1d21a68980146189860844 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 14 Jul 2022 18:26:17 -0700 Subject: [PATCH 018/630] Refresh menu on modax redircts, omit excess listeners from legacy lists --- static/js/labels.js | 39 +++++++++----------- temba/campaigns/views.py | 7 +++- temba/msgs/views.py | 2 +- temba/triggers/views.py | 5 +-- templates/campaigns/campaign_list_spa.haml | 4 +- templates/contacts/contact_list.haml | 18 ++++----- templates/contacts/contact_list_include.haml | 8 ++-- templates/contacts/contactgroup_list.haml | 2 +- templates/gear_links_include.haml | 2 +- templates/includes/short_pagination.haml | 10 ++--- templates/msgs/message_box.haml | 17 +++++---- templates/spa_frame.haml | 10 ++++- 12 files changed, 68 insertions(+), 56 deletions(-) diff --git a/static/js/labels.js b/static/js/labels.js index e36d4cb6ca2..1a1fe8db3ce 100644 --- a/static/js/labels.js +++ b/static/js/labels.js @@ -43,18 +43,16 @@ function getObjectRowLabels(objectId) { return labelIds.sort(numericComparator); } -function runActionOnObjectRows(action) { +function runActionOnObjectRows(action, onSuccess) { var objectIds = getCheckedIds(); jQuery.ajaxSettings.traditional = true; fetchPJAXContent(window.lastFetch || '', '#pjax', { postData: { objects: objectIds, action: action, pjax: 'true' }, - onSuccess: function (data, textStatus) { - wireTableListeners(); - }, + onSuccess: onSuccess, }); } -function unlabelObjectRows(labelId) { +function unlabelObjectRows(labelId, onSuccess) { var objectsIds = getCheckedIds(); var addLabel = false; @@ -67,11 +65,11 @@ function unlabelObjectRows(labelId) { action: 'unlabel', pjax: 'true', }, - onSuccess: wireTableListeners, + onSuccess: onSuccess, }); } -function postLabelChanges(smsIds, labelId, addLabel, number, onError) { +function postLabelChanges(smsIds, labelId, addLabel, number, onError, onSuccess) { fetchPJAXContent(window.lastFetch || '', '#pjax', { postData: { objects: smsIds, @@ -83,17 +81,16 @@ function postLabelChanges(smsIds, labelId, addLabel, number, onError) { }, onSuccess: function (data, textStatus) { recheckIds(); - wireTableListeners(); + if (onSuccess) { + onSuccess(); + } }, onError: onError, }); } -function labelObjectRows(labelId) { - labelObjectRows(labelId, false); -} +function labelObjectRows(labelId, forceRemove, onSuccess) { -function labelObjectRows(labelId, forceRemove) { var objectRowsIds = getCheckedIds(); var labeledIds = getLabeledIds(labelId); @@ -137,7 +134,7 @@ function labelObjectRows(labelId, forceRemove) { return; } - postLabelChanges(objectRowsIds, labelId, addLabel); + postLabelChanges(objectRowsIds, labelId, addLabel, null, null, onSuccess); } /** @@ -280,39 +277,39 @@ function handleRowSelections(row) { function wireActionHandlers() { $('.page-content').on('click', '.object-btn-label', function () { - labelObjectRows($(this).data('id')); + labelObjectRows($(this).data('id'), false, wireTableListeners); }); if ($('.object-btn-unlabel').length > 0) { if (current_label_id) { $('.page-content').on('click', '.object-btn-unlabel', function () { - labelObjectRows(current_label_id, true); + labelObjectRows(current_label_id, true, wireTableListeners); }); } } $('.page-content').on('click', '.object-btn-restore', function () { - runActionOnObjectRows('restore'); + runActionOnObjectRows('restore', wireTableListeners); }); $('.page-content').on('click', '.object-btn-archive', function () { - runActionOnObjectRows('archive'); + runActionOnObjectRows('archive', wireTableListeners); }); $('.page-content').on('click', '.object-btn-delete', function () { - runActionOnObjectRows('delete'); + runActionOnObjectRows('delete', wireTableListeners); }); $('.page-content').on('click', '.object-btn-resend', function () { - runActionOnObjectRows('resend'); + runActionOnObjectRows('resend', wireTableListeners); }); $('.page-content').on('click', '.object-btn-close', function () { - runActionOnObjectRows('close'); + runActionOnObjectRows('close', wireTableListeners); }); $('.page-content').on('click', '.object-btn-reopen', function () { - runActionOnObjectRows('reopen'); + runActionOnObjectRows('reopen', wireTableListeners); }); } diff --git a/temba/campaigns/views.py b/temba/campaigns/views.py index d0b0b699e89..83b0861a821 100644 --- a/temba/campaigns/views.py +++ b/temba/campaigns/views.py @@ -54,12 +54,15 @@ class CampaignCRUDL(SmartCRUDL): class Menu(MenuMixin, SmartTemplateView): def derive_menu(self): + org = self.request.user.get_org() + menu = [] menu.append( self.create_menu_item( menu_id="active", name=_("Active"), icon="campaign", + count=org.campaigns.filter(is_active=True, is_archived=False).count(), href="campaigns.campaign_list", ) ) @@ -69,6 +72,7 @@ def derive_menu(self): menu_id="archived", name=_("Archived"), icon="archive", + count=org.campaigns.filter(is_active=True, is_archived=True).count(), href="campaigns.campaign_archived", ) ) @@ -216,7 +220,8 @@ class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartLi def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["org_has_campaigns"] = Campaign.objects.filter(org=self.request.user.get_org()).count() - context["folders"] = self.get_folders() + if not self.is_spa(): + context["folders"] = self.get_folders() context["request_url"] = self.request.path return context diff --git a/temba/msgs/views.py b/temba/msgs/views.py index 004c8197779..d963a754a85 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -957,7 +957,7 @@ def render_to_response(self, context, **response_kwargs): class Create(ModalMixin, OrgPermsMixin, SmartCreateView): fields = ("name", "messages") - success_url = "hide" + success_url = "uuid@msgs.msg_filter" form_class = LabelForm success_message = "" submit_button_name = _("Create") diff --git a/temba/triggers/views.py b/temba/triggers/views.py index fc75bff5838..b82a5a34af1 100644 --- a/temba/triggers/views.py +++ b/temba/triggers/views.py @@ -215,12 +215,11 @@ def derive_menu(self): from .types import TYPES_BY_SLUG - org_triggers = org.triggers.filter(is_active=True, is_archived=False) - + org_triggers = org.triggers.filter(is_active=True) menu.append( self.create_menu_item( name=_("Active"), - count=org_triggers.count(), + count=org_triggers.filter(is_archived=False).count(), href=reverse("triggers.trigger_list"), icon="radio", ) diff --git a/templates/campaigns/campaign_list_spa.haml b/templates/campaigns/campaign_list_spa.haml index 98489ae0f76..18fc390c81f 100644 --- a/templates/campaigns/campaign_list_spa.haml +++ b/templates/campaigns/campaign_list_spa.haml @@ -18,7 +18,7 @@ return; } var row = event.target.closest("tr"); - var id = row.getAttribute("data-object-id"); + var id = row.getAttribute("data-uuid"); fetchURL("/campaign/read/" + id + "/"); } @@ -49,7 +49,7 @@ %table.list.lined.selectable.scrolled %tbody -for obj in object_list - %tr.campaign.object-row.select-row(data-object-id="{{ obj.uuid }}" onclick='handleRowClicked(event)') + %tr.campaign.object-row.select-row(data-object-id="{{ obj.id }}" data-uuid="{{ obj.uuid }}" onclick='handleRowClicked(event)') - if org_perms.campaigns.campaign_update %td.campaign.checkbox.object-row-checkbox %temba-checkbox{onclick:"handleRowSelection(this)"} diff --git a/templates/contacts/contact_list.haml b/templates/contacts/contact_list.haml index aa8c2e34dfe..c167c51584b 100644 --- a/templates/contacts/contact_list.haml +++ b/templates/contacts/contact_list.haml @@ -94,7 +94,7 @@ .secondary-buttons.mb-6 -if org_perms.contacts.contact_create - %temba-modax#create-label-modal(header='{% trans "Create Contact" %}' endpoint="{% url 'contacts.contact_create' %}") + %temba-modax#create-contact-modal(header='{% trans "Create Contact" %}' endpoint="{% url 'contacts.contact_create' %}") .button-light.block.mt-3 -trans "Create Contact" @@ -136,17 +136,17 @@ .list-buttons.flex.items-center.-mx-2.h-full -if 'restore' in actions - .button-action(onclick='runActionOnObjectRows("restore")') + .button-action(onclick='runActionOnObjectRows("restore", wireTableListeners)') .-mt-1.mr-2.glyph.icon-checkmark -trans "Activate" -if 'block' in actions - .button-action(onclick='runActionOnObjectRows("block")') + .button-action(onclick='runActionOnObjectRows("block", wireTableListeners)') .-mt-1.mr-2.glyph.icon-user-block -trans "Block" -if 'archive' in actions - .button-action(onclick='runActionOnObjectRows("archive")') + .button-action(onclick='runActionOnObjectRows("archive", wireTableListeners)') .-mt-1.mr-2.glyph.icon-box -trans "Archive" @@ -156,7 +156,7 @@ -trans "Delete" -if 'unlabel' in actions - .button-action(onclick="unlabelObjectRows({{current_group.pk}});") + .button-action(onclick="unlabelObjectRows({{current_group.pk}}, wireTableListeners);") .-mt-1.mr-2.glyph.icon-user-remove -trans "Remove From Group" @@ -251,7 +251,7 @@ deleteConfirmation.addEventListener("temba-button-clicked", function(event){ if (!event.detail.button.secondary) { - runActionOnObjectRows("delete"); + runActionOnObjectRows("delete", wireTableListeners); } deleteConfirmation.open = false; }); @@ -341,16 +341,16 @@ {% if org_perms.contacts.contact_block %} $(".lp-frame").on('click', ".object-btn-unblock", function() { - runActionOnObjectRows("unblock"); + runActionOnObjectRows("unblock", wireTableListeners); }); $(".lp-frame").on('click', ".object-btn-block", function() { - runActionOnObjectRows("block"); + runActionOnObjectRows("block", wireTableListeners); }); {% endif %} {% if org_perms.contacts.contact_unstop %} $(".lp-frame").on('click', ".object-btn-unstop", function() { - runActionOnObjectRows("unstop"); + runActionOnObjectRows("unstop", wireTableListeners); }); {% endif %} diff --git a/templates/contacts/contact_list_include.haml b/templates/contacts/contact_list_include.haml index b34d63ee152..697667d4efe 100644 --- a/templates/contacts/contact_list_include.haml +++ b/templates/contacts/contact_list_include.haml @@ -9,17 +9,17 @@ .list-buttons.flex.items-center.-mx-2.h-full -if 'restore' in actions - .button-action(onclick='runActionOnObjectRows("restore")') + .button-action(onclick='runActionOnObjectRows("restore", wireTableListeners)') .-mt-1.mr-2.glyph.icon-checkmark -trans "Activate" -if 'block' in actions - .button-action(onclick='runActionOnObjectRows("block")') + .button-action(onclick='runActionOnObjectRows("block", wireTableListeners)') .-mt-1.mr-2.glyph.icon-user-block -trans "Block" -if 'archive' in actions - .button-action(onclick='runActionOnObjectRows("archive")') + .button-action(onclick='runActionOnObjectRows("archive", wireTableListeners)') .-mt-1.mr-2.glyph.icon-box -trans "Archive" @@ -29,7 +29,7 @@ -trans "Delete" -if 'unlabel' in actions - .button-action(onclick="unlabelObjectRows({{current_group.pk}});") + .button-action(onclick="unlabelObjectRows({{current_group.pk}}, wireTableListeners);") .-mt-1.mr-2.glyph.icon-user-remove -trans "Remove From Group" diff --git a/templates/contacts/contactgroup_list.haml b/templates/contacts/contactgroup_list.haml index 66bea42eba5..298ee537ebe 100644 --- a/templates/contacts/contactgroup_list.haml +++ b/templates/contacts/contactgroup_list.haml @@ -10,7 +10,7 @@ deleteConfirmation.open = true; deleteConfirmation.addEventListener("temba-button-clicked", function(event){ if (!event.detail.button.secondary) { - runActionOnObjectRows("delete"); + runActionOnObjectRows("delete", wireTableListeners); } deleteConfirmation.open = false; }); diff --git a/templates/gear_links_include.haml b/templates/gear_links_include.haml index 6e62cb38401..162046fdf04 100644 --- a/templates/gear_links_include.haml +++ b/templates/gear_links_include.haml @@ -88,7 +88,7 @@ function showModax(endpoint) { const modax = document.querySelector("temba-modax[id='" + endpoint + "']"); if(modax) { - modax.setAttribute("open", "true"); + modax.open = true; } } diff --git a/templates/includes/short_pagination.haml b/templates/includes/short_pagination.haml index 49279ee7358..84df7f9cc11 100644 --- a/templates/includes/short_pagination.haml +++ b/templates/includes/short_pagination.haml @@ -32,7 +32,7 @@ %temba-icon(name="tag" clickable="true") .label-menu.px-6.py-4(slot="dropdown") -for label in labels_flat - .lbl-menu(onclick='labelObjectRows({{label.id}})' data-id='{{label.id}}') + .lbl-menu(onclick='labelObjectRows({{label.id}}, false, refreshMenu)' data-id='{{label.id}}') .flex.items-center.py-1.hover-linked .glyph.message-label.label-checkbox .name.px-1 @@ -47,12 +47,12 @@ -if 'restore' in actions - .linked.ml-4(onclick='runActionOnObjectRows("restore")') + .linked.ml-4(onclick='runActionOnObjectRows("restore", refreshMenu)') %temba-tip(position="top" text='{{_("Reactivate")|escapejs}}') %temba-icon.show-loading(name="publish" size="1.2" clickable="true") -if 'archive' in actions - .linked.ml-4(onclick='runActionOnObjectRows("archive")') + .linked.ml-4(onclick='runActionOnObjectRows("archive", refreshMenu)') %temba-tip(position="top" text='{{_("Archive")|escapejs}}') %temba-icon.show-loading(name="archive" clickable="true") @@ -69,12 +69,12 @@ %temba-icon(name="trash-2" clickable="true") -if 'unlabel' in actions - .linked.ml-4(onclick="unlabelObjectRows({{current_group.pk}});") + .linked.ml-4(onclick="unlabelObjectRows({{current_group.pk}}, false, refreshMenu);") %temba-tip(position="top" text='{{_("Remove from group")|escapejs}}') %temba-icon.show-loading(name="x" clickable="true") -if 'block' in actions - .linked.ml-4(onclick='runActionOnObjectRows("block")') + .linked.ml-4(onclick='runActionOnObjectRows("block", refreshMenu)') %temba-tip(position="top" text='{{_("Block")|escapejs}}') %temba-icon.show-loading(name="slash" clickable="true") diff --git a/templates/msgs/message_box.haml b/templates/msgs/message_box.haml index d088443b7ae..bfb9c8a15e0 100644 --- a/templates/msgs/message_box.haml +++ b/templates/msgs/message_box.haml @@ -102,12 +102,12 @@ -trans "Remove Label" - if 'archive' in actions - .button-action(onclick='runActionOnObjectRows("archive")') + .button-action(onclick='runActionOnObjectRows("archive, wireTableListeners)') .-mt-1.mr-2.glyph.icon-box -trans "Archive" - if 'restore' in actions - .button-action(onclick='runActionOnObjectRows("restore")') + .button-action(onclick='runActionOnObjectRows("restore", wireTableListeners)') .-mt-1.mr-2.glyph.icon-download -trans "Restore" @@ -117,7 +117,7 @@ -trans "Delete" - if 'resend' in actions - .button-action(onclick='runActionOnObjectRows("resend")') + .button-action(onclick='runActionOnObjectRows("resend", wireTableListeners)') .mt-1.mr-2.glyph.icon-loop.text-sm -trans "Resend" @@ -131,7 +131,7 @@ -for node in labels -if node.obj.is_folder and node.children %li.dropdown-submenu - .lbl-menu.cursor-pointer(href='#' onclick='labelObjectRows({{node.obj.id}})' data-id='{{node.obj.id}}') + .lbl-menu.cursor-pointer(href='#' onclick='labelObjectRows({{node.obj.id}}, false, wireTableListeners)' data-id='{{node.obj.id}}') .flex.items-center.py-1.hover-linked .icon-arrow-right-8.text-2xl.-ml-1.-mt-1.mr-1 .name.px-2 @@ -139,7 +139,7 @@ %ul.dropdown-menu.label-menu.border-none - for child in node.children %li - .lbl-menu.object-btn-label.px-4(href='#' onclick='labelObjectRows({{child.obj.id}})' data-id='{{child.obj.id}}') + .lbl-menu.object-btn-label.px-4(href='#' onclick='labelObjectRows({{child.obj.id}}, false, wireTableListeners)' data-id='{{child.obj.id}}') .flex.items-center.py-1.hover-linked .glyph.message-label.label-checkbox .name.px-1 @@ -147,7 +147,7 @@ -for node in labels -if not node.obj.is_folder %li - .lbl-menu(href='#' onclick='labelObjectRows({{node.obj.id}})' data-id='{{node.obj.id}}') + .lbl-menu(href='#' onclick='labelObjectRows({{node.obj.id}}, false, wireTableListeners)' data-id='{{node.obj.id}}') .flex.items-center.py-1.hover-linked .glyph.message-label.label-checkbox .name.px-1 @@ -277,7 +277,7 @@ deleteConfirmation.addEventListener("temba-button-clicked", function(event){ if (!event.detail.button.secondary) { - runActionOnObjectRows("delete"); + runActionOnObjectRows("delete", wireTableListeners); } deleteConfirmation.open = false; }); @@ -291,6 +291,9 @@ function handleCreateLabelModalSubmitted(event) { refresh(function() { recheckIds(); }, true); + if (refreshMenu) { + refreshMenu(); + } } function handleSendMessageClicked() { diff --git a/templates/spa_frame.haml b/templates/spa_frame.haml index 2db9313afd2..7e9c8390e89 100644 --- a/templates/spa_frame.haml +++ b/templates/spa_frame.haml @@ -588,6 +588,13 @@ document.title = spaTitle || ""; } + function refreshMenu() { + var menu = document.querySelector("temba-menu"); + if (menu) { + menu.refresh(); + } + } + function hideLoading() { var container = document.querySelector(".spa-container"); if (container) { @@ -703,7 +710,6 @@ } function showModax(header, endpoint, onSubmit) { - var modax = document.querySelector("temba-modax#shared-modax"); if (onSubmit) { modax["-temba-submitted"] = Function(onSubmit); @@ -711,6 +717,8 @@ modax["-temba-submitted"] = undefined; } + modax["-temba-redirected"] = refreshMenu; + modax.header = header; modax.endpoint = endpoint; modax.headers = { "TEMBA-SPA": 1} From 581a2e4245f3427c6d09f0b7b24343cf8111018b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 18 Jul 2022 09:16:35 -0500 Subject: [PATCH 019/630] Add Contact.open_ticket which uses a ticket modifier --- temba/contacts/models.py | 43 ++++++++++++++++++++++++------------- temba/contacts/tests.py | 11 ++++++++++ temba/mailroom/modifiers.py | 28 ++++++++++++++++++++++++ temba/tests/mailroom.py | 14 ++++++++++++ 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 03536dbe81a..05404aa3995 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -660,6 +660,21 @@ def resolve(cls, channel, urn): contact_urn = ContactURN.objects.get(id=response["urn"]["id"]) return contact, contact_urn + @classmethod + def from_urn(cls, org, urn_as_string, country=None): + """ + Looks up a contact by a URN string (which will be normalized) + """ + try: + urn_obj = ContactURN.lookup(org, urn_as_string, country) + except ValueError: + return None + + if urn_obj and urn_obj.contact and urn_obj.contact.is_active: + return urn_obj.contact + else: + return None + @property def anon_identifier(self): """ @@ -997,21 +1012,6 @@ def modified(contact): return [c.id for c in contacts if modified(c)] - @classmethod - def from_urn(cls, org, urn_as_string, country=None): - """ - Looks up a contact by a URN string (which will be normalized) - """ - try: - urn_obj = ContactURN.lookup(org, urn_as_string, country) - except ValueError: - return None - - if urn_obj and urn_obj.contact and urn_obj.contact.is_active: - return urn_obj.contact - else: - return None - @classmethod def bulk_change_status(cls, user, contacts, status): cls.bulk_modify(user, contacts, [modifiers.Status(status=status)]) @@ -1053,6 +1053,19 @@ def apply_action_delete(cls, user, contacts): on_transaction_commit(lambda: release_contacts.delay(user.id, [c.id for c in contacts])) + def open_ticket(self, user, ticketer, topic, body: str, assignee=None): + """ + Opens a new ticket for this contact. + """ + mod = modifiers.Ticket( + ticketer=modifiers.TicketerRef(uuid=str(ticketer.uuid), name=ticketer.name), + topic=modifiers.TopicRef(uuid=str(topic.uuid), name=topic.name), + body=body, + assignee=modifiers.UserRef(email=assignee.email, name=assignee.name) if assignee else None, + ) + self.modify(user, [mod]) + return self.tickets.order_by("id").last() + def block(self, user): """ Blocks this contact removing it from all non-smart groups diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index a929c00e8bf..d425c810a3a 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -1547,6 +1547,17 @@ def test_block_and_stop(self, mock_contact_modify): ) mock_contact_modify.reset_mock() + @mock_mailroom + def test_open_ticket(self, mock_contact_modify): + mock_contact_modify.return_value = {self.joe.id: {"contact": {}, "events": []}} + + ticket = self.joe.open_ticket( + self.admin, self.org.ticketers.get(), self.org.default_ticket_topic, "Looks sus", assignee=self.agent + ) + + self.assertEqual(self.org.default_ticket_topic, ticket.topic) + self.assertEqual("Looks sus", ticket.body) + @mock_mailroom def test_release(self, mr_mocks): # create a contact with a message diff --git a/temba/mailroom/modifiers.py b/temba/mailroom/modifiers.py index 79625ac9180..d6aa685e4af 100644 --- a/temba/mailroom/modifiers.py +++ b/temba/mailroom/modifiers.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field +from typing import Optional @dataclass(frozen=True) @@ -13,6 +14,24 @@ class GroupRef: name: str +@dataclass(frozen=True) +class TicketerRef: + uuid: str + name: str + + +@dataclass(frozen=True) +class TopicRef: + uuid: str + name: str + + +@dataclass(frozen=True) +class UserRef: + email: str + name: str + + @dataclass(frozen=True) class Modifier: type: str @@ -55,6 +74,15 @@ class Groups(Modifier): modification: str +@dataclass(frozen=True) +class Ticket(Modifier): + type: str = field(default="ticket", init=False) + ticketer: TicketerRef + topic: TopicRef + body: str + assignee: Optional[UserRef] + + @dataclass(frozen=True) class URNs(Modifier): type: str = field(default="urns", init=False) diff --git a/temba/tests/mailroom.py b/temba/tests/mailroom.py index ae295b325fa..4f5d7aa7d5e 100644 --- a/temba/tests/mailroom.py +++ b/temba/tests/mailroom.py @@ -369,6 +369,20 @@ def apply_modifiers(org, user, contacts, modifiers: list): for contact in contacts: update_groups_locally(contact, [g.uuid for g in mod.groups], add=add) + elif mod.type == "ticket": + ticketer = org.ticketers.get(uuid=mod.ticketer.uuid, is_active=True) + topic = org.topics.get(uuid=mod.topic.uuid, is_active=True) + assignee = org.users.get(email=mod.assignee.email, is_active=True) if mod.assignee else None + for contact in contacts: + contact.tickets.create( + org=org, + ticketer=ticketer, + topic=topic, + status=Ticket.STATUS_OPEN, + body=mod.body, + assignee=assignee, + ) + elif mod.type == "urns": assert len(contacts) == 1, "should never be trying to bulk update contact URNs" assert mod.modification == "set", "should only be setting URNs from here" From 4302c4d39708995a93bacb800bd5b669f59f03b4 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 18 Jul 2022 10:52:55 -0500 Subject: [PATCH 020/630] Add new fields to Ticket record who or what flow opened a ticket --- .../0036_backfill_ticket_reply_timings.py | 4 +- .../0039_ticket_opened_by_ticket_opened_in.py | 30 +++++++ temba/tickets/models.py | 5 +- temba/tickets/tests.py | 80 +------------------ 4 files changed, 38 insertions(+), 81 deletions(-) create mode 100644 temba/tickets/migrations/0039_ticket_opened_by_ticket_opened_in.py diff --git a/temba/tickets/migrations/0036_backfill_ticket_reply_timings.py b/temba/tickets/migrations/0036_backfill_ticket_reply_timings.py index 3d19f60e44e..e0d35caec1f 100644 --- a/temba/tickets/migrations/0036_backfill_ticket_reply_timings.py +++ b/temba/tickets/migrations/0036_backfill_ticket_reply_timings.py @@ -13,7 +13,7 @@ class CountAndSeconds: seconds: int = 0 -def backfill_ticket_reply_timings(apps, schema_editor): +def backfill_ticket_reply_timings(apps, schema_editor): # pragma: no cover Org = apps.get_model("orgs", "Org") TicketDailyTiming = apps.get_model("tickets", "TicketDailyTiming") @@ -52,7 +52,7 @@ def record(dt, secs): ) -def reverse(apps, schema_editor): +def reverse(apps, schema_editor): # pragma: no cover pass diff --git a/temba/tickets/migrations/0039_ticket_opened_by_ticket_opened_in.py b/temba/tickets/migrations/0039_ticket_opened_by_ticket_opened_in.py new file mode 100644 index 00000000000..7aa7e9478b5 --- /dev/null +++ b/temba/tickets/migrations/0039_ticket_opened_by_ticket_opened_in.py @@ -0,0 +1,30 @@ +# Generated by Django 4.0.6 on 2022-07-18 15:50 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("orgs", "0101_remove_org_administrators_remove_org_agents_and_more"), + ("flows", "0291_flowrun_flows_run_active_or_waiting_has_session"), + ("tickets", "0038_remove_ticket_tickets_ticketer_external_id_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="ticket", + name="opened_by", + field=models.ForeignKey( + null=True, on_delete=django.db.models.deletion.PROTECT, related_name="opened_tickets", to="orgs.user" + ), + ), + migrations.AddField( + model_name="ticket", + name="opened_in", + field=models.ForeignKey( + null=True, on_delete=django.db.models.deletion.PROTECT, related_name="opened_tickets", to="flows.flow" + ), + ), + ] diff --git a/temba/tickets/models.py b/temba/tickets/models.py index b99fa9110e1..61511fe7d74 100644 --- a/temba/tickets/models.py +++ b/temba/tickets/models.py @@ -215,8 +215,11 @@ class Ticket(models.Model): status = models.CharField(max_length=1, choices=STATUS_CHOICES) assignee = models.ForeignKey(User, on_delete=models.PROTECT, null=True, related_name="assigned_tickets") - # when this ticket was opened, first replied to, closed, modified opened_on = models.DateTimeField(default=timezone.now) + opened_in = models.ForeignKey("flows.Flow", null=True, on_delete=models.PROTECT, related_name="opened_tickets") + opened_by = models.ForeignKey(User, null=True, on_delete=models.PROTECT, related_name="opened_tickets") + + # when this ticket was first replied to, closed, modified replied_on = models.DateTimeField(null=True) closed_on = models.DateTimeField(null=True) modified_on = models.DateTimeField(default=timezone.now) diff --git a/temba/tickets/tests.py b/temba/tickets/tests.py index 8285cbafdb7..646a96ec794 100644 --- a/temba/tickets/tests.py +++ b/temba/tickets/tests.py @@ -1,4 +1,4 @@ -from datetime import date, datetime +from datetime import date from unittest.mock import patch from django.test.utils import override_settings @@ -6,7 +6,7 @@ from django.utils import timezone from temba.contacts.models import Contact -from temba.tests import CRUDLTestMixin, MigrationTest, TembaTest, matchers, mock_mailroom +from temba.tests import CRUDLTestMixin, TembaTest, matchers, mock_mailroom from temba.utils.dates import datetime_to_timestamp from .models import ( @@ -934,79 +934,3 @@ def _record_last_close(self, org, d: date, seconds: int, undo: bool = False): TicketDailyTiming.objects.create( count_type=TicketDailyTiming.TYPE_LAST_CLOSE, scope=f"o:{org.id}", day=d, count=count, seconds=seconds ) - - -class BackfillTicketDailyReplyTimingsTest(MigrationTest): - app = "tickets" - migrate_from = "0035_ticketdailytiming_ticket_replied_on_and_more" - migrate_to = "0036_backfill_ticket_reply_timings" - - def setUpBeforeMigration(self, apps): - ticketer = self.org.ticketers.get() - contact = self.create_contact("Bob", phone="+1234567890") - - # ticket opened on May 1 - self.ticket1 = self.create_ticket( - ticketer, contact, "Help", opened_on=datetime(2022, 5, 1, 10, 30, 0, 0, tzinfo=timezone.utc) - ) - - # first reply 30 mins later, then another 30 mins after that - self._ticket_reply( - self.ticket1, "What is the problem?", datetime(2022, 5, 1, 11, 0, 0, 0, tzinfo=timezone.utc) - ) - self._ticket_reply(self.ticket1, "Still there?", datetime(2022, 5, 1, 11, 30, 0, 0, tzinfo=timezone.utc)) - - # another ticket opened on May 1 - self.ticket2 = self.create_ticket( - ticketer, contact, "Help", opened_on=datetime(2022, 5, 1, 13, 0, 0, 0, tzinfo=timezone.utc) - ) - - # only reply 1 hour later - self._ticket_reply( - self.ticket2, "What is the problem?", datetime(2022, 5, 1, 14, 0, 0, 0, tzinfo=timezone.utc) - ) - - # another ticket opened on May 2, no replies - self.ticket3 = self.create_ticket( - ticketer, contact, "Help", opened_on=datetime(2022, 5, 2, 13, 0, 0, 0, tzinfo=timezone.utc) - ) - - # finally another ticket on May 2 which has a reply that is already counted - self.ticket4 = self.create_ticket( - ticketer, contact, "Help", opened_on=datetime(2022, 5, 2, 15, 0, 0, 0, tzinfo=timezone.utc) - ) - self._ticket_reply(self.ticket4, "Hi?", datetime(2022, 5, 2, 15, 30, 0, 0, tzinfo=timezone.utc)) - - self.ticket4.replied_on = datetime(2022, 5, 1, 15, 30, 0, 0, tzinfo=timezone.utc) - self.ticket4.save(update_fields=("replied_on",)) - - TicketDailyTiming.objects.create( - count_type=TicketDailyTiming.TYPE_FIRST_REPLY, - scope=f"o:{self.org.id}", - day=date(2022, 5, 2), - count=1, - seconds=30 * 60, - ) - - def test_migration(self): - self.ticket1.refresh_from_db() - self.ticket2.refresh_from_db() - self.ticket3.refresh_from_db() - self.ticket4.refresh_from_db() - - self.assertEqual(datetime(2022, 5, 1, 11, 0, 0, 0, tzinfo=timezone.utc), self.ticket1.replied_on) - self.assertEqual(datetime(2022, 5, 1, 14, 0, 0, 0, tzinfo=timezone.utc), self.ticket2.replied_on) - self.assertIsNone(self.ticket3.replied_on) - self.assertEqual(datetime(2022, 5, 2, 15, 30, 0, 0, tzinfo=timezone.utc), self.ticket4.replied_on) - - self.assertEqual( - [(date(2022, 5, 1), 2), (date(2022, 5, 2), 1)], - TicketDailyTiming.get_by_org(self.org, TicketDailyTiming.TYPE_FIRST_REPLY).day_totals(), - ) - self.assertEqual( - [(date(2022, 5, 1), 2700.0), (date(2022, 5, 2), 1800.0)], - TicketDailyTiming.get_by_org(self.org, TicketDailyTiming.TYPE_FIRST_REPLY).day_averages(), - ) - - def _ticket_reply(self, ticket, text, when): - self.create_broadcast(self.admin, text, contacts=[ticket.contact], ticket=ticket, created_on=when) From 78e44f794c7d3ee6234561020f0094661f567ac0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 18 Jul 2022 10:44:18 -0500 Subject: [PATCH 021/630] Add Open Ticket modal view to contact read page --- temba/contacts/models.py | 2 +- temba/contacts/tests.py | 54 +++++++++++++++++++++++++++++++++ temba/contacts/views.py | 64 +++++++++++++++++++++++++++++++++++++++- temba/settings_common.py | 3 ++ 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 05404aa3995..5b4a59c20bf 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -1063,7 +1063,7 @@ def open_ticket(self, user, ticketer, topic, body: str, assignee=None): body=body, assignee=modifiers.UserRef(email=assignee.email, name=assignee.name) if assignee else None, ) - self.modify(user, [mod]) + self.modify(user, [mod], refresh=False) return self.tickets.order_by("id").last() def block(self, user): diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index d425c810a3a..16c5b4c733f 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -673,6 +673,60 @@ def test_scheduled(self): response = self.requestView(schedule_url, self.admin) self.assertEqual(3, len(response.json()["results"])) + @mock_mailroom + def test_open_ticket(self, mr_mocks): + contact = self.create_contact("Joe", phone="+593979000111") + internal = self.org.ticketers.get() + general = self.org.default_ticket_topic + + open_url = reverse("contacts.contact_open_ticket", args=[contact.id]) + + self.assertUpdateFetch( + open_url, allow_viewers=False, allow_editors=True, form_fields=("topic", "body", "assignee") + ) + + # try to submit with empty body + self.assertUpdateSubmit( + open_url, + {"ticketer": internal.id, "topic": general.id, "body": "", "assignee": ""}, + form_errors={"body": "This field is required."}, + object_unchanged=contact, + ) + + # can submit with no assignee + response = self.assertUpdateSubmit( + open_url, {"ticketer": internal.id, "topic": general.id, "body": "Help", "assignee": ""} + ) + + # should have new ticket + ticket = contact.tickets.get() + self.assertEqual(internal, ticket.ticketer) + self.assertEqual(general, ticket.topic) + self.assertEqual("Help", ticket.body) + self.assertIsNone(ticket.assignee) + + # and we're redirected to that ticket + self.assertRedirect(response, f"/ticket/all/open/{ticket.uuid}/") + + # create external ticketer + zendesk = Ticketer.create(self.org, self.admin, "zendesk", "Zendesk", config={}) + + # now ticketer is an option on the form + self.assertUpdateFetch( + open_url, allow_viewers=False, allow_editors=True, form_fields=("ticketer", "topic", "body", "assignee") + ) + + self.assertUpdateSubmit( + open_url, {"ticketer": zendesk.id, "topic": general.id, "body": "Help again", "assignee": self.agent.id} + ) + + # should have new ticket + ticket = contact.tickets.order_by("id").last() + self.assertEqual(zendesk, ticket.ticketer) + self.assertEqual(general, ticket.topic) + self.assertEqual("Help again", ticket.body) + self.assertEqual(self.agent, ticket.assignee) + @mock_mailroom def test_archive(self, mr_mocks): contact = self.create_contact("Joe", phone="+593979000111") diff --git a/temba/contacts/views.py b/temba/contacts/views.py index a3549e1aacb..5441c65e61c 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -37,6 +37,7 @@ from temba.contacts.templatetags.contacts import MISSING_VALUE from temba.mailroom.events import Event from temba.notifications.views import NotificationTargetMixin +from temba.orgs.models import User from temba.orgs.views import ( DependencyDeleteModal, DependencyUsagesModal, @@ -45,7 +46,7 @@ OrgObjPermsMixin, OrgPermsMixin, ) -from temba.tickets.models import Ticket +from temba.tickets.models import Ticket, Ticketer, Topic from temba.utils import analytics, json, languages, on_transaction_commit from temba.utils.dates import datetime_to_timestamp, timestamp_to_datetime from temba.utils.fields import ( @@ -559,6 +560,7 @@ class ContactCRUDL(SmartCRUDL): "filter", "blocked", "omnibox", + "open_ticket", "update_fields", "update_fields_input", "export", @@ -885,6 +887,15 @@ def get_gear_links(self): modax=_("Start Flow"), ) ) + if self.has_org_perm("contacts.contact_open_ticket"): + links.append( + dict( + id="open-ticket", + title=_("Open Ticket"), + href=reverse("contacts.contact_open_ticket", args=[self.object.id]), + modax=_("Open Ticket"), + ) + ) if self.has_org_perm("contacts.contact_update"): links.append( @@ -1462,6 +1473,57 @@ def get_context_data(self, **kwargs): context["value"] = self.get_object().get_field_display(contact_field) return context + class OpenTicket(ComponentFormMixin, ModalMixin, OrgObjPermsMixin, SmartUpdateView): + """ + Opens a new ticket for this contact. + """ + + class Form(forms.Form): + ticketer = forms.ModelChoiceField( + queryset=Ticketer.objects.none(), label=_("Ticket Service"), required=True + ) + topic = forms.ModelChoiceField(queryset=Topic.objects.none(), label=_("Topic"), required=True) + body = forms.CharField(label=_("Body"), widget=forms.Textarea, required=True) + assignee = forms.ModelChoiceField( + queryset=User.objects.none(), + label=_("Assignee"), + widget=SelectWidget(), + required=False, + empty_label=_("Unassigned"), + ) + + def __init__(self, instance, org, **kwargs): + super().__init__(**kwargs) + + self.fields["ticketer"].queryset = org.ticketers.order_by("id") + self.fields["topic"].queryset = org.topics.order_by("name") + self.fields["assignee"].queryset = Ticket.get_allowed_assignees(org).order_by("email") + + form_class = Form + submit_button_name = _("Open") + success_message = "" + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["org"] = self.request.org + return kwargs + + def derive_exclude(self): + # don't show ticketer select if they don't have external ticketers + return ["ticketer"] if self.request.org.ticketers.count() == 1 else [] + + def save(self, obj): + self.ticket = obj.open_ticket( + self.request.user, + self.form.cleaned_data.get("ticketer") or self.request.org.ticketers.first(), + self.form.cleaned_data["topic"], + self.form.cleaned_data["body"], + assignee=self.form.cleaned_data.get("assignee"), + ) + + def get_success_url(self): + return f"{reverse('tickets.ticket_list')}all/open/{self.ticket.uuid}/" + class Block(OrgObjPermsMixin, SmartUpdateView): """ Block this contact diff --git a/temba/settings_common.py b/temba/settings_common.py index 810210c5382..b10c85b1ac0 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -392,6 +392,7 @@ "history", "menu", "omnibox", + "open_ticket", "restore", "search", "start", @@ -603,6 +604,7 @@ "contacts.contact_list", "contacts.contact_menu", "contacts.contact_omnibox", + "contacts.contact_open_ticket", "contacts.contact_read", "contacts.contact_restore", "contacts.contact_search", @@ -739,6 +741,7 @@ "contacts.contact_list", "contacts.contact_menu", "contacts.contact_omnibox", + "contacts.contact_open_ticket", "contacts.contact_read", "contacts.contact_restore", "contacts.contact_search", From e7aa821449fc1950454fa6716e396065c50938e3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 19 Jul 2022 15:30:31 -0500 Subject: [PATCH 022/630] Improve user list page --- temba/orgs/tests.py | 12 ++-- temba/orgs/views.py | 64 ++++++++++++--------- templates/orgs/org_manage.haml | 74 ++++++++----------------- templates/orgs/user_list.haml | 24 ++++++++ templates/smartmin/users/user_list.haml | 1 - 5 files changed, 92 insertions(+), 83 deletions(-) create mode 100644 templates/orgs/user_list.haml delete mode 100644 templates/smartmin/users/user_list.haml diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 75dcfa6666f..10968413a43 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -4132,14 +4132,14 @@ def assert_superuser_only(mgmt_url): assert_superuser_only(update_url) assert_superuser_only(delete_url) - response = self.client.get(manage_url + "?flagged=1") - self.assertFalse(self.org in response.context["object_list"]) + response = self.client.get(manage_url + "?filter=flagged") + self.assertNotIn(self.org, response.context["object_list"]) - response = self.client.get(manage_url + "?anon=1") - self.assertFalse(self.org in response.context["object_list"]) + response = self.client.get(manage_url + "?filter=anon") + self.assertNotIn(self.org, response.context["object_list"]) - response = self.client.get(manage_url + "?suspended=1") - self.assertFalse(self.org in response.context["object_list"]) + response = self.client.get(manage_url + "?filter=suspended") + self.assertNotIn(self.org, response.context["object_list"]) response = self.client.get(manage_url) self.assertEqual(200, response.status_code) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index 8ed5c4f62e4..d35d3bb598d 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -61,7 +61,7 @@ from temba.classifiers.models import Classifier from temba.flows.models import Flow from temba.formax import FormaxMixin -from temba.utils import analytics, get_anonymous_user, json, languages, str_to_bool +from temba.utils import analytics, get_anonymous_user, json, languages from temba.utils.email import is_valid_address, send_template_email from temba.utils.fields import ( ArbitraryJsonChoiceField, @@ -707,6 +707,7 @@ class List(SmartListView): link_fields = ("username",) ordering = ("-date_joined",) search_fields = ("username",) + filters = (("all", _("All")), ("beta", _("Beta")), ("staff", _("Staff"))) def get_username(self, user): return mark_safe(f"{user.username}") @@ -724,7 +725,21 @@ def get_orgs(self, user): return mark_safe(f"{org_links}{more}") def derive_queryset(self, **kwargs): - return super().derive_queryset(**kwargs).filter(is_active=True).exclude(id=get_anonymous_user().id) + qs = super().derive_queryset(**kwargs).filter(is_active=True).exclude(id=get_anonymous_user().id) + + obj_filter = self.request.GET.get("filter") + if obj_filter == "beta": + qs = qs.filter(groups__name="Beta") + elif obj_filter == "staff": + qs = qs.filter(is_staff=True) + + return qs + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["filter"] = self.request.GET.get("filter", "all") + context["filters"] = self.filters + return context class Update(ComponentFormMixin, SmartUpdateView): class Form(UserUpdateForm): @@ -1953,7 +1968,14 @@ class Manage(SmartListView): default_order = ("-credits", "-created_on") search_fields = ("name__icontains", "created_by__email__iexact", "config__icontains") link_fields = ("name", "owner") - title = _("Workspaces") + filters = ( + ("all", _("All")), + ("anon", _("Anonymous")), + ("flagged", _("Flagged")), + ("suspended", _("Suspended")), + ("nyaruka", "Nyaruka"), + ) + name_filters = {"nyaruka"} def get_used(self, obj): if not obj.credits: # pragma: needs cover @@ -2007,36 +2029,28 @@ def get_name(self, obj): ) def derive_queryset(self, **kwargs): - queryset = super().derive_queryset(**kwargs) - queryset = queryset.filter(is_active=True) + qs = super().derive_queryset(**kwargs).filter(is_active=True) brands = self.request.branding.get("keys") if brands: - queryset = queryset.filter(brand__in=brands) - - anon = self.request.GET.get("anon") - if anon: - queryset = queryset.filter(is_anon=str_to_bool(anon)) - - suspended = self.request.GET.get("suspended") - if suspended: - queryset = queryset.filter(is_suspended=str_to_bool(suspended)) + qs = qs.filter(brand__in=brands) - flagged = self.request.GET.get("flagged") - if flagged: - queryset = queryset.filter(is_flagged=str_to_bool(flagged)) + obj_filter = self.request.GET.get("filter") + if obj_filter == "anon": + qs = qs.filter(is_anon=True) + elif obj_filter == "flagged": + qs = qs.filter(is_flagged=True) + elif obj_filter == "suspended": + qs = qs.filter(is_suspended=True) + elif obj_filter in self.name_filters: + qs = qs.filter(name__icontains=obj_filter) - queryset = queryset.annotate(credits=Sum("topups__credits")) - queryset = queryset.annotate(paid=Sum("topups__price")) - - return queryset + return qs.annotate(credits=Sum("topups__credits")).annotate(paid=Sum("topups__price")) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["searches"] = ["Nyaruka"] - context["anon_query"] = str_to_bool(self.request.GET.get("anon")) - context["flagged_query"] = str_to_bool(self.request.GET.get("flagged")) - context["suspended_query"] = str_to_bool(self.request.GET.get("suspended")) + context["filter"] = self.request.GET.get("filter", "all") + context["filters"] = self.filters return context def lookup_field_link(self, context, field, obj): diff --git a/templates/orgs/org_manage.haml b/templates/orgs/org_manage.haml index 4a0d00e5527..52df6a72603 100644 --- a/templates/orgs/org_manage.haml +++ b/templates/orgs/org_manage.haml @@ -1,8 +1,28 @@ -extends "smartmin/list.html" - --load compress temba smartmin humanize -load i18n +-block title + -trans "Workspaces" + +-block pre-table + .flex.mb-4.items-center + .bg-gray-100.px-4.py-2.rounded-lg.inline-block.mr-4.self-center.-mb-1 + -for filter_key, filter_name in filters + -if filter == filter_key + .font-normal.inline-block.px-1 + {{ filter_name }} + -else + %a.inline-block.px-1(href='?filter={{ filter_key }}')< + {{ filter_name }} + -if not forloop.last + \ | + + .search-box.flex-grow + %form#search-form(method='get') + {% csrf_token %} + %input(type="hidden" name="filter" value='{{ filter }}') + %temba-textinput(name='search' value='{{ search }}') + -block extra-style {{block.super}} @@ -21,7 +41,7 @@ } #header-owner { - + } .field_created_on { @@ -32,51 +52,3 @@ .field_service { width: 40px; } - --block title - -trans "Workspaces" - --block pre-table - .flex.mb-4.items-center - .bg-gray-100.px-4.py-2.rounded-lg.inline-block.mr-4.self-center.-mb-1 - -if search == "" - .font-normal.inline-block.px-1 - All - -else - %a.inline-block.px-1(href='?search=')< - All - \ | - -if anon_query - .font-normal.inline-block.px-1 - Anonymous - -else - %a.inline-block.px-1(href='?anon=1')< - Anonymous - \ | - -if flagged_query - .font-normal.inline-block.px-1 - Flagged - -else - %a.inline-block.px-1(href='?flagged=1')< - Flagged - \ | - -if suspended_query - .font-normal.inline-block.px-1 - Suspended - -else - %a.inline-block.px-1(href='?suspended=1')< - Suspended - - -for s in searches - | - -if search == s - .font-normal.inline-block.px-1 - {{ s }} - -else - %a.inline-block.px-1(href='?search={{s}}') - {{ s }} - - .search-box.flex-grow - %form#search-form(method='get') - {% csrf_token %} - %temba-textinput(name='search' value='{{search}}') diff --git a/templates/orgs/user_list.haml b/templates/orgs/user_list.haml new file mode 100644 index 00000000000..ea1f870da1f --- /dev/null +++ b/templates/orgs/user_list.haml @@ -0,0 +1,24 @@ +-extends "smartmin/list.html" +-load i18n + +-block title + -trans "Users" + +-block pre-table + .flex.mb-4.items-center + .bg-gray-100.px-4.py-2.rounded-lg.inline-block.mr-4.self-center.-mb-1 + -for filter_key, filter_name in filters + -if filter == filter_key + .font-normal.inline-block.px-1 + {{ filter_name }} + -else + %a.inline-block.px-1(href='?filter={{ filter_key }}')< + {{ filter_name }} + -if not forloop.last + \ | + + .search-box.flex-grow + %form#search-form(method='get') + {% csrf_token %} + %input(type="hidden" name="filter" value='{{ filter }}') + %temba-textinput(name='search' value='{{ search }}') diff --git a/templates/smartmin/users/user_list.haml b/templates/smartmin/users/user_list.haml deleted file mode 100644 index c36908571b0..00000000000 --- a/templates/smartmin/users/user_list.haml +++ /dev/null @@ -1 +0,0 @@ --extends "smartmin/list.html" \ No newline at end of file From c3c86cb01dbcfb48ebdac1c3b215d5084758e9d1 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 08:09:20 -0500 Subject: [PATCH 023/630] Delete unused template --- templates/smartmin/users/user_forget.haml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 templates/smartmin/users/user_forget.haml diff --git a/templates/smartmin/users/user_forget.haml b/templates/smartmin/users/user_forget.haml deleted file mode 100644 index 375f6e2fdf3..00000000000 --- a/templates/smartmin/users/user_forget.haml +++ /dev/null @@ -1,16 +0,0 @@ --extends "orgs/login/login_base.html" - --load smartmin i18n - --block login-title - -trans "Reset Password" - --block login-content - -blocktrans - Enter the email address you used to sign up. We will - send you an email with details on how to reset your password. - - %form.mt-8(method="post" action="{% url 'users.user_forget' %}") - {% csrf_token %} - %temba-textinput(type="email" name="email" required="" placeholder='{{_("Email Address")|escapejs}}') - %input.mt-4.button-primary(type="submit" value='{{_("Reset Password")}}') From cd91c50aeb9a387fe0dc945afee92e590c7f8f6c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 08:37:56 -0500 Subject: [PATCH 024/630] Remove CSRF checks on org manage and user list views --- temba/orgs/views.py | 11 +++++++++-- templates/orgs/org_manage.haml | 1 - templates/orgs/user_list.haml | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index d35d3bb598d..4ace526bb4e 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -709,6 +709,10 @@ class List(SmartListView): search_fields = ("username",) filters = (("all", _("All")), ("beta", _("Beta")), ("staff", _("Staff"))) + @csrf_exempt + def dispatch(self, *args, **kwargs): + return super().dispatch(*args, **kwargs) + def get_username(self, user): return mark_safe(f"{user.username}") @@ -1975,7 +1979,10 @@ class Manage(SmartListView): ("suspended", _("Suspended")), ("nyaruka", "Nyaruka"), ) - name_filters = {"nyaruka"} + + @csrf_exempt + def dispatch(self, *args, **kwargs): + return super().dispatch(*args, **kwargs) def get_used(self, obj): if not obj.credits: # pragma: needs cover @@ -2042,7 +2049,7 @@ def derive_queryset(self, **kwargs): qs = qs.filter(is_flagged=True) elif obj_filter == "suspended": qs = qs.filter(is_suspended=True) - elif obj_filter in self.name_filters: + elif obj_filter and obj_filter != "all": qs = qs.filter(name__icontains=obj_filter) return qs.annotate(credits=Sum("topups__credits")).annotate(paid=Sum("topups__price")) diff --git a/templates/orgs/org_manage.haml b/templates/orgs/org_manage.haml index 52df6a72603..ff10f000544 100644 --- a/templates/orgs/org_manage.haml +++ b/templates/orgs/org_manage.haml @@ -19,7 +19,6 @@ .search-box.flex-grow %form#search-form(method='get') - {% csrf_token %} %input(type="hidden" name="filter" value='{{ filter }}') %temba-textinput(name='search' value='{{ search }}') diff --git a/templates/orgs/user_list.haml b/templates/orgs/user_list.haml index ea1f870da1f..eaa131843d9 100644 --- a/templates/orgs/user_list.haml +++ b/templates/orgs/user_list.haml @@ -19,6 +19,5 @@ .search-box.flex-grow %form#search-form(method='get') - {% csrf_token %} %input(type="hidden" name="filter" value='{{ filter }}') %temba-textinput(name='search' value='{{ search }}') From 0ade1843bb3d041be7f5d97bdb1f8fa5fe8c9852 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 09:03:10 -0500 Subject: [PATCH 025/630] Allow searching by user names --- temba/orgs/views.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index 4ace526bb4e..cb64bdb2b45 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -703,17 +703,16 @@ class UserCRUDL(SmartCRUDL): ) class List(SmartListView): - fields = ("username", "orgs", "date_joined") - link_fields = ("username",) + fields = ("email", "name", "orgs", "date_joined") ordering = ("-date_joined",) - search_fields = ("username",) + search_fields = ("email", "first_name", "last_name") filters = (("all", _("All")), ("beta", _("Beta")), ("staff", _("Staff"))) @csrf_exempt def dispatch(self, *args, **kwargs): return super().dispatch(*args, **kwargs) - def get_username(self, user): + def get_email(self, user): return mark_safe(f"{user.username}") def get_orgs(self, user): From e39e1af336a91e14100d2393535bffba98c23203 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 10:54:53 -0500 Subject: [PATCH 026/630] Simplify testing of staff only views --- temba/orgs/tests.py | 59 +++++++++++++++++++++++++------------------- temba/tests/crudl.py | 11 +++++++++ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 10968413a43..e91d3e3d65d 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -4106,31 +4106,13 @@ def test_org_timezone(self): def test_administration(self): self.setUpLocations() - def assert_superuser_only(mgmt_url): - # no access to anon - self.client.logout() - self.assertLoginRedirect(self.client.get(mgmt_url)) - - # or editors - self.login(self.editor) - self.assertLoginRedirect(self.client.get(mgmt_url)) - - # or even admins - self.login(self.admin) - self.assertLoginRedirect(self.client.get(mgmt_url)) - - # only superusers or staff - self.login(self.superuser) - response = self.client.get(mgmt_url) - self.assertEqual(200, response.status_code) - manage_url = reverse("orgs.org_manage") update_url = reverse("orgs.org_update", args=[self.org.id]) delete_url = reverse("orgs.org_delete", args=[self.org.id]) - assert_superuser_only(manage_url) - assert_superuser_only(update_url) - assert_superuser_only(delete_url) + self.assertStaffOnly(manage_url) + self.assertStaffOnly(update_url) + self.assertStaffOnly(delete_url) response = self.client.get(manage_url + "?filter=flagged") self.assertNotIn(self.org, response.context["object_list"]) @@ -4141,6 +4123,10 @@ def assert_superuser_only(mgmt_url): response = self.client.get(manage_url + "?filter=suspended") self.assertNotIn(self.org, response.context["object_list"]) + response = self.client.get(manage_url + "?filter=nyaruka") + self.assertIn(self.org, response.context["object_list"]) + self.assertNotIn(self.org2, response.context["object_list"]) + response = self.client.get(manage_url) self.assertEqual(200, response.status_code) self.assertNotContains(response, "(Flagged)") @@ -4152,7 +4138,7 @@ def assert_superuser_only(mgmt_url): # should contain our test org self.assertContains(response, "Temba") - response = self.client.get(manage_url + "?flagged=1") + response = self.client.get(manage_url + "?filter=flagged") self.assertTrue(self.org in response.context["object_list"]) # and can go to that org @@ -4483,12 +4469,34 @@ def test_languages(self): class UserCRUDLTest(TembaTest, CRUDLTestMixin): + def test_list(self): + list_url = reverse("orgs.user_list") + + self.assertStaffOnly(list_url) + + response = self.requestView(list_url, self.customer_support) + self.assertEqual(9, len(response.context["object_list"])) + + response = self.requestView(list_url + "?filter=beta", self.customer_support) + self.assertEqual(set(), set(response.context["object_list"])) + + response = self.requestView(list_url + "?filter=staff", self.customer_support) + self.assertEqual({self.customer_support, self.superuser}, set(response.context["object_list"])) + + response = self.requestView(list_url + "?search=admin@nyaruka.com", self.customer_support) + self.assertEqual({self.admin}, set(response.context["object_list"])) + + response = self.requestView(list_url + "?search=admin@nyaruka.com", self.customer_support) + self.assertEqual({self.admin}, set(response.context["object_list"])) + + response = self.requestView(list_url + "?search=Andy", self.customer_support) + self.assertEqual({self.admin}, set(response.context["object_list"])) + def test_update(self): update_url = reverse("orgs.user_update", args=[self.editor.id]) # this is a customer support only view - self.assertLoginRedirect(self.requestView(update_url, self.editor)) - self.assertLoginRedirect(self.requestView(update_url, self.admin)) + self.assertStaffOnly(update_url) response = self.requestView(update_url, self.customer_support) self.assertEqual(200, response.status_code) @@ -4544,8 +4552,7 @@ def test_delete(self): delete_url = reverse("orgs.user_delete", args=[self.editor.id]) # this is a customer support only view - self.assertLoginRedirect(self.requestView(delete_url, self.editor)) - self.assertLoginRedirect(self.requestView(delete_url, self.admin)) + self.assertStaffOnly(delete_url) response = self.requestView(delete_url, self.customer_support) self.assertEqual(200, response.status_code) diff --git a/temba/tests/crudl.py b/temba/tests/crudl.py index 45d7ba59be7..c77ce6dd437 100644 --- a/temba/tests/crudl.py +++ b/temba/tests/crudl.py @@ -216,6 +216,17 @@ def as_user(user, allowed): as_user(org2_admin, allowed=False) return as_user(admin, allowed=True) + def assertStaffOnly(self, url): + viewer, editor, agent, admin, org2_admin = self.get_test_users() + + self.requestView(url, None, checks=[LoginRedirect()]) + self.requestView(url, viewer, checks=[LoginRedirect()]) + self.requestView(url, editor, checks=[LoginRedirect()]) + self.requestView(url, admin, checks=[LoginRedirect()]) + + self.requestView(url, self.superuser, checks=[StatusCode(200)]) + self.requestView(url, self.customer_support, checks=[StatusCode(200)]) + class BaseCheck: def pre_check(self, test_cls, desc): From 7f501ae958ec2389d3b85ca8408ad1404fb5b5fc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 13:30:41 -0500 Subject: [PATCH 027/630] Update CHANGELOG.md for v7.5.0 --- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dad95e6668..e9c3fe81c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +v7.5.0 +---------- + * Improve user list page + * Add new fields to Ticket record who or what flow opened a ticket + * Refresh menu on modax redircts, omit excess listeners from legacy lists + * Fix field label vs name in new UI + * Add start flow bulk action in new UI + * Show zeros in menu items in new UI + * Add workspace selection to account page in new UI + * Scroll main content pane up on page replacement in new UI + v7.4.2 ---------- * Update copyright notice diff --git a/pyproject.toml b/pyproject.toml index 733e5d9a26f..d818beb0e7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.4.2" +version = "7.5.0" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 3e9891eaca50e37bc5daf568b6fbd71293bf5d0f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 20 Jul 2022 13:46:50 -0500 Subject: [PATCH 028/630] Move black setting into pyproject.toml --- code_check.py | 2 +- pyproject.toml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code_check.py b/code_check.py index 23170d90182..6e7d5baa8a9 100755 --- a/code_check.py +++ b/code_check.py @@ -40,7 +40,7 @@ def status(line): cmd("isort temba") status("Running black") - cmd("black --line-length=119 temba") + cmd("black temba") if not args.skip_flake: status("Running flake8") diff --git a/pyproject.toml b/pyproject.toml index d818beb0e7f..72fae6cc80f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,9 @@ codecov = "^2.1.11" responses = "^0.12.1" beautifulsoup4 = "^4.9.3" +[tool.black] +line-length = 119 + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" From ea5fe8134288e7f186df6bc1b52777544df2742c Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Thu, 21 Jul 2022 15:32:52 +0200 Subject: [PATCH 029/630] Allow claiming WAC test numbers --- temba/channels/types/whatsapp_cloud/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temba/channels/types/whatsapp_cloud/views.py b/temba/channels/types/whatsapp_cloud/views.py index 236d506682e..f9b8a8a49fc 100644 --- a/temba/channels/types/whatsapp_cloud/views.py +++ b/temba/channels/types/whatsapp_cloud/views.py @@ -123,7 +123,7 @@ def get_context_data(self, **kwargs): display_phone_number=target_phone["display_phone_number"], phone_number_id=target_phone["id"], waba_id=target_waba_details["id"], - currency=target_waba_details["currency"], + currency=target_waba_details.get("currency", "USD"), business_id=business_id, message_template_namespace=target_waba_details["message_template_namespace"], ) From f8a7ce9288d0e2aa065eec218452a0c8b9874392 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 09:10:40 -0500 Subject: [PATCH 030/630] Update CHANGELOG.md for v7.5.1 --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9c3fe81c31..b702e05af6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.1 +---------- + * Allow claiming WAC test numbers + * Move black setting into pyproject.toml + * Add Open Ticket modal view to contact read page + v7.5.0 ---------- * Improve user list page diff --git a/pyproject.toml b/pyproject.toml index 72fae6cc80f..68b238ce980 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.0" +version = "7.5.1" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From c7340a4f367ca7b34bfaa7b6baf02e4312b4e802 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 10:32:06 -0500 Subject: [PATCH 031/630] Only show active ticketers and topics on Open Ticket modal --- temba/contacts/tests.py | 4 ++++ temba/contacts/views.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 16c5b4c733f..6f238df97f3 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -679,6 +679,10 @@ def test_open_ticket(self, mr_mocks): internal = self.org.ticketers.get() general = self.org.default_ticket_topic + # create deleted ticketer + deleted_ticketer = Ticketer.create(self.org, self.admin, "mailgun", "Deleted", config={}) + deleted_ticketer.release(self.admin) + open_url = reverse("contacts.contact_open_ticket", args=[contact.id]) self.assertUpdateFetch( diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 5441c65e61c..8a023b95b05 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -1495,8 +1495,8 @@ class Form(forms.Form): def __init__(self, instance, org, **kwargs): super().__init__(**kwargs) - self.fields["ticketer"].queryset = org.ticketers.order_by("id") - self.fields["topic"].queryset = org.topics.order_by("name") + self.fields["ticketer"].queryset = org.ticketers.filter(is_active=True).order_by("id") + self.fields["topic"].queryset = org.topics.filter(is_active=True).order_by("name") self.fields["assignee"].queryset = Ticket.get_allowed_assignees(org).order_by("email") form_class = Form @@ -1510,12 +1510,12 @@ def get_form_kwargs(self): def derive_exclude(self): # don't show ticketer select if they don't have external ticketers - return ["ticketer"] if self.request.org.ticketers.count() == 1 else [] + return ["ticketer"] if self.request.org.ticketers.filter(is_active=True).count() == 1 else [] def save(self, obj): self.ticket = obj.open_ticket( self.request.user, - self.form.cleaned_data.get("ticketer") or self.request.org.ticketers.first(), + self.form.cleaned_data.get("ticketer") or self.request.org.ticketers.filter(is_active=True).first(), self.form.cleaned_data["topic"], self.form.cleaned_data["body"], assignee=self.form.cleaned_data.get("assignee"), From 89c78f2ce5da6158794a0715780a4824c2cfbf83 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 21 Jul 2022 09:18:26 -0700 Subject: [PATCH 032/630] Fix typo on archive button --- templates/msgs/message_box.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/msgs/message_box.haml b/templates/msgs/message_box.haml index bfb9c8a15e0..948085834d1 100644 --- a/templates/msgs/message_box.haml +++ b/templates/msgs/message_box.haml @@ -102,7 +102,7 @@ -trans "Remove Label" - if 'archive' in actions - .button-action(onclick='runActionOnObjectRows("archive, wireTableListeners)') + .button-action(onclick='runActionOnObjectRows("archive", wireTableListeners)') .-mt-1.mr-2.glyph.icon-box -trans "Archive" From ba0ac32ab0ebae52aeb634c3fd94ef3090c19b8e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 11:20:11 -0500 Subject: [PATCH 033/630] Update CHANGELOG.md for v7.5.2 --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b702e05af6b..3ce982ed286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.2 +---------- + * Fix typo on archive button + * Only show active ticketers and topics on Open Ticket modal + * Add data migration to fix non-waiting sessions with no ended_on + v7.5.1 ---------- * Allow claiming WAC test numbers diff --git a/pyproject.toml b/pyproject.toml index 68b238ce980..d471f5b9564 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.1" +version = "7.5.2" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From e57c5774326119bf379c54b7042d89ad6bd2390c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 12:29:04 -0500 Subject: [PATCH 034/630] Expose opened_by and opened_in over ticket API --- temba/api/v2/serializers.py | 4 ++++ temba/api/v2/tests.py | 14 +++++++++++--- temba/api/v2/views.py | 13 ++++++++++--- temba/tests/base.py | 3 +++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/temba/api/v2/serializers.py b/temba/api/v2/serializers.py index bcf52dedfe8..0103501e700 100644 --- a/temba/api/v2/serializers.py +++ b/temba/api/v2/serializers.py @@ -1442,6 +1442,8 @@ class TicketReadSerializer(ReadSerializer): topic = fields.TopicField() assignee = fields.UserField() opened_on = serializers.DateTimeField(default_timezone=pytz.UTC) + opened_by = fields.UserField() + opened_in = fields.FlowField() modified_on = serializers.DateTimeField(default_timezone=pytz.UTC) closed_on = serializers.DateTimeField(default_timezone=pytz.UTC) @@ -1459,6 +1461,8 @@ class Meta: "body", "assignee", "opened_on", + "opened_by", + "opened_in", "modified_on", "closed_on", ) diff --git a/temba/api/v2/tests.py b/temba/api/v2/tests.py index 38d1dbd2ef0..8edb716c457 100644 --- a/temba/api/v2/tests.py +++ b/temba/api/v2/tests.py @@ -4549,10 +4549,12 @@ def test_tickets(self, mock_ticket_reopen, mock_ticket_close): mailgun = Ticketer.create(self.org, self.admin, MailgunType.slug, "Mailgun", {}) ann = self.create_contact("Ann", urns=["twitter:annie"]) bob = self.create_contact("Bob", urns=["twitter:bobby"]) + flow = self.create_flow("Support") + ticket1 = self.create_ticket( - mailgun, ann, "Help", closed_on=datetime(2021, 1, 1, 12, 30, 45, 123456, pytz.UTC) + mailgun, ann, "Help", opened_by=self.admin, closed_on=datetime(2021, 1, 1, 12, 30, 45, 123456, pytz.UTC) ) - ticket2 = self.create_ticket(mailgun, bob, "Really") + ticket2 = self.create_ticket(mailgun, bob, "Really", opened_in=flow) ticket3 = self.create_ticket(mailgun, bob, "Pleeeease help", assignee=self.agent) # on another org @@ -4560,7 +4562,7 @@ def test_tickets(self, mock_ticket_reopen, mock_ticket_close): self.create_ticket(zendesk, self.create_contact("Jim", urns=["twitter:jimmy"], org=self.org2), "Stuff") # no filtering - with self.assertNumQueries(NUM_BASE_REQUEST_QUERIES + 5): + with self.assertNumQueries(NUM_BASE_REQUEST_QUERIES + 7): response = self.fetchJSON(url, readonly_models={Ticket}) resp_json = response.json() @@ -4578,6 +4580,8 @@ def test_tickets(self, mock_ticket_reopen, mock_ticket_close): "topic": {"uuid": str(self.org.default_ticket_topic.uuid), "name": "General"}, "body": "Pleeeease help", "opened_on": format_datetime(ticket3.opened_on), + "opened_by": None, + "opened_in": None, "modified_on": format_datetime(ticket3.modified_on), "closed_on": None, }, @@ -4590,6 +4594,8 @@ def test_tickets(self, mock_ticket_reopen, mock_ticket_close): "topic": {"uuid": str(self.org.default_ticket_topic.uuid), "name": "General"}, "body": "Really", "opened_on": format_datetime(ticket2.opened_on), + "opened_by": None, + "opened_in": {"uuid": str(flow.uuid), "name": "Support"}, "modified_on": format_datetime(ticket2.modified_on), "closed_on": None, }, @@ -4602,6 +4608,8 @@ def test_tickets(self, mock_ticket_reopen, mock_ticket_close): "topic": {"uuid": str(self.org.default_ticket_topic.uuid), "name": "General"}, "body": "Help", "opened_on": format_datetime(ticket1.opened_on), + "opened_by": {"email": "admin@nyaruka.com", "name": "Andy"}, + "opened_in": None, "modified_on": format_datetime(ticket1.modified_on), "closed_on": "2021-01-01T12:30:45.123456Z", }, diff --git a/temba/api/v2/views.py b/temba/api/v2/views.py index 464377374ed..585363b3d6a 100644 --- a/temba/api/v2/views.py +++ b/temba/api/v2/views.py @@ -11,7 +11,6 @@ from django import forms from django.contrib.auth import authenticate, login -from django.contrib.auth.models import User from django.db.models import Prefetch, Q from django.http import HttpResponse, JsonResponse from django.utils.translation import gettext_lazy as _ @@ -37,7 +36,7 @@ from temba.globals.models import Global from temba.locations.models import AdminBoundary, BoundaryAlias from temba.msgs.models import Broadcast, Label, LabelCount, Msg, SystemLabel -from temba.orgs.models import OrgMembership, OrgRole +from temba.orgs.models import OrgMembership, OrgRole, User from temba.templates.models import Template, TemplateTranslation from temba.tickets.models import Ticket, Ticketer, Topic from temba.utils import splitting_getlist, str_to_bool @@ -3481,8 +3480,11 @@ class TicketsEndpoint(ListAPIMixin, WriteAPIMixin, BaseAPIView): * **contact** - the UUID and name of the contact (object), filterable as `contact` with UUID. * **status** - the status of the ticket, e.g. 'open' or 'closed'. * **topic** - the topic of the ticket (object). + * **assignee** - the user assigned to the ticket (object). * **body** - the body of the ticket (string). * **opened_on** - when this ticket was opened (datetime). + * **opened_by** - the user who opened the ticket (object). + * **opened_in** - the flow which opened the ticket (object). * **modified_on** - when this ticket was last modified (datetime). * **closed_on** - when this ticket was closed (datetime). @@ -3502,8 +3504,11 @@ class TicketsEndpoint(ListAPIMixin, WriteAPIMixin, BaseAPIView): "contact": {"uuid": "f1ea776e-c923-4c1a-b3a3-0c466932b2cc", "name": "Jim"}, "status": "open", "topic": {"uuid": "040edbfe-be55-48f3-864d-a4a7147c447b", "name": "Support"}, + "assignee": {"email": "bob@flow.com", "name": "Bob McFlow"}, "body": "Where did I leave my shorts?", "opened_on": "2013-02-27T09:06:15.456", + "opened_by": null, + "opened_in": {"uuid": "54cd8e2c-6334-49a4-abf9-f0fa8d0971da", "name": "Support Flow"}, "modified_on": "2013-02-27T09:07:18.234", "closed_on": null }, @@ -3538,7 +3543,9 @@ def filter_queryset(self, queryset): Prefetch("ticketer", queryset=Ticketer.objects.only("uuid", "name")), Prefetch("topic", queryset=Topic.objects.only("uuid", "name")), Prefetch("contact", queryset=Contact.objects.only("uuid", "name")), - "assignee", + Prefetch("assignee", queryset=User.objects.only("email", "first_name", "last_name")), + Prefetch("opened_by", queryset=User.objects.only("email", "first_name", "last_name")), + Prefetch("opened_in", queryset=Flow.objects.only("uuid", "name")), ) return queryset diff --git a/temba/tests/base.py b/temba/tests/base.py index 6b2114e9202..62c80c4ec96 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -638,6 +638,7 @@ def create_ticket( assignee=None, opened_on=None, opened_by=None, + opened_in=None, closed_on=None, closed_by=None, ): @@ -653,6 +654,8 @@ def create_ticket( status=Ticket.STATUS_CLOSED if closed_on else Ticket.STATUS_OPEN, assignee=assignee, opened_on=opened_on, + opened_by=opened_by, + opened_in=opened_in, closed_on=closed_on, ) TicketEvent.objects.create( From 5df03fccebd8649a04304e66ff78393ca4f1df0e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 14:22:30 -0500 Subject: [PATCH 035/630] Fix related names on Flow.topics and Flow.users and add Topic.release --- ..._alter_flow_topic_dependencies_and_more.py | 26 +++++++++++++++++++ temba/flows/models.py | 4 +-- temba/tickets/models.py | 10 +++++++ temba/tickets/tests.py | 17 ++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 temba/flows/migrations/0293_alter_flow_topic_dependencies_and_more.py diff --git a/temba/flows/migrations/0293_alter_flow_topic_dependencies_and_more.py b/temba/flows/migrations/0293_alter_flow_topic_dependencies_and_more.py new file mode 100644 index 00000000000..6ade4249191 --- /dev/null +++ b/temba/flows/migrations/0293_alter_flow_topic_dependencies_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 4.0.6 on 2022-07-21 19:01 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("tickets", "0039_ticket_opened_by_ticket_opened_in"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("flows", "0292_ensure_session_ended_on"), + ] + + operations = [ + migrations.AlterField( + model_name="flow", + name="topic_dependencies", + field=models.ManyToManyField(related_name="dependent_flows", to="tickets.topic"), + ), + migrations.AlterField( + model_name="flow", + name="user_dependencies", + field=models.ManyToManyField(related_name="dependent_flows", to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/temba/flows/models.py b/temba/flows/models.py index 3608ab66734..eeb6465828e 100644 --- a/temba/flows/models.py +++ b/temba/flows/models.py @@ -194,8 +194,8 @@ class Flow(LegacyUUIDMixin, TembaModel, DependencyMixin): label_dependencies = models.ManyToManyField(Label, related_name="dependent_flows") template_dependencies = models.ManyToManyField(Template, related_name="dependent_flows") ticketer_dependencies = models.ManyToManyField(Ticketer, related_name="dependent_flows") - topic_dependencies = models.ManyToManyField(Topic, related_name="dependent_topics") - user_dependencies = models.ManyToManyField(User, related_name="dependent_users") + topic_dependencies = models.ManyToManyField(Topic, related_name="dependent_flows") + user_dependencies = models.ManyToManyField(User, related_name="dependent_flows") soft_dependent_types = {"flow", "campaign_event", "trigger"} # it's all soft for flows diff --git a/temba/tickets/models.py b/temba/tickets/models.py index 61511fe7d74..d099aae8bb9 100644 --- a/temba/tickets/models.py +++ b/temba/tickets/models.py @@ -178,6 +178,16 @@ def create(cls, org, user, name: str): def create_from_import_def(cls, org, user, definition: dict): return cls.create(org, user, definition["name"]) + def release(self, user): + assert not (self.is_system and self.org.is_active), "can't release system topics" + + super().release(user) + + self.is_active = False + self.name = self._deleted_name() + self.modified_by = user + self.save(update_fields=("name", "is_active", "modified_by", "modified_on")) + class Meta: constraints = [models.UniqueConstraint("org", Lower("name"), name="unique_topic_names")] diff --git a/temba/tickets/tests.py b/temba/tickets/tests.py index 646a96ec794..6ea84a49e37 100644 --- a/temba/tickets/tests.py +++ b/temba/tickets/tests.py @@ -730,6 +730,23 @@ def _import(definition, preview=False): self.assertIsNone(topic15) self.assertEqual(Topic.ImportResult.IGNORED_LIMIT_REACHED, result) + def test_release(self): + topic1 = Topic.create(self.org, self.admin, "Sales") + flow = self.create_flow("Test") + flow.topic_dependencies.add(topic1) + + topic1.release(self.admin) + + self.assertFalse(topic1.is_active) + self.assertTrue(topic1.name.startswith("deleted-")) + + flow.refresh_from_db() + self.assertTrue(flow.has_issues) + + # can't release default topic + with self.assertRaises(AssertionError): + self.org.default_ticket_topic.release(self.admin) + class TeamTest(TembaTest): def test_create(self): From cc5ed99a71319b4db99be5a591de7874b83714dd Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 15:04:39 -0500 Subject: [PATCH 036/630] Add view to interrupt a contact --- temba/contacts/models.py | 7 +++++++ temba/contacts/tests.py | 25 +++++++++++++++++++++++++ temba/contacts/views.py | 22 ++++++++++++++++++++++ temba/settings_common.py | 2 ++ 4 files changed, 56 insertions(+) diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 5b4a59c20bf..005bb233720 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -1066,6 +1066,13 @@ def open_ticket(self, user, ticketer, topic, body: str, assignee=None): self.modify(user, [mod], refresh=False) return self.tickets.order_by("id").last() + def interrupt(self): + """ + Interrupts this contact's current flow + """ + if self.current_flow: + mailroom.queue_interrupt(self.org, contacts=[self]) + def block(self, user): """ Blocks this contact removing it from all non-smart groups diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 6f238df97f3..fedb5dc7a2d 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -1616,6 +1616,31 @@ def test_open_ticket(self, mock_contact_modify): self.assertEqual(self.org.default_ticket_topic, ticket.topic) self.assertEqual("Looks sus", ticket.body) + @mock_mailroom + def test_interrupt(self, mr_mocks): + # noop when contact not in a flow + self.joe.interrupt() + + self.assertEqual([], mr_mocks.queued_batch_tasks) + + flow = self.create_flow("Test") + self.joe.current_flow = flow + self.joe.save(update_fields=("current_flow",)) + + self.joe.interrupt() + + self.assertEqual( + [ + { + "type": "interrupt_sessions", + "org_id": self.org.id, + "task": {"contact_ids": [self.joe.id]}, + "queued_on": matchers.Datetime(), + }, + ], + mr_mocks.queued_batch_tasks, + ) + @mock_mailroom def test_release(self, mr_mocks): # create a contact with a message diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 8a023b95b05..7f0fa99f33b 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -564,6 +564,7 @@ class ContactCRUDL(SmartCRUDL): "update_fields", "update_fields_input", "export", + "interrupt", "block", "restore", "archive", @@ -896,6 +897,14 @@ def get_gear_links(self): modax=_("Open Ticket"), ) ) + if self.has_org_perm("contacts.contact_interrupt"): + links.append( + dict( + title=_("Interrupt"), + js_class="posterize", + href=reverse("contacts.contact_interrupt", args=(self.object.id,)), + ) + ) if self.has_org_perm("contacts.contact_update"): links.append( @@ -1524,6 +1533,19 @@ def save(self, obj): def get_success_url(self): return f"{reverse('tickets.ticket_list')}all/open/{self.ticket.uuid}/" + class Interrupt(OrgObjPermsMixin, SmartUpdateView): + """ + Interrupt this contact + """ + + fields = () + success_url = "uuid@contacts.contact_read" + success_message = "" + + def save(self, obj): + obj.interrupt() + return obj + class Block(OrgObjPermsMixin, SmartUpdateView): """ Block this contact diff --git a/temba/settings_common.py b/temba/settings_common.py index d2100d0cafc..af4ececdc7d 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -390,6 +390,7 @@ "stopped", "filter", "history", + "interrupt", "menu", "omnibox", "open_ticket", @@ -601,6 +602,7 @@ "contacts.contact_export", "contacts.contact_filter", "contacts.contact_history", + "contacts.contact_interrupt", "contacts.contact_list", "contacts.contact_menu", "contacts.contact_omnibox", From 7e2bd4d8b790a2da33c295f2525baa02d3ada025 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 21 Jul 2022 14:28:21 -0700 Subject: [PATCH 037/630] Fix id for custom fields modal --- templates/contacts/contact_update_fields.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/contacts/contact_update_fields.haml b/templates/contacts/contact_update_fields.haml index dc84970b6d9..3768329d399 100644 --- a/templates/contacts/contact_update_fields.haml +++ b/templates/contacts/contact_update_fields.haml @@ -19,7 +19,7 @@ {{block.super}} :javascript var input_url = '/contact/update_fields_input/{{contact.id}}/?field='; - var body = document.querySelector("#update-custom-fields, #gear-modax, #shared-modax").shadowRoot.querySelector(".modax-body"); + var body = document.querySelector("#update-custom-fields, #gear-modax").shadowRoot.querySelector(".modax-body"); var fieldSelect = body.querySelector("temba-select[name='contact_field']"); fieldSelect.addEventListener('change', function(event) { var selectedField = event.target.values[0].value; From 24eb8aa1555744515958394e3a2dba2424864f92 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 21 Jul 2022 14:30:03 -0700 Subject: [PATCH 038/630] Update CHANGELOG.md for v7.5.3 --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ce982ed286..869f48b5622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.3 +---------- + * Fix id for custom fields modal + v7.5.2 ---------- * Fix typo on archive button diff --git a/pyproject.toml b/pyproject.toml index d471f5b9564..c57ae3086c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.2" +version = "7.5.3" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From e7ab41cc2fb1bfe416e4466b126da39d75590791 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 21 Jul 2022 15:31:10 -0500 Subject: [PATCH 039/630] Add util for easier gear menu creation --- temba/contacts/views.py | 108 ++++++++++------------------------------ temba/utils/views.py | 37 ++++++++++++++ 2 files changed, 64 insertions(+), 81 deletions(-) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 8a023b95b05..47f61f8cc99 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -59,7 +59,7 @@ ) from temba.utils.models import patch_queryset_count from temba.utils.models.es import IDSliceQuerySet -from temba.utils.views import BulkActionMixin, ComponentFormMixin, NonAtomicMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ComponentFormMixin, DropdownMenuMixin, NonAtomicMixin, SpaMixin from .models import ( URN, @@ -774,7 +774,7 @@ def render_to_response(self, context, **response_kwargs): return HttpResponse(json.dumps(json_result), content_type="application/json") - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, DropdownMenuMixin, SmartReadView): slug_url_kwarg = "uuid" fields = ("name",) select_related = ("current_flow",) @@ -862,105 +862,51 @@ def post(self, request, *args, **kwargs): return HttpResponse("unknown action", status=400) # pragma: no cover - def get_gear_links(self): - links = [] - + def build_dropdown_menu(self, menu): if self.object.status == Contact.STATUS_ACTIVE: - if not self.is_spa() and self.has_org_perm("msgs.broadcast_send"): - links.append( - dict( - id="send-message", - title=_("Send Message"), - style="button-primary", - href=f"{reverse('msgs.broadcast_send')}?c={self.object.uuid}", - modax=_("Send Message"), - ) + menu.add_modax( + _("Send Message"), "send-message", f"{reverse('msgs.broadcast_send')}?c={self.object.uuid}" ) - if self.has_org_perm("flows.flow_broadcast"): - links.append( - dict( - id="start-flow", - title=_("Start Flow"), - href=f"{reverse('flows.flow_broadcast', args=[])}?c={self.object.uuid}", - modax=_("Start Flow"), - ) + menu.add_modax( + _("Start Flow"), "start-flow", f"{reverse('flows.flow_broadcast')}?c={self.object.uuid}" ) if self.has_org_perm("contacts.contact_open_ticket"): - links.append( - dict( - id="open-ticket", - title=_("Open Ticket"), - href=reverse("contacts.contact_open_ticket", args=[self.object.id]), - modax=_("Open Ticket"), - ) + menu.add_modax( + _("Open Ticket"), "open-ticket", reverse("contacts.contact_open_ticket", args=[self.object.id]) ) if self.has_org_perm("contacts.contact_update"): - links.append( - dict( - id="edit-contact", - title=_("Edit"), - modax=_("Edit Contact"), - on_submit="contactUpdated()", - href=f"{reverse('contacts.contact_update', args=[self.object.pk])}", - ) + menu.add_modax( + _("Edit"), + "edit-contact", + f"{reverse('contacts.contact_update', args=[self.object.id])}", + title=_("Edit Contact"), + on_submit="contactUpdated()", ) if not self.is_spa(): - links.append( - dict( - id="update-custom-fields", - title=_("Custom Fields"), - modax=_("Custom Fields"), - on_submit="contactUpdated()", - href=f"{reverse('contacts.contact_update_fields', args=[self.object.pk])}", - ) + menu.add_modax( + _("Custom Fields"), + "update-custom-fields", + f"{reverse('contacts.contact_update_fields', args=[self.object.id])}", + on_submit="contactUpdated()", ) if self.object.status != Contact.STATUS_ACTIVE and self.has_org_perm("contacts.contact_restore"): - links.append( - dict( - title=_("Activate"), - style="button-primary", - js_class="posterize", - href=reverse("contacts.contact_restore", args=(self.object.pk,)), - ) - ) - + menu.add_url_post(_("Activate"), reverse("contacts.contact_restore", args=(self.object.id,))) if self.object.status != Contact.STATUS_BLOCKED and self.has_org_perm("contacts.contact_block"): - links.append( - dict( - title=_("Block"), - style="button-primary", - js_class="posterize", - href=reverse("contacts.contact_block", args=(self.object.pk,)), - ) - ) - + menu.add_url_post(_("Block"), reverse("contacts.contact_block", args=(self.object.id,))) if self.object.status != Contact.STATUS_ARCHIVED and self.has_org_perm("contacts.contact_archive"): - links.append( - dict( - title=_("Archive"), - style="btn-primary", - js_class="posterize", - href=reverse("contacts.contact_archive", args=(self.object.pk,)), - ) - ) + menu.add_url_post(_("Archive"), reverse("contacts.contact_archive", args=(self.object.id,))) - user = self.get_user() - if user.is_superuser or user.is_staff: - links.append( - dict( - title=_("Service"), - posterize=True, - href=f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("contacts.contact_read", args=[self.get_object().uuid])}', - ) + if self.request.user.is_superuser or self.request.user.is_staff: + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("contacts.contact_read", args=[self.object.uuid])}', ) - return links - class Scheduled(OrgObjPermsMixin, SmartReadView): """ Merged list of upcoming scheduled events (campaign event fires and scheduled broadcasts) diff --git a/temba/utils/views.py b/temba/utils/views.py index 174211c3d73..0087b542862 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -271,3 +271,40 @@ class CourierURLHandler(ExternalURLHandler): class MailroomURLHandler(ExternalURLHandler): service = "Mailroom" + + +class DropdownMenu: + """ + Utility for building dropdown menus + """ + + def __init__(self): + self.items = [] + + def add_url_post(self, label: str, url: str): + self.items.append({"title": label, "href": url, "js_class": "posterize"}) + + def add_modax(self, label: str, modal_id: str, url: str, *, title: str = None, on_submit: str = None): + self.items.append( + { + "id": modal_id, + "title": label, + "modax": title or label, + "href": url, + "on_submit": on_submit, + } + ) + + +class DropdownMenuMixin: + """ + Mixin for views that have a dropdown menu + """ + + def get_gear_links(self): + menu = DropdownMenu() + self.build_dropdown_menu(menu) + return menu.items + + def build_dropdown_menu(self, menu: DropdownMenu): # pragma: no cover + pass From dcb568ef28b37d221cdba1b9eb698b3537844bc9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 10:34:37 -0500 Subject: [PATCH 040/630] Convert all conact views to use new dropdownmenu mixin --- temba/contacts/views.py | 109 +++++++++------------------------------- temba/utils/views.py | 6 +++ 2 files changed, 31 insertions(+), 84 deletions(-) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 47f61f8cc99..95a9475c2ef 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -1047,16 +1047,14 @@ def get(self, request, *args, **kwargs): } return JsonResponse(summary) - class List(ContactListView): + class List(DropdownMenuMixin, ContactListView): title = _("Active Contacts") system_group = ContactGroup.TYPE_DB_ACTIVE def get_bulk_actions(self): return ("block", "archive", "send") if self.has_org_perm("contacts.contact_update") else () - def get_gear_links(self): - links = [] - + def build_dropdown_menu(self, menu): is_spa = "HTTP_TEMBA_SPA" in self.request.META search = self.request.GET.get("search") @@ -1068,31 +1066,19 @@ def get_gear_links(self): try: parsed = parse_query(self.org, search) if parsed.metadata.allow_as_group: - links.append( - dict( - id="create-smartgroup", - title=_("Create Smart Group"), - modax=_("Create Smart Group"), - href=f"{reverse('contacts.contactgroup_create')}?search={quote_plus(search)}", - ) + menu.add_modax( + _("Create Smart Group"), + "create-smartgroup", + f"{reverse('contacts.contactgroup_create')}?search={quote_plus(search)}", ) except SearchException: # pragma: no cover pass if self.has_org_perm("contacts.contactfield_list") and not is_spa: - links.append(dict(title=_("Manage Fields"), href=reverse("contacts.contactfield_list"))) + menu.add_link(_("Manage Fields"), reverse("contacts.contactfield_list")) if self.has_org_perm("contacts.contact_export"): - links.append( - dict( - id="export-contacts", - title=_("Export"), - modax=_("Export Contacts"), - href=self.derive_export_url(), - ) - ) - - return links + menu.add_modax(_("Export"), "export-contacts", self.derive_export_url(), title=_("Export Contacts")) def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) @@ -1128,7 +1114,7 @@ def get_context_data(self, *args, **kwargs): context["reply_disabled"] = True return context - class Archived(ContactListView): + class Archived(DropdownMenuMixin, ContactListView): title = _("Archived Contacts") template_name = "contacts/contact_archived.haml" system_group = ContactGroup.TYPE_DB_ARCHIVED @@ -1147,70 +1133,35 @@ def get_context_data(self, *args, **kwargs): context["reply_disabled"] = True return context - def get_gear_links(self): - links = [] + def build_dropdown_menu(self, menu): if self.has_org_perm("contacts.contact_delete"): - links.append( - dict( - title=_("Delete All"), - style="btn-default", - on_click="handleDeleteAllContacts(event)", - js_class="contacts-btn-delete-all", - href="#", - ) - ) - return links + menu.add_js(_("Delete All"), "handleDeleteAllContacts(event)", "contacts-btn-delete-all") - class Filter(ContactListView, OrgObjPermsMixin): + class Filter(OrgObjPermsMixin, DropdownMenuMixin, ContactListView): template_name = "contacts/contact_filter.haml" - def get_gear_links(self): - links = [] - + def build_dropdown_menu(self, menu): is_spa = "HTTP_TEMBA_SPA" in self.request.META if self.has_org_perm("contacts.contactfield_list") and not is_spa: - links.append(dict(title=_("Manage Fields"), href=reverse("contacts.contactfield_list"))) + menu.add_link(_("Manage Fields"), reverse("contacts.contactfield_list")) if not self.group.is_system and self.has_org_perm("contacts.contactgroup_update"): - links.append( - dict( - id="edit-group", - title=_("Edit Group"), - modax=_("Edit Group"), - href=reverse("contacts.contactgroup_update", args=[self.group.id]), - ) + menu.add_modax( + _("Edit Group"), "edit-group", reverse("contacts.contactgroup_update", args=[self.group.id]) ) if self.has_org_perm("contacts.contact_export"): - links.append( - dict( - id="export-contacts", - title=_("Export"), - modax=_("Export Contacts"), - href=self.derive_export_url(), - ) - ) + menu.add_modax(_("Export"), "export-contacts", self.derive_export_url(), title=_("Export Contacts")) - links.append( - dict( - id="group-usages", - title=_("Usages"), - modax=_("Usages"), - href=reverse("contacts.contactgroup_usages", args=[self.group.uuid]), - ) + menu.add_modax( + _("Usages"), "group-usages", reverse("contacts.contactgroup_usages", args=[self.group.uuid]) ) if not self.group.is_system and self.has_org_perm("contacts.contactgroup_delete"): - links.append( - dict( - id="delete-group", - title=_("Delete Group"), - modax=_("Delete Group"), - href=reverse("contacts.contactgroup_delete", args=[self.group.uuid]), - ) + menu.add_modax( + _("Delete Group"), "delete-group", reverse("contacts.contactgroup_delete", args=[self.group.uuid]) ) - return links def get_bulk_actions(self): return ("block", "archive") if self.group.is_smart else ("block", "unlabel") @@ -1549,27 +1500,17 @@ def derive_menu(self): ) return menu - class List(SpaMixin, OrgPermsMixin, BulkActionMixin, SmartListView): + class List(SpaMixin, OrgPermsMixin, BulkActionMixin, DropdownMenuMixin, SmartListView): fields = ("name", "query", "count", "created_on") search_fields = ("name__icontains", "query") default_order = ("name",) paginate_by = 250 - def get_gear_links(self): - links = [] + def build_dropdown_menu(self, menu): group_type = self.request.GET.get("type", "") - if group_type != "smart" and self.has_org_perm("contacts.contactgroup_create"): - links.append( - { - "id": "new-group", - "title": _("New Group"), - "style": "button-primary", - "href": f"{reverse('contacts.contactgroup_create')}", - "modax": _("New Group"), - } - ) - return links + if group_type != "smart" and self.has_org_perm("contacts.contactgroup_create"): + menu.add_modax(_("New Group"), "new-group", f"{reverse('contacts.contactgroup_create')}") def get_bulk_actions(self): return ("delete",) if self.has_org_perm("contacts.contactgroup_delete") else () diff --git a/temba/utils/views.py b/temba/utils/views.py index 0087b542862..c1343fa6bef 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -281,6 +281,12 @@ class DropdownMenu: def __init__(self): self.items = [] + def add_link(self, label: str, url: str): + self.items.append({"title": label, "href": url}) + + def add_js(self, label: str, on_click: str, link_class: str): + self.items.append({"title": label, "on_click": on_click, "js_class": link_class, "href": "#"}) + def add_url_post(self, label: str, url: str): self.items.append({"title": label, "href": url, "js_class": "posterize"}) From 54bb87c03ac99412cb1c10c2aaea399736e9a092 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 12:16:46 -0500 Subject: [PATCH 041/630] Use client method to interrupt contact instead of task --- temba/contacts/models.py | 6 ++++-- temba/contacts/tests.py | 21 +++------------------ temba/contacts/views.py | 2 +- temba/mailroom/client.py | 11 ++++++----- temba/mailroom/tests.py | 13 +++++++++++++ temba/tests/mailroom.py | 31 +++++++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 26 deletions(-) diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 005bb233720..3d5c038fc01 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -1066,12 +1066,14 @@ def open_ticket(self, user, ticketer, topic, body: str, assignee=None): self.modify(user, [mod], refresh=False) return self.tickets.order_by("id").last() - def interrupt(self): + def interrupt(self, user) -> bool: """ Interrupts this contact's current flow """ if self.current_flow: - mailroom.queue_interrupt(self.org, contacts=[self]) + sessions = mailroom.get_client().contact_interrupt(self.org.id, user.id, self.id) + return len(sessions) > 0 + return False def block(self, user): """ diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index fedb5dc7a2d..ec5c762c02f 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -1619,27 +1619,12 @@ def test_open_ticket(self, mock_contact_modify): @mock_mailroom def test_interrupt(self, mr_mocks): # noop when contact not in a flow - self.joe.interrupt() - - self.assertEqual([], mr_mocks.queued_batch_tasks) + self.assertFalse(self.joe.interrupt(self.admin)) flow = self.create_flow("Test") - self.joe.current_flow = flow - self.joe.save(update_fields=("current_flow",)) - - self.joe.interrupt() + MockSessionWriter(self.joe, flow).wait().save() - self.assertEqual( - [ - { - "type": "interrupt_sessions", - "org_id": self.org.id, - "task": {"contact_ids": [self.joe.id]}, - "queued_on": matchers.Datetime(), - }, - ], - mr_mocks.queued_batch_tasks, - ) + self.assertTrue(self.joe.interrupt(self.admin)) @mock_mailroom def test_release(self, mr_mocks): diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 7f0fa99f33b..8d3f694a3db 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -1543,7 +1543,7 @@ class Interrupt(OrgObjPermsMixin, SmartUpdateView): success_message = "" def save(self, obj): - obj.interrupt() + obj.interrupt(self.request.user) return obj class Block(OrgObjPermsMixin, SmartUpdateView): diff --git a/temba/mailroom/client.py b/temba/mailroom/client.py index 5de5a2279bb..c3cb55ea2b4 100644 --- a/temba/mailroom/client.py +++ b/temba/mailroom/client.py @@ -230,14 +230,15 @@ def contact_modify(self, org_id, user_id, contact_ids, modifiers: list[Modifier] return self._request("contact/modify", payload) def contact_resolve(self, org_id: int, channel_id: int, urn: str): - payload = { - "org_id": org_id, - "channel_id": channel_id, - "urn": urn, - } + payload = {"org_id": org_id, "channel_id": channel_id, "urn": urn} return self._request("contact/resolve", payload) + def contact_interrupt(self, org_id: int, user_id: int, contact_id: int): + payload = {"org_id": org_id, "user_id": user_id, "contact_id": contact_id} + + return self._request("contact/interrupt", payload) + def contact_search(self, org_id, group_uuid, query, sort, offset=0, exclude_ids=()) -> SearchResults: payload = { "org_id": org_id, diff --git a/temba/mailroom/tests.py b/temba/mailroom/tests.py index 024eacf4858..60632d034ac 100644 --- a/temba/mailroom/tests.py +++ b/temba/mailroom/tests.py @@ -348,6 +348,19 @@ def test_contact_resolve(self, mock_post): json={"org_id": self.org.id, "channel_id": 345, "urn": "tel:+1234567890"}, ) + @patch("requests.post") + def test_contact_interrupt(self, mock_post): + mock_post.return_value = MockResponse(200, '{"sessions": 1}') + + response = get_client().contact_interrupt(self.org.id, 3, 345) + + self.assertEqual({"sessions": 1}, response) + mock_post.assert_called_once_with( + "http://localhost:8090/mr/contact/interrupt", + headers={"User-Agent": "Temba"}, + json={"org_id": self.org.id, "user_id": 3, "contact_id": 345}, + ) + @patch("requests.post") def test_contact_search(self, mock_post): mock_post.return_value = MockResponse( diff --git a/temba/tests/mailroom.py b/temba/tests/mailroom.py index 4f5d7aa7d5e..150befb4600 100644 --- a/temba/tests/mailroom.py +++ b/temba/tests/mailroom.py @@ -16,6 +16,7 @@ from temba import mailroom from temba.campaigns.models import CampaignEvent, EventFire from temba.contacts.models import URN, Contact, ContactField, ContactGroup, ContactURN +from temba.flows.models import FlowRun, FlowSession from temba.locations.models import AdminBoundary from temba.mailroom.client import ContactSpec, MailroomClient, MailroomException from temba.mailroom.modifiers import Modifier @@ -172,6 +173,17 @@ def contact_resolve(self, org_id: int, channel_id: int, urn: str): "urn": {"id": contact_urn.id, "identity": contact_urn.identity}, } + @_client_method + def contact_interrupt(self, org_id: int, user_id: int, contact_id: int): + contact = Contact.objects.get(id=contact_id) + + # get the waiting session IDs + session_ids = list(contact.sessions.filter(status=FlowSession.STATUS_WAITING).values_list("id", flat=True)) + + exit_sessions(session_ids, FlowSession.STATUS_INTERRUPTED) + + return {"sessions": len(session_ids)} + @_client_method def parse_query(self, org_id: int, query: str, parse_only: bool = False, group_uuid: str = ""): org = Org.objects.get(id=org_id) @@ -669,3 +681,22 @@ def decrement_credit(org): r.decr(f"org:{org.id}:cache:credits_remaining:{active_topup_id}", 1) return active_topup_id or None + + +def exit_sessions(session_ids: list, status: str): + FlowRun.objects.filter(session_id__in=session_ids).update( + status=status, exited_on=timezone.now(), modified_on=timezone.now() + ) + FlowSession.objects.filter(id__in=session_ids).update( + status=status, + ended_on=timezone.now(), + wait_started_on=None, + wait_expires_on=None, + timeout_on=None, + current_flow_id=None, + ) + + for session in FlowSession.objects.filter(id__in=session_ids): + session.contact.current_flow = None + session.contact.modified_on = timezone.now() + session.contact.save(update_fields=("current_flow", "modified_on")) From 8125ea1203b433de30d9c24db88445386849d0ab Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 14:02:41 -0500 Subject: [PATCH 042/630] Sort permissions a-z --- temba/settings_common.py | 298 +++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/temba/settings_common.py b/temba/settings_common.py index d2100d0cafc..992de34ad3c 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -387,7 +387,6 @@ "blocked", "break_anon", "export", - "stopped", "filter", "history", "menu", @@ -396,8 +395,9 @@ "restore", "search", "start", - "update_fields", + "stopped", "update_fields_input", + "update_fields", ), "contacts.contactfield": ("api", "json", "menu", "update_priority", "featured", "filter_by_type"), "contacts.contactgroup": ("api", "menu"), @@ -409,47 +409,47 @@ "orgs.org": ( "account", "accounts", - "smtp_server", "api", - "country", "clear_cache", + "country", "create_login", "create_sub_org", "dashboard", "download", - "edit", "edit_sub_org", + "edit", "export", "grant", "home", "import", - "join", "join_accept", + "join", "languages", - "manage", - "manage_accounts", "manage_accounts_sub_org", + "manage_accounts", "manage_integrations", + "manage", "menu", - "vonage_account", - "vonage_connect", "plan", "plivo_connect", - "whatsapp_cloud_connect", "profile", "prometheus", "resthooks", "service", "signup", + "smtp_server", "spa", "sub_orgs", "surveyor", + "token", "transfer_credits", "trial", "twilio_account", "twilio_connect", "two_factor", - "token", + "vonage_account", + "vonage_connect", + "whatsapp_cloud_connect", "workspace", ), "channels.channel": ( @@ -467,9 +467,9 @@ "channels.channelevent": ("api", "calls"), "flows.flowstart": ("api",), "flows.flow": ( - "activity", "activity_chart", "activity_list", + "activity", "api", "archived", "assets", @@ -478,13 +478,13 @@ "category_counts", "change_language", "copy", - "editor", - "export", - "export_translation", "download_translation", - "import_translation", + "editor", "export_results", + "export_translation", + "export", "filter", + "import_translation", "menu", "recent_contacts", "results", @@ -531,14 +531,14 @@ "Dashboard": ("orgs.org_dashboard",), "Surveyors": ( "contacts.contact_api", - "contacts.contactgroup_api", "contacts.contactfield_api", + "contacts.contactgroup_api", "flows.flow_api", "locations.adminboundary_api", + "msgs.msg_api", "orgs.org_api", "orgs.org_spa", "orgs.org_surveyor", - "msgs.msg_api", ), "Granters": ("orgs.org_grant",), "Customer Support": ( @@ -560,18 +560,18 @@ "orgs.org_delete", "orgs.org_grant", "orgs.org_manage", - "orgs.org_update", "orgs.org_service", "orgs.org_spa", + "orgs.org_update", "orgs.topup_create", "orgs.topup_manage", "orgs.topup_update", "orgs.user_list", "orgs.user_update", - "policies.policy_create", - "policies.policy_update", "policies.policy_admin", + "policies.policy_create", "policies.policy_history", + "policies.policy_update", ), "Administrators": ( "airtime.airtimetransfer_list", @@ -583,12 +583,29 @@ "archives.archive.*", "campaigns.campaign.*", "campaigns.campaignevent.*", + "channels.channel_api", + "channels.channel_bulk_sender_options", + "channels.channel_claim", + "channels.channel_configuration", + "channels.channel_create_bulk_sender", + "channels.channel_create_caller", + "channels.channel_create", + "channels.channel_delete", + "channels.channel_facebook_whitelist", + "channels.channel_list", + "channels.channel_menu", + "channels.channel_read", + "channels.channel_update", + "channels.channelevent.*", + "channels.channellog_connection", + "channels.channellog_list", + "channels.channellog_read", "classifiers.classifier_api", "classifiers.classifier_connect", - "classifiers.classifier_read", "classifiers.classifier_delete", "classifiers.classifier_list", "classifiers.classifier_menu", + "classifiers.classifier_read", "classifiers.classifier_sync", "classifiers.intent_api", "contacts.contact_api", @@ -609,102 +626,85 @@ "contacts.contact_restore", "contacts.contact_search", "contacts.contact_stopped", - "contacts.contact_update", - "contacts.contact_update_fields", "contacts.contact_update_fields_input", + "contacts.contact_update_fields", + "contacts.contact_update", "contacts.contactfield.*", "contacts.contactgroup.*", "contacts.contactimport.*", "csv_imports.importtask.*", + "flows.flow.*", + "flows.flowlabel.*", + "flows.flowrun_delete", + "flows.flowstart.*", + "flows.ruleset.*", "globals.global.*", "ivr.ivrcall.*", "locations.adminboundary_alias", "locations.adminboundary_api", "locations.adminboundary_boundaries", "locations.adminboundary_geometry", - "notifications.notification.*", + "msgs.broadcast.*", + "msgs.broadcastschedule.*", + "msgs.label.*", + "msgs.msg_api", + "msgs.msg_archive", + "msgs.msg_archived", + "msgs.msg_delete", + "msgs.msg_export", + "msgs.msg_failed", + "msgs.msg_filter", + "msgs.msg_flow", + "msgs.msg_inbox", + "msgs.msg_label", + "msgs.msg_menu", + "msgs.msg_outbox", + "msgs.msg_sent", + "msgs.msg_update", "notifications.incident.*", + "notifications.notification.*", "orgs.org_account", "orgs.org_accounts", - "orgs.org_smtp_server", "orgs.org_api", "orgs.org_country", "orgs.org_create_sub_org", "orgs.org_dashboard", "orgs.org_download", - "orgs.org_edit", "orgs.org_edit_sub_org", + "orgs.org_edit", "orgs.org_export", "orgs.org_home", "orgs.org_import", "orgs.org_languages", - "orgs.org_manage_accounts", "orgs.org_manage_accounts_sub_org", + "orgs.org_manage_accounts", "orgs.org_manage_integrations", "orgs.org_menu", - "orgs.org_vonage_account", - "orgs.org_vonage_connect", "orgs.org_plan", "orgs.org_plivo_connect", "orgs.org_profile", "orgs.org_prometheus", "orgs.org_resthooks", + "orgs.org_smtp_server", "orgs.org_spa", "orgs.org_sub_orgs", + "orgs.org_token", "orgs.org_transfer_credits", "orgs.org_twilio_account", "orgs.org_twilio_connect", "orgs.org_two_factor", - "orgs.org_token", + "orgs.org_vonage_account", + "orgs.org_vonage_connect", "orgs.org_workspace", "orgs.topup_list", "orgs.topup_read", - "channels.channel_api", - "channels.channel_bulk_sender_options", - "channels.channel_claim", - "channels.channel_configuration", - "channels.channel_create", - "channels.channel_create_bulk_sender", - "channels.channel_create_caller", - "channels.channel_facebook_whitelist", - "channels.channel_delete", - "channels.channel_list", - "channels.channel_menu", - "channels.channel_read", - "channels.channel_update", - "channels.channelevent.*", - "channels.channellog_list", - "channels.channellog_read", - "channels.channellog_connection", - "flows.flow.*", - "flows.flowstart.*", - "flows.flowlabel.*", - "flows.ruleset.*", - "flows.flowrun_delete", - "schedules.schedule.*", - "msgs.broadcast.*", - "msgs.broadcastschedule.*", - "msgs.label.*", - "msgs.msg_api", - "msgs.msg_archive", - "msgs.msg_archived", - "msgs.msg_delete", - "msgs.msg_export", - "msgs.msg_failed", - "msgs.msg_filter", - "msgs.msg_flow", - "msgs.msg_inbox", - "msgs.msg_label", - "msgs.msg_menu", - "msgs.msg_outbox", - "msgs.msg_sent", - "msgs.msg_update", - "policies.policy_read", - "policies.policy_list", "policies.policy_give_consent", + "policies.policy_list", + "policies.policy_read", "request_logs.httplog_list", "request_logs.httplog_read", "request_logs.httplog_webhooks", + "schedules.schedule.*", "templates.template_api", "tickets.ticket.*", "tickets.ticketer.*", @@ -712,6 +712,8 @@ "triggers.trigger.*", ), "Editors": ( + "airtime.airtimetransfer_list", + "airtime.airtimetransfer_read", "api.apitoken_refresh", "api.resthook_api", "api.resthooksubscriber_api", @@ -719,14 +721,25 @@ "api.webhookevent_list", "api.webhookevent_read", "archives.archive.*", - "airtime.airtimetransfer_list", - "airtime.airtimetransfer_read", "campaigns.campaign.*", "campaigns.campaignevent.*", + "channels.channel_api", + "channels.channel_bulk_sender_options", + "channels.channel_claim", + "channels.channel_configuration", + "channels.channel_create_bulk_sender", + "channels.channel_create_caller", + "channels.channel_create", + "channels.channel_delete", + "channels.channel_list", + "channels.channel_menu", + "channels.channel_read", + "channels.channel_update", + "channels.channelevent.*", "classifiers.classifier_api", - "classifiers.classifier_read", "classifiers.classifier_list", "classifiers.classifier_menu", + "classifiers.classifier_read", "classifiers.intent_api", "contacts.contact_api", "contacts.contact_archive", @@ -746,54 +759,24 @@ "contacts.contact_restore", "contacts.contact_search", "contacts.contact_stopped", - "contacts.contact_update", - "contacts.contact_update_fields", "contacts.contact_update_fields_input", + "contacts.contact_update_fields", + "contacts.contact_update", "contacts.contactfield.*", "contacts.contactgroup.*", "contacts.contactimport.*", "csv_imports.importtask.*", - "ivr.ivrcall.*", + "flows.flow.*", + "flows.flowlabel.*", + "flows.flowstart_api", + "flows.flowstart_list", + "flows.ruleset.*", "globals.global_api", + "ivr.ivrcall.*", "locations.adminboundary_alias", "locations.adminboundary_api", "locations.adminboundary_boundaries", "locations.adminboundary_geometry", - "notifications.notification_list", - "orgs.org_account", - "orgs.org_api", - "orgs.org_download", - "orgs.org_export", - "orgs.org_home", - "orgs.org_import", - "orgs.org_menu", - "orgs.org_profile", - "orgs.org_resthooks", - "orgs.org_spa", - "orgs.org_two_factor", - "orgs.org_token", - "orgs.org_workspace", - "orgs.topup_list", - "orgs.topup_read", - "channels.channel_api", - "channels.channel_bulk_sender_options", - "channels.channel_claim", - "channels.channel_configuration", - "channels.channel_create", - "channels.channel_create_bulk_sender", - "channels.channel_create_caller", - "channels.channel_delete", - "channels.channel_list", - "channels.channel_menu", - "channels.channel_read", - "channels.channel_update", - "channels.channelevent.*", - "flows.flow.*", - "flows.flowstart_api", - "flows.flowstart_list", - "flows.flowlabel.*", - "flows.ruleset.*", - "schedules.schedule.*", "msgs.broadcast.*", "msgs.broadcastschedule.*", "msgs.label.*", @@ -811,10 +794,27 @@ "msgs.msg_outbox", "msgs.msg_sent", "msgs.msg_update", - "policies.policy_read", - "policies.policy_list", + "notifications.notification_list", + "orgs.org_account", + "orgs.org_api", + "orgs.org_download", + "orgs.org_export", + "orgs.org_home", + "orgs.org_import", + "orgs.org_menu", + "orgs.org_profile", + "orgs.org_resthooks", + "orgs.org_spa", + "orgs.org_token", + "orgs.org_two_factor", + "orgs.org_workspace", + "orgs.topup_list", + "orgs.topup_read", "policies.policy_give_consent", + "policies.policy_list", + "policies.policy_read", "request_logs.httplog_webhooks", + "schedules.schedule.*", "templates.template_api", "tickets.ticket.*", "tickets.ticketer_api", @@ -827,10 +827,14 @@ "campaigns.campaign_menu", "campaigns.campaign_read", "campaigns.campaignevent_read", + "channels.channel_list", + "channels.channel_menu", + "channels.channel_read", + "channels.channelevent_calls", "classifiers.classifier_api", - "classifiers.classifier_read", "classifiers.classifier_list", "classifiers.classifier_menu", + "classifiers.classifier_read", "classifiers.intent_api", "contacts.contact_archived", "contacts.contact_blocked", @@ -848,44 +852,28 @@ "contacts.contactgroup_menu", "contacts.contactgroup_read", "contacts.contactimport_read", - "globals.global_api", - "locations.adminboundary_boundaries", - "locations.adminboundary_geometry", - "locations.adminboundary_alias", - "notifications.notification_list", - "orgs.org_account", - "orgs.org_download", - "orgs.org_export", - "orgs.org_home", - "orgs.org_menu", - "orgs.org_profile", - "orgs.org_spa", - "orgs.org_two_factor", - "orgs.org_workspace", - "orgs.topup_list", - "orgs.topup_read", - "channels.channel_list", - "channels.channel_menu", - "channels.channel_read", - "channels.channelevent_calls", - "flows.flow_activity", "flows.flow_activity_chart", + "flows.flow_activity", "flows.flow_archived", "flows.flow_assets", "flows.flow_campaign", "flows.flow_category_counts", - "flows.flow_export", + "flows.flow_editor", "flows.flow_export_results", + "flows.flow_export", "flows.flow_filter", "flows.flow_list", "flows.flow_menu", - "flows.flow_editor", "flows.flow_recent_contacts", "flows.flow_results", "flows.flow_revisions", "flows.flow_run_table", "flows.flow_simulate", "flows.flowstart_list", + "globals.global_api", + "locations.adminboundary_alias", + "locations.adminboundary_boundaries", + "locations.adminboundary_geometry", "msgs.broadcast_schedule_list", "msgs.broadcast_schedule_read", "msgs.label_api", @@ -899,10 +887,22 @@ "msgs.msg_menu", "msgs.msg_outbox", "msgs.msg_sent", + "notifications.notification_list", + "orgs.org_account", + "orgs.org_download", + "orgs.org_export", + "orgs.org_home", "orgs.org_menu", - "policies.policy_read", - "policies.policy_list", + "orgs.org_menu", + "orgs.org_profile", + "orgs.org_spa", + "orgs.org_two_factor", + "orgs.org_workspace", + "orgs.topup_list", + "orgs.topup_read", "policies.policy_give_consent", + "policies.policy_list", + "policies.policy_read", "tickets.ticketer_api", "tickets.topic_api", "triggers.trigger_archived", @@ -918,6 +918,12 @@ "globals.global_api", "msgs.broadcast_api", "notifications.notification_list", + "orgs.org_account", + "orgs.org_home", + "orgs.org_menu", + "orgs.org_profile", + "orgs.org_spa", + "policies.policy_give_consent", "tickets.ticket_api", "tickets.ticket_assign", "tickets.ticket_assignee", @@ -925,12 +931,6 @@ "tickets.ticket_menu", "tickets.ticket_note", "tickets.topic_api", - "orgs.org_account", - "orgs.org_home", - "orgs.org_menu", - "orgs.org_profile", - "orgs.org_spa", - "policies.policy_give_consent", ), "Prometheus": (), } From c8d6bc7680187cd5ba32cd4ac9401463285c7a07 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 14:08:45 -0500 Subject: [PATCH 043/630] Sort by types as well in PERMISSIONS --- temba/settings_common.py | 124 +++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/temba/settings_common.py b/temba/settings_common.py index 992de34ad3c..b482bc89807 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -375,8 +375,22 @@ "api.resthook": ("api", "list"), "api.webhookevent": ("api",), "api.resthooksubscriber": ("api",), + "archives.archive": ("api", "run", "message"), "campaigns.campaign": ("api", "archived", "archive", "activate", "menu"), "campaigns.campaignevent": ("api",), + "channels.channel": ( + "api", + "bulk_sender_options", + "claim", + "configuration", + "create_bulk_sender", + "create_caller", + "errors", + "facebook_whitelist", + "menu", + ), + "channels.channellog": ("connection",), + "channels.channelevent": ("api", "calls"), "classifiers.classifier": ("connect", "api", "sync", "menu"), "classifiers.intent": ("api",), "contacts.contact": ( @@ -402,10 +416,56 @@ "contacts.contactfield": ("api", "json", "menu", "update_priority", "featured", "filter_by_type"), "contacts.contactgroup": ("api", "menu"), "contacts.contactimport": ("preview",), - "ivr.ivrcall": ("start",), - "archives.archive": ("api", "run", "message"), + "flows.flowstart": ("api",), + "flows.flow": ( + "activity_chart", + "activity_list", + "activity", + "api", + "archived", + "assets", + "broadcast", + "campaign", + "category_counts", + "change_language", + "copy", + "download_translation", + "editor", + "export_results", + "export_translation", + "export", + "filter", + "import_translation", + "menu", + "recent_contacts", + "results", + "revisions", + "run_table", + "simulate", + "upload_action_recording", + "upload_media_action", + ), + "flows.flowsession": ("json",), "globals.global": ("api", "unused"), + "ivr.ivrcall": ("start",), "locations.adminboundary": ("alias", "api", "boundaries", "geometry"), + "msgs.broadcast": ("api", "detail", "schedule", "schedule_list", "schedule_read", "send"), + "msgs.label": ("api", "delete_folder"), + "msgs.msg": ( + "api", + "archive", + "archived", + "export", + "failed", + "filter", + "flow", + "inbox", + "label", + "menu", + "outbox", + "sent", + "update", + ), "orgs.org": ( "account", "accounts", @@ -452,66 +512,6 @@ "whatsapp_cloud_connect", "workspace", ), - "channels.channel": ( - "api", - "bulk_sender_options", - "claim", - "configuration", - "create_bulk_sender", - "create_caller", - "errors", - "facebook_whitelist", - "menu", - ), - "channels.channellog": ("connection",), - "channels.channelevent": ("api", "calls"), - "flows.flowstart": ("api",), - "flows.flow": ( - "activity_chart", - "activity_list", - "activity", - "api", - "archived", - "assets", - "broadcast", - "campaign", - "category_counts", - "change_language", - "copy", - "download_translation", - "editor", - "export_results", - "export_translation", - "export", - "filter", - "import_translation", - "menu", - "recent_contacts", - "results", - "revisions", - "run_table", - "simulate", - "upload_action_recording", - "upload_media_action", - ), - "flows.flowsession": ("json",), - "msgs.msg": ( - "api", - "archive", - "archived", - "export", - "failed", - "filter", - "flow", - "inbox", - "label", - "menu", - "outbox", - "sent", - "update", - ), - "msgs.broadcast": ("api", "detail", "schedule", "schedule_list", "schedule_read", "send"), - "msgs.label": ("api", "delete_folder"), "orgs.topup": ("manage",), "policies.policy": ("admin", "history", "give_consent"), "request_logs.httplog": ("webhooks", "classifier", "ticketer"), From ede67fcaa2b94ebac703e1e655c53fd0ec76a562 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 14:36:25 -0500 Subject: [PATCH 044/630] Add features to BRANDING which determines whether brands have access to features --- temba/orgs/tests.py | 3 ++- temba/orgs/views.py | 12 +++++------- temba/settings_common.py | 10 +--------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index e91d3e3d65d..f1824fcc665 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -1187,7 +1187,8 @@ def test_country_view(self): # if location support is disabled in the branding, don't display country formax current_branding = settings.BRANDING["rapidpro.io"] - with override_settings(BRANDING={"rapidpro.io": {**current_branding, "location_support": False}}): + + with override_settings(BRANDING={"rapidpro.io": {**current_branding, "features": []}}): response = self.client.get(home_url) self.assertNotContains(response, "Rwanda") diff --git a/temba/orgs/views.py b/temba/orgs/views.py index 78e9b8300b2..bef60c5d144 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -3306,10 +3306,7 @@ def get_gear_links(self): return links def derive_formax_sections(self, formax, context): - - # add the channel option if we have one - user = self.request.user - org = user.get_org() + org = self.request.org if self.has_org_perm("orgs.org_edit"): formax.add_section("org", reverse("orgs.org_edit"), icon="icon-office") @@ -3321,7 +3318,7 @@ def derive_formax_sections(self, formax, context): if self.has_org_perm("orgs.org_languages"): formax.add_section("languages", reverse("orgs.org_languages"), icon="icon-language") - if self.has_org_perm("orgs.org_country") and org.get_branding().get("location_support"): + if self.has_org_perm("orgs.org_country") and "locations" in org.get_branding().get("features", []): formax.add_section("country", reverse("orgs.org_country"), icon="icon-location2") if self.has_org_perm("orgs.org_smtp_server"): @@ -3343,6 +3340,7 @@ class Home(SpaMixin, FormaxMixin, InferOrgMixin, OrgPermsMixin, SmartReadView): title = _("Your Account") def get_gear_links(self): + org = self.request.org links = [] if self.has_org_perm("channels.channel_claim"): @@ -3351,7 +3349,7 @@ def get_gear_links(self): if self.has_org_perm("classifiers.classifier_connect"): links.append(dict(title=_("Add Classifier"), href=reverse("classifiers.classifier_connect"))) - if self.has_org_perm("tickets.ticketer_connect"): + if self.has_org_perm("tickets.ticketer_connect") and "ticketers" in org.get_branding().get("features", []): links.append(dict(title=_("Add Ticketing Service"), href=reverse("tickets.ticketer_connect"))) if len(links) > 0: @@ -3468,7 +3466,7 @@ def derive_formax_sections(self, formax, context): if self.has_org_perm("orgs.org_languages"): formax.add_section("languages", reverse("orgs.org_languages"), icon="icon-language") - if self.has_org_perm("orgs.org_country") and org.get_branding().get("location_support"): + if self.has_org_perm("orgs.org_country") and "locations" in org.get_branding().get("features", []): formax.add_section("country", reverse("orgs.org_country"), icon="icon-location2") if self.has_org_perm("orgs.org_smtp_server"): diff --git a/temba/settings_common.py b/temba/settings_common.py index d2100d0cafc..17b1ab344a6 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -45,14 +45,6 @@ USE_DEPRECATED_PYTZ = True -# ----------------------------------------------------------------------------------- -# Location support -# ----------------------------------------------------------------------------------- -LOCATION_SUPPORT = True - -# hardcode the postgis version so we can do reset db's from a blank database -POSTGIS_VERSION = (2, 1) - # ----------------------------------------------------------------------------------- # set the mail settings, override these in your settings.py # if your site was at http://temba.io, it might look like this: @@ -346,7 +338,7 @@ "logo": "brands/rapidpro/logo.png", "allow_signups": True, "flow_types": ["M", "V", "B", "S"], # see Flow.FLOW_TYPES - "location_support": True, + "features": ["locations", "ticketers"], "tiers": dict(multi_user=0, multi_org=0), "bundles": [], "welcome_packs": [dict(size=5000, name="Demo Account"), dict(size=100000, name="UNICEF Account")], From e01cf4f434b4e50a3fd855e80a16e0c8becc5993 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 22 Jul 2022 15:14:27 -0500 Subject: [PATCH 045/630] Add tests --- temba/contacts/tests.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index ec5c762c02f..446c49b478e 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -801,6 +801,43 @@ def test_restore(self, mr_mocks): other_org_contact.refresh_from_db() self.assertEqual(Contact.STATUS_STOPPED, other_org_contact.status) + @mock_mailroom + def test_interrupt(self, mr_mocks): + contact = self.create_contact("Joe", phone="+593979000111") + other_org_contact = self.create_contact("Hans", phone="+593979123456", org=self.org2) + + MockSessionWriter(contact, self.create_flow("Test")).wait().save() + MockSessionWriter(other_org_contact, self.create_flow("Test", org=self.org2)).wait().save() + + interrupt_url = reverse("contacts.contact_interrupt", args=[contact.id]) + + # can't interrupt if not logged in + response = self.client.post(interrupt_url, {"id": contact.id}) + self.assertLoginRedirect(response) + + self.login(self.user) + + # can't interrupt if just regular user + response = self.client.post(interrupt_url, {"id": contact.id}) + self.assertLoginRedirect(response) + + self.login(self.admin) + + response = self.client.post(interrupt_url, {"id": contact.id}) + self.assertEqual(302, response.status_code) + + contact.refresh_from_db() + self.assertIsNone(contact.current_flow) + + # can't interrupt contact in other org + restore_url = reverse("contacts.contact_interrupt", args=[other_org_contact.id]) + response = self.client.post(restore_url, {"id": other_org_contact.id}) + self.assertLoginRedirect(response) + + # contact should be unchanged + other_org_contact.refresh_from_db() + self.assertIsNotNone(other_org_contact.current_flow) + def test_delete(self): contact = self.create_contact("Joe", phone="+593979000111") other_org_contact = self.create_contact("Hans", phone="+593979123456", org=self.org2) From a2a1048294890ae568e82b8034db419183c5b3a7 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Sat, 23 Jul 2022 00:03:07 +0200 Subject: [PATCH 046/630] Add logging for IG channel claim failures --- temba/channels/types/instagram/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/temba/channels/types/instagram/views.py b/temba/channels/types/instagram/views.py index bc31c9cb9ff..ccd8438c985 100644 --- a/temba/channels/types/instagram/views.py +++ b/temba/channels/types/instagram/views.py @@ -1,3 +1,5 @@ +import logging + import requests from smartmin.views import SmartFormView, SmartModelActionView @@ -11,6 +13,8 @@ from ...models import Channel from ...views import ClaimViewMixin +logger = logging.getLogger(__name__) + class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): @@ -115,7 +119,8 @@ def clean(self): response_json = response.json() self.cleaned_data["ig_user_id"] = response_json.get("instagram_business_account").get("id") - except Exception: + except Exception as e: + logger.error(f"Unable to connect Instagram channel with error: {str(e)}", exc_info=True) raise forms.ValidationError(_("Sorry your Instagram channel could not be connected. Please try again")) return self.cleaned_data From 4e04a9b04259c965885c57be5b44f7bccda9c7cb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 25 Jul 2022 15:18:22 -0500 Subject: [PATCH 047/630] Add Media model --- temba/msgs/migrations/0176_media.py | 38 +++++++++++++++++++++++++++++ temba/msgs/models.py | 17 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 temba/msgs/migrations/0176_media.py diff --git a/temba/msgs/migrations/0176_media.py b/temba/msgs/migrations/0176_media.py new file mode 100644 index 00000000000..f33509806cb --- /dev/null +++ b/temba/msgs/migrations/0176_media.py @@ -0,0 +1,38 @@ +# Generated by Django 4.0.6 on 2022-07-25 20:17 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("orgs", "0101_remove_org_administrators_remove_org_agents_and_more"), + ("msgs", "0175_alter_msg_failed_reason"), + ] + + operations = [ + migrations.CreateModel( + name="Media", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("content_type", models.CharField(max_length=64)), + ("url", models.URLField(db_index=True, max_length=2048)), + ("alternates", models.JSONField()), + ("duration", models.IntegerField(default=0)), + ("created_on", models.DateTimeField(default=django.utils.timezone.now)), + ( + "created_by", + models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ("org", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="orgs.org")), + ( + "thumbnail", + models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to="msgs.media"), + ), + ], + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 586ae5c28fb..7970b14418b 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -40,6 +40,23 @@ class UnreachableException(Exception): pass +class Media(models.Model): + """ + An uploaded media file that can be used as an attachment on messages. + """ + + org = models.ForeignKey(Org, on_delete=models.PROTECT) + content_type = models.CharField(max_length=64) + url = models.URLField(max_length=2048, db_index=True) + alternates = models.JSONField() + + duration = models.IntegerField(default=0) + thumbnail = models.ForeignKey("msgs.Media", null=True, on_delete=models.PROTECT) + + created_by = models.ForeignKey(User, on_delete=models.PROTECT) + created_on = models.DateTimeField(default=timezone.now) + + class Broadcast(models.Model): """ A broadcast is a message that is sent out to more than one recipient, such From e2a7003fe26f974a353f92507da1d9bb4063b3d3 Mon Sep 17 00:00:00 2001 From: Rafael Soares Date: Mon, 25 Jul 2022 15:34:11 -0300 Subject: [PATCH 048/630] tweak slack channel claim views help texts --- temba/channels/types/slack/tests.py | 8 ++++---- temba/channels/types/slack/views.py | 12 +++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/temba/channels/types/slack/tests.py b/temba/channels/types/slack/tests.py index 95b9325708d..b45e17c78e8 100644 --- a/temba/channels/types/slack/tests.py +++ b/temba/channels/types/slack/tests.py @@ -56,7 +56,7 @@ def test_claim(self, mock_api_call): response.context["form"].errors["bot_token"][0], ), - # test to claim a channel with a bot token that already exists for another organization + # test to claim a channel with a bot token that already exists for another workspace. auth_test = { "ok": True, "url": "https://12345-team-group.slack.com/", @@ -80,7 +80,7 @@ def test_claim(self, mock_api_call): }, ) self.assertEqual( - "A slack channel for this bot already exists in another organization.", + "A slack channel for this bot already exists in another workspace.", response.context["form"].errors["bot_token"][0], ) @@ -125,7 +125,7 @@ def test_claim(self, mock_api_call): response = self.client.get(config_url) self.assertEqual(response.status_code, 200) - # test to claim a channel with a bot token that already exists in this organization + # test to claim a channel with a bot token that already exists in this workspace response = self.client.post( url, { @@ -135,7 +135,7 @@ def test_claim(self, mock_api_call): }, ) self.assertEqual( - "A slack channel for this bot already exists in this organization.", + "A slack channel for this bot already exists in this workspace.", response.context["form"].errors["bot_token"][0], ) diff --git a/temba/channels/types/slack/views.py b/temba/channels/types/slack/views.py index f7148befc71..5cffcba7af5 100644 --- a/temba/channels/types/slack/views.py +++ b/temba/channels/types/slack/views.py @@ -14,20 +14,18 @@ class Form(ClaimViewMixin.Form): user_token = forms.CharField( label=_("User OAuth Token"), help_text=_( - "In https://api.slack.com/apps select your bot app and go to Features / OAuth & Permissions to see this information." + "In Slack select your bot app and go to Features / OAuth & Permissions to see this information." ), ) bot_token = forms.CharField( label=_("Bot User OAuth Token"), help_text=_( - "In https://api.slack.com/apps select your bot app and go to Features / OAuth & Permissions to see this information." + "In Slack select your bot app and go to Features / OAuth & Permissions to see this information." ), ) verification_token = forms.CharField( label=_("Verification Token"), - help_text=_( - "In https://api.slack.com/apps go to Settings / Basic information, find in App Credentials and paste here." - ), + help_text=_("In Slack go to Settings / Basic information, find in App Credentials and paste here."), ) def clean_user_token(self): @@ -56,8 +54,8 @@ def clean_bot_token(self): if existing: if existing.org_id == self.request.user.get_org().id: - raise ValidationError(_("A slack channel for this bot already exists in this organization.")) - raise ValidationError(_("A slack channel for this bot already exists in another organization.")) + raise ValidationError(_("A slack channel for this bot already exists in this workspace.")) + raise ValidationError(_("A slack channel for this bot already exists in another workspace.")) return value From 710f9d6e522059dc3ab391004007b93b90578766 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 25 Jul 2022 18:03:36 -0500 Subject: [PATCH 049/630] Add option to style button as primary --- temba/contacts/views.py | 7 +++++-- temba/utils/views.py | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 95a9475c2ef..8e48a914dd8 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -866,7 +866,10 @@ def build_dropdown_menu(self, menu): if self.object.status == Contact.STATUS_ACTIVE: if not self.is_spa() and self.has_org_perm("msgs.broadcast_send"): menu.add_modax( - _("Send Message"), "send-message", f"{reverse('msgs.broadcast_send')}?c={self.object.uuid}" + _("Send Message"), + "send-message", + f"{reverse('msgs.broadcast_send')}?c={self.object.uuid}", + primary=True, ) if self.has_org_perm("flows.flow_broadcast"): menu.add_modax( @@ -1510,7 +1513,7 @@ def build_dropdown_menu(self, menu): group_type = self.request.GET.get("type", "") if group_type != "smart" and self.has_org_perm("contacts.contactgroup_create"): - menu.add_modax(_("New Group"), "new-group", f"{reverse('contacts.contactgroup_create')}") + menu.add_modax(_("New Group"), "new-group", f"{reverse('contacts.contactgroup_create')}", primary=True) def get_bulk_actions(self): return ("delete",) if self.has_org_perm("contacts.contactgroup_delete") else () diff --git a/temba/utils/views.py b/temba/utils/views.py index c1343fa6bef..72fe256cfe2 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -290,7 +290,9 @@ def add_js(self, label: str, on_click: str, link_class: str): def add_url_post(self, label: str, url: str): self.items.append({"title": label, "href": url, "js_class": "posterize"}) - def add_modax(self, label: str, modal_id: str, url: str, *, title: str = None, on_submit: str = None): + def add_modax( + self, label: str, modal_id: str, url: str, *, title: str = None, on_submit: str = None, primary: bool = False + ): self.items.append( { "id": modal_id, @@ -298,6 +300,7 @@ def add_modax(self, label: str, modal_id: str, url: str, *, title: str = None, o "modax": title or label, "href": url, "on_submit": on_submit, + "style": "button-primary" if primary else "", } ) From f5e3e2689f9ec21a07b1bc84f4f1ba88a1cccd95 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 25 Jul 2022 18:09:16 -0500 Subject: [PATCH 050/630] Rename DropdownMenu to ContentMenu --- temba/contacts/views.py | 22 +++++++++++----------- temba/utils/views.py | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 8e48a914dd8..3dc65d7e8c3 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -59,7 +59,7 @@ ) from temba.utils.models import patch_queryset_count from temba.utils.models.es import IDSliceQuerySet -from temba.utils.views import BulkActionMixin, ComponentFormMixin, DropdownMenuMixin, NonAtomicMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ComponentFormMixin, ContentMenuMixin, NonAtomicMixin, SpaMixin from .models import ( URN, @@ -774,7 +774,7 @@ def render_to_response(self, context, **response_kwargs): return HttpResponse(json.dumps(json_result), content_type="application/json") - class Read(SpaMixin, OrgObjPermsMixin, DropdownMenuMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" fields = ("name",) select_related = ("current_flow",) @@ -862,7 +862,7 @@ def post(self, request, *args, **kwargs): return HttpResponse("unknown action", status=400) # pragma: no cover - def build_dropdown_menu(self, menu): + def build_content_menu(self, menu): if self.object.status == Contact.STATUS_ACTIVE: if not self.is_spa() and self.has_org_perm("msgs.broadcast_send"): menu.add_modax( @@ -1050,14 +1050,14 @@ def get(self, request, *args, **kwargs): } return JsonResponse(summary) - class List(DropdownMenuMixin, ContactListView): + class List(ContentMenuMixin, ContactListView): title = _("Active Contacts") system_group = ContactGroup.TYPE_DB_ACTIVE def get_bulk_actions(self): return ("block", "archive", "send") if self.has_org_perm("contacts.contact_update") else () - def build_dropdown_menu(self, menu): + def build_content_menu(self, menu): is_spa = "HTTP_TEMBA_SPA" in self.request.META search = self.request.GET.get("search") @@ -1117,7 +1117,7 @@ def get_context_data(self, *args, **kwargs): context["reply_disabled"] = True return context - class Archived(DropdownMenuMixin, ContactListView): + class Archived(ContentMenuMixin, ContactListView): title = _("Archived Contacts") template_name = "contacts/contact_archived.haml" system_group = ContactGroup.TYPE_DB_ARCHIVED @@ -1136,14 +1136,14 @@ def get_context_data(self, *args, **kwargs): context["reply_disabled"] = True return context - def build_dropdown_menu(self, menu): + def build_content_menu(self, menu): if self.has_org_perm("contacts.contact_delete"): menu.add_js(_("Delete All"), "handleDeleteAllContacts(event)", "contacts-btn-delete-all") - class Filter(OrgObjPermsMixin, DropdownMenuMixin, ContactListView): + class Filter(OrgObjPermsMixin, ContentMenuMixin, ContactListView): template_name = "contacts/contact_filter.haml" - def build_dropdown_menu(self, menu): + def build_content_menu(self, menu): is_spa = "HTTP_TEMBA_SPA" in self.request.META if self.has_org_perm("contacts.contactfield_list") and not is_spa: @@ -1503,13 +1503,13 @@ def derive_menu(self): ) return menu - class List(SpaMixin, OrgPermsMixin, BulkActionMixin, DropdownMenuMixin, SmartListView): + class List(SpaMixin, OrgPermsMixin, BulkActionMixin, ContentMenuMixin, SmartListView): fields = ("name", "query", "count", "created_on") search_fields = ("name__icontains", "query") default_order = ("name",) paginate_by = 250 - def build_dropdown_menu(self, menu): + def build_content_menu(self, menu): group_type = self.request.GET.get("type", "") if group_type != "smart" and self.has_org_perm("contacts.contactgroup_create"): diff --git a/temba/utils/views.py b/temba/utils/views.py index 72fe256cfe2..fb8455b5163 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -273,9 +273,9 @@ class MailroomURLHandler(ExternalURLHandler): service = "Mailroom" -class DropdownMenu: +class ContentMenu: """ - Utility for building dropdown menus + Utility for building content menus """ def __init__(self): @@ -305,15 +305,15 @@ def add_modax( ) -class DropdownMenuMixin: +class ContentMenuMixin: """ - Mixin for views that have a dropdown menu + Mixin for views that have a content menu (hamburger icon with dropdown items) """ def get_gear_links(self): - menu = DropdownMenu() - self.build_dropdown_menu(menu) + menu = ContentMenu() + self.build_content_menu(menu) return menu.items - def build_dropdown_menu(self, menu: DropdownMenu): # pragma: no cover + def build_content_menu(self, menu: ContentMenu): # pragma: no cover pass From b63abfcf235f17358b73445bd9ab3dffa97c58a2 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Mon, 25 Jul 2022 16:27:17 -0700 Subject: [PATCH 051/630] Fix scripts on contact page start modal --- static/js/temba.js | 8 ++++++++ templates/flows/flow_broadcast.haml | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/static/js/temba.js b/static/js/temba.js index 7b8390549b5..363251c76f7 100644 --- a/static/js/temba.js +++ b/static/js/temba.js @@ -3,6 +3,14 @@ if (typeof console == 'undefined') { this.console = { log: function (msg) {} }; } +function getModax(id) { + var modax = document.querySelector(id); + if (!modax) { + modax = document.querySelector("#shared-modax") + } + return modax +} + function checkInner(event) { if (event.target) { var checkbox = event.target.querySelector("temba-checkbox"); diff --git a/templates/flows/flow_broadcast.haml b/templates/flows/flow_broadcast.haml index 046a7e3126b..03f0a5cb93a 100644 --- a/templates/flows/flow_broadcast.haml +++ b/templates/flows/flow_broadcast.haml @@ -80,7 +80,7 @@ :javascript function resetWarnings() { - var modax = document.querySelector("#start-flow, #shared-modax"); + var modax = getModax("#start-flow"); var modalBody = modax.shadowRoot; var warnings = modalBody.querySelector(".warnings"); @@ -111,7 +111,7 @@ return operands.join(" OR "); } - var modax = document.querySelector("#start-flow, #shared-modax"); + var modax = getModax("#start-flow"); var modalBody = modax.shadowRoot; var queryField = modalBody.querySelector('.query'); var flowSelect = modalBody.querySelector("temba-select[name='flow']"); @@ -177,7 +177,7 @@ var handleDialogButton = function(event){ - var modax = document.querySelector("#start-flow, #shared-modax"); + var modax = getModax("#start-flow"); var modalBody = modax.shadowRoot; if (modax.suspendSubmit) { From fb22e89c9fcdd3fba4d963e473ab67499bdcb1ff Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 25 Jul 2022 18:47:24 -0500 Subject: [PATCH 052/630] Update CHANGELOG.md for v7.5.4 --- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 869f48b5622..1a8c41c1581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +v7.5.4 +---------- + * Fix scripts on contact page start modal + * Add logging for IG channel claim failures + * Add features to BRANDING which determines whether brands have access to features + * Sort permissions a-z + * Fix related names on Flow.topics and Flow.users and add Topic.release + * Expose opened_by and opened_in over ticket API + v7.5.3 ---------- * Fix id for custom fields modal diff --git a/pyproject.toml b/pyproject.toml index c57ae3086c5..f86928b7f5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.3" +version = "7.5.4" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From b9371f4d65fdd3991bfd62f3d97f833fcf9d9809 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 09:23:14 -0500 Subject: [PATCH 053/630] Contact interrupt menu option should only appear when they're in a flow --- temba/contacts/tests.py | 14 +++++++++++++- temba/contacts/views.py | 10 ++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 446c49b478e..f1b84aaebdc 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -806,12 +806,24 @@ def test_interrupt(self, mr_mocks): contact = self.create_contact("Joe", phone="+593979000111") other_org_contact = self.create_contact("Hans", phone="+593979123456", org=self.org2) + read_url = reverse("contacts.contact_read", args=[contact.uuid]) + interrupt_url = reverse("contacts.contact_interrupt", args=[contact.id]) + + self.login(self.admin) + + # no interrupt option if not in a flow + response = self.client.get(read_url) + self.assertNotContains(response, interrupt_url) + MockSessionWriter(contact, self.create_flow("Test")).wait().save() MockSessionWriter(other_org_contact, self.create_flow("Test", org=self.org2)).wait().save() - interrupt_url = reverse("contacts.contact_interrupt", args=[contact.id]) + # now it's an option + response = self.client.get(read_url) + self.assertContains(response, interrupt_url) # can't interrupt if not logged in + self.client.logout() response = self.client.post(interrupt_url, {"id": contact.id}) self.assertLoginRedirect(response) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index 91debe1eca4..d436ac5e343 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -880,14 +880,8 @@ def build_content_menu(self, menu): menu.add_modax( _("Open Ticket"), "open-ticket", reverse("contacts.contact_open_ticket", args=[self.object.id]) ) - if self.has_org_perm("contacts.contact_interrupt"): - links.append( - dict( - title=_("Interrupt"), - js_class="posterize", - href=reverse("contacts.contact_interrupt", args=(self.object.id,)), - ) - ) + if self.has_org_perm("contacts.contact_interrupt") and self.object.current_flow: + menu.add_url_post(_("Interrupt"), reverse("contacts.contact_interrupt", args=(self.object.id,))) if self.has_org_perm("contacts.contact_update"): menu.add_modax( From 75b783810cbea3a3937e91272074c891e5576367 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 09:32:14 -0500 Subject: [PATCH 054/630] Let editors interrupt contacts --- temba/settings_common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/temba/settings_common.py b/temba/settings_common.py index 7d4a2b9c184..18bf33ba36f 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -745,6 +745,7 @@ "contacts.contact_export", "contacts.contact_filter", "contacts.contact_history", + "contacts.contact_interrupt", "contacts.contact_list", "contacts.contact_menu", "contacts.contact_omnibox", From 26676d8c0c4625bbd96b285689f8d3df0d50aeab Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 11:40:27 -0500 Subject: [PATCH 055/630] Update upload media action endpoint to use new Media model --- temba/flows/tests.py | 44 +++++++++++++++++++---------- temba/flows/views.py | 19 ++++--------- temba/msgs/migrations/0176_media.py | 8 ++++-- temba/msgs/models.py | 34 +++++++++++++++++++++- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 5fe558a872f..0729248bc1e 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -34,7 +34,7 @@ from temba.tickets.models import Ticketer from temba.triggers.models import Trigger from temba.utils import json -from temba.utils.uuid import uuid4 +from temba.utils.uuid import UUID, uuid4 from .checks import mailroom_url from .models import ( @@ -2974,41 +2974,55 @@ def test_broadcast_background_flow(self, mr_mocks): self.assertTrue(start.include_active) self.assertEqual('name ~ "frank"', start.query) - @patch("temba.flows.views.uuid4") + @patch("temba.msgs.models.uuid4") def test_upload_media_action(self, mock_uuid): flow = self.create_flow("Test") other_org_flow = self.create_flow("Test", org=self.org2) action_url = reverse("flows.flow_upload_media_action", args=[flow.uuid]) - def assert_upload(filename, expected_type, expected_url): + def assert_upload(filename, expected_json): with open(filename, "rb") as data: response = self.client.post(action_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") - self.assertEqual(response.status_code, 200) - actual_type = response.json()["type"] - actual_url = response.json()["url"] - self.assertEqual(expected_type, actual_type) - self.assertEqual(expected_url, actual_url) + self.assertEqual(response.status_code, 200) + self.assertEqual(expected_json, response.json()) self.login(self.admin) - mock_uuid.side_effect = ["11111-111-11", "22222-222-22", "33333-333-33", "44444-444-44"] + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("2f42e913-6a19-44c5-90ee-cdf7b14ad5c0"), + UUID("f661c405-524e-4bd7-83e2-c93ffe35aa60"), + UUID("67ec31c7-a85f-4834-9da2-dee2c7b56576"), + ] assert_upload( f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", - "image/jpeg", - f"/media/attachments/{self.org.id}/{flow.id}/steps/11111-111-11/steve%20marten.jpg", + { + "uuid": "6a65f14f-b762-4485-b860-96a322292775", + "content_type": "image/jpeg", + "type": "image/jpeg", + "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", + }, ) assert_upload( f"{settings.MEDIA_ROOT}/test_media/snow.mp4", - "video/mp4", - f"/media/attachments/{self.org.id}/{flow.id}/steps/22222-222-22/snow.mp4", + { + "uuid": "2f42e913-6a19-44c5-90ee-cdf7b14ad5c0", + "content_type": "video/mp4", + "type": "video/mp4", + "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/2f42e913-6a19-44c5-90ee-cdf7b14ad5c0/snow.mp4", + }, ) assert_upload( f"{settings.MEDIA_ROOT}/test_media/snow.m4a", - "audio/mp4", - f"/media/attachments/{self.org.id}/{flow.id}/steps/33333-333-33/snow.m4a", + { + "uuid": "f661c405-524e-4bd7-83e2-c93ffe35aa60", + "content_type": "audio/mp4", + "type": "audio/mp4", + "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", + }, ) # can't upload for flow in other org diff --git a/temba/flows/views.py b/temba/flows/views.py index fcde9f72d84..dcf8d540669 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -40,6 +40,7 @@ from temba.flows.tasks import export_flow_results_task, update_session_wait_expires from temba.ivr.models import IVRCall from temba.mailroom import FlowValidationException +from temba.msgs.models import Media from temba.orgs.models import IntegrationType, Org from temba.orgs.views import ( DependencyDeleteModal, @@ -63,7 +64,6 @@ ) from temba.utils.s3 import public_file_storage from temba.utils.text import slugify_with -from temba.utils.uuid import uuid4 from temba.utils.views import BulkActionMixin, SpaMixin from .models import ( @@ -720,20 +720,11 @@ class UploadMediaAction(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" def post(self, request, *args, **kwargs): - return JsonResponse(self.save_media_upload(self.request.FILES["file"])) - - def save_media_upload(self, file): - flow = self.get_object() - - # browsers might send m4a files but correct MIME type is audio/mp4 - extension = file.name.split(".")[-1] - if extension == "m4a": - file.content_type = "audio/mp4" - - path = f"attachments/{flow.org.id}/{flow.id}/steps/{str(uuid4())}/{file.name}" - path = public_file_storage.save(path, file) # storage classes can rewrite saved paths + media = Media.from_upload( + self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() + ) - return {"type": file.content_type, "url": public_file_storage.url(path)} + return JsonResponse(media.as_json()) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): title = _("Flows") diff --git a/temba/msgs/migrations/0176_media.py b/temba/msgs/migrations/0176_media.py index f33509806cb..3cdfd218813 100644 --- a/temba/msgs/migrations/0176_media.py +++ b/temba/msgs/migrations/0176_media.py @@ -1,10 +1,12 @@ -# Generated by Django 4.0.6 on 2022-07-25 20:17 +# Generated by Django 4.0.6 on 2022-07-26 16:22 import django.db.models.deletion import django.utils.timezone from django.conf import settings from django.db import migrations, models +import temba.utils.uuid + class Migration(migrations.Migration): @@ -19,9 +21,11 @@ class Migration(migrations.Migration): name="Media", fields=[ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("uuid", models.UUIDField(default=temba.utils.uuid.uuid4)), ("content_type", models.CharField(max_length=64)), ("url", models.URLField(db_index=True, max_length=2048)), - ("alternates", models.JSONField()), + ("is_ready", models.BooleanField(default=False)), + ("alternates", models.JSONField(default=dict)), ("duration", models.IntegerField(default=0)), ("created_on", models.DateTimeField(default=django.utils.timezone.now)), ( diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 7970b14418b..980a1095021 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -26,6 +26,7 @@ from temba.utils import chunk_list, on_transaction_commit from temba.utils.export import BaseExportAssetStore, BaseExportTask from temba.utils.models import JSONAsTextField, LegacyUUIDMixin, SquashableModel, TembaModel, TranslatableField +from temba.utils.s3 import public_file_storage from temba.utils.text import clean_string from temba.utils.uuid import uuid4 @@ -45,17 +46,48 @@ class Media(models.Model): An uploaded media file that can be used as an attachment on messages. """ + uuid = models.UUIDField(default=uuid4) org = models.ForeignKey(Org, on_delete=models.PROTECT) content_type = models.CharField(max_length=64) url = models.URLField(max_length=2048, db_index=True) - alternates = models.JSONField() + # fields that will be set after upload by a processing task + is_ready = models.BooleanField(default=False) + alternates = models.JSONField(default=dict) duration = models.IntegerField(default=0) thumbnail = models.ForeignKey("msgs.Media", null=True, on_delete=models.PROTECT) created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) + @classmethod + def from_upload(cls, org, user, file, flow): + uuid = uuid4() + + # browsers might send m4a files but correct MIME type is audio/mp4 + extension = file.name.split(".")[-1] + if extension == "m4a": + file.content_type = "audio/mp4" + + path = f"attachments/{org.id}/{flow.id}/steps/{uuid}/{file.name}" + path = public_file_storage.save(path, file) # storage classes can rewrite saved paths + + return cls.objects.create( + uuid=uuid, + org=org, + content_type=file.content_type, + url=public_file_storage.url(path), + created_by=user, + ) + + def as_json(self) -> dict: + return { + "uuid": str(self.uuid), + "content_type": self.content_type, + "type": self.content_type, # deprecated + "url": self.url, + } + class Broadcast(models.Model): """ From bbb00742710a8deec00c7ddd342301e54f179160 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 12:12:36 -0500 Subject: [PATCH 056/630] Remove unused upload_recording endpoint --- temba/flows/tests.py | 19 +++++++++++-------- temba/flows/views.py | 25 ++++++++++--------------- temba/settings_common.py | 5 +---- templates/flows/flow_editor.haml | 2 +- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 0729248bc1e..d1dae668bc5 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -2975,21 +2975,21 @@ def test_broadcast_background_flow(self, mr_mocks): self.assertEqual('name ~ "frank"', start.query) @patch("temba.msgs.models.uuid4") - def test_upload_media_action(self, mock_uuid): + def test_upload_media(self, mock_uuid): flow = self.create_flow("Test") other_org_flow = self.create_flow("Test", org=self.org2) - action_url = reverse("flows.flow_upload_media_action", args=[flow.uuid]) + upload_url = reverse("flows.flow_upload_media", args=[flow.uuid]) + + def assert_upload(user, filename, expected_json): + self.login(user) - def assert_upload(filename, expected_json): with open(filename, "rb") as data: - response = self.client.post(action_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") self.assertEqual(response.status_code, 200) self.assertEqual(expected_json, response.json()) - self.login(self.admin) - mock_uuid.side_effect = [ UUID("6a65f14f-b762-4485-b860-96a322292775"), UUID("2f42e913-6a19-44c5-90ee-cdf7b14ad5c0"), @@ -2998,6 +2998,7 @@ def assert_upload(filename, expected_json): ] assert_upload( + self.admin, f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", { "uuid": "6a65f14f-b762-4485-b860-96a322292775", @@ -3007,6 +3008,7 @@ def assert_upload(filename, expected_json): }, ) assert_upload( + self.editor, f"{settings.MEDIA_ROOT}/test_media/snow.mp4", { "uuid": "2f42e913-6a19-44c5-90ee-cdf7b14ad5c0", @@ -3016,18 +3018,19 @@ def assert_upload(filename, expected_json): }, ) assert_upload( + self.editor, f"{settings.MEDIA_ROOT}/test_media/snow.m4a", { "uuid": "f661c405-524e-4bd7-83e2-c93ffe35aa60", "content_type": "audio/mp4", - "type": "audio/mp4", + "type": "video/mp4", "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", }, ) # can't upload for flow in other org with open(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "rb") as data: - upload_url = reverse("flows.flow_upload_media_action", args=[other_org_flow.uuid]) + upload_url = reverse("flows.flow_upload_media", args=[other_org_flow.uuid]) response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") self.assertLoginRedirect(response) diff --git a/temba/flows/views.py b/temba/flows/views.py index dcf8d540669..9ea0f0b6273 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -62,7 +62,6 @@ SelectWidget, TembaChoiceField, ) -from temba.utils.s3 import public_file_storage from temba.utils.text import slugify_with from temba.utils.views import BulkActionMixin, SpaMixin @@ -200,7 +199,6 @@ class FlowCRUDL(SmartCRUDL): "download_translation", "import_translation", "export_results", - "upload_action_recording", "editor", "results", "run_table", @@ -214,7 +212,8 @@ class FlowCRUDL(SmartCRUDL): "revisions", "recent_contacts", "assets", - "upload_media_action", + "upload_media", + "upload_media_action", # deprecated ) model = Flow @@ -703,27 +702,23 @@ def post_save(self, obj): return obj - class UploadActionRecording(OrgObjPermsMixin, SmartUpdateView): - def post(self, request, *args, **kwargs): # pragma: needs cover - path = self.save_recording_upload( - self.request.FILES["file"], self.request.POST.get("actionset"), self.request.POST.get("action") - ) - return JsonResponse(dict(path=path)) + class UploadMediaAction(OrgObjPermsMixin, SmartUpdateView): # pragma: no cover + permission = "flows.flow_upload_media" + slug_url_kwarg = "uuid" - def save_recording_upload(self, file, actionset_id, action_uuid): # pragma: needs cover - flow = self.get_object() - return public_file_storage.save( - "recordings/%d/%d/steps/%s.wav" % (flow.org.pk, flow.id, action_uuid), file + def post(self, request, *args, **kwargs): + media = Media.from_upload( + self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() ) + return JsonResponse(media.as_json()) - class UploadMediaAction(OrgObjPermsMixin, SmartUpdateView): + class UploadMedia(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" def post(self, request, *args, **kwargs): media = Media.from_upload( self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() ) - return JsonResponse(media.as_json()) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): diff --git a/temba/settings_common.py b/temba/settings_common.py index 36f10653d33..a6a00baf0bd 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -434,8 +434,7 @@ "revisions", "run_table", "simulate", - "upload_action_recording", - "upload_media_action", + "upload_media", ), "flows.flowsession": ("json",), "globals.global": ("api", "unused"), @@ -629,7 +628,6 @@ "flows.flowlabel.*", "flows.flowrun_delete", "flows.flowstart.*", - "flows.ruleset.*", "globals.global.*", "ivr.ivrcall.*", "locations.adminboundary_alias", @@ -762,7 +760,6 @@ "flows.flowlabel.*", "flows.flowstart_api", "flows.flowstart_list", - "flows.ruleset.*", "globals.global_api", "ivr.ivrcall.*", "locations.adminboundary_alias", diff --git a/templates/flows/flow_editor.haml b/templates/flows/flow_editor.haml index 63973c177c9..74f22a4bb45 100644 --- a/templates/flows/flow_editor.haml +++ b/templates/flows/flow_editor.haml @@ -259,7 +259,7 @@ // TODO: migrate to API? revisions: '/flow/revisions/{{object.uuid}}/', recents: '/flow/recent_contacts/{{object.uuid}}/', - attachments: '/flow/upload_media_action/{{object.uuid}}/', + attachments: '/flow/upload_media/{{object.uuid}}/', languages: base + 'language', environment: base + 'environment', activity: '/flow/activity/{{object.uuid}}/', From a532ed72eed267238f4da47e2cb7311f10c6b22e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 12:34:47 -0500 Subject: [PATCH 057/630] Fix test --- temba/flows/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index d1dae668bc5..bbcb1fe9e31 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -3023,7 +3023,7 @@ def assert_upload(user, filename, expected_json): { "uuid": "f661c405-524e-4bd7-83e2-c93ffe35aa60", "content_type": "audio/mp4", - "type": "video/mp4", + "type": "audio/mp4", "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", }, ) From d0789e1394cfc92df70f6368410a76bfa283d5a9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 13:19:58 -0500 Subject: [PATCH 058/630] Add stub task --- temba/msgs/models.py | 15 ++++++++++++++- temba/msgs/tasks.py | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 980a1095021..dc651f066c3 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -62,6 +62,8 @@ class Media(models.Model): @classmethod def from_upload(cls, org, user, file, flow): + from .tasks import process_media_upload + uuid = uuid4() # browsers might send m4a files but correct MIME type is audio/mp4 @@ -72,7 +74,7 @@ def from_upload(cls, org, user, file, flow): path = f"attachments/{org.id}/{flow.id}/steps/{uuid}/{file.name}" path = public_file_storage.save(path, file) # storage classes can rewrite saved paths - return cls.objects.create( + media = cls.objects.create( uuid=uuid, org=org, content_type=file.content_type, @@ -80,6 +82,17 @@ def from_upload(cls, org, user, file, flow): created_by=user, ) + on_transaction_commit(lambda: process_media_upload.delay(media.id)) + + return media + + def process_upload(self): + # TODO process using ffmpeg wrapper + + # self.is_ready = True + # self.save(update_fields=("is_ready",)) + pass + def as_json(self) -> dict: return { "uuid": str(self.uuid), diff --git a/temba/msgs/tasks.py b/temba/msgs/tasks.py index 65a7919cb22..dfbf49e8233 100644 --- a/temba/msgs/tasks.py +++ b/temba/msgs/tasks.py @@ -5,7 +5,7 @@ from temba.utils import analytics from temba.utils.celery import nonoverlapping_task -from .models import Broadcast, BroadcastMsgCount, ExportMessagesTask, LabelCount, Msg, SystemLabelCount +from .models import Broadcast, BroadcastMsgCount, ExportMessagesTask, LabelCount, Media, Msg, SystemLabelCount logger = logging.getLogger(__name__) @@ -57,3 +57,8 @@ def squash_msgcounts(): SystemLabelCount.squash() LabelCount.squash() BroadcastMsgCount.squash() + + +@shared_task +def process_media_upload(media_id): + Media.objects.get(id=media_id).process_upload() From bd9a9628b907d600968aa6368d2ac391ebea2b56 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 14:46:27 -0500 Subject: [PATCH 059/630] Rework Media model to allow alternates to be Media instances too --- temba/contacts/tests.py | 9 ++------- temba/msgs/migrations/0176_media.py | 17 +++++++++++++---- temba/msgs/models.py | 11 +++++++++-- temba/msgs/tests.py | 29 +++++++++++++++++++++++++++++ temba/tests/base.py | 4 ++++ 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 6f238df97f3..ed9157ea44d 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -11,7 +11,6 @@ from openpyxl import load_workbook from django.conf import settings -from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import ValidationError from django.db import connection from django.db.models import Value as DbValue @@ -6167,16 +6166,12 @@ def test_create_and_preview(self): response = self.client.post(create_url, {}) self.assertFormError(response, "form", "file", "This field is required.") - def upload(path): - with open(path, "rb") as f: - return SimpleUploadedFile(path, content=f.read()) - # try uploading an empty CSV file - response = self.client.post(create_url, {"file": upload("media/test_imports/empty.csv")}) + response = self.client.post(create_url, {"file": self.upload("media/test_imports/empty.csv")}) self.assertFormError(response, "form", "file", "Import file doesn't contain any records.") # try uploading a valid XLSX file - response = self.client.post(create_url, {"file": upload("media/test_imports/simple.xlsx")}) + response = self.client.post(create_url, {"file": self.upload("media/test_imports/simple.xlsx")}) self.assertEqual(302, response.status_code) imp = ContactImport.objects.get() diff --git a/temba/msgs/migrations/0176_media.py b/temba/msgs/migrations/0176_media.py index 3cdfd218813..d6115a43730 100644 --- a/temba/msgs/migrations/0176_media.py +++ b/temba/msgs/migrations/0176_media.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0.6 on 2022-07-26 16:22 +# Generated by Django 4.0.6 on 2022-07-26 19:40 import django.db.models.deletion import django.utils.timezone @@ -23,10 +23,14 @@ class Migration(migrations.Migration): ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("uuid", models.UUIDField(default=temba.utils.uuid.uuid4)), ("content_type", models.CharField(max_length=64)), + ("path", models.CharField(max_length=2048)), ("url", models.URLField(db_index=True, max_length=2048)), ("is_ready", models.BooleanField(default=False)), - ("alternates", models.JSONField(default=dict)), ("duration", models.IntegerField(default=0)), + ( + "relationship", + models.CharField(choices=[("T", "Thumbnail"), ("A", "Alternate")], max_length=1, null=True), + ), ("created_on", models.DateTimeField(default=django.utils.timezone.now)), ( "created_by", @@ -34,8 +38,13 @@ class Migration(migrations.Migration): ), ("org", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="orgs.org")), ( - "thumbnail", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to="msgs.media"), + "original", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="children", + to="msgs.media", + ), ), ], ), diff --git a/temba/msgs/models.py b/temba/msgs/models.py index dc651f066c3..7d45034c5b3 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -46,16 +46,22 @@ class Media(models.Model): An uploaded media file that can be used as an attachment on messages. """ + RELATIONSHIP_THUMBNAIL = "T" + RELATIONSHIP_ALTERNATE = "A" + RELATIONSHIP_CHOICES = ((RELATIONSHIP_THUMBNAIL, "Thumbnail"), (RELATIONSHIP_ALTERNATE, "Alternate")) + uuid = models.UUIDField(default=uuid4) org = models.ForeignKey(Org, on_delete=models.PROTECT) content_type = models.CharField(max_length=64) + path = models.CharField(max_length=2048) url = models.URLField(max_length=2048, db_index=True) # fields that will be set after upload by a processing task is_ready = models.BooleanField(default=False) - alternates = models.JSONField(default=dict) duration = models.IntegerField(default=0) - thumbnail = models.ForeignKey("msgs.Media", null=True, on_delete=models.PROTECT) + + original = models.ForeignKey("msgs.Media", null=True, on_delete=models.PROTECT, related_name="children") + relationship = models.CharField(max_length=1, choices=RELATIONSHIP_CHOICES, null=True) created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) @@ -78,6 +84,7 @@ def from_upload(cls, org, user, file, flow): uuid=uuid, org=org, content_type=file.content_type, + path=path, url=public_file_storage.url(path), created_by=user, ) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 11c3e9c28e8..58554adb894 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -19,6 +19,7 @@ ExportMessagesTask, Label, LabelCount, + Media, Msg, SystemLabel, SystemLabelCount, @@ -27,11 +28,39 @@ from temba.tests import AnonymousOrg, CRUDLTestMixin, TembaTest from temba.tests.engine import MockSessionWriter from temba.tests.s3 import MockS3Client, jsonlgz_encode +from temba.utils.uuid import UUID from .tasks import squash_msgcounts from .templatetags.sms import as_icon +class MediaTest(TembaTest): + @patch("temba.msgs.models.uuid4") + def test_model(self, mock_uuid): + flow = self.create_flow("Color") + mock_uuid.side_effect = [UUID("6a65f14f-b762-4485-b860-96a322292775")] + media = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "image/jpeg"), + flow=flow, + ) + + self.assertEqual("6a65f14f-b762-4485-b860-96a322292775", str(media.uuid)) + self.assertEqual(self.org, media.org) + self.assertEqual("image/jpeg", media.content_type) + self.assertEqual( + f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg", + media.path, + ) + self.assertEqual( + f"/media/attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve%20marten.jpg", + media.url, + ) + self.assertEqual(self.admin, media.created_by) + self.assertFalse(media.is_ready) + + class MsgTest(TembaTest): def setUp(self): super().setUp() diff --git a/temba/tests/base.py b/temba/tests/base.py index 62c80c4ec96..0bccf1b2657 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -765,6 +765,10 @@ def tearDown(self): def mockReadOnly(self, assert_models: set = None): return MockReadOnly(self, assert_models=assert_models) + def upload(self, path: str, content_type="text/plain"): + with open(path, "rb") as f: + return SimpleUploadedFile(path, content=f.read(), content_type=content_type) + class TembaNonAtomicTest(TembaTestMixin, SmartminTestMixin, TransactionTestCase): """ From bcaac51cf6cf3cdedcdaa89bb718ad43e6798b4f Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 26 Jul 2022 14:52:10 -0700 Subject: [PATCH 060/630] Fix modax reference for field edit --- templates/contacts/contact_read.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/contacts/contact_read.haml b/templates/contacts/contact_read.haml index d1c0d682c30..d3bb0aa2c97 100644 --- a/templates/contacts/contact_read.haml +++ b/templates/contacts/contact_read.haml @@ -568,7 +568,7 @@ $('.contact-field-value.editable').live('click', function(evt) { var endpoint = '{% url "contacts.contact_update_fields" object.pk %}'; var field_id = $(this).parent().data('id'); - var modax = document.querySelector("#update-custom-fields, #shared-modax"); + var modax = getModax("#update-custom-fields"); modax.endpoint = endpoint + '?field=' + field_id; modax.open = true; From 73838b4dfa61d8669df652db12665413a6f77860 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Tue, 26 Jul 2022 15:10:35 -0700 Subject: [PATCH 061/630] Remaining fallback modax references --- templates/contacts/contact_list.haml | 2 +- templates/contacts/contact_update.haml | 4 ++-- templates/contacts/contact_update_fields_input.haml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/contacts/contact_list.haml b/templates/contacts/contact_list.haml index 3c199a89378..6dd60c063f6 100644 --- a/templates/contacts/contact_list.haml +++ b/templates/contacts/contact_list.haml @@ -294,7 +294,7 @@ function handleStartFlowClicked(evt) { var sendEndpoint = "{% url 'flows.flow_broadcast' %}"; - var startModal = document.querySelector("#shared-modax, #start-modal"); + var startModal = getModax("#start-modal"); startModal.header = '{{_("Start Flow")|escapejs}}'; var ids = getCheckedUuids(); diff --git a/templates/contacts/contact_update.haml b/templates/contacts/contact_update.haml index e9ee9ee49d2..01262b6291a 100644 --- a/templates/contacts/contact_update.haml +++ b/templates/contacts/contact_update.haml @@ -44,7 +44,7 @@ }); function createMoveLinks() { - var body = document.querySelector("#edit-contact, #gear-modax, #shared-modax").shadowRoot.querySelector(".modax-body"); + var body = getModax("#edit-contact").shadowRoot.querySelector(".modax-body"); $(body).find('.order-helper').remove(); var idx = 0; @@ -69,7 +69,7 @@ } function moveUp(link) { - var body = document.querySelector("#edit-contact, #gear-modax, #shared-modax").shadowRoot.querySelector(".modax-body"); + var body = getModax("#edit-contact").shadowRoot.querySelector(".modax-body"); var group = $(body).find('#' + link).parents('.control-group'); var previous = group.prev(); previous.before(group); diff --git a/templates/contacts/contact_update_fields_input.haml b/templates/contacts/contact_update_fields_input.haml index 916ef72e40f..62888dfab17 100644 --- a/templates/contacts/contact_update_fields_input.haml +++ b/templates/contacts/contact_update_fields_input.haml @@ -16,7 +16,7 @@ :javascript - var modaxBody = document.querySelector("#update-custom-fields, #gear-modax, #shared-modax").shadowRoot.querySelector(".modax-body"); + var modaxBody = getModax("#update-custom-fields").shadowRoot.querySelector(".modax-body"); // aggressively grab focus when we load var ele = $(modaxBody).find('temba-textinput[name="field_value"]'); From 2ffaf8b7b5386193139ed0182402257d2434f414 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 26 Jul 2022 17:52:34 -0500 Subject: [PATCH 062/630] Update CHANGELOG.md for v7.5.5 --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8c41c1581..69ab2bc7976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.5 +---------- + * Remaining fallback modax references + * Add util for easier gear menu creation + * Add option to interrupt a contact from read page + v7.5.4 ---------- * Fix scripts on contact page start modal diff --git a/pyproject.toml b/pyproject.toml index f86928b7f5c..1d53e140503 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.4" +version = "7.5.5" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 336aa1d4f0ba7a800a6d0099bb542dc8d6581291 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 08:37:28 -0500 Subject: [PATCH 063/630] Rework Media model to be a dict of content_type: path --- temba/flows/tests.py | 6 ------ temba/flows/views.py | 4 ++-- temba/msgs/migrations/0176_media.py | 21 ++++----------------- temba/msgs/models.py | 23 ++++------------------- temba/msgs/tests.py | 10 +++++----- 5 files changed, 15 insertions(+), 49 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index bbcb1fe9e31..cffbdd4c4c3 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -3001,8 +3001,6 @@ def assert_upload(user, filename, expected_json): self.admin, f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", { - "uuid": "6a65f14f-b762-4485-b860-96a322292775", - "content_type": "image/jpeg", "type": "image/jpeg", "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", }, @@ -3011,8 +3009,6 @@ def assert_upload(user, filename, expected_json): self.editor, f"{settings.MEDIA_ROOT}/test_media/snow.mp4", { - "uuid": "2f42e913-6a19-44c5-90ee-cdf7b14ad5c0", - "content_type": "video/mp4", "type": "video/mp4", "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/2f42e913-6a19-44c5-90ee-cdf7b14ad5c0/snow.mp4", }, @@ -3021,8 +3017,6 @@ def assert_upload(user, filename, expected_json): self.editor, f"{settings.MEDIA_ROOT}/test_media/snow.m4a", { - "uuid": "f661c405-524e-4bd7-83e2-c93ffe35aa60", - "content_type": "audio/mp4", "type": "audio/mp4", "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", }, diff --git a/temba/flows/views.py b/temba/flows/views.py index 9ea0f0b6273..df884c2b635 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -710,7 +710,7 @@ def post(self, request, *args, **kwargs): media = Media.from_upload( self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() ) - return JsonResponse(media.as_json()) + return JsonResponse({"type": list(media.paths.keys())[0], "url": media.url}) class UploadMedia(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" @@ -719,7 +719,7 @@ def post(self, request, *args, **kwargs): media = Media.from_upload( self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() ) - return JsonResponse(media.as_json()) + return JsonResponse({"type": list(media.paths.keys())[0], "url": media.url}) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): title = _("Flows") diff --git a/temba/msgs/migrations/0176_media.py b/temba/msgs/migrations/0176_media.py index d6115a43730..3e5f65ce863 100644 --- a/temba/msgs/migrations/0176_media.py +++ b/temba/msgs/migrations/0176_media.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0.6 on 2022-07-26 19:40 +# Generated by Django 4.0.6 on 2022-07-27 13:27 import django.db.models.deletion import django.utils.timezone @@ -11,8 +11,8 @@ class Migration(migrations.Migration): dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("orgs", "0101_remove_org_administrators_remove_org_agents_and_more"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("msgs", "0175_alter_msg_failed_reason"), ] @@ -22,30 +22,17 @@ class Migration(migrations.Migration): fields=[ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("uuid", models.UUIDField(default=temba.utils.uuid.uuid4)), - ("content_type", models.CharField(max_length=64)), - ("path", models.CharField(max_length=2048)), ("url", models.URLField(db_index=True, max_length=2048)), + ("name", models.CharField(max_length=255)), + ("paths", models.JSONField(default=dict)), ("is_ready", models.BooleanField(default=False)), ("duration", models.IntegerField(default=0)), - ( - "relationship", - models.CharField(choices=[("T", "Thumbnail"), ("A", "Alternate")], max_length=1, null=True), - ), ("created_on", models.DateTimeField(default=django.utils.timezone.now)), ( "created_by", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), ), ("org", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="orgs.org")), - ( - "original", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="children", - to="msgs.media", - ), - ), ], ), ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 7d45034c5b3..d23a4673632 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -46,23 +46,16 @@ class Media(models.Model): An uploaded media file that can be used as an attachment on messages. """ - RELATIONSHIP_THUMBNAIL = "T" - RELATIONSHIP_ALTERNATE = "A" - RELATIONSHIP_CHOICES = ((RELATIONSHIP_THUMBNAIL, "Thumbnail"), (RELATIONSHIP_ALTERNATE, "Alternate")) - uuid = models.UUIDField(default=uuid4) org = models.ForeignKey(Org, on_delete=models.PROTECT) - content_type = models.CharField(max_length=64) - path = models.CharField(max_length=2048) url = models.URLField(max_length=2048, db_index=True) + name = models.CharField(max_length=255) # original filename + paths = models.JSONField(default=dict) # dict of {content_type1: path1, content_type2: path2, ...} # fields that will be set after upload by a processing task is_ready = models.BooleanField(default=False) duration = models.IntegerField(default=0) - original = models.ForeignKey("msgs.Media", null=True, on_delete=models.PROTECT, related_name="children") - relationship = models.CharField(max_length=1, choices=RELATIONSHIP_CHOICES, null=True) - created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) @@ -83,9 +76,9 @@ def from_upload(cls, org, user, file, flow): media = cls.objects.create( uuid=uuid, org=org, - content_type=file.content_type, - path=path, url=public_file_storage.url(path), + name=file.name, + paths={file.content_type: path}, created_by=user, ) @@ -100,14 +93,6 @@ def process_upload(self): # self.save(update_fields=("is_ready",)) pass - def as_json(self) -> dict: - return { - "uuid": str(self.uuid), - "content_type": self.content_type, - "type": self.content_type, # deprecated - "url": self.url, - } - class Broadcast(models.Model): """ diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 58554adb894..eaa7b3bf913 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -48,15 +48,15 @@ def test_model(self, mock_uuid): self.assertEqual("6a65f14f-b762-4485-b860-96a322292775", str(media.uuid)) self.assertEqual(self.org, media.org) - self.assertEqual("image/jpeg", media.content_type) - self.assertEqual( - f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg", - media.path, - ) self.assertEqual( f"/media/attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve%20marten.jpg", media.url, ) + self.assertEqual( + {"image/jpeg": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg"}, + media.paths, + ) + self.assertEqual("steve marten.jpg", media.name) self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) From d8f559f493224a935e8d36681b3ea1e55d298e8a Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 10:16:43 -0500 Subject: [PATCH 064/630] Update CHANGELOG.md for v7.5.6 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69ab2bc7976..9a4a3ed4997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.6 +---------- + * Remove unused upload_recording endpoint + * Add Media model + v7.5.5 ---------- * Remaining fallback modax references diff --git a/pyproject.toml b/pyproject.toml index 1d53e140503..3c2170f017a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.5" +version = "7.5.6" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 7f607a683ec797a8757287db96a2c70d42c44b91 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 12:26:56 -0500 Subject: [PATCH 065/630] Process audio media to get duration --- poetry.lock | 17 ++++++++++++- pyproject.toml | 1 + temba/msgs/media.py | 59 ++++++++++++++++++++++++++++++++++++++++++++ temba/msgs/models.py | 9 ++++--- temba/msgs/tests.py | 12 +++++++++ 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 temba/msgs/media.py diff --git a/poetry.lock b/poetry.lock index efe1e38b97f..94873c7d4b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -529,6 +529,20 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "ffmpeg-python" +version = "0.2.0" +description = "Python bindings for FFmpeg - with complex filtering support" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +future = "*" + +[package.extras] +dev = ["tox (==3.12.1)", "Sphinx (==2.1.0)", "pytest (==4.6.1)", "pytest-mock (==1.10.4)", "numpy (==1.16.4)", "future (==0.17.1)"] + [[package]] name = "flake8" version = "4.0.1" @@ -1367,7 +1381,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "0573251ae204443987637e1033148f5146f82a08eeb7c7d56889e3a49b5e4aeb" +content-hash = "f9c943e0438fba490d6d2114b710ac4e05618987605fb6dd613fe0f7dbdd58e4" [metadata.files] amqp = [ @@ -1654,6 +1668,7 @@ et-xmlfile = [ {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, ] +ffmpeg-python = [] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, diff --git a/pyproject.toml b/pyproject.toml index 3c2170f017a..d9dcadaef4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ packaging = "^20.9" requests-toolbelt = "^0.9.1" chardet = "^4.0.0" openpyxl = "^3.0.9" +ffmpeg-python = "^0.2.0" [tool.poetry.dev-dependencies] black = "^22.1.0" diff --git a/temba/msgs/media.py b/temba/msgs/media.py new file mode 100644 index 00000000000..46de7bfb241 --- /dev/null +++ b/temba/msgs/media.py @@ -0,0 +1,59 @@ +from tempfile import NamedTemporaryFile + +import ffmpeg + +from temba.utils.s3 import public_file_storage + + +def process_upload(media): + content_type, path = _get_uploaded_content(media) + media_type, sub_type = content_type.split("/") + + with public_file_storage.open(path, mode="rb") as stream: + # download the media from storage to a local temp file + with NamedTemporaryFile(suffix=media.name, delete=True) as temp: + temp.write(stream.read()) + temp.flush() + temp.seek(0) + + if media_type == "image": + _process_image_upload(media, sub_type, path, temp) + elif media_type == "audio": + _process_audio_upload(media, sub_type, path, temp) + elif media_type == "video": + _process_video_upload(media, sub_type, path, temp) + + +def _process_image_upload(media, sub_type, path, file): + pass + + +def _process_audio_upload(media, sub_type, path, file): + # if sub_type != "mp3": + # media.paths["audio/mp3"] = _convert_audio(path, "libmp3lame", "mp3") + # if sub_type != "mp4": + # media.paths["audio/mp4"] = _convert_audio(path, "aac", "m4a") + + media.duration = _get_duration(file) + + +def _process_video_upload(media, sub_type: str, path: str, file): + # TODO generate thumbnail + + media.duration = _get_duration(file) + + +def _get_duration(file) -> int: + """ + Uses ffprobe to get the duration of the audio or video file + """ + output = ffmpeg.probe(file.name) + return int(float(output["format"]["duration"]) * 1000) + + +def _get_uploaded_content(media) -> tuple: + """ + Gets the content type and path of the uploaded media + """ + content_type = list(media.paths.keys())[0] + return content_type, media.paths[content_type] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index d23a4673632..3f1aea77b73 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -30,6 +30,8 @@ from temba.utils.text import clean_string from temba.utils.uuid import uuid4 +from .media import process_upload + logger = logging.getLogger(__name__) @@ -87,11 +89,10 @@ def from_upload(cls, org, user, file, flow): return media def process_upload(self): - # TODO process using ffmpeg wrapper + process_upload(self) - # self.is_ready = True - # self.save(update_fields=("is_ready",)) - pass + self.is_ready = True + self.save(update_fields=("paths", "is_ready", "duration")) class Broadcast(models.Model): diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index eaa7b3bf913..a0343562643 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -60,6 +60,18 @@ def test_model(self, mock_uuid): self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) + def test_process(self): + flow = self.create_flow("Color") + audio = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.m4a", "audio/mp4"), + flow=flow, + ) + audio.process_upload() + + self.assertEqual(3809, audio.duration) + class MsgTest(TembaTest): def setUp(self): From bff1b482a9c253a5105a7c2c22a3ae78981fa467 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 12:27:39 -0500 Subject: [PATCH 066/630] Auto-format ci.yml --- .github/workflows/ci.yml | 156 +++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43f092589d6..946461114dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,98 +4,98 @@ jobs: test: name: Test env: - python-version: '3.9.x' - postgis-version: '3.1' - redis-version: '5.0.6' - node-version: '10' - elastic-version: '7.17.2' - rpindexer-version: '7.3.7' - mailroom-version: '7.3.18' + python-version: "3.9.x" + postgis-version: "3.1" + redis-version: "5.0.6" + node-version: "10" + elastic-version: "7.17.2" + rpindexer-version: "7.3.7" + mailroom-version: "7.3.18" DJANGO_SETTINGS_MODULE: temba.settings_ci strategy: matrix: - pg-version: ['12', '13'] + pg-version: ["12", "13"] runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v1 + - name: Checkout code + uses: actions/checkout@v1 - - name: Install PostgreSQL and PostGIS - uses: nyaruka/postgis-action@v2.1.0 - with: - postgresql version: ${{ matrix.pg-version }} - postgis version: ${{ env.postgis-version }} - postgresql db: temba - postgresql user: temba - postgresql password: temba - postgresql arguments: '--jit=off' + - name: Install PostgreSQL and PostGIS + uses: nyaruka/postgis-action@v2.1.0 + with: + postgresql version: ${{ matrix.pg-version }} + postgis version: ${{ env.postgis-version }} + postgresql db: temba + postgresql user: temba + postgresql password: temba + postgresql arguments: "--jit=off" - - name: Install Linux packages - run: | - sudo apt update - sudo apt install -y --no-install-recommends libgdal-dev gettext + - name: Install Linux packages + run: | + sudo apt update + sudo apt install -y --no-install-recommends libgdal-dev gettext - - name: Install Python - uses: actions/setup-python@v1 - with: - python-version: ${{ env.python-version }} + - name: Install Python + uses: actions/setup-python@v1 + with: + python-version: ${{ env.python-version }} - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-in-project: true + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-in-project: true - - name: Install Redis - uses: zhulik/redis-action@v1.0.0 - with: - redis version: ${{ env.redis-version }} + - name: Install Redis + uses: zhulik/redis-action@v1.0.0 + with: + redis version: ${{ env.redis-version }} - - name: Install ElasticSearch - uses: nyaruka/elasticsearch-action@master - with: - elastic version: ${{ env.elastic-version }} + - name: Install ElasticSearch + uses: nyaruka/elasticsearch-action@master + with: + elastic version: ${{ env.elastic-version }} - - name: Install Node - uses: actions/setup-node@v1 - with: - node-version: ${{ env.node-version }} + - name: Install Node + uses: actions/setup-node@v1 + with: + node-version: ${{ env.node-version }} - - name: Initialize environment - run: | - poetry install - npm install - sudo npm install -g less - ln -s ${{ github.workspace }}/temba/settings.py.dev ${{ github.workspace }}/temba/settings.py - poetry run ./manage.py migrate - # fetch and extract rp-indexer - wget https://github.com/nyaruka/rp-indexer/releases/download/v${{ env.rpindexer-version }}/rp-indexer_${{ env.rpindexer-version }}_linux_amd64.tar.gz - tar -xvf rp-indexer_${{ env.rpindexer-version }}_linux_amd64.tar.gz rp-indexer - # fetch, extract and start mailroom - wget https://github.com/nyaruka/mailroom/releases/download/v${{ env.mailroom-version }}/mailroom_${{ env.mailroom-version }}_linux_amd64.tar.gz - tar -xvf mailroom_${{ env.mailroom-version }}_linux_amd64.tar.gz mailroom - ./mailroom -db=postgres://temba:temba@localhost:5432/temba?sslmode=disable -redis=redis://localhost:6379/10 -log-level=info > mailroom.log & + - name: Initialize environment + run: | + poetry install + npm install + sudo npm install -g less + ln -s ${{ github.workspace }}/temba/settings.py.dev ${{ github.workspace }}/temba/settings.py + poetry run ./manage.py migrate + # fetch and extract rp-indexer + wget https://github.com/nyaruka/rp-indexer/releases/download/v${{ env.rpindexer-version }}/rp-indexer_${{ env.rpindexer-version }}_linux_amd64.tar.gz + tar -xvf rp-indexer_${{ env.rpindexer-version }}_linux_amd64.tar.gz rp-indexer + # fetch, extract and start mailroom + wget https://github.com/nyaruka/mailroom/releases/download/v${{ env.mailroom-version }}/mailroom_${{ env.mailroom-version }}_linux_amd64.tar.gz + tar -xvf mailroom_${{ env.mailroom-version }}_linux_amd64.tar.gz mailroom + ./mailroom -db=postgres://temba:temba@localhost:5432/temba?sslmode=disable -redis=redis://localhost:6379/10 -log-level=info > mailroom.log & - - name: Run pre-test checks - run: | - # test that everything is well formatted, no missing migrations etc - poetry run ./code_check.py --debug - # check we can collect and compress all static files - poetry run ./manage.py collectstatic --noinput --verbosity=0 - poetry run ./manage.py compress --extension=".haml" --settings=temba.settings_compress + - name: Run pre-test checks + run: | + # test that everything is well formatted, no missing migrations etc + poetry run ./code_check.py --debug + # check we can collect and compress all static files + poetry run ./manage.py collectstatic --noinput --verbosity=0 + poetry run ./manage.py compress --extension=".haml" --settings=temba.settings_compress - - name: Run tests - run: | - poetry run coverage run manage.py test --keepdb --noinput --verbosity=2 - poetry run coverage report -i - poetry run coverage report -i --rcfile .coveragerc_todo - poetry run coverage xml + - name: Run tests + run: | + poetry run coverage run manage.py test --keepdb --noinput --verbosity=2 + poetry run coverage report -i + poetry run coverage report -i --rcfile .coveragerc_todo + poetry run coverage xml - - name: Mailroom log - if: failure() - run: cat mailroom.log + - name: Mailroom log + if: failure() + run: cat mailroom.log - - name: Upload coverage - if: success() - uses: codecov/codecov-action@v2 - with: - fail_ci_if_error: true + - name: Upload coverage + if: success() + uses: codecov/codecov-action@v2 + with: + fail_ci_if_error: true From f161a34f4cca810224fdfcdaac81eb7a32ad9ec2 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 12:28:23 -0500 Subject: [PATCH 067/630] Install ffmpeg for CI testing --- .github/workflows/ci.yml | 2 +- temba/msgs/tests.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 946461114dd..f3954b90c88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: - name: Install Linux packages run: | sudo apt update - sudo apt install -y --no-install-recommends libgdal-dev gettext + sudo apt install -y --no-install-recommends libgdal-dev gettext ffmpeg - name: Install Python uses: actions/setup-python@v1 diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index a0343562643..1c88e8897ce 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -60,17 +60,41 @@ def test_model(self, mock_uuid): self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) - def test_process(self): - flow = self.create_flow("Color") - audio = Media.from_upload( + def test_process_audio_wav(self): + media = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav"), + flow=self.create_flow("Color"), + ) + media.process_upload() + + self.assertTrue(media.is_ready) + self.assertEqual(5110, media.duration) + + def test_process_audio_m4a(self): + media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.m4a", "audio/mp4"), - flow=flow, + flow=self.create_flow("Color"), + ) + media.process_upload() + + self.assertTrue(media.is_ready) + self.assertEqual(3809, media.duration) + + def test_process_video_mp4(self): + media = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4"), + flow=self.create_flow("Color"), ) - audio.process_upload() + media.process_upload() - self.assertEqual(3809, audio.duration) + self.assertTrue(media.is_ready) + self.assertEqual(3809, media.duration) class MsgTest(TembaTest): From 0b31a473c7e5784b4a3814e75ace7b921cd5ec13 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 27 Jul 2022 15:34:45 -0500 Subject: [PATCH 068/630] Generate thumbnil when processing video media --- temba/msgs/media.py | 60 ++++++++++++++++++++++++++++++++++++++++----- temba/msgs/tests.py | 31 ++++++++++++++++++++--- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/temba/msgs/media.py b/temba/msgs/media.py index 46de7bfb241..56793b13523 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -1,3 +1,4 @@ +import os from tempfile import NamedTemporaryFile import ffmpeg @@ -12,7 +13,8 @@ def process_upload(media): with public_file_storage.open(path, mode="rb") as stream: # download the media from storage to a local temp file with NamedTemporaryFile(suffix=media.name, delete=True) as temp: - temp.write(stream.read()) + data = stream.read() + temp.write(data) temp.flush() temp.seek(0) @@ -29,20 +31,59 @@ def _process_image_upload(media, sub_type, path, file): def _process_audio_upload(media, sub_type, path, file): - # if sub_type != "mp3": - # media.paths["audio/mp3"] = _convert_audio(path, "libmp3lame", "mp3") - # if sub_type != "mp4": - # media.paths["audio/mp4"] = _convert_audio(path, "aac", "m4a") + if sub_type != "mp3": + media.paths["audio/mp3"] = _create_new_audio_version(path, file, "mp3", codec="libmp3lame") + if sub_type != "mp4": + media.paths["audio/mp4"] = _create_new_audio_version(path, file, "m4a", codec="aac") media.duration = _get_duration(file) def _process_video_upload(media, sub_type: str, path: str, file): - # TODO generate thumbnail + media.paths["image/jpg"] = _create_new_video_thumbnail(path, file) media.duration = _get_duration(file) +def _create_new_audio_version(path: str, file, new_extension: str, codec: str) -> str: + """ + Creates a new audio version of the given media file + """ + + def transform(in_name, out_name): + ffmpeg.input(in_name).output(out_name, acodec=codec).overwrite_output().run() + + return _create_new_file(path, file, new_extension, transform) + + +def _create_new_video_thumbnail(path: str, file) -> str: + """ + Creates a new thumbnail for the given video file + """ + + def transform(in_name, out_name): + ffmpeg.input(in_name, ss="00:00:00").filter("scale", "640", -1).output( + out_name, vframes=1 + ).overwrite_output().run() + + return _create_new_file(path, file, "jpg", transform) + + +def _create_new_file(path: str, file, new_extension: str, transform) -> str: + """ + Creates a new file from the given media file using the given transform function + """ + + new_path = _change_extension(path, new_extension) + + with NamedTemporaryFile(suffix="." + new_extension, delete=True) as temp: + transform(file.name, temp.name) + + public_file_storage.save(new_path, temp) + + return new_path + + def _get_duration(file) -> int: """ Uses ffprobe to get the duration of the audio or video file @@ -57,3 +98,10 @@ def _get_uploaded_content(media) -> tuple: """ content_type = list(media.paths.keys())[0] return content_type, media.paths[content_type] + + +def _change_extension(filename: str, extension: str) -> str: + """ + Changes the extension of a filename + """ + return os.path.splitext(filename)[0] + "." + extension diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 1c88e8897ce..0d2d5bb5f7f 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -61,40 +61,65 @@ def test_model(self, mock_uuid): self.assertFalse(media.is_ready) def test_process_audio_wav(self): + flow = self.create_flow("Color") media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav"), - flow=self.create_flow("Color"), + flow=flow, ) media.process_upload() self.assertTrue(media.is_ready) self.assertEqual(5110, media.duration) + self.assertEqual( + { + "audio/wav": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.wav", + "audio/mp3": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.mp3", + "audio/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.m4a", + }, + media.paths, + ) def test_process_audio_m4a(self): + flow = self.create_flow("Color") media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.m4a", "audio/mp4"), - flow=self.create_flow("Color"), + flow=flow, ) media.process_upload() self.assertTrue(media.is_ready) self.assertEqual(3809, media.duration) + self.assertEqual( + { + "audio/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.m4a", + "audio/mp3": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.mp3", + }, + media.paths, + ) def test_process_video_mp4(self): + flow = self.create_flow("Color") media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4"), - flow=self.create_flow("Color"), + flow=flow, ) media.process_upload() self.assertTrue(media.is_ready) self.assertEqual(3809, media.duration) + self.assertEqual( + { + "video/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.mp4", + "image/jpg": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.jpg", + }, + media.paths, + ) class MsgTest(TembaTest): From a52eae42924fdba83772f2d34acb6553229cd1e0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 10:04:25 -0500 Subject: [PATCH 069/630] Update CHANGELOG.md for v7.5.7 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4a3ed4997..1ffcb3670dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.7 +---------- + * Add constraint to ensure non-waiting/active runs have exited_on set + * Add constraint to ensure non-waiting sessions have an ended_on + v7.5.6 ---------- * Remove unused upload_recording endpoint diff --git a/pyproject.toml b/pyproject.toml index 3c2170f017a..8d2f6c85880 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.6" +version = "7.5.7" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 5abef51d0155dd25f4eaf72cc05b8f4b22bcb99f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 09:56:09 -0500 Subject: [PATCH 070/630] Add new fields to msgs.Media --- temba/flows/views.py | 13 +---- ...edia_content_type_media_height_and_more.py | 51 +++++++++++++++++++ .../migrations/0178_populate_media_path.py | 23 +++++++++ ...ter_media_content_type_alter_media_path.py | 23 +++++++++ temba/msgs/models.py | 19 +++++-- temba/msgs/tests.py | 6 +-- 6 files changed, 114 insertions(+), 21 deletions(-) create mode 100644 temba/msgs/migrations/0177_media_alternates_media_content_type_media_height_and_more.py create mode 100644 temba/msgs/migrations/0178_populate_media_path.py create mode 100644 temba/msgs/migrations/0179_alter_media_content_type_alter_media_path.py diff --git a/temba/flows/views.py b/temba/flows/views.py index df884c2b635..d12c6f3adaf 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -213,7 +213,6 @@ class FlowCRUDL(SmartCRUDL): "recent_contacts", "assets", "upload_media", - "upload_media_action", # deprecated ) model = Flow @@ -702,16 +701,6 @@ def post_save(self, obj): return obj - class UploadMediaAction(OrgObjPermsMixin, SmartUpdateView): # pragma: no cover - permission = "flows.flow_upload_media" - slug_url_kwarg = "uuid" - - def post(self, request, *args, **kwargs): - media = Media.from_upload( - self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() - ) - return JsonResponse({"type": list(media.paths.keys())[0], "url": media.url}) - class UploadMedia(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" @@ -719,7 +708,7 @@ def post(self, request, *args, **kwargs): media = Media.from_upload( self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() ) - return JsonResponse({"type": list(media.paths.keys())[0], "url": media.url}) + return JsonResponse({"type": media.content_type, "url": media.url}) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): title = _("Flows") diff --git a/temba/msgs/migrations/0177_media_alternates_media_content_type_media_height_and_more.py b/temba/msgs/migrations/0177_media_alternates_media_content_type_media_height_and_more.py new file mode 100644 index 00000000000..c64b9c49a7a --- /dev/null +++ b/temba/msgs/migrations/0177_media_alternates_media_content_type_media_height_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 4.0.6 on 2022-07-28 14:41 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0176_media"), + ] + + operations = [ + migrations.AddField( + model_name="media", + name="content_type", + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name="media", + name="height", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="media", + name="path", + field=models.CharField(max_length=2048, null=True), + ), + migrations.AddField( + model_name="media", + name="size", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="media", + name="width", + field=models.IntegerField(default=0), + ), + migrations.AlterField( + model_name="media", + name="url", + field=models.URLField(db_index=True, max_length=2048, unique=True), + ), + migrations.AddField( + model_name="media", + name="original", + field=models.ForeignKey( + null=True, on_delete=django.db.models.deletion.CASCADE, to="msgs.media", related_name="alternates" + ), + ), + ] diff --git a/temba/msgs/migrations/0178_populate_media_path.py b/temba/msgs/migrations/0178_populate_media_path.py new file mode 100644 index 00000000000..b3a8e8061d1 --- /dev/null +++ b/temba/msgs/migrations/0178_populate_media_path.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-07-28 14:43 + +from django.db import migrations + + +def populate_media_path(apps, schema_editor): # pragma: no cover + Media = apps.get_model("msgs", "Media") + for media in Media.objects.filter(content_type=None, path=None): + content_type = list(media.paths.keys())[0] + path = media.paths[content_type] + + media.content_type = content_type + media.path = path + media.save(update_fields=("content_type", "path")) + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0177_media_alternates_media_content_type_media_height_and_more"), + ] + + operations = [migrations.RunPython(populate_media_path)] diff --git a/temba/msgs/migrations/0179_alter_media_content_type_alter_media_path.py b/temba/msgs/migrations/0179_alter_media_content_type_alter_media_path.py new file mode 100644 index 00000000000..5346145e8ba --- /dev/null +++ b/temba/msgs/migrations/0179_alter_media_content_type_alter_media_path.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-07-28 14:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0178_populate_media_path"), + ] + + operations = [ + migrations.AlterField( + model_name="media", + name="content_type", + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name="media", + name="path", + field=models.CharField(max_length=2048), + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index d23a4673632..defe85ad0c3 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -48,17 +48,25 @@ class Media(models.Model): uuid = models.UUIDField(default=uuid4) org = models.ForeignKey(Org, on_delete=models.PROTECT) - url = models.URLField(max_length=2048, db_index=True) - name = models.CharField(max_length=255) # original filename - paths = models.JSONField(default=dict) # dict of {content_type1: path1, content_type2: path2, ...} + url = models.URLField(max_length=2048, db_index=True, unique=True) + name = models.CharField(max_length=255) # filename including extension + content_type = models.CharField(max_length=255) + path = models.CharField(max_length=2048) + original = models.ForeignKey("self", null=True, on_delete=models.CASCADE, related_name="alternates") # fields that will be set after upload by a processing task + size = models.IntegerField(default=0) # bytes + duration = models.IntegerField(default=0) # milliseconds + width = models.IntegerField(default=0) # pixels + height = models.IntegerField(default=0) # pixels is_ready = models.BooleanField(default=False) - duration = models.IntegerField(default=0) created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) + # TODO remove + paths = models.JSONField(default=dict) + @classmethod def from_upload(cls, org, user, file, flow): from .tasks import process_media_upload @@ -78,7 +86,8 @@ def from_upload(cls, org, user, file, flow): org=org, url=public_file_storage.url(path), name=file.name, - paths={file.content_type: path}, + content_type=file.content_type, + path=path, created_by=user, ) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index eaa7b3bf913..8be9a242262 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -52,11 +52,9 @@ def test_model(self, mock_uuid): f"/media/attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve%20marten.jpg", media.url, ) - self.assertEqual( - {"image/jpeg": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg"}, - media.paths, - ) self.assertEqual("steve marten.jpg", media.name) + self.assertEqual("image/jpeg", media.content_type) + self.assertEqual(f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg", media.path) self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) From 2cc482894e1997beea986147c4e6af33ccccad91 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 12:23:40 -0500 Subject: [PATCH 071/630] WIP --- temba/msgs/media.py | 66 +++++++++++++++++++++++++------------------- temba/msgs/models.py | 22 ++++++++++----- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/temba/msgs/media.py b/temba/msgs/media.py index 56793b13523..00221d76fab 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -4,13 +4,15 @@ import ffmpeg from temba.utils.s3 import public_file_storage +from temba.utils.uuid import uuid4 +from .models import Media -def process_upload(media): - content_type, path = _get_uploaded_content(media) - media_type, sub_type = content_type.split("/") - with public_file_storage.open(path, mode="rb") as stream: +def process_upload(media: Media): + media_type, sub_type = media.content_type.split("/") + + with public_file_storage.open(media.path, mode="rb") as stream: # download the media from storage to a local temp file with NamedTemporaryFile(suffix=media.name, delete=True) as temp: data = stream.read() @@ -18,34 +20,39 @@ def process_upload(media): temp.flush() temp.seek(0) + media.size = len(data) + if media_type == "image": - _process_image_upload(media, sub_type, path, temp) + _process_image_upload(media, sub_type, temp) elif media_type == "audio": - _process_audio_upload(media, sub_type, path, temp) + _process_audio_upload(media, sub_type, temp) elif media_type == "video": - _process_video_upload(media, sub_type, path, temp) + _process_video_upload(media, sub_type, temp) + media.is_ready = True + media.save() -def _process_image_upload(media, sub_type, path, file): + +def _process_image_upload(media: Media, sub_type: str, file): pass -def _process_audio_upload(media, sub_type, path, file): +def _process_audio_upload(media: Media, sub_type: str, file): if sub_type != "mp3": - media.paths["audio/mp3"] = _create_new_audio_version(path, file, "mp3", codec="libmp3lame") + _create_alternate_audio(media, file, "audio/mp3", "mp3", codec="libmp3lame") if sub_type != "mp4": - media.paths["audio/mp4"] = _create_new_audio_version(path, file, "m4a", codec="aac") + _create_alternate_audio(media, file, "audio/mp4", "m4a", codec="aac") media.duration = _get_duration(file) -def _process_video_upload(media, sub_type: str, path: str, file): - media.paths["image/jpg"] = _create_new_video_thumbnail(path, file) +def _process_video_upload(media: Media, sub_type: str, file): + # media.paths["image/jpg"] = _create_new_video_thumbnail(media.path, file) media.duration = _get_duration(file) -def _create_new_audio_version(path: str, file, new_extension: str, codec: str) -> str: +def _create_alternate_audio(original: Media, file, new_content_type: str, new_extension: str, codec: str) -> str: """ Creates a new audio version of the given media file """ @@ -53,10 +60,10 @@ def _create_new_audio_version(path: str, file, new_extension: str, codec: str) - def transform(in_name, out_name): ffmpeg.input(in_name).output(out_name, acodec=codec).overwrite_output().run() - return _create_new_file(path, file, new_extension, transform) + return _create_new_media(original, file, transform, new_extension) -def _create_new_video_thumbnail(path: str, file) -> str: +def _create_new_video_thumbnail(media: str, file) -> str: """ Creates a new thumbnail for the given video file """ @@ -66,22 +73,31 @@ def transform(in_name, out_name): out_name, vframes=1 ).overwrite_output().run() - return _create_new_file(path, file, "jpg", transform) + return _create_new_media(media, file, transform, "jpg") -def _create_new_file(path: str, file, new_extension: str, transform) -> str: +def _create_new_media(original: Media, file, transform, new_content_type: str, new_extension: str) -> Media: """ - Creates a new file from the given media file using the given transform function + Creates a new media instance by transforming an original with an ffmpeg pipeline """ - new_path = _change_extension(path, new_extension) + new_path = _change_extension(original.path, new_extension) with NamedTemporaryFile(suffix="." + new_extension, delete=True) as temp: transform(file.name, temp.name) public_file_storage.save(new_path, temp) - return new_path + return Media.objects.create( + uuid=uuid4(), + org=original.org, + url=public_file_storage.url(new_path), + name=file.name, + content_type=new_content_type, + path=new_path, + original=original, + created_by=original.created_by, + ) def _get_duration(file) -> int: @@ -92,14 +108,6 @@ def _get_duration(file) -> int: return int(float(output["format"]["duration"]) * 1000) -def _get_uploaded_content(media) -> tuple: - """ - Gets the content type and path of the uploaded media - """ - content_type = list(media.paths.keys())[0] - return content_type, media.paths[content_type] - - def _change_extension(filename: str, extension: str) -> str: """ Changes the extension of a filename diff --git a/temba/msgs/models.py b/temba/msgs/models.py index dd1a7215e53..81313d9fceb 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -30,8 +30,6 @@ from temba.utils.text import clean_string from temba.utils.uuid import uuid4 -from .media import process_upload - logger = logging.getLogger(__name__) @@ -70,7 +68,15 @@ class Media(models.Model): paths = models.JSONField(default=dict) @classmethod - def from_upload(cls, org, user, file, flow): + def get_storage_path(org, uuid, filename): + """ + Returns the storage path for the given filename. Differs slightly from that used by the media endpoint because + it preserves the original filename which courier still needs if there's no media record for an attachment URL. + """ + return f"{settings.STORAGE_ROOT_DIR}/{org.id}/media/{str(uuid)[0:4]}/{uuid}/{filename}" + + @classmethod + def from_upload(cls, org, user, file): from .tasks import process_media_upload uuid = uuid4() @@ -80,7 +86,7 @@ def from_upload(cls, org, user, file, flow): if extension == "m4a": file.content_type = "audio/mp4" - path = f"attachments/{org.id}/{flow.id}/steps/{uuid}/{file.name}" + path = cls.get_storage_path(org, uuid, file.name) path = public_file_storage.save(path, file) # storage classes can rewrite saved paths media = cls.objects.create( @@ -98,10 +104,12 @@ def from_upload(cls, org, user, file, flow): return media def process_upload(self): - process_upload(self) + from .media import process_upload - self.is_ready = True - self.save(update_fields=("paths", "is_ready", "duration")) + assert not self.is_ready, "media file is already processed" + assert not self.original, "only original uploads can be processed" + + process_upload(self) class Broadcast(models.Model): From c3d025bcb2716e52fd641bbddbd149a9b45f2acc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 12:35:13 -0500 Subject: [PATCH 072/630] Update Media to use similiar storage path as media API endpoint --- temba/flows/tests.py | 6 +++--- temba/flows/views.py | 4 +--- temba/msgs/models.py | 12 ++++++++++-- temba/msgs/tests.py | 8 ++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 2d95a46d654..6481200e950 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -3001,7 +3001,7 @@ def assert_upload(user, filename, expected_json): f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", { "type": "image/jpeg", - "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", + "url": f"/media/test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", }, ) assert_upload( @@ -3009,7 +3009,7 @@ def assert_upload(user, filename, expected_json): f"{settings.MEDIA_ROOT}/test_media/snow.mp4", { "type": "video/mp4", - "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/2f42e913-6a19-44c5-90ee-cdf7b14ad5c0/snow.mp4", + "url": f"/media/test_orgs/{self.org.id}/media/2f42/2f42e913-6a19-44c5-90ee-cdf7b14ad5c0/snow.mp4", }, ) assert_upload( @@ -3017,7 +3017,7 @@ def assert_upload(user, filename, expected_json): f"{settings.MEDIA_ROOT}/test_media/snow.m4a", { "type": "audio/mp4", - "url": f"/media/attachments/{self.org.id}/{flow.id}/steps/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", + "url": f"/media/test_orgs/{self.org.id}/media/f661/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", }, ) diff --git a/temba/flows/views.py b/temba/flows/views.py index d12c6f3adaf..b88e3fd0000 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -705,9 +705,7 @@ class UploadMedia(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" def post(self, request, *args, **kwargs): - media = Media.from_upload( - self.request.org, self.request.user, self.request.FILES["file"], flow=self.get_object() - ) + media = Media.from_upload(self.request.org, self.request.user, self.request.FILES["file"]) return JsonResponse({"type": media.content_type, "url": media.url}) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): diff --git a/temba/msgs/models.py b/temba/msgs/models.py index defe85ad0c3..33d225a4988 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -68,7 +68,15 @@ class Media(models.Model): paths = models.JSONField(default=dict) @classmethod - def from_upload(cls, org, user, file, flow): + def get_storage_path(cls, org, uuid, filename): + """ + Returns the storage path for the given filename. Differs slightly from that used by the media endpoint because + it preserves the original filename which courier still needs if there's no media record for an attachment URL. + """ + return f"{settings.STORAGE_ROOT_DIR}/{org.id}/media/{str(uuid)[0:4]}/{uuid}/{filename}" + + @classmethod + def from_upload(cls, org, user, file): from .tasks import process_media_upload uuid = uuid4() @@ -78,7 +86,7 @@ def from_upload(cls, org, user, file, flow): if extension == "m4a": file.content_type = "audio/mp4" - path = f"attachments/{org.id}/{flow.id}/steps/{uuid}/{file.name}" + path = cls.get_storage_path(org, uuid, file.name) path = public_file_storage.save(path, file) # storage classes can rewrite saved paths media = cls.objects.create( diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 8be9a242262..25e7ca92f75 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -37,24 +37,24 @@ class MediaTest(TembaTest): @patch("temba.msgs.models.uuid4") def test_model(self, mock_uuid): - flow = self.create_flow("Color") mock_uuid.side_effect = [UUID("6a65f14f-b762-4485-b860-96a322292775")] media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "image/jpeg"), - flow=flow, ) self.assertEqual("6a65f14f-b762-4485-b860-96a322292775", str(media.uuid)) self.assertEqual(self.org, media.org) self.assertEqual( - f"/media/attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve%20marten.jpg", + f"/media/test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", media.url, ) self.assertEqual("steve marten.jpg", media.name) self.assertEqual("image/jpeg", media.content_type) - self.assertEqual(f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/steve marten.jpg", media.path) + self.assertEqual( + f"test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve marten.jpg", media.path + ) self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) From 035d97ea2ad82e13a69d06bcd6c6bab13ac6ce41 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 14:41:14 -0500 Subject: [PATCH 073/630] Re-work media to use Media instances for alternates --- media/test_media/bubbles.m4a | Bin 0 -> 46468 bytes media/test_media/snow.m4a | Bin 684558 -> 0 bytes media/test_media/synth.mp3 | Bin 0 -> 52079 bytes temba/flows/tests.py | 5 +- temba/msgs/media.py | 54 +++++--------- temba/msgs/models.py | 54 ++++++++++---- temba/msgs/tests.py | 138 +++++++++++++++++++++++++---------- 7 files changed, 164 insertions(+), 87 deletions(-) create mode 100644 media/test_media/bubbles.m4a delete mode 100644 media/test_media/snow.m4a create mode 100644 media/test_media/synth.mp3 diff --git a/media/test_media/bubbles.m4a b/media/test_media/bubbles.m4a new file mode 100644 index 0000000000000000000000000000000000000000..8134b16b9e04bfbf8ea02dd09f09844079009702 GIT binary patch literal 46468 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%0AY6~kE8oN2-LP#K1WRG#B%sq1#)q`( z1}OS-QdB&lN!9rhSJ>10e}7%X`p50?5$TRYH8b6gq@iv9d!QSh$L`Sps|45xFSZo&gY=X2#q zR#+Q?Tk1kCwWnwaya8)n1KI_dAigez!ypV>-g;GPci8pTXv4&Nsv|ROCu<;d{?Pm` z33YU;e6s&@R(oBc@~y#3obi4+M-w1COx-yaCgn6pt-(>p|`q z^lIiKgPNcX#TwTgVNK}s7Y$fDznvl*R*1X6#ywq{@6scKXRiUUa`$-Qfg~}4c$ZcY zP(dDRmgv8AMsLi~eP++rf5RISPGbr8$~(M^pFn1i^G$Q}FVgM)?@yvt1#*eS3C+ z56DCtat{0oLgUjR0t{NvH5_uG+8(&>ls@1p-a}}AgK0wwrVc6iioMIgDHZ+b3}qlC zNRA4@@?oYxVg&pQ3Q%@9j1OkGaHj%3r(0@#H}OQH1iPq+M-`w4So(Zt6IUR|%RGQ! z)ITHVTN^>VP{#EXMBl+EM+gg?XFn>&68$Tf;?P|2=Y~#br?%H-hIYZ*==`5XG&!t4 zhJRXnX&e3y;m$T+t9xSN;ZS<#{@b%lZuNBbmo(eSy#M^VoE$`|bgxExFKGrNqo?<- zT6R|&o>xowyw#a+uZ-QdqVt$R zu3J-N8wfjS7PmT)P9qa&-}Od3h+?mZ zY-b7^%cN1uyAcBEG;7?Y{!#+Y=^zGLAXg~xa4pzCpjd*ohQ#azFKaGv#1Dktjq%6N z1&wvJ&)VTEpXRr?xnB(5U{5SxFcdM-6 z(V4V?U=2Fb5qwdo_UuhpESN%L(EgL^W(_@{6k?e@CUBN*43r9ZZRUq{VRvi-8&N%r zZyRljR#S-h{t?{?acGvu%$3KNCW0yS)%_0b<72uoEMM33;gP~u;X8sVZ|xtg%aBF} zUtpjjk0!i^sjRdZd3_WNsn5T2(qL^d(f)R5sZ|`)=ugrlD^b@dG7@(UM=M6mI**MB zc@`TzX^w8$N(xIEzP(CKv1mzZxG9bv9v`1yU;bd|<)Rr27ur|7-+$L=yIWiHEi>yj z#X3zK*Bf##w3GK%;pRAsY^&kRFPNWLZ;kyF6XUb&T}cESh%xD(J;qOkyN{X!t%KOQi~U1D}$xZa$;Z>jB`l2fi3KEm}*Ya0xN!4*}aa{$Y^ND9Fs(q z#_=Pr(9$PU6%=0AhsPgH>@-JH?{8mk#jCK}(n?dBjMLEvP8!&{yXz~Zji^Mjow1AB zle!Qa4Z0$ds)EEdv;QbO-hJQ$@)dUtEfRA}3FKaS zW7_r>eE%??R0cn+ABWjd0cj0xjrO70^tvn`D!}lTfQc^9g!b}D8>(R}En-nm*9(L3 z9%`CPGj`IFAOlx0o5E97E#$~@E%P$=d3ob9+C@G(RY8Eq5w1BLqCUbULdV5!_-sao z`g8(2Cz$CrSNb;MOn;D_6Xeb_ap0wn%axrkf_6eFy!lZ!b1zGATpw}y0GQ}{AhI9; z7MeR#9fl1a_P=og@MN6{U^1W;qg{@BQX^$@V;cf!_!?lWA@u^q*-Jw0VV4`8TlZ-H zMNZI%)R!+RH`b}^9$~{c+N;gaPI41@-gDQnOxzjtRa_} z3t*njgzOI(FP*EO6uxU4LmQtl%hL5`1gE+iK9GfHyE;M;X(MszlKw+AwKtv#!4X+i zcN*G0l@wECMhJIB{?_Lu&R(gEZtt{pL%xvAN_C7_r@o!4`tc^Uw>n%92C||Qx`u`m zVxF(xl|RvA7TKm?q)*Cn%(mtdj$|8wAgfiSt~Ar-fkieJf-|a{oZapBUH_`s$}P;z zuN*5)f9h&rkDqySmAx0NZCiR_E{ObjUr%Mno(PMMgNvVkzZZLFp37sk*X@DH-OHN{ z6NYK%l!MT7I{56}59br8Ms_vp5Xlb=YX@-G{%Af{OMehOMXh+Z;6^)f^6R^%%OMWZ zk!ADg@y3>>W|nW-YDe+M5eIEQC1f^7uiNpse!KA31H#ijZdzyKdPj^@Gf8oB#q(B0 z7)I5ae8h1>_{n%UnO1dWb#Ok$RooF3N^%U&rZ3^B{oOfcPofaPZ`Y(k|0+pD-#erB zKme}yh$%?z+F+B)aANNdz|ubNq<h5`F(j8Bl|T3tH>OSZsYC5!4n#LqHUHtQ zWENQ-3mqOicmIQuaH82_i!g+|xh(w-G?d~=mF8!VsYUJt0?zXbda~RBSBjKTSP z2!%b}%3=-c(ca&(wjIky=t`y5+b#_vpDy*f2F55|t=L7avEW6wPZx;uX#&5#*|`65 z=7bh8^|g74?fpbk6Ft_*91a^ogPB{Dld=6=o#&MW@dIxw7o5J;+I2?wwYY8mf7DpX zw7B?*oi#n}%4*dyWETlYaL^&N4=PTPdjjU|!iW@d&BY?SWyPNVsH|>HA0Jhl`iZ9#)YR*z>x!8G)0}sP20znZk=r0$33R_^+@%X zkxXxz+oe1bt2_9^lS}$XCxT&@5xFNRUl|qQJW}M|Ezy=yn}p~w!f5SW;OPPXp+5WH z^ed;op6XP8!}V+EbIwsWM$T4P_1gqr{bjKVWLAtK1I86xZ*jAEtFcE8EiRgML}~aM z@VNZ?_euDH2vU+@tV<>HV#LQM(E7E4FW$4SylOg==jS?K{41uSo(i4aa|ia}ajRoc zJ$bVFrB{n@fQzyE6k;cfHJedi|G#w6>(%FQ6n_I>G+zH|Nwnp>3c=ia^6YC>rSr;% z*TdXtBTfQ9_MHzAs2sHDC$uTnLb&Fo^)uXU{h0H)UY`wJm0SW~edVo=Z_G*S@{)xf zs=P#5sR_o=Mp*?UpF5a=jP>mrmw3Ti!>-@Kzi}Egpi>bg^boAoHyjaLcGrw%&GRLF zesP|h^K;h_5(CW@z7d7E;dul7>Qz?&idROZt?zt~>q`v3cVl~{N~nT?fH23rKX< zJ=%K!CYk@okbA;Dp?@g7V$X0yy{qcJsz!l(G!;;>y@K-9_iB^dHHZS(J!Bgg=4ue4 zVTuU>wH&Nn?SCOcy?5_$3G0{bZou%k%lKr^pALt+^32Jp2a>+Vn76Axx$^Qb0XTl+Jfe%RXN?>&?Y_l?_Z?w zNGmQT=}UR9DX}?0^PSGDZi%>{^7%Y4ud0SMDHHadYi1~T_kJXA>GRpziDAk`Et1S{ z`%0C+gB|xsbKI^Hh~4JuC<0zEo$@#6#@zs`W1}igoFz2n|ku;)4aUd3#xJ2t5*3*^UHa`3HHMZQR@>D^QDrSY#&bFE&-XsuY=iL=f`&2~L<87^s<16QHCOhZ-Qa7vGlAu+WJ(v0 z;yxFY@vWs^L&Yd03H(kcoqe{ecDtZm88q zHZWjNZe0>c1;fg3cd8p&CL@%u#2R9*aT>vA{!W| z6(Eixk0K-_s~QKJ?b}I!bqFa;m=VU~0vch+qk|4#!H#$2eMz~f_6B5-JGzJODm7VV z_eJOr<`wL2S{`AL{l*K($IYl8mdz#gjuv0i(o5ZX<|-ooRG+B|F;x2H4##->NTJfM z0e*Bhh+ONB<#0hvNJzPICn_D~jdXhXVK56LP;b<@&zYS*AuIAJ+X@1(2Ko&mf9!K- zB)}-qZOApc+k-TX+r)=Kk=nWG*T-GWEq`)%$=$DXCn2Z4nWM_Ms5q7@p$Wj8) zW{RAX+)=?~=PbpI>;|UHCFZnj8S4^;2BVz5Sp}y8BF=^Y+sgZhGfiXzum|a99y70a zM@1CKgUY=3Ym2rLZzOf`-1BJ=)y3*LIaa~;|s`=h|AJOm6zSgz9-dcBH_DPJkrZ8$(c0(0Ur2g6ZKXSg)f*%vdj4wib26cqw%27qwTs zXZTdW7hrW;rpe6KN@Op#8dM|eYwq_g4HmQ29=M88N%MF`!obRei`O7Z{}>(2FIQ%R zx*p;N>DAdr%Ql1}O=M3PWQE^sihed^q}k?__gsm^^MG=%&?pekDF-bYA^Q&|)_~|P zqBAj&l`-(_quZqxQzZL7|H939;-oHRG8Cf7C9TS)a6#BaN10~ik~wFQQV&yhL(~Y7 zkU5y=)cv`qH5TPS37}=71&~B-0|DJ}UR{J_;h!3|Cm3|iAtlixK2#B=W~@L?stCT_ zUB5MVpB^Q&X|{Plb8}OBOxlEItM?;v?^v4U4nemU1|U7mpI{N6>iV?^^-B z-z-`>9L)jwsqQk5<}i0EMt4IXQ5VLG=eu)N1?+DC5N=K|+$sO?t`J-httdxVcrmz~ z-scyz+2G-y#FKdF7ppuYGS6aw4x{;NR)oxT^Uuh-d_cUyAeQ5w;J>77cq%ExJ{#S^ z-{6bonk3w)7K)RaS zK|%t0o++f?TnP626ZyDD{^NE7aa8QlmZPL zoIO@+8Zg$4S;U8yeVXrb5k3d!5Dh*qT7(3mIIyS3!S-Fe7ZOfPJK+(7)73tfBK27TODl71$n~Zsi)%L>|C9}adTHMndH#(>M@H#V*_)9^Y9<~P-?>^2W7Q^@64m`T_=}GUC zdV^t?%D|d_bAUX!_{c`{jQ4ojnr7QGHNkJk)-PJOwCl|HX!O6LRtCgX(QEmdrmjjrSW>Q zmNdpqk$WzyaWf;DgbwLGH^Z%ii(@~k_qK>>ecXgF{=)>s$>`h#*w=&l$U6R*zk?r-fbevsfuW0nbQny}Wgc;g@e4c7#n=aKp2+dSpuGm^s*HS*_Yrsx-D991=GpAI0N8rI$sDer`hol&FnQZgKOXM9rr@t>v;`1s<%kvSsI zvH=(7s!{_;>S9ClIV2HzuGYxP?Jtoz{p9>Z#G%()&|K*-&(w%IUPs9@qY-QNOj{e= zbabzgf<6EIKJ;wZ6YFQ(02T~JZf=du_C=%-wk9 zuMw9qDIwwC`YbMm>-Z=4=ykh-2ipzUE-`0wX&| z=Cpe~Pc>IxjVRI-hpze7353(RcMAc!gomXmWLm!Qj*zoCE~@E zh(zJ^x!GTxj`mgZ_-Gx{VQc_+u_}JU4t)OHGvZP3WvmmVgU-gnu2`mptgQ2o9#@zXpHMR&8%6OBdxwM`yo&SQ=Ou z+|*@lnjAbMlO1_go!RPk%QdIRWlr(r*T3j#zy2Zn$)^k|EkunEk1-mUm;qj!%>~CS zZgT^(R;lU|>&!cs4v%GY7qkq$sq-FM5`TJE>9~X;lKwF1Fpy~mh0a2hE$?%o+X}3+ zlM8Y_$iKgF00Z}X+aS_$@!quCxa|JHufA_b9Ja0|7~eVM9ckox^yKkPSB#IX#O=4Q zTAX{AD%DROXGb+Y{|_=`((Z<0Wg|$%Fy3^1bNKW(if2*q zk^CZ8t!k(gKjiwnwW`xQs;ZXdRc1XKwf$~D#8>gk z4Eo9g_)9>{^~ufXL%_JXX(l&8J1*jHb$w26daquWxatfrH?H%ZunR5v3-m!YLO=-@ z0=f?eor;1T%XqKfd*9QKw-6&BO(JQ5*u zZg=x3z6P4ZgE3LWa^B9=h2yLJf))~OW|~p(vX;n$+VTBo<9ZBzyAOpF&ZaEH;pyl> z2GeWWXmM(oA+W)LSgg93%T4uTkMPwLSK5dVKyn7(4@#9 z>qW(zaz3SCUvjnki_-F{7mP-#QI2gYvvmto5f;yX z&v*rIVlEe@w$S#jR8==iNBeCHH;(Gnr%*2%$nHoM^?DdCVr<>@Fdc47KhDs)*jKy- zzjZn;y2na9EP;mpZJ4Glt@pq3H68W4i0-Qekxk+zB@=dQjyWo3)KF_I9t38D76^42 z#%IihrvVDi*5Vh-lu`rx+anq&VqZ0-JUx|JN|U~dBj)*C9_Iz&=c+-xa+{KDDD!>k z<1i=bF4{A5x9SqHVC~RHLG{l+cZ+#xVV|OA_H9fZUdwm8Wot^7sg4|>-tXDyNmX0w zT6|@`q(*V-{t-Qw;J1NQ*8zRkBk5SbLYH0;4P6Ks=ZN~%M8g%56AxJG14*fR>u z8+W4=t26DM+}*69{=Gu}a`tx8ceU2GRPAA@mKnjjKcn7VTrwW~ARwMRG3*^tfkEH9 z&cy8NsPjo+Dama%)2|$@Ek3u3_jO4Z3K=)jk^LXOqob*a0b-9KEo4SR8V&xG5SLH* z4qF0wss>?y9`+C0F@A6WCS)5~Vfk5S>;+>BQxtMB(6YL7$-8BqM?N`i z?D~bf*qITF;FgUmlNGD(`iFd>P6Ag^Q6fI7BDQG^+8yiF)O)7uTfUX4!x)b*j&g+U z#&*?HrecZ`NJP0YWg#ARgRkO6n2{08H{*5CCJ*yeF}uUg22{2v z1h8CFboQOezz@}I2{{Ixi%%eOrc7+KLHpe0$X4fwG~e#^!!Z{Rx#Q)_iQQm8A=Hv_ zS?n-8=PVRal`n#QxUCS`%;1;c9ZzOu*B;%H2jXso@2Su!qmcH zRu7-aD;PMOMhVCUsSJT4%U$1K`iYY<7dBmd*J%#J7g;5@E}#B&iada$_U~eBGv* zu=@C|FNTKHS^_2MOE3^XFN|3~#B?c#P|TXGb>v75p=l}v=SFi2|HPR}OiACgsXUXV zjV~YkyY;{RB_iFeC+cN$`bt13M(D@%lK-&7ca!;Z;jdHlGv0=^eMZWWC!9LcHEDZZD_}p7 zM9=pTg?*D?FTr_2D3b2$22+j;9#LsN;$H@Se>#Sq@cm{e=*fM2Ql`c~0q&teP&0hA zAqaq_1Y%>4&Xu*R98JjuSvG4S1FT7dqUd^a7|!*|-kx7r>VT06i2Ztq8rA0$FX^sv zk3t~&nuwe}XOeniRGVh04O+a9L2orC#!Ft10;E_~MFeXcJX*rI_gJGXv@hHHJZ5Re zE1hlZ1+H*6<0TkfWoLKMLPXgZEnrCJ4$>SSC=+ETP^KGhT2mO#&^8+cBNUE>sMnU{ z457%to2Q@AY?nOB7oLsvc5|D`r%7n*2HF0suEIv{+5khgob^)UFtzPujNheh|XFy2QpcfiR=MDx7i7#bUUTH zy4h(h6VoNI68Fe&cjKa4Helr3!sK`qv@8}rn=bTshfE#a-WbQ43Q$l&5X#ox1&aO0 z@xS82Y6IzX7$;X>4yI<$(=mKr8@4XzNA`L|1DJX1!QVW0qb9Pm17ywOzr%(}7RCRs z{`gUUP!%gvE`Wf8A4S}^r62l!l#4~x4PowcoDpq9sBF)2+Funh#H4pG!{_QyNTYE2 zC8(;+jv9-x;tV;1T0osJEyz2yZ3N?mTF#p}QgDME0`ya0r&$X8j|~92p!`UEReNXw zZwJKktnI=*B(U`0j{V#a$VYFTgzYF6G%SCa3G8LbRg^*$GDGt-dc@zvCV&>E^U0Zu zP3R;C-;19kmy(Q4ync{ljT8$!nh6zl%TY{6Klirnd0wKXU{$ap`P;%wM_mLjnA%UD zN*Jwcl(=ClJ4zSq)@qg-rj`94ufn8P+ZEk%es+2`ods|YF;@Gk&>@{AUiaJU=W_>P zVcZHo6xcstM>S1A!umf?SU&W2cb{u{yglT``e*u=XP*3JmX_MpISA{PFY1=pF~OB1 z86}IF%{gOtknvK(ozx{=*~T8g4CW7rO!bk0#BRcDjMp;ghh9cl^hm53(y1!a&rEMo z+rsX8ZoD>{=4=N{!_Er^SH1Ez)wwBSw72ee@V01y4hM9z3z!b!eoSt6hwwnKvJG7B zaKJbDi0r{x$z|I(1)0Bz8~Q$(`fR<=@(04lF6yu-pQq!q8Jbsuje$IgKFeBurEO}d zanS1dCc81te|8X-h_5TbhE;X|6Bfazn!rUxi*=IM#6qvqT4I-&TG{ry-;}sOw_FV9 zCrguwcaf^rGSaXM_4* zrxg82gmHI+O*Up5T`5@@o~YzxA^iYX1oLZlv<7LE6pSDAFU0*11I#asxvN?dR)^fe zQAt|$O~d~6YBfd&xG=d%j5GBu)W7lq5qEB?&bQ>#o|fYm7ZhkV`+BJQyc(^`R+1+= zyL0oQMY`sOMtZ9e*ETd|HCfiXJm;6N+;(-A5D3FXAm{Bl0US)9>QKm($#4k4H2HcI zW)biUPLCDvgP4G#+*Llt1K)b8z2XekgA*_MH9)R{^;sl5{=iIbjvxA5I2zTzu7b%J}Cs3br|rM9h53xNI=5% z!`RsJ?pzM4p;b&V&*y7dV3|@)=pdJn$Uzv4F(?f6B(~`{bhhxJ9JFwQ%x32 z8Joa+HG3l35JR_zq?alFa5+}$2>LAP_=WLdtrH74gYED^$v&k~2{TVKf1`L)t8Kol z&fe))q&Rq&Leefdu$+GRTyS*v+8e6_6ss*`o>Uv%J^S?EBbHBz$X`wIzg1+p7bg8809CukNASM#QG>$s^%IGIY#gLC-{{Fln zG2`I(F+jvN|3x5@AF_RSa$b3yihu5|>xWGp6#rG7QoFVRDRD0SIF|l#_tPJ}D2RDZ z0fSh3^mB}#)E~L3)P)j&9pFNap!a)B@61$Bh60NjbU3znT$t!}J>4r`=9W&Rjrl9q zhkB(y>=}`hrbi+7(_;N zH&;bed6{=cSlqW1&7ZI^oc_>}&Ubil$d0%_tt7f^`!%D-+fAKS5R~Ry}Ll%Q{5o4u+F>@eC1)6 zpV}~=5-Id9+ptVMXT$~}7kC%ky|UipVGD-X4z8k9J}1p1E_~I^Rh%M)i^m&0!w(-f z4#|1r1okP!6nVpxs^_k^U(Q0tD{yYv{jbj5d_IFh56rau(ANly`@V_gLuF1PBTi7l||Bd@O*_9e^#=3XacB}sV>PxJgEEs;`x3#0hQUAn; zepq?-i2Z`wdSPDJ)9dJ5@8}mTNr(AL!TjHZBh-DnYaa!lT)y}1zz(7`4|DYGN=Z)< z>eTMmLGAI|p88W|Cwk9JnYAsc@L*s*y3O=-70*+pGcw^U>n)|@+Y|UEk+d%~3T3u7 z-q6A8?wcYBj<(1)CS8qQg*8oljZl-(_H?OFa50RUo^rlP=B;`P+9)=Dl!xcG2^=nfZO}Ic}PqU5Gpy z&bmhl=V_OVBb@dm24)Ys#D#IV=N)aB=3;KGmS7t2bx}=JS>L93-$JtRctgCXp;2Mw z^LoSC$G~qP(4vuVO8x)3(UZbN?47NMmfl+#uyQ8)iR0(%uChbe=M%f$C3&G4VQ@FB;z#r*-!!#dH&?>>5_sm7 zp`!cERMf-Kgt}hoB7A<-`$NF!G)J?e1ysd`VM-Be zSs)spjd8h?HvjlPW6!LOESnS(s9!SIq zG^8`7_3u74kML-LAve!mhpFDsl)s*&MW(+jE9Utg2eB+R@HQ~=jZ<4-1KEj`yntC3 z`gtm6;C~ED!LiuD+hsye1jV9P)B?LWF8HWDhtTj>FKvJ23&#N;;uLRJxDfxl;OUA9NK!MqKb1mKQliaG0n5j@Z5gwnw`bi z?n&4QqYc*?UgPz{E%>BH1k172puIcU+I25s_Y`IMmf>2L)`<9oam|w0lDUJLn+?Gn zm9UviePPYp$nYGZj~V1|Ue+k~R#808#-dDM&aVQnT*_g|^Vh_JPvR>YoFc!pQh?^L z`&0g3gR)AW+PcLfDMY<I@^}rkraaKeLX&|I5gOoi@2vVA25I9t5NWj{_BEM5v}N)y4AL-Rt($A zHVz^qfl)R{nK@le$fE*<38elYh0QRlE<(Nq+_1=ZE99yroI-TYG6I9>n4W z+6-na@|2c|DAJ_~pLirbh#6@}_p}3#4TQ5DJ1sV96XkC?%BGoKjW$h+(lUJUq2JqP zlPVtM`@o;aeSHU#Bw&z~$z~WrhI8UI$2#T_nF*iv?Z@@MvN3x4X=#NF%rskqOO4ai zT*;y~E95SXLQBT7lCF%s4lao(|K`&33^d#}8Dq>mh;TMlSm-=fr0=glNi}l_8bU1 zdOy4U9FIToH{|1eduD8LtMA+ofI-*DL*#cUXSxeiPR9}XJ})`9s$PjKK9}=(`!B`% zU>8;f4}hrp&vN!~se|MBphv$zM*q%Vaas;gFThkN2w`ww>VzcyfB27Mwlk=<&)P5% zfjNmxsK&7cT$+pc31{9QGR=|d0D-|B+tah4+~gEQ&YfN$*H12F58x;9K|#}gwy|O# zMIzf5X+(i%Aw3G6KvpdnwE9Cj6LCla_+q`sLlO~LmYhX{GmX_t55biWmurn6zHJdX zV9iq}*5N^GUG zur{c6-%8HT?O;{7fo#o_TUVd$Wm%pn>6Z5^CL6+#t3J9TVZ+~|zyg{XRs9G~S6>&- zOn+1M$3Do0FuZ)6%hnJrmH!bCJ!S_su|SOdpG0i*&|Rs0`EXCKe>`v39GW}Dm1z8p$6 zLb>UfbbB=0+(n#o3>%VII^F3M-5Q1sC7hZH>(nVjG8>^%2%EbUr>Ly^+K`i^jEtGt zepkQ$dOZ50#^dwZb-mxO*YgN*Zw2JyjL|7J?C`ijd0>c{U zOb6nzdMf~roaP|>78kM<*&Zk4{4K`2+(}=qZ)`L3h12>&(gea{Xbz|){g`$D=(h`k zKr>N>aRJNJek_9)Ya;h0a1dy=*AL-Z7TN%k20687qr8gebji^Lo16VU5;;F8R_-{m z^&Rh;jsJG@gMij4S?&nOn1KH-TLC5?j3IDG>kORe_&MfUKHW83#W(Nz*QQ(h=S*?r zMB74(7vd0QnuZ^r;MSN;*7oPQwqklg6UgbXfxm8$RAU+>w2Y21=@`V}(~eEB<#^qa z?b?@{1M)EFEH(@|Ab?bIDZ1r`v;Ok?@ughzKY>Q9bvdkq;t~s$g$LwI zcL3!AUiiePEmt$tP%f$7pOG|bMESl#^>ex(x2yMf#H!B<*r%wBXbA1%hr-z zV6>JUXu|JORYxt-#ucC_VfGP4cEgD#iWyzEbUUehQ}+>F9;GvC6MHlGTPo=ObYBIP zrag|sC|GYkF*e57kPJzdg7si<@3T;#$lRk0E18z`<&<)V44`_vMV*+C|4AAr0TwCX zK4m(=d!qrwTUhF<7Ml(U9{{8?(h@{`@}WOkmk`DVL>6^Zhv0%k=r}lE34=QzER)Ym z5j9MQbG;lRNqNO!sAzyYQnP+bd)1-@WyqvN5c$j$hLg@BbpD$Vm7(I2Vi4xe_q+Ob zF&CoGnDkJX=`Q8}wa3)J3fkyt4EMh(55DU>x)|JQNDu<77z%JX2)1?u9cDi?jHY$- zU3bsAnrR$egp`q6I_G!ocvhw|qlOz$yz_6CXIFN|Wa&5ES6AK9|DA|5S8csI``?9A zL>LF%rF*I<)?oYDN`meR3a1gub=t$slqtan%S-Ki2`lKbAtcm$zBR^+R#l1T-&LuO01;NzBL_`s?_5g7$R$DAW3!g7y6%`T z62T4J$FWPqim{QfJRLe%cz%s}Xk>vzcf8 zI1`z`o?lW6wb0X#&rR<8`)~ate}z_mxP}1)ZBj&SjQ;A}a-aLbf{j8q6e9`E9olcV zD69DmCwLjG)8-vVXQT;-4kWpAKTkNEx!Bd1DLYa3%5SG01}DY~XfK~nhO~i`qXY5Ly9nVPH_PfFlfFD6&PV6_hDPh8DW;Q!TfUm{)}qQvO$={i|URD zQybT$)3P9lEH)65PC=NPC?jRBR3p)fCBmKHnS!cvu1fVHIZd4>5Q`Fa?p~Y z42&OV0h|hQIP+uTtk9I?I(R91uS?`n`In=ud&efE&Jh9_2V!NuGO7r$&P!q(&{7^4 zZLyh!#@B=K>^+Fq{Gz-JlNXwpb14yJ+X1&jgYt?725=fAxD`pr@xgS9=t3-V z0&HCtcl%4C{Pt91 zoFZ_6-s%PuS8;Mr^~h~3;7(vS-(;@e1A><;v-kU8n__E2a{1N)T7;RD_ssW^+{(nL zLjV9jK30^9DT?nbJ_A@&Foy@J5GFpq)sukT!rq^vl0D%`4m(Rs6y8E}e;*p`Ll`O( zXIX95dun10tPh!8TLLQEAZKjh4FMb`=;jh~gb>{>NT(>AyxU`H`97LRB~Hr9ABrLl zcghn7y%95Ya$AG=zzwrX1l(>7fS}olbTyH|?cl+1Qx#!qXBxL34v_`NuA^o-(*zBO~MC z%(9f^ezDB5CqWFk)vOEa{p%S5jxt6{;SduQcoUAq!d&1GP!NaPh-nyljyqY$EoLlV zI5ATvQokguzyNeH5abntfU>Y~n{?C5hUQfLsfu`8cwRydxb-zS*rID9h_eI&JwRTr z|36A5@<`ZKz$3Kp!B~B~gRX8zsq*s*o||t#hAxE2=NJ5E5Hu!iu{mUDe0B z9txOS=I1Pr_BCk-Ecc!~Bi#2UH(J+58DJUzq8}bGQkQi;7R1|wRWHAW)dfo}e`a++ z!ljl5z7n#+w-VT$I_}A|FsNj+P@VQ~BVbEK2DF96?5v!{46Uj0XP7puYp z_=%I_;6CX)yy{%84+*AsZDTccd8p>9YVr{iX=xelD0Lju!cpKGKZ_Ju9BYt)9g00y zeWGGK#xnut^($`DX5jVPpXu*oH*KoQ0WB}kutx@ul#eB)>)|_o7xl=?=ZAuI!tB?= z=5=Cz@9M{rhXJ4|!1uxSj>Nbr*?h#Pe&5rC4|hsZL#<9a3W}^wR@^=t(icMCrU<5J4rLa` z`BmyGOnH|6j2xM{DJO?jJ$K;gEDAQQ>+hHI+-=!OMLVYzJR{DXWxpI(*99SqqYwr2 z!P0M+k{+*h*ai-gLRBI3JQe9JFCt+XT)*N3S~hfA_2m~3v!E`Qe#t%SA`~l#wPEL! zp!s%2b43iJN))Ze(5c1)%%#Zxq`r^XN58+0_@hJ>bn2bk-$Zizp^fkKE|N7iHM#uvPsV8lrFYq5b%S5WbOr$|~<;%kh`*RMQ zn~pr$@V}7X5&nJS_>O6&(m%UghXT9X%rQ`n43|llzd!nZ-tH=%tA{BLD7A6H8L;Lx zu`zG%_8#&7_ON1PgXb__xL*gJvq-;l>i(5?3%=s2g$(WQDN*arXZc9o_ZzhgtfD82TT8s$#ZSdoSQ>=(m(EF>n}%Rr}xTdlR;k z&REuWF($>6K!9}Eg3@lPfCMCvt(YY_xpHi%b(x5<4#wXc<8?luOqz+ZgQF=Fd{20% zzhV#lkJ>u(3-l{W`HDUH!Kd`pGxr&$3$#f%OVOIGgU5*ne z;>O&`C+oMoL#)OkM`BQhQUiTy90!DJr)LRN`{*tD*1iJ~d=|i0A@p4umd4tnllD3oBrJL7GOstGEnO>=2{+zcPkC@B zMW$}-;!F4tNsbA!!w_}|b!>FXTPGFqPnU-&LgVsWEY?lGdC;-dfoYoZJCnIZlU+V+ zg}JC*cm7~i%;h}DpC@l>7w@z)m)%e7j(TNz_Om35q$tAl3rYZzfhlwX$!Pg_TU;5d z-K@hje*5TbGj&otk!68hdThhF0a4%S9@#vbPM#pS9cH1c-I@#uT;Ry5avR-I70!gp z-$fWB$r+*#a7UMWUBlX_GM{o)m6goH^Uzp_u`LtK(09wp0q^ltU;G~}hPZJL>iU`! zjPDD#Lq6s1ZgjB-ohsg&=JmKucSwI@k7f2f>H5^0fk=yi5Esb?xA*MpNKHgx3?hF}A`y;&duMWGI`~1D&BfyV_ zSVGGb9{!XreVjBt?7r$XYky=Y;X@o3s|{;fmBAQ>5?yQ2GzbKz|G;FgZs_OPn?iJNBzo3cRcC ztMw8xYJOmmci_tG z^@pKvDyx^~5?&VXj0V85ulYsX;G*M!k8z-VdCxpU9be}n+m!y>JrH=_GIzIa+P}9c zAP>@`05}mDWd9sg;Umc+VuhE$un_vxk-7q5_NiNNJzYF`>boi2c9(*P{BDQB!PJ95 z$?8`Il#|}T4Uz+7N$4`YoVBhHa^J))rB7h-@OP{$9(D|V!o#;uyfO6{J+b%YYm1(v z-1G@?V~F@aR^0ZD#sbjdVPc@ICc}2r^(b!$EX#8I0!Rd9VemRB(@vz1(vAF9zJWl1 z-HP>=ElK{JNy#us3dE=R4=c5AVpr9~P1hH~- zScCYJRZ01_R~o0CL1}Zx5tcAUQLHfuG>WFf>d?hpP&0DT%W@Iw6pUZ?W(K#N-*Iwb zyAyyGWTP$61>yiH)eg<)1&b@S0|TMb{O-EEaCL2HvgE6L)=Gf@h#nlwG9`?^OQEsN zGRXW?!1ju9n{UVDZ~$94UEy2blzKCb6z6v4@#gOrHRMQI@I7KpQ@fMm8|6HFQFp`tXsigsMtu#6Y85K71lI0`yu2D(dEO+>=q>FoTjzKw7({@ zqS9B#N`439pN#8CZCWvY=8q;j;PaMd>v6&g$zwsqs*o?M-gWDKX&?=0RWmH$bhymu3 zq|{i%(#XQd^y^QXom=<-3T$BsIU(_FZ*k!Ee=HfF6kp^)dMz%%B$;4Nqvr&ATuDDb zE#7!ICJe2Ia#yuBM=1gcgWhy@*RwB5a)hDTOArhc<9Tl>PydQk!d_@R!&lGCQx8c^ zI_83qeg~?&bJz*S4p|s?+bqcX&>yRDDGUhxxa*sm%*}RU+ct!>l4rAGB2y-xqy%42 zkyP=rev%xVnRZ|r8?JSx0=HXC6Pkq{`?f1%?Y&Q&yD(>3?9NGWSt4C?%ho}aWX*w? zqT@FcO3?vV&R6=cG3a>HipYiW*?_bVZ+f^2VPxJKqI2d3w`NRs(>-vuX8KZwcw&CtPka}le-&tzg`%gDbwXvyn7}5 zB-Q(?B~dN>mc0U%NjNnU=)tXagG_^CVMnph=0K89ghK{opLEv5Qh@)?o3QiXtZ7ZH zD-QG~0E(nmSfO*V*|g>kNV)$tw|-et^0}#2`Hf-psEjAs3mRKXptV4khh{tB6N`DN z3H4;<$;|Kcv3$Rz-2j@u0@!yI@xyCCm`ZWl1hT~<+cMk54WwhN$Ht`5Vj)UjVVASk z4ty<(=u_bK?)pbE1Al9S?}oVIpt@}6`B}VlcbzMtLbg{lhKT=pdTb?v4n{8qkTQr2 zZU8_3b97+>fZt#PW-~3&t#!XpMjChb)nyOFSBq0iqh60$KG3_8ZLkXt25)uJKd8>Ch#H+=im$u38<1qh0Y%dfATwn%XgmU;4daA&a+70y zg%;0kDF&+rma*3}Ie=utCXl1z#pIIA*|wON`^fXHJSF(NtMV9qS<9HV>?4_g3GJ3g zQIHjR@zM2cA}&VzEjdRuU`y9V@n-URyaM+6>{`CrFEW`A#ff)M#J6vSJco>xp!bBt?j(Y@>(Lp-+= zm@>0j%MIK!49&DIv^a)#z~$61G_IJJ8C@xN!oH7-rFnK39OFt6k%B@wz zK0|BrHJQjp_kF{s=b>xBJ{SR7WhQVw8qto30I|H=T@x`oks$en1Qiy4|A{O-fU#v} zD|}H&+vp`OonPw+V1~2;5O=g-J|)@Q)b6cNd#}OtOA|QrIov~taV`C)l&#O%eXYP} z+X18jnEgBm2?mvC#e#9iiiM<&IT$t>B#E(JnO|wpY#lESD*fN+mn)D}V5p6Rr}G($zSwYerV=z#W86YIbw=6P?%NS=a3kF6tFp zkzq2$hTRsH9gvfDqCj#;Fefs3jD_>!8%`Q{nlj{O8!QG9Np{8Y= z`5|t{-Ms+fOn14p$b07EhIs1wod~cp^iqVU103x$>>OE~z)gKv*?{{{s*l>lF*LwK zI#pyGB)PZ4z^9%O>H`WY6+O>P+b;au3g2vatg=hKzWUCgFRR}Is z0E(C?-`%C=M1GK00h+;72YYjq6%1Yv1X6T%DxV5TVInAK0(Or|(YnlsPjo~JESFlG z#Z>$1wq_$fH%kHzM4T)uca^OOWe8LNDiG=*p?thEJ5Z@L>BO5ksFwWL>ZqmCHx&bP zidrloM1{5po%MEnj{ajdV|hrSDgE}MT})?G9I{8t&X9&@H&s&SCn#D=!9U_Gk3+p@ zKHxIkw!FAk`(onM?i=j>POJb~%>9q66_|2|rlW9l>)H4P?uq^K8-u<;s;O~!L`xM# zTBM03hhZBXa=eso3f27ys5dfGb=HFzi1j<~Wc?nduoGha#O%FJsDy+Do#Ot?q1%$9 zi|u#XntRiXv^P?s>|l%%WH*0HaB(&odS$>=VE0zIVD6&k#!da>7=_y1p{Wm+Y*6m* zKQ;C&jna{%F=rj#d3X6|2cr4RG%&8j5_k9X-8%Oz8})MON$}T^Pnlze9l1M7NU{RlwR>R3z7KB)y^yR=?O0yZTN{A10K0{Pz7cx(lhfmh7*s{WW z+My|spF1P@IREEwMl1%N;W5v@)Foe5z_u?kiIUWTwb z1O2fNcy5vF)3NtDkFguybu^6Jn`UgUffe)%w8A^4aF-ZFN1&Iw%zAE-@@?a?Yy%1y z$1jsJOgh}E=_*h7TDusK{RD8-?(U2bL@rUjzt5%FR90T#>b`$_Aou;+jz*h#2d@h8@F&yl5#k&_N zUq(&@W!V5ByilnYyI|9YRd|HH*C|P+d>W(AZQt@FjveUkY>^sA^}0-2NUasmG%QEo zu?lG4pK9-NaohhSL|8GZ58Bz=e9uKxfRHr%7=e&#zk;SWDZ%+jcR@8@v; zQfkTGPqfrj>e{f7&1lypAQr024A`-_@A`Acu3;xYSjXP;fhH9nNWCw6QyXLRC#>Rb zk<+8$50`&002m^T9oU*@;U&NLy8#7E$eeTd=T@aAX712@ZXbzEpnAU8f39MIV9k!b zYn+&0oYq$XNLUR&|E7=2S&RRgjVd(R_WAXV;GA1>U;IMYP3X+x+6Ie|f>rgu+Do6h z%KN-;Lwzuc)VPjU>U#^(g(+VqYK&nv^iv<+yU7d~N231v*M_d`l=z zsq33<*NxVN9PT0V79h@%bHclazfYumo>~y44e@Zp)(pNIY9(Nx$`8QnO=*tbNBor_ z2|7`#MjvuhO@y8)BIEP6j7*7ubu~MoG=(;3A}l+SS`+Cs88|n8HR5$001`ZL%!8u4 z08OlMw_+nyd$DIEj1OS&OW6X^hjv_ET;$s$qNifvCAVns@VQ(? zTNJKCaaOyp_}#r@xht*-w(c)gBjLsR5|*jn>ECy>PtJZg)3%!> zLTzyvh6hK1G;Q2=0;`4c%itS=bRf?$7F2{{r=5>I)=sRA@{PdwAPef+{0fHGhTKUe*rx9x5e@vQUPxSt8PcK#Jas`+hky|JJ2H;7mO z>zdLn$Qka{B4s@B)XQrncNz*QG)y;Ww#QRd>ENWSVgZG){tCp$Fk{2u1*AA)=OD@O z5G=QwSt5Yx8Kl#V*zT?EXsxG^M8xwR{Yi_tapHG@&?|Kcyp!M<3W0#lIq#BVx28En z2XBwtS9vXR^5S3Heq-6`p*EoOK^|MBh3PFjl9Hsea22~@1ryAs7N7*Is8hBiS<8o( z#c|lg)>f-vfW4_uWRb5Ss6<_{?iC*ZcQ)?46iji zZM)Y_di`7R!-m=Rm;c-Jx4E`&eP-<76bC1d7Z|K>{MpLW~q`CL4F?J78Q&HcXIA)JwRTKDO;Fw6YfLh1#z z;jU+AV=p666a@zC(HN&=NPJ0IgyRn=#}<8*2j`taWjoQ};@k=rF9FCy_uPk5*^c3Wj zhAes;0R@8T$ko_=>5aFqDb@vXF1R35x+h)9^A*78_n(kmK!E&i`PK&TZYa#x#5_s zon#%l2v`B#`fkeB9o=^i{>S`pOHoTe{n?layEi8_EZ+L!+U)$9|GkjWTAJj4M{q4v ze))=^#qe6*rl~Xh@)*34uC>{Glgl*dag$GMK+e6z*sllLZhU2C>)R1XjyPJ?VP#$#dgVT@_u^x&z6L zp)B^`HaEDtCz7VeU4Z^BlF==kLtXCS%_dTbTBoJZ&;ko|?yx}^-v_m)?>gjPWy#_P z$n(L?3ur=W5lGma_r=|pjK`M))z0$ljY7Lhz9@*|e= zVmiYA_UMN@Pd7H@!#jj^K{xQx)9W`J`_;9R>Je|B3zS#sgj$?sP4G;Qxwg)X1 zXBzBt_=%8ofb*mpgW`k=nU?^VR{#M2BVI~!5ao~if|=V#SbhhEbWNC^a5@pqN;fL9 zb?4ON3-JLvKif03UOpYVZVE0(2 z8+Hs)66!l+pZCbNuZA^76veM+IN4dv=X|kn1^unu_^3HFL(@!;biyg$4IE(l@U*%iT#0DEX+mYtu^zRd zwRCORskJw@yF2C(U~s$nRt#AD118i>z^MoG9G~f-il?ftlo?hFx1iwbz=7o7{`vs) zba+TlxTJ3!cxmLBpV*zhA=szL(+X7(u$+2>A)O63IH&LzZ}i|+aW)@CfTJ8NL!Hb? zxI75pM{I~C2n+f(NXZm${A&nJc&HD`9$$#UfszE=eUBjr+4C-ZW}F;3<-fj#m4V5X zpC;a$LH$<@;>AV)v9!ltrm;0Rp5dTp+1skFjHlyNK{gy+Q0=Lst8N}mNm9Y+1`r&^ z*1ZHHu;q3L%RWiDML=0v(_;D5H9!ae2Yzl-x5LL(Xw7&uam;4N#|B#UHS`fFf4ibaZ8yR^&#j%ZeDYIgYLYuQO2S%SHn zHcfGn0P5ZvTwE6yC!h(FE%cU^nT0jX`-#<@;fYp-I%Qi*lC?(VL>CT-Zk?0Q_c|2` zmNQ!{Gkq`!XPN`LIBkMd8<``zMhEq{z5^LdqYv-HQVn)@0F=xM*o3z31$XIlW!IPw zoo?~b>;{j4Z+<1Br@SYl^+_&-Q(dnd;2S9K@aXFFnT9u&UZL>4_fF7DPJ@b^3VJ69 zuvLXZ>fR0hq3kl)bYpyosy1%1_VbVVX`fUypTn`W&LC@3DC;68s)Q|Zi&FzWQ!a0A z=;c$$zZt}u-F>t3q%5s3!1wObv6toKy>TR)r0}EDPU+Ahbf*cPn=9$FOLC&aG#6teUo+VOyq; z55_a7*~}oUPR{U6lqjf1Ib;?<r>vL%#c?{*5g~u8ccUX{*Rw;7r@mupHGr`-@@6 z(}lhHL)CyO2Sio>>SOCBZJ@7tk0IMOKbBtr!0inn_=0e8!}1Z3eFB^ttgp9XWQwEk z?Hi)i1i@loVTPW|*$x!%2u$~dDG^`cZjz@*)nGWq%s`kt14Nn5gMH`tJRP9cT6T84 z!jFH$V>7N>rQCkm^8qq5Z5LL@gN_0Hj4jI%s@fSmQb!|!qaiPZgk`TS7B*XU;*qnjaGX;2NS2+B@@UM@+5G09w69JRzGWeJmQ^4EPmNccno&^Pz*n#SaZJZ`)KAjgiuh?lSH~(5 zO!7`uoRl6wxluJf)1eXDEKqsFlk@bBPa?eyb3FB6d?2#Fzs;y1_X7>nN>WTm{Z&U9 zY5vSUKvT>g4|uj~O>66k;nnY9-+>)luYk03%y5XY{1HoEe2Bgm;?Gj1BJpz~Ir2x2u_{ejHXL=bUY^5=kS!UpOTUG%2! zZ^%eVZfkD8CQe1fE5k%$w+Ny4)R5x%P1EV9^frSOQh#?BJY6AWj11g&_Pw z6kh3uqr;w!@fXL&w0i2>1+!@M_e(W)PS}b26uBKCIaBH1ca!P=jB+{_BS)}Pn}{?) zU^qmp9Vs845M0MhWlo7&$hbL{;XkOAf#cf<+B8MVFUxP|^HE()28pMQHM!*3_N|ndQ5Sk|$qbca=fUsw1c0h)*QOs4X{E z=-S_2t2O1HP5$cxF6peDQ(As^Yg61<)E4$0E@zcy!>8PE3oZm0uBcug@0^VB%p$K2 zpkOfF4XWaJ{-5*x#e!$k7GYO}j7d z_5}BUU8;bex^qg;%1#M>IU))xWv;1r-KV4$CYlEx>24$(AO}IB8FAyI?wSYGbiW zWH5jJ`|T4uQjP8FS1!cNxn6q8)ocwzuyyI5ON7||qU8POkZbyi>C@9n4k`!>`7h7^ zgGQl9Rt636)ceGXl(8#&UQmYb9#1>`pz+}I+$T455%w}caV&kq)|lF_9|XIcH)i3W zbG?716*md2jts`{@9mCTyuHlEtu$ocV*ZfyCs+CsOj!4Kw)og8=!AV&)&_RM;zW9V zQ){YW*4Q#7>tUR1{CmXnatalG9boiqIt2)^)1!c{5`*-aUZQ%bc$t8$M;SfoO8?ATY&ix|P0aV1kEyti z0w~GH4(yAu@2?V*Ei4zcPv>j2GZNR$TfV|JrwT)B4}ZGyZU23@uOD$Dbz??f`6|Tf z7mLgGOH)|{fM>t&<%Dy)+%s@S;TNvUtnd8ma@_=5^~K!%71x`JNa)?K1%0^%!42*@ z!V>@3yoKOzi{z(%t!{h^q-@}*_m^nnU)N9K9D#bgJqqXSXR2$Hh&TUHU;L=#uYuWCN>^57ifduYSl$KsZj} z?gZGQ{+W@%W5T<4yz+}CN*73} z1jzInOqOL4Pj_@J-T%ek=3lly4}k3+{1f&$z@Q_?>`VNP-F$zQ6{EiK3@_}b_)75- zJze)+{|JI|)2&{FEQ9eyz%TDRu%jqm2Ro=ym==Yc4Xe`o^p@14lE zPn;jzEcv$GEcuJHvTj{AcP-p?Wa!0e_|82iZyY*wcQhe%F>+E+S#YgB;756mv7uAP zmF8_3bGMUK=M#i=rkZzC^+sFz0FA|dfqn~Z)C|yX?#;iiw?FqVr@=M@gr1}0*@?R=vd?$#HTN2kvI0`0dcie;MBOg4UW?jL_1fMXdwuF7kY3n`jqFa+2UE( z`|!AIC&JH?hs>88b~!)!>eN`pM9eb*R7e?95FMbSx@`e}-W~ixN`nmP<#Rq9c|ID6 zAfNSmBs|^a=<^zWJY+s6-Vy@gbIe}e7Wo{c#UI+_cA#g?@vp?IvERPC9&xt{q{RzL zb>Bf9d0f!i(yyV}Lp$#?zIi-ds0&qEvU(R5Y9EM~9c7-MLjU48`=0iK>sYW8w`siU zJ~B!5<<`B5;KQRq>E`|ir+O>yjDC>a`&HnkE?%K>riDBfa)Na!Vy>6i`1!YY^NmrT ze-Ely-Tx8X#qSO^KRUKc$7EKi^MAi>f5KnR}>WO&$nl1^Lg z!1s0`T{flu!xoN7M047KwaFn+rTY*$W>w{F`m=Jo4$4^f{&enr!0IN4#gRzT41!y@ zaE*==kXYAB1pQ)~sFb1L;+^hn3n%M76{}KqouJwG?VP)-VqUrWe4?6ZmtLH4yJ?F? z-SAQ?vhE{}CXFwMTz7c9-+rIcoaW(=%(*{pWsQ{Kp~K%Yr91n`q2}Bj^tEA)#t)CH zxY%Af6Bb<6k!6rtZ-Q4ZQP(n6Ca#2;f3R>tE!7$qXW;v6jFC*c0!~y!tDqk?Nl==~ zMY(ijt-w=2tcMPhP=F4E32HY94X-wFawpicgKUzzc}BTDy;3V=%#TD|1PYTN8d@LH z!U04ofSJv+J?)5wHen>1`EH@{n}4tty7~9IcCSGc7AkP}0jd%dh_)B2tcOAKO(O9T znA`GING8*f+uz-=(iQfv3s$}mDMc40S(#?7$hFV9CJ08Yw*{b9oeV#?%c<2)VhWL% zy1BuIjjczb#XK1F>Ce&a29TT>(Wop{hBoKEttw#8<*l2bKO!QHa*j@kUS~zk2nmRU zxc)z~Jlot!G%{XtIyQ!kgQ4M^fjOcE$^=j|CCqevnO;iNToE6r~k#Q78mIzv%WS50OERGJZa)}VM!%ecM?YpK|$;aCt<8$;~mLten zQ5#@EMxEva#uB5&MyOhT|n<>K0g^ zG%r>R?h2;4m1CU|&iW1y-*#RB%N2FuE`<-MO8whp4q@7Y@Ccs3KOIxmf#4SBIAO~9 zn+?hA6L=;#XI39=P`EoIPkoSy+96Y-`Rn-V@oBn7riCsjgEoYyk~ zE(47seXwWG!RsU$)C8i!eX?b}2zr@T=6Q`ZeN@cw;3iq;OH@TS{(CE@LZ2|^b?r6& zL7SPA#C4rk-UvKYk(eElt(OV77e-W`;50MjME?Y>_l5tAH3Eyo z&Blg~p+Vw2J4n<0iB6nrsRDn=!4jZ3zm%BH_f}Q)Rw&Z~6n46aZ%^?7rLZ2&yfi(! z(PL&Gq0xKLH;bx5gPDhLdwgSzG-)f&8KI}ciFm+N07hp(@``YS43bbk4e(rHeH>%4 z4o-eZT&jI*Q4Oe)NQo{dC8Q@I_llfYE+kyTi!?Tx*0!)K>ySa|%}@WgwrhCi{HKCR zb>5>*lJd98^w7!oU-lO9ve)mt!@5EBl?@VOUz5i>{O2yCV#y6-LHIt9QkF->f%Muq#xRJHV7%jWub_0RD2W>IRj#} z=nk+RJM91iG6fV&Cjr{O?t0_Pv4ZxgCGxPsP9vUep@fErB)^=~37njdHU`Z-Ql3Of z!|KWM&9RkjVZyh6>s)VQf$IeT++&~;&^iP~(Lyq0&={;OYynG~?YZ8BmPdIX9?%e2 zH~3>Amb2cCe341 z%q|8skhx&C@CsGC>2>{m1*rJ<3 z14w9=rMv{wef|wQYo)jSvuF}*&(bvrXVwj&iGT{_C1`!9l{VX-AvuK{Rr(H^;C&VX zbTEEO=+Vlc@6Wr&y--Kvma0}&4(rDt2m}yXGX-r~A5;eHjVIpqp0-DiigSA<)VoTv z$uh_3xbv-K5EV8!Lc@;nSt;f&rQtNe-yRA3LgW-0nSk1@q~r*KBFK@`BjP;!XH#c} zn2wKO(y)B8+x#!zx<)8SOMsijqrZYuQOMhcJyU)MU-^hKYF+h;tl}#535EwC`-_2l zk^<2QfW5f`HY)ekHBc0G19{;u)$i1G=bDdHhdi5pAQ5TTk8^&#$dNAY4&irsai=r}*9k5J$?7!?tK$U$$z=7X0zmHBu zqbTp(2m^Vn0bP0Q!Q_eSv*8!s{`vBaU~3H8|IjzR9FxPhGsU-15B{;&kbex$0FnuT zEk;|w^nemqCLl~FDbna^^!QR&*bC=ZTRa7Jd5}K%1qDd@_4Z7(eM^sI&m;Seo2MQ3 zqrJSVzPLDR*8@qLaKaa+zWNgX>+N^*vxb)|9_~DllIB0*<bk5l{3bGaHG6FC=}!ZH z4!ro*_i{d$%qRrQ4sA8vO~D&cIXJ^t%0ub)m9|G+E?v58I=W-?%8kFisb5F?ebQpH z^P5{rLojVZcXM7RQSclkrK~YBSM#4_lZx2jP9;&E35xXJ6`<{MZ(KecV*_&;Xfx;(@ z{L()*5f)26EqnKww`%D{n_$)2r%7M@Qc^wN|FnHC`WK-?>Fbrdj}Fpijg9>h5QpeT zVkWnX-0J%5m%07uXMlT;EqufA%&|QkMx&s#sLdA#_=*j7Dzo2*2J4`uju#_GH}{2G zPrexR`1{xsvzD56gv`Ls)L@V7juqMxb|kF+6tS*P>in=y7JBu`3zH|m|2J+kQNL+$ zx67V`W3tdy3jR{T;mS(C>CyE%#UHW%=;?k}S1gm>&OX+jKeQPATL5}n|5%TyS>u(z z`QhtYt}a~N+yCNIOGj;y$@n)^R}H7o#%$fw-{c?HCY@z@X7foeqhEWU7u%}0mpF>4 zhBcpG9H~8jc4E!)uknj(tD3#SnxFLCdwDn;WBQebY$5(PYm9oUu;gIj*S)9 zGZgP$-ni?!wD0qOXOx)(L>3t#Q)QrN%^`1aeZ(-sYde(NHMKGFug~+st4{^=9^7Z` zd@$t9^dziDTiLnOCU~>J+{dGu(Dr1}h5gIAeCGjEH6qOP?YK+o`;8T1_Vpe9eQmW7 z-O&h2_3HzQs=T;D%$Q^s1{PlemCG$6`y=-}GiO%!$S#r3Qg#j6R%h7~SLju$&OU#< z^3?A{*74nrM-QyY8%=)re%n?2dHV#*9&OvdVwm{w zt>@W)n|e2#(06)w@ym`a7hl}?%gOA*_dDZXMF)JGQ4`zefGmIRxHSm8sye25S zL0$cYg#0@0J{hb$D6hOSSHZwsPxc~vR?*%r9=lJ5Q(XsCR=j-4tiEM`Z=ZPT^~%P0 zinR@^)vte{e|tfbf=hGYl84o&BK|}SC*fz?H6^N4vJE<|?|NsJ+L5-%NcHnr?mUI|+I^rc*rLB3;t@0k@gpc4!fTCMeda@FPJ zleP1-5N&mSVtL*;|9IW1`J2RRWB|9HGqBAao{XrQkOrMWbCzJ@|6*GE0VUi{10xDr zn}UJdq*u~s&dXScZeA>1mdW{9T4WM}2PKv*)LH38d+$vy4)22*}>Tg z;YNVlnz(`dvDfe#bTlclV(h4^Oc_x8U`X%s_Rs%j{A0GbNZHZ_;=Wbg4L{TAn%Tmp z6G}!(jE%}}LD(mD{SgD`m!fkTKwumd1h%r$IT7I61^R0nRmqru9^ob%&O>}Lf~G}*$mD0_oBD-GDutq{N{gvevCQRdb_ zZ>0xhfsUO~J~R>*+7{6Do`7GJ^c}*>oxldmI^y41#O4@`xAC%HBVuDwnW&5(Qt)b( znmdkH@VxI2kK2K!)vZsLiSnwv1WpYH1rDHgu=vXOpav&fm;niu84LYAIX$5S=WO;C*iU-F5bECb?;qS;S4jSFtswMav5XVm$djZ zdJ8l!a`V8%sfOC_87!w1b`Q z1D*#n*fSE)YN9Z4lR4u9!FZeL1Cw-m*72TxZ5JOoK_6aof8w&62G5HVO8rOs3AqvT zvOg6F7|=3BKub}S4%9Y)?YDwSr3_GCXOd96j9D0PglF10tIsQl=6WNcnZ;qs*k{UJ z2CiJZA=7<)xq)7EJrH|!v{zFRaR!jSV98A7`e3>aI>q}WRf(Sk!|PlXHirUd!Oy+B zh1@w7tMa*HCsf~`Uejb(FADfD8>bAqw#{OfF2|kWgUvAJH?c7A^Ku>8+!E#=9K?vn0Kr9-+q2S_7b0!oJrDPeTO=w|o+5AQwQ&e^%nu5+&MKA-pd^|Et`-M=y^ zW@+&(8JxoNp+fbZB{b<10Yh^XyfR3bCK(FXg|=HUhPwR-GA8C3!l|gEvF}RG&fCTK zyJg>Dky;^wP`J-ZR5zcHPwmY6Nek0c&V`xOEno9h zPm`j4V>L2TTlqDz@5{6VYJzkxbPa#_L&^q7W1(8(t5UuxAN zBNx$xN=fd0BHAc~00#6!SPDJ3+1PRH^xaMeMbLiWBE+b%m?|l^`@%%0zXDL_VZu*SeRPIKmn2hO5Ou>AiME#E&0cI)xgX zz^(#SaOm(a3x=|?)tKvzXztligYgmwiAa*f=(g0EFj?Xiq*e+9InoFB)1G4S58yws#-0Y6OqpR}oz^8EhbtXaJ3 zG}fI;>UkxsyJya0QxD)7kj^JB_&Y6N4xrH<81D}CfmQ#}Ene=`lNN73aq;>dbw_W> zBwbj>oibK#Qlp;LWZcr7m*z7))KmpjV(;M!iV?LfdgP?!a$Np?eGDCjH{ie0n6BtcdaEhfhTkkss?ER%z`&_RI z6RbfW-(}5Cd?B8kFy~uU`(1FLKgV9ZVFE*h4Cj;RQKAPq{?y%P22%oiPg=5JSsY7q z$L`E2rT$kkFsZ2MT#_|}mk5!~B^3eMb?Q0%QQjH9njHuWr!PKI1w^z)78U|Obm7b} zx8ekAVFG0o)e%6753utYi~6w9Ml$|K9ds}0@}5+hrt%$1VP16rP)qo;BclvDB7UpPt*!ZzP` z-us{`EQIRci5TKntg+{7m5gLA?3=(Up|S8Q>4PvNQI(o`6*}QO(-NS&@GST)VK);> zzvSmyx3=qE8w@WSTI1PERL38-3r;nqsk|>b#`LyA&b_}0mC~|Q#km*euSQYFP>+61 zIv+xmwK`+{zVVc)m#qggB=W$xTznUKrH3}0&rYqji|QqQ(v^#eEE(S^&k#EfZ$Iuv zOT-9&i411qyY#9Isthnf1{Zp&7a<^80Wyx7+OGX5e^%oa+NfmcJ9+j3l!aVE=Stn{ zO``3E?Y^2{*&CRq8j@M-{v7U%^$G>53i+RH5Ov)sb}<=~ctq$eByvF9g$4tQDuCo& z*nhKU3!iijvC8D1nEkRi$abo6_28ze1eK`Aho~xjpehJ+v!BgG{qzO)K{I~v#e36X z$#3tv$kppZ=$~I$!2eSh&Zi3A-2S8;41l|fR2d;I1YHQLrhYoPBmzSI=WV-v<%3Hm z4i{|zgd*cmS&$^t|4@^7RO=cO3r!W1P$BJwy+R?%renyiS$z+X@r{|=N42g{Se~H` zv6TNsvM_(Hv&#N&6g%}uNSKy^5kf+PtDrLvQ@@fgJ?}i*$tOY;R)TPYaWqA!plJQ) zb?T=PLbnjDY9y?R8ujPO`zNY_HTs>UuryZ$6>Jz#vD&n8dhKbtSQO}-+-s76C6uLtf z&#Psm0r1g56wI@$cO6TC9aTc;72VI*QfOrPJ+Ej7^$4of^LY$DKfCX!HPKAe*9uyd z6^Ky>5=O2)Z=qfAmR{LD|N&6u!IOKf3um-^xNs2Tp^Sso$)j zB1u$6eSCsb$cq5_HB3nUGd0TUj5_f03A1aX$MoQ$g;dIy+~W};MA0^?5aCzB4lbQm zhT0O75#LMkD`2REqc#%9nDyuVJ7IDm%p z0`Hj)Ef9tNLtQBr699(t8EK*D1y$o9M6gyBQDeq#0&47tqJE<-yz`-X|G!`~;?oUQ z_4;}88Jz-kMgSQhL25#5Z1;9B`K%!WijC9`k#AVEocvfomEWS`MrH~y z$X#x`x;j{HA5pyVUp@CN66>eGwA8!VLcW%)wc%9Ktg$5hrcw*2A+hKa64XLNWH9@+ zb_u~Gs@ug5qMY`QtESwViwAt|lhkZa_iUBd^A|u=D2d_?+R!E9zy#eW{jus#tw44n7VpL7bSstf&BM}Fg4^uiBeqhr5NIb-G9&Lu!> z;gRnt{1EAAtm4P~;9CJE-~Sgy+{4^dkRR)TVVy~SO>ndVQUVRd{PWE0(#Y+?d7~v* z@XI^jq5N$@aKV+n$9cn3PB9${A|JY8`Vz;hK0`g!dJ1{GF-yv?V6j3KtPk4bm>M0l z$7WW=&d2jNDe2j5dmv*mi3j@m>5+jPFKxZ^KCV+@`5!*LoNANNV~Ovi+y_M11GuC+ z)Av?lnDiYFl{yy3ntrYtyVKuL7T@6RD`}wQ@MAogng0#`EJYVPNT|sW=zqp7{`fM& z?!v`eT|xkSLc{Er2mIAm##gC)qyhbKwJWdE4!MuE0y&9Ox8qvbPr-;b9Uo>se&H66 z5T9G+rTWGdO8n|j8Q7_lkJ%*9N>BEn!IYD}f*Em+{^dXKp$jPU>j#phUpo855#HBm zyJP1U2V|10n2qj|bXC#*t5tSceJ|BCX?F#m7JpCI(fyp1mA(GcL{oqtfZrWF7iV&n)+X|UNT;G41-kSR@b3w;&VPPmmP zXKXF^E=zim4XXTisUlaA!a(&^_Rqq2W={^VS|^qshY5k@zq)%7Bk6IWjekLEGF(XR z06SIPVB~(I2zcff;N5We{}G9Y>G6Bu?V9QEW(DE;sD)it4UQy z&CtLamvoE3NlvFsM^ic?8f3OsS}%fvQPRe|V6uPHbeO?RBCS%j9Da{y2g; z2%s3;|ME^|v#Xx+^OM%QTLKh8G;dTm1-=shUdgxs(CWR}{)2>f2omBOlmq;uz(9hY zqSi~w^~X9b*#GAVu(aGX?(>q>YMBC?OT2XCC321<^AMV)He0~VBVbLi&*hKzE;=Rv z`weYbpO24dVcAUpy_*`na@Bb*47@GT>Uh;wNsWgVWT+?IY%pu29@gN_%2Krg?t_J? z7a-9;K~ePjjOuJ*Y{0#c#u2Lq$`Q6A+19iWc1PfLV_=6rc( zyToEe_GSyHH)f-YsQtqP#ptSzm*&r&O``^9RK7+aA35sKuY(?wI0E4Q&UI$Zfh!t( z$_{##_A9B?&vGHgm>kue5A3K1>=gQ*2sI`%E@q2ZIX1bgcOPu!OP`02VE9_KrZCRO zlSditnw}tB=mC?s_NJ-~gFwE~sqK|<<(JJd6pzwLeB;}qTM-dbT)G58vePquetblS z1XFL%O>5W)+8*axy-(3jQDAfgMiE673%liCdcRl2f6c|Y+mze6B+ng)vDV02AUqst zPp+QT=T)`565@8-e4qDt1mcohFIbZ@QIn~cMj9x;zJ|2*u;MHJCTl2h4MLOKns@k6 zU;mq+7%jRDY$x~Thrg6vZ|XJf&(Lr|SGiVx|1DwZ@9iqL5pTQYrk)>9is+s|?&VD?jQT^`D#$(1X5(Yn&)o>W zFKTqgs4R#m6j19(_&zb>XkF!$!&b-Ib z!42d5F!7!Ncr8vD4=LuWVWkc|4I{ZdL3m-mh1qy_mr2Otmj($_u`D0Xd*K;^2Tj$P z3P)IS%FO4h?M0)Pzk#uqa5!F;(wOhGj6IvD#{a&-Jv_8M5vQ7=I{25%u=l2l0?Lnr z-K)l@MVjR!a7a&=eo=s|TiWP?MHzx&=x3V&&+Z1Ve)57;g_ed?-^FSAMQwZxYF*gp z&dJS*cOPK+WP|(nUv*_IXnbmnwa6yY{mBl4tv|A@)j@l2W@Li{2y~ib&s?e|8FTs* zz7{CP$*i8>XU35j^OVDlc#G$gx)GDS`(8*{ibV)pMV0jgQY8~6B0O?^QZ6-9miFJo zeLYt;R|9QgBFS#!3}K%jnL2@zwt*Kx>|-OIGAR@6?Q`=e3KK*6N%=4=05ogAiMVt}BDqzN@`e*=NFuVWW z!W{F#?k)Xr$ht>C4AUj*=!B{PXq5M!QNuO4k*UvbF6gM3Kzl-r&)`k39|&_Hz5s_1 zIqrxch*+UDB!~-}irF6x4H}B&x!)bAF_KU9oDdm4TKuHB77(nJ5Lx5nd&7~nz zWwBlcbPt_E1kgHSa$mI><4KW~bZm|sSE?Zd18~kA)o49?zE7DlXN#b3=%&7UcZ(9) zhO)}trq`f^<1mr>0Qwj9K|*ZQriqh$tHNS8Ge*>J9!bCh2w@~4$;9~=6VM}x?-iw! zN%%$|A^Z!%UIeu_O%lbSM)me@g;6-XHZtF`gJrFkT>|-Rus0XZ4}Wpb&(D|wM2OJ1 zB?|}#2nQ=`FkvjU@0+Fjfd!|_d1se*4T>NI&H3~MMEnOFneH(M(b_Jrmf=*wkHf6x zQxz@2&0C*SF$4ZvrwhVG$D(|`a|?Y(=DQu#AzauOwC2CrwetqO4V^0r=`aFt7y3ZH ze~Bk|5~?pQ;M|&UApV!u35V4^``_}ESmi-LUeio(vjVxD46mgjBXBu}?TqK#T6U>g zrS)G?ai-{xt4u2>IVdXPk4 z-~9XVXITmLL25?WEmnlrqF*q%3}yzmYs(Jq?}cEes2-M2j)`s!&F@u?=N9W<+UfC= z_547pTnGr}1m-KU+eyXf0{24;M6kBYch592Sx$+k-=E8^wqlD%0(Kyfw49vb7X-LS z;|4z*fUHMdB4&OIv>Hp9PrTKA-dt{wQ3z)*rW8NES$Cb{9O^K3{oFiAV;`urd`2pE zR2Ozz1nr&{3<5&9yD*tw7z|QX(re`g6l(}3m)!3(d(O-6iv)Y zN|pGV0);`KcmHeih=Miz&~KHhc#ULW=Q-R)#xLRR%5e{5b7B_Ea_mTXTC@=*pq8gI zdx|VcYyIKcU=L5A!OfC(GJHaDG4>Xbp!u>oz7!vN6IudMA8+_YC&3VwK>C$XWQk1o5ewaD<=yWiob zl=3}FZ92>t0SixW)w+bX_U*6 zJ?;DJOV%wPuQ&YnW@<|L&ugs zK9Ml4`JoSgkOv;AQ7GGqkvoz{^Ut5qh_NeaPHW)K;Hi6El~JNiri)IKvbqzetl6}P ze&d%uvR3tOJlH*bGt~4TI=SnXBxg{&fx-F8W87xJ@1sy!c^h`qd9wt!4Hw6193|o~ zjlWrDC$OxY9tUC_OxXo2Kl{i!RSRol*>%%;&1yHY-5V>*v9_UVuF4&x#Tp|17=QRV z$D4aUtu%T$}mmidGThqJ1u?4e=#Ax#5{j;8M%w3G!9GsGh zP{_CrP&gL4{`Zi4l3=b`{A`P@+5gJo{0Z?ESUOf%qFn^3+?VeOC;N+woIRrU>3LG~ zYkY7CfZY^QJfM{sEMA>yEQ6}DM>SY%V|xtfK#D**r8nIt*Ii_?Xnkh4VmO6VDCp{| z*eAqSbW~T5=Kg^(m5}e@I2h0v)c-eRnd61yl_9U7YpOKo3rQYcb>Q_qdlDu_3u)xzaU}p&>(VN{bX+TyciU?7K4+mec zq`eJsl@Z&oGuML@S|1F|6bR0@TG*YqQChsa@xJQHu!HCJEe$wttNQwstYN^-UgWlm zG-ET4>Ahhb6Au5rR@aV8*Q+%|9HLDd5%1%%&?#w!U!EH^RbJ9rqbs#twA?3JJz3<3#n(~cHrQW`Qlcqdj zZ6Mko-OTWXh11*YmO@?S0`%nNdG-cuQU0>l!C+}z{mvhIi_*@%XpM1e(_0%st4vxB zhV!wCQTGE5*6|;g23Pkbw))st<*@t}xQOF!alB(&vXd$7(#c>Pao+hu_|_+(WXq+C zZfbLiy2_p+!!2S7VihE=ALvgAatvzY+UKD+p|**3GCM{AG2WY_weN{oePeA;dC2x+ zheWUJ>@-lPx$X4Hs(w-z%V5YhZVu>Vq_ki~4f3<~GOzRcT$^M0tEb+Cgzpv{Sfv^I zy>6r~rfgnw*IGAXK1%E-_+Tn$X!VyIj(t|qE7P**J2Gst=)??E_1;wK=MNdBS+aF% z0qnY_yvc%_Gugckr*Ru>Vi^TJwg<}End~&~4S~cp1)p8UK#-4rfL79NTzd$2c=?e` zrzhtZ63MR`4I5tsJsXE|hwbGfI2BfuM{vwFJGhj$HAq&i;3ODf-OV!2akrLWrj>N* zkp`*T14S8fTQ2hBV0z#*hgqDXOkwnIa8z~Dg^U{5(KY0ST6|Cg7FOmAz?>u)L5 zQmJGMMtD#|b&A0=kNEm&@JLDf)B_*7hm0mnC|^lr;mFBMNM@G=qx>!bcgeA|(5fN7 zQm=@tFMeO|0Z&FlBMZ0^V!{0}upc{+uTk?!h4p35@QgJ*1z{i>)Hqn1v|Ut2!QY8* zkyu1YKF-h5*_DGCqf2LI6*bA#VLTr3Ju$8-=QK3;uO+BEF#0nA7hKQCAjZ9ep6-&I zRSENilWQP<&${2^@Ef#^EGGF0^jCik{-9a{*D~`Oivimb`jbGe_$KxJ<15=GT`c92 zfgs@Xvu(oaVwwD)jt5B(Rj4j)QOIxy_`NDq3U?QRnO&8^Kjk28N$!w1VZDdltHP8~ z10YcZTQx{6wFFlI%}o@C=D1~3Or&1$3tDoOHE=GHSUA?U3fE4Gfj9n)95Xk$`p5~V z=|I*;@|<}pqUUKe+JzFnR6QO2E|dh#hO-)8$w-Ju??ugjzn=5E_55eHZlVLw*sOs{ z#t@Psp+!d52}pk)*-Szpvc`-Pc+AH;g{J5;;bQcKeR%&(7rRfQj(9Ul9&`I&TkkLR zD%Dm4mOLlR_5zP{Rqm6e3{zmv53emQL*ZWPs7wDx}0_q^jKgD2+W(5l1)XDqw(UAMFbmb2D!jZDfNU0Oy`K5dNWucUej zr0*SI#0!8ocyAmFlq4_Sv9uH|6tL!9A|*|l)8O8XN()_ku#u;Yoc_(v@b8WtIE~E} zs+P7$zLgxCzaNIbY>4QCEj1|5d(e~Bs52Y2ZfOO*Tzn1Y_U!~Bju?L;Zz&q}vI-`j zhdSD6=KdyI{%G%=+%|YO89Ibn=hZa%dzL}PNtqeAV9h8TLpKuCo&SZMyvw1aZgkk7 z%5rZ`DjPrq-7@aFQ z*q9l33R#ruq)=tK++Aw?4*pfqR5ge}Nm8!Z@l!=<0`&YrBLN@1O9m(U7;bZQCHuEG zN0T|;sWs|a`|RoP0Z>2j98=$Uz+Gvhh=9k~m_15<%FQhkv;< zk>HS4pa|2L+sNxA?@axU6bkz7o2K^?{hOMMpw;tAJE`;6(sox08dyFV%=vOd8oX7t zTI*DB@)}MC^i;6yDsRB_;SNr~ML?^m4P~Ec5wz^nsBJ{M;9D_#u0-vt@2qS&k;5K> zAb-mIhN|EBv5TP5a&P^7OEY#qn7xBMZ$s0AkN`F{`y)OLTR^5wYwK0QYfPetcCtqA zhlL#U=#KG>+V}V3Y1k^FFd`-C82&wtoz;;KM~?+t8~I1(%s+7KBmD$-4q_R(YTul@ z2d7-Mfa{QJvRTQ(FpyQd`grO^(dDgxr3~VP`PeaH$xMr?GzID|r7 zD7@$fBmJ6yyXP&i?2mK7fX^;gG;w5eNJ8bXu(&z$F9u@uq;~)9Ew?~nT8JRL(>%zv zN7bB@x`7};YSfAfeQ^+x^TS|_a?c_lu>^g>*1;rZ#9~g8-5C;qkmsuuB_ryL`WBJIgQv>8%deD6>m9cUD zV}ZRfXDUtL9s427lHOMP-T3KQZCK~Pb0jx^?V0vsv7t!isii{~Q;R9jxrW%`!_u&L zRHB}uU7|(|_bji3(0Gb-FWj2rV0HUk*LUE}$w77he2_Nrs92vRo0|`}lHBjLtf42l z)~(-v7*hws%lHKce`RkR*9$Q1GbLW0e^cq^vZNQc6l%o>xkxqGxtPiL zlWb%z8@^L9R1Qg=gv9PxTEWi*gMOtq~m~4~r1Z^fmxh{^Z3H&4@PFO{IS!|CF+!<{c4#u*Pnu zIJRH?^H0^)e=T`I{u_L*svXMyv#^&^!mmu4?=J5o?M`p~USB87F)JnYO>M*h0--z- zy|!%m3*gC98UOWmOuhFXnCsol_7Prl^)L9a6qzyZikTM5HW)_djW$xlmC|%i=CVe4 zRE9&2UZiV`Y;Bf|SN>b-F)8+#RCc;S>d3!#NnB}!JiATCJ>tmtq&K!L3`~sg-l6UO z=QZXhke-l&n@83zEOk?Em}}RZij+~Bk}m%C)?#7|pa)RvGJe(w{7mW?weexaC(+5N z5p3;ATyb>TRHJW}<-T8$iW~RU!!sv9n9(Is1Hvw!Facz7+FE<5-;k0i;INWxvT^jS zO{VgjEV<+aoE^2@<7*j}K9W?a3rz);H=(Nu(bm?1j*A&J30boxJp4l}GP5FvBMlv;F+nQYG1~gc z`}~QT^Eu(IUy}{O1d^Rvi%qs;Oryit0&_OZ^0>)P=iE*;5@={Ei)7TdDk8mR=5dd$ z&l>O_f<9;NO&+v&I+Gom$C|Pvc#k?YEse)FCG%#{FroiuxG{4ckCGW5_j>VR9T7huT0lGZ>TZT?(|cw&#C@Y^W@9I zvmOhfu_#~Ttg(9UrRkITaL(7Zi4?J=K`a}dy$q#oa?rq!fh*C)_@{A<7mWDVJhIqL zo=*0D$?<`c88d$?cxj023@sdkDIO7yek3FHuyCu$^I2_nG+v z1;$qxrnRK|8hN(DAis1x*_9cOFX4xxu%u(Z?_9-h={6( zjA?1de7>&FSH}(Y%z1apf?v!(LhOUnwI&(=**EMwfLx^OrRle2d#!{yvjRr(lp&`P zVwT0KLx#Zj`o{R^Vnn=o0sbineU$}{@PewJ`{PcXc)TguV-h)7Ox2(Z>Pys*Vm%_#MxN6Z zg20#Fn2}NcKs^6IcjRpXt2eswF&!0cSRMLXcPPSIYdVltLvTCNv&MlqMlkbN))r6x zQCnW=G>6K09&k{c=xua_C%$gyTVeK7;jXd}owwt$3dIb$e(agA_D?HIAQ%ixc>*r>HP{w&YQzi&$h8MJXALFr=5-$n4JL@xUikFl zRQ$PVXU%#Y6_#G1!y0)~VCu1+C;OMj&c@%YXf`3#iG9Yxu5wRi{Hf}9Zb4%yWX&Jy zl!Bg+3oM-mi$|wi_p}36gx1E7j%?ETVP)6GC!vTK2=v$CRA*;wRhkr&i}SZiOW*CkSNNY+mwm=bI!0m zpFvyWp1H`Fa^fI)n2>7SIw2n@*uQ3W6oC2mBN=~=oJDhVo6CVe$Dvw4=V)Lp=!&zl zOa^UNxnhMCxEPhccG`E4=p@_j@T2=PDOR^e52jp}U%;~|a~JLTF-6p3yrF6q_q?0R za1@rm{YPM*S%25+0$4)mM7qL99_)WqT>Oi%lFI4)rt^xDv#CA2rt20K+o*6z6htSw zsNd9WOK_*_BnDXq`PGZEQ3Q}cLzAH)KVQ9|ID->Y73`^=>F?#g2Og<%lb3r3$DH9_0 z3BdTc5VfrHCDO0}l5^zXJEyC%efs1xxL6hB9b%QgDUj*pg1@Gu+WV0h6#x)3@Aqsx zk6MV4WH`1SHfYMDhm-GFgYPR`<%9MzWyaxejX4zhshD5vFoR5DRtlh}w?6|w^n(!# z>60M8bY>T;`vQVGk`cE^pF z)>Drqf8qdq#vE^e`~#&aSsY1^v3cjC4NkyiBknaECaitppjGzb_pJ553C0ZC1Y>jY z?=IdHd8ZJeA+QngO&M}{#e#1Ao+e?P&*RAge3<{n@NrB4Pg`3$ z$U;z?dPaI-bjY^i$UAIQ`K)~cV7I?k5VBhH8_;T@5_JE zT7&19Z$;`%jC0_eQe?!YoD%DiXlU)I{aOByZy-^Q!iRsIoH0EuFCygp^pak@e?1K7 zG5Nq$=N6oL>3zKMg{nO%&y`9pu2qjwH^KQ1;Il?qRr#7O3oP#eEJ@jhpTIsaE9Mrw zUVD0X;3?`ON8i0>UN`d>pkJU%=g2{HkX$}dG4$X2=YHZ&bD*AR^^v1HutjN^zU+)sA4tsL~|K^$k~$KlxKh&oYl;4!Sq)H=y*Xbzr;(F~0!Lmk9>Hv^q6!s|#I2sv7%TQMozg1b|~SfcP)XgLQIt)JpM zviZHUCX1?~o}weg%yL!4`d(XQR6wt+*<-eyKB%jEYWxuH?(Vkd^U^y_s3}O5{>q^H z3th*fZ)!X|mv&@Fkw{0OSbTNZqka)Et`t- z!#;I6bB`00+!;7ioR3U-(n_m*6eS5Pi&dO_1EKuPD(MJ;ie)$>j_c0aSZRl-Gs7I-QrbA zbE~vYe>}ny)_8w4Ah-YTq)uwoRoVLm@qN~7D{*5%jcpdr^lb1KQal2qsfLz9PPI(?I?}e$zjI|FjEl zUQbC`&JN>%r;_?fQ$A4BpSNrw+or($O;xnk69K8%?<)>&-Qr2yGf$G5KW?io_%Mr& z#SX4q*kAR9A0+dsg}yTdSf1we#)Mw)=EHGeh{WyS+ODzt*K^lQ4~0gf7AnSvm-c1waqpI0NF_Xfo2PfPo?&{A zGB|H5{ahNlB_H2?t%jdVUXI5eRzAOUcrhcJ@B{tpj@u$*Af$JFZ45WA;^2#rjHGM% zj%&wHNx_6eQ%fi@e!yO$zZe4*X4?XR2+6%!kKx*CF}=As=@+yiI;HE-Z)>Xoh(yG( z4tI^mCecdkJXy1YU|Mt+4j5#No+?o$ez*emDex{7_ja&q`#t|!I}_&(L_~0B%R<{S zpBnhkJymrxsF;PC*XM&J);Bzrwpa3w!Wc3p7%iC`aJM4&$ z(J$_Dk&vX@LtCbXUySNvHo>tgWaZNA%16Jv=hrK*i#0Gs|HbxrR&!Md95>y3z!C5iC6IA{K3n4u ztW#_6+Eo+r@mD7XpDn4ZGAepV=2=KELj&@Xg__zdZ{xjq$`NLerbUYOmR`2hWEjct z4xOnha>mfFVv$3kxoS|)aPF+K zFa}^8f>WlJXS!N64AK^>!u=SpY_m{mk#O53xFqif2r?R9lCYB;<9i|BSx$ z&q0rs6i@0bsaw7~%F`Fu+*xt(b&LJ8RMPf`)-xJHZ_~BmmEf6p`EsCR>sb!k870Nd z`08+OSl4kbOH@Yu+drN1%|E+2t9Dcxxk8>FPmksS%^s)GvD-BH!(M ziR2=&kfb}Hpds(wYJA8_m&yT|PNqha+1Lt1aL{wC*Z_b<#bA9#-s9&6=>+&^lAAS9 zZiTlv4pxvxJ^1cFQ`U}eoiK_HZ(vpA7R(C*eEBZY^50rtMF|MtX;qLUC=fn`(W8B% z{E_PooK>TK%}CKMT)V>CDEd9uc6z9Jh?lI{g0p9L(CEd;pE+|(R>W48^36=&=zeD)A4v0Gj);-*FtPKh3Wd-gHx_UqrLlu@O2;UcxF+d zSyEzLqI2emjX>VKo3dBZ^Lj4EV)B~c>Ipt_&1mc?kE6Bv z>v$g{I1$6n>B%f-n0NYM;21~tTM&f17+2L|{x(VGLDA7N!98tNa7gfx zYK@5vbf|8FWiJ4#QY^6>*mm2Qw1EYXwYY&xYG$=u@ySe(9I5);N#jyY?M5Eoex-aj zXXIN{9d79y;3PhN_(RSG{(j(>Q#bkO&4Xa+P}t^F1QqhFgAU&|8)d!4GyE76sh4W& zA*W$O?&eCp1yG~^p!hIrMlCjNowJm@x0UOK*Ba8u-_Mv`%=fh}-Nkoyfn8HplFaJvnqa-}_ii+jndTB=$gWK1Kl2i{qf>kZWa^0&8m>pUbLM!pM zuaP}*p2j3sXX&CnuR~*#yf`(>zMYm>)Gf^(ShqHu8uWZ_ZyU19$v__bdh01FI6uK# zVLc?YAz$ONF{rPO{^Icu-bZzO&Z^mdk&~#T7izYNK$69;p$fgoh@f5wr|0=g`Pch~ zA^|pyD{T$A-_`h;RePA^8F2)-wg2V3Ufach=!{QN7 zE>j2Da@193fSGgxlfU>gROTanhw;&?DS4sRB<78Nz7sCJk*d zcz4m3e6iOo?e&lEwc`iiU)!=rWSxvvrW7H_y6=a6l$?u~U5*xtU3lqNW~hww&9!+) zvP>M;2PJJ_xP6J7r@h;eej1t5ZeLB$(%P%@GdV;nl20;o=WDqc?_V}+JFGzme({vl%XT6J$zKNK=fE;0_EVoaPngXSLQ;#;m@2X0-^JZ3dtaGjJU)&{q zB5euoO?)rOh=2>Pct5xU52;F zJ|~a9ihnybr)d&$s>1~^+gtDtXLWe#&TO;tn~~t29Xp&x(CHt{(IP<1u2}n%88@Te zRx)ph7@5}oKE-dbDNaZd9-MWtLSo{lM5l%~HNTHLM8G0aFpu+Rz8QOcs>k{y?}lp< zX9XJC&rnh1|9h>`ypv19AV&j-prN6+s{Zbi`G0Sts3d5Sp(MdW`d_6cGN44UuteA! zDa?AVx}n9B2`YU-&{nn6x2i;zy65|+>boFAe8C(z6X^@^I!gMA{E33TqRJQw$jAXP zn&*s9XZJl)676U=F5a5shk(@nNcd=fMA0pZ8U6SQgYdEX@>O$}3=w+g@ePb{tjdR4 zvm)bS#!XB@-B1LPUL;@is12y3pqgE0izWxuGV7dH_Nod*&h-iF0tn$rl{6Wqk8NE6 zwI;nE;i7O93KdniX-7MTR>by>DIQaQI!CGBp!W@DuAW459)xcmQM_T6MJA9|yRJyZ zI%^OL)ytxdYcaETND_oeaKn^V^OOfaERRLWE81uxxDaAQz1wD3@`ZigvqKo_MH^|s z_aRPUu`z*wziG<3s?cATm}&kVy8IFUp%^=uUHE-eSQM|up0Qz298A;?C>3di#N-}Mb*a_53);IyAzg@KV|$Fz ziw*mHn6Lv+ofVo1GbRmt&cn3uP&Ou_FuaDFkXx=OQNR~uGXde#*|v^WK;Vkb)R}@> z48H3j^)lb+AV_o3W!lb02+0k{NF;gj(UlRPH8&qG0tA+W7(?yKYz`d5bAeJYMx<}<&h zH%qh>??-7mtmA#UWA=f3KtW`VLQ1IAo|!a@+o!b~4#6Yc9c+2n0EGSgoTpr}r1 zNR<1Koyy(x;=@r^!QHwdqkJJnB|*6V8g+&$q4|4MQ**2bdhZlKppWw)o}lm?d1kEGv&vr2svg~E%vT>i9n&_S#UI1%3KKEe_1L!mm|lf^G?59wR98L^gnP&z6iW0nFctnBI6vGtL#dQp zTSPPksa`R824SN;qDrpkNaWA{lSC9mgQ)Vn#bTN6WMNzEt5HDt8)&n?LMpo!B+$jH z+Iv*TEta-%TO@rEVA0D$HN|useCJF}y0-$4K#bvYtc{uQBWS@HQjf|!z zw|EG>a&^py*>1>bWHSj%FZ`oIZ-}pc8F-tDaQZggP^9eO zv}>R)qpEA82&B{|G@$i5oS?Tk;MG_}S|8#xKBy|!p{b*=Ps*c4yb%t) z8p@lvrhfMRnJ6t9e1>xUAwUSG$W`_)+s9h+X-j~zsf6_ps-lnDc-Ue^$gWaf(e!Cc zpNNe}s<3DR!y}EhWk$ykxOxT@2ZMS-n#<#5Wxqw$AB~Z+J!3i-zgqR)7xulRYRrZ> zrweMP2aI_}eWPh%Xkyy*kC>nSQ_D{Z`fu8Y3F}cLiC|{;m(kVQa z4fjEGosv74b$E#p?Ki$Lehm$j4TZNGqCq2*M}~&n-eO7?Um3HrQHMoqVPRXG+$yk9 zLs3Nk@UpZaRP+Bf9leiA1V@WB!+(tk1EW5I4!Mr`Wpn1KF>zVb1bLr`-pZU=NYKsm zNj9m<7?ZD*hOY!(LXeMpcUZeN||2gfbErb$+;bXn~g3>7y{U1$d z9+qVKzI_k`G!$g)>r#T6Os0+4-Y6n&qhSjwsFe%ZSdG(StEk9crcP<4QqyFpIVo7` zOpE1)m}6;;TGF1PMH$ryCW?yk-u;f_{U1H_;klpZy3Xso&X1}W16V}Itp5jXBIRDV zFu%>o+=`cg+y|>o&=>3LUOtoC6|MS@>=f^dgrp+@`ppKx1cAY6?T|=<$W~RY)4>4f zz}NGdWFEzfI{s|@VC1<7=RC;bz*wlF6J)lyd+`NKx(&{}KQm4>J6JXN-YU?P|2H)J zQ@-IgFNY&DHe+9?C~+$`SuTJ7^3Qi|Wqaljd?C0-<-kl)XknL*kT`Ih`G;!3o@DX^ z?RC#$Hezm9(rw5O)Y*2csC23iBO!spkYb<>{fAoq-Qs!aQm1Rr3;SnFgCHAl?ScjB za*z|L)X`z9J))LQ*iOe52B@q9Z-0?Z+yYEH$a=7YTEtHPP)Ien#y%)F6pXqif>0ER zaPjWU9QG;n{7CCw6SGw5NQLP3Kt=jdN%)W@WF0e)5L<0;5kE~kYXGk2y5z`(gBa40 z(G_eHOyTS3S`Bjh2oM&CQzw8Nh~V2JVMYV(yQD`KBgB6Vxf>5Qz z8{IG}jQKO}a3Hdbk)-;_9#aOy+*r9e2tq@AyRCy59x#+P7_#!r@KI?cE`S-dRL65a zx#a78&5xCO&*n_MXQp1yc430_$a$|>MvLt7RzISJNWslJb|7~M9-x~F3JYA3Bmm2{ z##4{}X7s-jh^0GR-QYL?3XLMEmD~QB2E4k(1h1%t{l*Z27f5w+=xfFn@YSEXBisL? z(*=DTPw10Bi)+hHK71RzavO5h&8gO@f}VHGQUAHvB@xz%P3MGTMmHHCt|k%lb{dIZ zxUTNpN<$K(CJ}!>2`er<*=aWZRxb5pJMz>!rtY2humS;6N-6@r9tx7Q=fkW8{P7Bt z524c@1D!!H$ub?Qv;Xl&sP0Fz?BXByAC?~G$H=~3yxLd+7gARv;J(7zHVwcB3i)MarLD*?}?J_n`Y+` z5ii?#Z;HZ2z5g(Cw5=ecspBQFP(9nxTR5OGFSwh0_Sle@%audTE>WhJ^6{|5vKT{p zmWCEb%_%x0gEk^qjGNW&XC;~(I6y!DIL?$`FY<|#``VZP|ZGt~MAa1NMz(B!K zXPQ2RONN*R8YqYU3&YJmM~BZR9rfFeup**@Jesy!Jk&&Ox7#ZH`FyzNk{X@kM5J3i zricRtVO8)IW_1yk33v5JUY2%;YwJuztE4vib=h=g#@|7h0nCh7Da?gHw?R=IDIf)? zr)_xYLKtUJ_&mXwGwgboH*nWMlRvdO(kEtQ+Mc`aI(!Xl5Jgl5H+WgN^n1GAPeMNv zpTR~FEJ~sa`dxWv63*`IMZH7U!rIlYs}O+Dg#*}o4^g&S=Zh6Dgc(6f!QhnAqQOU? zU z74^XtG@&}sye!&d?_FzbG&?*uMq;XNHDyuw6@)`cm_tF>FgtP9(I62)Agn>s zxl=y}BDO=uY^9#z+7Am+`MFi5q5B&V8^yk2Z1@P(Ge?urp|-(!7GYI~k(!rPVKJUM z>x-Ld+S)zCS332O?8Pjus+Sv-It#IYyI~= z1TWn*9Y1k4b7Sv@(O1?UXWTS9cs{xbZuMQ!Dx*xa#AU&~`r}Y_+ZceOfmfyA1lWRs z{BjTk&Z&hIgC$Zm3+#F?WhDX)mM4>442Un;=?a=~TSzx@Xsy4>df+06y)cdzP)9d&%iB|M-|O zizw-Jh~!+!@bpZnF~t0VhhCH(Jja_Fz;tzXjLBk&^2+-O&-4jp!lWNwE;%`dgMLE+ zqKLz&CWQiEJNE$G#AUNqWz77q_cZ?nG^?KCk(Z1Q)}^SU;n1bf-0X36$eF}Asp3f1 z6^vI?cme*<9zX^N7Dfc&6suu;@*<={dIMlA;k@Y)^$Cj4_^Dc`!S#wuc5ZvMX#?Cs zmu90*vq7rMaiE(O6lcbJQiyEV$HQ~D9`RY7__`qhruAxe>CMhu49&Mdt%VaIA|AY4 zXX4bdQE}QaaA^mQwu)Z4OQR)!rUyg%m$pM92$Ejz>WPvd5HbiU!cq1=TvmI@z>mzio zUP3wozDOOlflM)=+&9zL5)0F$i*8Y% z`4Z-4nV??lWf?Jdw{9;T8oW9-C3I^~E%wijA?g zPPEg7p2n6qSru(Ltm);IjQuB1E&AoO0A$UPE%EQYn1N4^TCJaSaOg}c$x92I&f(SD zVp7lj(X;K;(V!7{Kg{B{NFU=&XEKQtOBC|43+5OiPu$#)RqA-(>gv$40~g*8)^gEU z0 z;v46;Q?T&kw5mNvPSd8)8OiwxaZ#7`3nkit$>Vu@&xa zR+`r_=C1Q2PE$M7Y?Muq01gv?nEVL{2$Zr)Vc;T_Ry_XtW;eRHI!Cp$kqG@ac<#>o zMhiLxn+aPkp5%SOGgO@9;@WW^*n2+XHP+N@YSg%s{bj?!dbPBtNx{H2jUf=KwKPk{!OYtVtO{`VU$#q1@^)&`e*7oevAVh8 zrAqgvUfofdoY!PX@HsKKqzC~yQ~{_;Sq^fU5{&?_$!8;R?2V>t8RJF+Zx8 z({M3vz!(k0J0L3$jpO@x1c5$LFu(Uj>fMYUoL*slfn2@;dZ>;Kp4&oa&|bcibpLK?A(t2m%#u#)3+Fq|r84t~FRvT3JZjFVGgS2P zYPhdIJm~REC{~FLX4r%_sMlS8JiFF(6eL;q{>(tTZ?K!Au269+=y*%)S(~Q7S{3mn zg@m7raC(DSXn|S@5|;B|<1>_4pp)1ZLwg@E{6blv|4p0P%F?gk=Od9v)bY6Q59M8`18k zuN6J_C7@#7ju=9QXIgNY%Q#b=tcGLh1X^h8z&(q<0%bD1(ytwE)9e|sWm;FadEw)+7vX>rZn8d!&HLD`ZNPD#GI&33Z;rn}pPcmiudt`Y zJAbPzaNy#igp1nN>jw_-M{c~@?e2YTo&TS?`Q?Y|ycyg#RxtABWAWxWvW8{DBI=sTQ3cuIqf zoMbMTuY5|4IxWtYxx)W-7&-gT!1rm(UsxCZ`}m{l*f?h7LT2c$f)ekG&`pPK&QUJ$ z_kfJkRH}0=MzkgS8xqqp!&k#>}$>Fma|g0cHhJMg!>s0W*Kh!6}{ph(n$e z(oS9-n%d+k#n(i9=1>qWePpuFo<=SrR~b(j@{Swp|7^ks%@3>jXk@NbROZ73d@8u_ z4h=z2@hP2)9gl6T8>g?Y%y|1m4Fcp@LNtm13ON)RV`@kiAjEFpdkMESR!0yV#DJyC zlp881s%yjZbV68fB^I7#UZy_*jsyVSWGzuE+awK>32=$bLpK!|;XFsX5lE z+;8EZmS%Ra4=N=ny(mHEV2r5LPr_^`a&9JPAF==9d1pz9*!6&z5ai(o$ruf`w3Rpr z^x(<&?j^-=?Loiuz1=ZN0ICL~nPuVk%5@Wwcz{h$Wq!tE!Zp*3t}7Jq#`dIO+i}en7G48OBEE-c!xQe!=zU`ZF%LhFLIs;U*U;`3LT9!T-RH@_b?ieQ;u*b(RH^3YV!58 zIvFX}1LK>iNvqaz5e*OKr;5GtKOrlJcxIU9?cn5%*3V<+Csb!FR2|q0g5^a3Ia3Y0 zhGJv8v?YKwYPUpNU1W{fB2ig{5+qSy2wpI4cy_MPDIFooMruohd^Z4yWd=3SeJ66% z|07g;x*@7_XN3U|l1sn7 zosqgh&7Opl(n^^d*Y=j|d>#LuLKz>z95yQ*!GzBXM<&vbe+#n6ufNMxe!-Cg@|m*k zWbb7=pVYI^2o%d1O;n(LaL{I`z>;ceUZfS*Q_$A#dLIX?Xo13pkqj-y{LYX!Y#!n? zI)dsMt8_{aj!jh4y!u#EqjA!B(?8U5ecl{_t+7rf$4j>RX|xN3Js zZw?2;OuQA3Ub}%#E(49PbL1SX^z>)LA77Zo8n2~We*SlC*G$@{>)S#bIpZVd>Rs8q zfLFpmUu{-}sj9oDRj%ApC#xmQU;_VImhb=mqEowPa|CmN5~B4s5HMXKV?swy$g|w; z)+Ip`t+)MC$~;#GjMs~?o*}Um()6LbNHIT`YWzAqUD=6O>Omq)*(;|a5NFrBT`hW} z!{_^8kcQ&cU*`|3O@GNoz#L#!R9*5{A*%GsB5<)k#P-d_+9XYGlQSqLt7C&lTav!4V&dUh}E ziaEw~yh{4+ef_1KHyk-0FmN*i@un2zichc!ty_k`NsEXuPn;lkBoV#{v|fbMQoN53 zWOy#hCt63Y&gv1Lw02JL5U-d%ROm%Ang5Oy;%<@wBj)s6xS>gNJp*4>-MB%3QE->J z+iu5Hl>bvL66fJM^Q$a|$2-hT0F) z$yDRnq?&Ez9+8ZsBs9{@Ox`f8TPc_??0W2VmW3ah4m#5MYnI{1V;S;WKb4W0tRhMr zQ|Nq?o4+4pUp-Z)8rmG@-+X8FNgD14+4VPwQHkI4QJy*Yz7~!A(ady1^McUMs=axK z71ENset_GPGxqa^Gv_L()b)2!sfvMN@{rC^(&qZ+T33P4q27!f@S64^7YlM#v zUy&I%0(g~xi309vxp7L(LbJ18C~}cg!zgxTq{=}SHGMN4Pr3yK%2eDBvL9{u>A{G; zV89BmgMt&(L?IjS*$lbQLP_{L8M~(qG2xw>1S+_T+DW@Pi$)?A=2OP>@6r z_E~JZ5Nm`9flF9%fSE*aaBzUOQ3G?v{>ha=Ly-e}FUzb#*+p3J!jo7XgA-ZhxNQCB znadW~#Xb!32HruZ6^F`Q7cCel41fE&JMoa$`1G*d#@@a6{Z@lfbBf+rMC7wfu0aML zozXsd*lha{Cd*vtaC>3;9~-`1wky~@L837WF*oqeVFrfT>unm}^_2Ph+mGhX zz|yB5W?mlu-;`Z`Yf=Iz3CU%1=H{yg`sY@!Jy~58IIelogd+{2TDUdCl$6+5ZO{GC z(*^PgT4kwo_{Aij@r&!P222lDpG~{Oa{Tk$(r?uh*F!!j)0Hf=3hU5V3ut77UAU<6 zN?TT6o{N4-sZ9Bi^_zUYZ{Lk0wb}C`XdNd@{>;BjKRhv4Hgo1>Jq7vQKP?~a7WIU8 zfB2wlb9|J#0QfFWdqg5o^aKDI~DRPI}uHFhsQmq}kE(^fC(|8L#-bhofzdTA2K-t`Oyoxd^x z1$hnm7}-v>Mxmci& zVq>y@M)rROXx%7FC3Q859sx11x+9y>WHW!HC>Yn$JC{6v-)kT?$=+PpipI9{$+Rl9 za{{P*C6J#B}Z`J|(ZiFn9#{)jyM?VZ&&R@sXLMa6-rkYQpFPkWQr zHDK#$9;pt9Q-_S7MA}!E?)&`5U|F{KS7|P94iz%;rRqfi>W%TV-|L~1W_AdIZWBHX z$D~Miyu6DXHQN^+W@davc4!E5b{}@1X1nDrF$7rvR|$BZ{gRnpic0<+?Pr|oG)GIi z8|v3{?$C|c9I7unDS;?T-vFD~AO&!sNNuBRpG!~YI&MPs5&x{eh3gP5bimkz7>$v# zl2;2wP{EMSm7Q7EX%~Fvh1C)8D!vg(usS@?pfr6i=#|a<#%COb@8@*aQxcMhRt)EC zWxQzvY$O)bqOIl-JJ)RG?saiECOV*~`Xp$^!t;h*X-r)jP|DAw62xRZU~Xj9A)gGk zU7q@Novdo?_|#6ULb3eV*Z!bpmUS! z@Uho6PbPmQD=!ewZoQ~@L?4&ue@5)oWrl{ilk=u3{U+XonRoxa;LF*aM>79i-q+|R z+EbLsDo!AOBX^I|aH-MO%cuV9IsB{py2FWk;cg=ZJwZ2PZ}${<^0V_9Pq=U_zh)!B z8%zaffDHc>d!w-}a$a6mS^jKJ@>OxD%uY-8@FEBa^JL~U5!P{sv`Y- z8iauK0ZbR~G%z#q6?}9c-)RH{v)MXKNBp+r!{@y%O^sg|e#)_^QNm9c z*Ub#Ik2>$x{&(}f`|DS1-k>ylzNca>b)A0Ek=Cl-qtM5oK{^r$|FL9iy30--W_+6Y z{^#d))Ax4Y`&A95)m`1%JCWz>!~goCA*l0IR8n1!?8!#r7g>Q?r4dF?ST z$V^Ri!!U+IA5=p{+*d1pFcZ;T453l}br3Y6CDf4Jy3{O=N~4K6^v zkAxRP1Zw|zROhR^m2Vpc$CIufGfR1WwzCRxRr!bT%v6i!rx)3a30!Z2w@?1Ohat|4 zOycwYUW(-X;x?{3u1ketx=j?FB)k(OzhMSUPLW<+a>>T2X4$&7rJI!2e~qgF1L8Qe zxbPP?;VxoD^p*bK@3eu+yn1Y;J_L;V{QUnod3*1cLJ|pP#wh_bTRD@2y$4_*l{El$ z{_B%f-7V|o4-w!w2}bje3tK(%(sBoyTfK0(H!x8B4+8z+bsrbok2X7Up~85CH-XQR zAoK6>*CzHBE-;r)HJR7!zctuwKN3L>oG<^qUc@vtDYrGufly`>Ds|Qq{6qRhhKuJz ztq(586U@H5FCYDVq2R2gxAXHSs{NeIQ#aQ&ANUB(i_v9Y#)*#;`hwf$eC%56MXT=1 z>Qsw|&UYr?mQ8So4i@L;@tA!sUZ;XSNdJ>f3Z9zh0-Gfj-+Sg47w&(saNk(Pcj^Id z;>b7knu+OBJcU^hlvW%R%PI0Em1uxN8*&uW&92y4$B#%RJ#eAKJY(hR?3L(b=SY5x??4x>29dN0T?hb~(M)5^aO zOFue1eWbpT_lLI1)2er=#0u;7kypL0K#;2#EJwQ*Dtsdt;ES!L8PC>Yc-?{xz;o$^ z*ij29?8YuMt2WZFKIUnrhe`c;qRzC`U#(kbjW#kNuHF_G-uA7*IGCAUVitV*lp$*S zdS=_4I|2vIRkuT6{I&cH1-TV7x~_U<5kIg+G`uuNMXUbWF{F0mV7kfAGyM>daWxvE zwlR>T&K@u?^B1`LC$F29gXgNg&Ki+pFE8Vt&Bd805IxYSbMziu8)PeLTjCAchYzF0 zaxh4CuiJC_s^NkyEEo(W3wl&muzF!2Nv6HY;$YP?dCcgu>X3*0=K%!Hofxh&oM4q6 zk*~_54n#uKQQk1E3d4VqK6)p9hRfy>KeBy6wZI&#!3P8?j_Xc%$VmJ?dqRFK!vhRi zN+2Ajlm`t>`qN9+F4$mR_6PpOW(Uu^)pt>y-S6l%(d94eCXRXh)GD9lCl6n4(N7<3 zcXg%icypIHBuA*n1uE;=w)ytHsqR-4sM---O9R|F35>%FtqSYTo%bOb&-&>zGkJ6H zieXQT1!2B6axRLJWcfu_F1^Yks43_KqRF+e-9iE+vL$`Cael;p9o1}-=cf`Rr)9?} zb{OgbHt4Gl8G>o`CqPIhDuo_AUangcH=2-0u^Ac?b?`orYcUw}DF=sNfX^3jlja&- zC30gi^zAUH?qD2X##s!sD+0z8Xw)aG914GybOPLEmG#_YONmH2u&57MS`Ha@_N8)h z_nPBG3Ndz0i%RVrj73W~sMZbQz-&bpezDkM@x*9r9xWKof5nBWb;(nCVIu&;W4$KL z6cAg@P4J+H;Gx4yfQox9y0t78+796cO2vV=dxdk+<=y}iqd!!|i_=&a)T&(QHqT|? zaiaWTt^6&hj~m&bKk-&3Yi@mMSI>)%CV%yqIra0gXOQo$Ty=qCeD=ra+xxT%$`g{*3;A_59ESOnohud#z>i%i@ueb^ZVBajCg? zX4LEPQlE&#T`SDD)hRbxr1wj9PyJoRon5tS+rpdQyzuJG*leEuoQ zBklpC=1neq`CS-v)Y{I&O^&cDkwh(vQ>E3s@98o6PifACmCeTeD#Vf<=CmpWxpGiK zxt7eX)E){u^kqJ~Kd0|OTru?hN1nI|WGTBIHbmcyoPkd3pRGCf{gZk&=8IxI$d~nH zqwMb$+3*$46!5Y~SqmN4wNvX9&ug(=l@B7T7ssM9UW~Er8=Wu$2p(pNatDZu)wp~0 zd!TA(sQSrBcx!D0N#`noaWR5oiA)$ik&_~|B{8`kw&PTP!_vrt5_8A!JBXR<9d}56 zzb4U#)c>-E|Lg8+bQ*H_U{+(2&6&hf`uZfayF}t3i}h#r1*`Gq=|d;KUf%+TupO;b zY-f?e+!lJq2X42#5fi27P1tuTUVTCQ+I>srqx+m4F8goCknlHqi!H^S(Q8`sKWYZxxm3D3mXAVhva8}zORgl&wN2Gw^UoK(%vp|46E znz^1CeYZB^7IQ`XWW?UaR*XUyB7JO?40&t_X?IUl?VJ}1qPVH_tHf^ia}qhgcrJJ3 zqM_P7#ZZxY9|RO;WZY;e^ac!cxGxaK73m?kx$t&d2Z^_?WLTe7%jDE-lWVJfGLJb8 zqq#Ov0boao+b~K3aQ5YnfSEh^=518oC|YYmZG=Ak9Avd4H(=gjnm#oWb<9C{Y70jO z2_*sZ4Fl!ceXkCVO;H~Z`-;Z3NjBqSd(PTO7hBsI&5E2Ykp=DinewGNd+Y1fUwokg zm_iq*6+)1h_EsAyA4?^>avW(0f+)yik-D4#Jr9^0=Jv1=wV3Et)uGpre9lDLAIYJU z(FmEK0Q_a1)b)|5;B6Jdx?<}U&j70!%&?zj_WD0N)j2?Y-LaXbaD0`2cl-3 zppX!js1@lePxD!TAARqyas3i)?%Scf5LFV+!o?+81Jgwr8|^Cs6Fl-*jvg|ga9zof z9-h(`%te*}Jzu2Bs+`<2cF3!ngN0VFYge<}m==y}9mI~-STUu7TATn*U-Kg7JACTD z-o5g+2P0pG9#XCWIPf$}!6yP09vln34k-e1DnjH?D1b!5F;0c)-5`=7RWFovvMCfvZi_Q`iw6 zBj~$u?eya{DI0;CiF)oR-FK>6Dj9a$DC<%ShP+8tv&ggDhy-`rk;^i6u}9?S^{u5= zZkPgk>XJFJ?9tYvmd-Lu(+Uy+hSDe$OuGMnc2k9_MrY9u zUJGAGM;G!}DIRB46QV!M?lsIwb(g2}$dld|A5u^;Pr6&(XXZ+CGsXo(GP#-tU*o>5 z;fJKc9;H=QzAW)!G%_vc5zKvUOhrKQGxJxk#)=g=kbCcsh29-eAK;3yJ4Q=A3i(qd zRxB}!%cz_2$4k89`k!5ldho`bIXuYZ(PhbnduBE-i?+5h6u;YIk}Xj}ic#*{q!>7M zht7Be+!;PNp`(N;T#WBbiO@CimA+F0IeYC6Cff#(7Xc8n5h&kII<})V7t8l`E98)+ zLK#@!iE^~xl#`V0XxHJ&hYmDjxR3*8L#iT|;xXf}Zzx-zz+5$`D-N7#^E@!me3BNa zaj{Cz0#p`&(l(v1kyVGg=(jkF&ts7z5vH7xvDf3$9b-KuK`(EHy$ZdVc3?)H@$yuX1nnHcF}!ffg#-(6+skUFaB+$zi6L*DYlvNT@K6I0 z_&f`xXXQ#N5(bzsNzjq_vsV=z(i2H!m@-_6U71cPYRb<#0xAVSje(>iOp8Xsa6)IP zm5ip1DZfzDNC2|*}!XzQ#}m0JpG`8wWIVX=de zH(!ItlqlBw|7sPZp0PMBJW*XLL7D!U6qMFB57+O98d5v;42HC^xoyEa7cUnHhUHL| z!ye_@=TkuccY{k|!ATk4x6epTi%I10D@b6?gA0x^jUbVjOB#>>oZRJnis$Qd9Qmt$Iq+JuqY85^K|Q zxsQ%1K5hQUzA8QTFz(c1g11aouJbKK@_A;43_2z!IE(^MMKOkvO*|8uoU>s_V&&?H zf?C6|7`!;}exj$5=JS{Lr#RF7n&9%!cB7}dGe_3Fc6o^&6k-rtbVS)lh-%MU|D~if?^Te}hItk=? zP#?>G(YbD>ZL#-KQ*5HfpXngO%Ym_NN`rvi4)3nAJ3Oc(M7u|QmoQ;S+(q}RcwPBw z_RZ9_QyX_27#^PHFvw>r%&@hxo*%jXv1DVx`!Bnpr`kPuqS0!%Z{F#wIvHWF3Adm* zAz&zv#c3m{i!7^V8vcvOAezQ6%t*sy!VlN-emnfTyx_83O-6CA)z0_aKz!%CO=pO7 zX?REexM(>+ZWn%+h*D&*tCEqecHT>wozZJ{@cs^%&e(Az3dA(`R=f$| zAU|+CmK7gc!m-D@oX*{s*^&qO{`{r^Dt+tlRPIF{MQZ!=oZV7>&#FsykA$dTh&qH& z*mLE0_uTNJw{`NSY0i=t(__rEuB5?zF8-abQqDML{h95$D#@jN^tYZvwd}_1PQS`| zd|otfp+lkeWCB9{n_mn!Np^E`cw!)uAC)Q$!Y@JoVk1(s2>Zo?Z>E}XA*1hdaOJ@T!z>B%j#SAju2?wu_ zk^pS@<$5=Xv4uVvW(~DX=e@}fcxV}*uj4rWqyyM3v&6(+ax=24RTiLMG<0i>?4E9P z^ZF;Irat><32*lZe0>?V;9eVy?L^h)xxNg9^@m!Ly4t35{HjX{qwP|_9k~+^pw%v3x*{8q)(>IVHImdnT6!%ctD5cq(K}N+IB(ed z3+|n@;G!XJ8|d`C|AF*gc<8dj@3^%RJ8H{&`)F$9IJc;E-{`U@zDEPVSiz8tN}b>) z1;SSv>lEBhi|~RL{&OPqIF0({%`=e|nEHS^7zGX|QGvJNF9t5fJXZIdD*>l^E>}p$ z>)wBzb2(N`#C^-1ZoGw&B}5l-YpMmAvzdc7u5H$?#->aa9#@q6zDc;F;sg`U^LzJCc!Oqy-&xy&VX5L?UyqI~eJjS3uM-$(qo=8ZNPYV;K zkH!I<*shnA<@x(KG!#**UU>?9f79uU?U0rC{e6DM99a7o5BfU;gy&Y1ljmLA|A0fN z5CxiFVPGEb7#aDjO55G)H{SG=+q(%w@q&*vf{(G(s>(;-ozp!>Cpc9~diw0n!^{K7{Zh2`6BbfVfA%?UP3EVPdTt^|EZl=V{B(CZh zGpi5RRklxn+GCu9H81S=l^&VTSg6WdbKV(70S?lsu55hy# z{tW2YOaJCZ+9f&ObhN_bksZ(1{`Tb9r`1nGVLJ}}WeDlS#asXJ%j(ePy)%N*#j+A} z_jvT@-TX(qR-39&TK{r*Pbpa{*BaAAatZ!LV5T88XnuV*M}r(Q60%xS{wEG!se@DEKo54 zE11`*c1)g@D$-kJGEZMTt}Dd6Cts$B{-JRbTzY`d@&yDri>*AxOr3)af#<+-WJ-)V zLm8*>>7VBItq9suWU)}LPd7H^K-7ddX8+^1`Jw$@ZwdRW^^RmX3fyzgzj@pV8j%I0 z)CRmZIut2phrHl;DgyBHW`G7~j3hw&1mCOYCA35hHXAbQvjr6P_Kt2MxSh^7gyG?h z09_ac27SJczxu8NKONykz$_?GqRzO2%4W-eB1G0Run}kGSpP5gna-jW+8sWO#`0Hn z3&5DG)u&V@YY$maB99vLRM}%y?azw6WB-KSzoHA0_F;pu;Ozx=cQK^tV^)qtxgGyq z8fP-$8{hcw^b90*+8s1RTe&VvlJDavs~5*_W2TaKgZbUEvjJc2y& z81urEjeBTzt!U0}t`EL2SF5s0*~;q~X=YeE^-tKb^sx@xFVyI4`4Pbo1GN&E_JKXY zm7Sx;d@IPN<4cJc{`wp}i9*EWNXsp)+m1BaVjy3)>vmQo%NjgdlBcEyT4=Wx$>y)H z{f*kX7w--Lj^JWEY$lyW1s7~h^1V6{9D+fhAVbDr1R)Qm_xkpq5g>;eTxo>7gS3|3 z8sES3w_9&_l+6ogO3VYN@%-jqazMj$-3^YM^SNXv>S+l(cf)Ow^c( z2z_4N6gk@vS0`qXa{@a%rh{%YMvzeSwzmy4bt89c8(Y9K@L4i*2s3vcd022JlfB0B zn{K>Aw^l~*YQ^Q6Av&>i1CE(?IrB2ruLd|3E@3uPN0Sm^XwxeAk$WJs~g=43%;f_X|_YY z(gd-37Z@ABm$z71#IIALd?%bXqFC+lW)3>J)Z~aQc-M`tZp2XOTk@C{pLBkSUX8D0 zcatdiLY24ArLxNeNxx@HLR%~1ZMG?m2dPo)aCLOUl)&9|LD4qD%dyA~-Hw_11BF0_ z0^8dOSOvLxgAZ;YES_?FYQQo3 zc;=b||1uKLwLr5=2i`6ySj+dFhtX51i*15Yh`cxe&J3=g1A&eX9ijSqmRQk(tm2LK zxJm9Z7)cmhMZwKW@z&5Npl}q=ZL1Fk6^LOAH2fvfbH#c*0q(AjvSP43FbBF`lKTQG zhidLU{IGTQNn7>bgGRTgk$N&RJUDP{_)x)Kk!n?=|7Xqm8|#EZtKH)K`l z-Iy~?gP!Lew*gVn6-;r?q7xDV!8z$10%YY5GpBh2E>wB~I%G7qS{zRfcJzeW#FZpV z3PV9HnV0;V27TfPU|3fdK^6R3SAYXA|AOMe!0(!U+ZX)JYqxZsmEAq#4_oyl0h%u; zmNRUGiAFrG9r|snZ!UZonyi-Smvd?}8H(W6sV1)F&fV}cCI;oXhZXUyZa>)Ax4DcM z{WOD};$c zYB~uTe5sD`N{9+UK)_%E!;rKu=hQ_OGOLnm9XevW%;j-d z7;ryUY44pKQ<@zlvNIcDTwFW<`QqrR=sT5lPur5}6ha~Zo?D_2Q~^>MU9KS!tWx`< zcuJ%inG^53FqWtwOT$QpL+q9HDZm;5d~!lyMsPffuBMT2Dj{TDu38xZ7QG|+97n7W zC$njH1>zzST3^t{~w-_rn0&Pt>D`<`nrnfEHQLG z--NDhY*JE-Fi10=iity34wFVU;d1*hRu)YBUQ!&yT)ZBkjDIij9eVGvFT5+uKd#1f zwp6pf;nx1-!@9rMaQ^w-`&>lx@=LIfPk!}Fp!{;n@z+Ph%F9tmmUevYcIDGHUF@>) z>Gj;L1RCY(Jv27F@&xy3>47#;p8J|RjHJ{{(Lepk-&0JnQ><9SsLd+z&U#!|SkT%7 zYqyLucIPO3DZiAqOjhnYS#{?US&aTeT(Sf1v}NS%SY}lES|eDx_Mgc1UfG|B$KxU(M^F*5HSxYwfbtDN5HKYo$X=tb&Kbf} zI`K?UVbH{WIH3_twn82|8NRI}=bH1~Z!A1g0k6yNk)?E70qAH>X%f5z-S>^gqV z-w?bsciZ#-nD(;r^j#NO9ZhDfaK^(Jj)HWv);dVGL&o&<&)Aa4&{ND+2QKZ9w6(C$3~W0($HJjqusPr|GyGNQ=ikc@e#G#} zuBX*2PbSs2-u9A{DO3E%E$xe{iV{Cd7{`et-h$kAoeVln#1 zkH$cSt*q__&u}#2+#VOR)H&wBVQ8!q8(V+uD%H4H@&-SBfF~qTn*;W&%AST8qA8zT zuiOr}7?62w|FGVbTWfDYH*x)C>$D4UGbU&ZKSK6xMaJu>&x5~AfC9yPLg%Xo5^Ma~ z>si%4s*qkxuJrJ1XCO0m<7N-cKuvTlTdw>`QW*JiytOkWaVN6#arU6@l;BKyFz(*n zZy;R06w$^&TQ5xQE)f`sR;eSt#;he_G2J;v#KrWvZFi8J9bbHOlc4&x=O24DzX_J~ z^72@WuY2H4c;%586nEpXQyHiMb zy=z_y-OV90T8gf8dNd#j+iD`o+7Gaef7ug<M;pVEuLY5^{kN2 zA7Dq5{<~b+{-yV8q^dLN1!?|@Et9@L(Af70En>UDe+0{miXZ7~^O8_OD30~QOtAb8 zp3htw!Gpm-W$6% z#{BH7$pa<3Qo7I6+uy0;R3^@K5aSV$f3;=E!NHqR_k^K{4)ywI2&NMVLgym(diXC~ zt0b72)UG>?%vdRy4UgG20Vzt+f#-rXBt@N~LjyVbI-hs%HypE*sOc_AD+=B=TJVp~ zXjUc}?eXU+xRQReN2%r&e8=FR_S`a!wkuwGG~>ms`fGWw_;H&>)E!1wD_6EtctLx; zvqa(zcg4U&{mbIb(sHwS)5VebWfPF&VN;J4f!pn7|Crr*YgKNf0Ml(=Fqyo%E%cW+ zp?iNCUH}3`Xu9c5q^W|dA9D`qXcI2-U2?+wba-gylSF*VY~F4r{hU!gLSL1Zp=P&f ze;oTKaQ@L`!S0ElX7N2eKQ#Th8KqwiD=<-{ZD9dF0 zbfLT+Q+?xzEGvB`4NXRc7>O8d!_pxiOPl$G=xVGfS2K7P8pcBqE12-WhkKgsLo@?h z-$Wk$6Xttdy@s6dXXnb)ID@t7z^rWD+xu7N_J!ODvKD-@@3lCYO;w&geCJqZVt2*S zk#(^|*#qV>*@3^mdU^^XDh{@-y?r8VgkCaY?qm6(VmA#50e;qYo;-Cxcp2O)At_N0LJJ7Y>9Gy!RExlNn~2kX`l+iRvI0g0 z(*>8A#;R@d?#kQU7n)z(I$aXB^xj{i<>78@JfHV9oYvLC3@rV-C#mwKC1bmLM_&v{ z|J|NKjH#K1qN(6+Mz?u*pjBWQu2?x{#qES-fBJ{X{84)7{1!aik2v;05ERHzS+{AZ zIdSvyfWT78uiHD*9Y2L-nCu+yeZIP;rTvXb^GZee$f{iV^kwvVZ2b(cOOb2gSeyv8 z2FkyV{wgT^ea%rOq$T?52I$6wGx7f?k(@W>6mf~Rf4<89uK}69AiHO){nKBX5qmh6 z6pVwpde!R_MM@05W5crmwYO|f;iYqzVCZNI4Y%!llly{$jeqDuASzmq&~Yt?MnW+% zM+{($=$&7n)=GwM^ZYdr|L1nkT?}kU9N^~zYc-CIu!SP;SZwHDIvbL?8JIsM-h8}F z1{(p&yxhdptwa{IFfin>s_tNyC`}S7s$7G3yR$Ak=k+P(vFg3|eGxE>63Rv@QZyl* z!SO&NO-&O3-+QV?M?=ubxDpvYFQk_%k(k7=7! zc3>rRwGLQU2Zq!Pp;B_%D3{_Yl$Gj=A*FRNhcV3dd-c8jZe9O%bKS1X?frheU(d($ z@wh+ujx><(wP9nUSHq1)oKxBUIIpaZbD)jheJBU}tRAu7i@3RHg!sut!mw*_i00T3=C74;9G0X7`ieUN|Difu4 z%5O~dk^A4!0?fvg`fs{UX{G8>S26o`b@80|I0V!jU|Emp=lex!o*4 zbF-s~eRH$&Z7Qa1cI0acCe6SICr=JG%w}Y9hAyDFRbl$Q9{oS8+*@NPpJvsf+P;a; zqvdSO$92CNU+4e9XCJ+eBd*4IV|BmngI4KriDX>#sK`3dWzwJ~GDV^irdE>dIGysH z*|D~;%cxD>O;jiM4Q}&%>?JtOjvXQbR_cy-A`#f#S88>#et&JP9>?eP#p%I&cMtQ$ z#P|JjTBauYOgoX8`1vEs3#NQJLbORzlFN3)HV{ZW){%;jYF5d>sog3t> z{Iph{2UzL2d4-UTA;3j}3nTm}lBbwiX}LTxiIh{~`ea&yCcH#Z#nL7_lCfo;0yc!5 zwL0bS!DDvDStqHsqc6vp2}dyOzpvdWdwtONi-C&!z5aZ$>0VJ%2W}DmMG^)Iu6}_|b;p z2Qd3+%AjwrT7*pP@CMnn(kEf=6hEJ4j)r%F&M8-NyGtN1J{x?!;55*xL-bSE(O@b5 z-Z;lV4Xr_vpozc1bQy?_RX}jz&_)yu^4zhL$OS+SMS5(@yIjP#Gq1Ic@%72@J(?*q zDZ}X%%v_MomQ(tcL|n~r!Gi!wGrOkHgqhTn(I)?@bPy8Neh)28voP60s32wslA6T6 z?S~uA&4o(AT@n^&%QH%uItKFR5Mi<)pVWH$Q>cdX z7Ff!w`nKNhBZ95+YHxt&2}l9+62HO$PTUZJ1>n0C_lL;s5=Pn16lH)(DAccksfm;Y z#mzH-1)g>;5NhlpdoDW#cvpqxL{QYx6obeGb*g@sX*RSz^u^4ES=MrvmIin7mG|N{ z@~8;yigNgBYO}oCjD-b}6Db=jDB>7Ym5Y+E^z{rbKtS4oa%P6|85TfNBE!*6U^Ywy zmSX@sd&XC;kQN6xVCW4IS~F;$7=x1;h-qOfYQI>@^^qPB=9JJ}!Q~GE4 zUodD$!$(FXB1QqZ!cLfz{Y>qB*yf@4C&e;h!&{>p-&V!ltUVt4u4}XCk0%-Xq~48} zmdBlQxQieF^}TT9gxCBUuz@pFgOnZ3Yu?Jnse|WRIgbsW@4vt0ao8XKpY*%g!@TAE zkI9?&`h4+QlQ>JcwoE-7^v9QjsXZqiA6_4xX1CrI1%=qu(coAC1_tR~B`(@?si)vr)OCr%J_uzIQj^nd_$W1Ex#xl3fh`E;#_~0M#utCUmjJZ}y>WvB=}j z>8yWv+WD@z zkp=#uIR#Z_FA5Fdwcq9bOsvKd)1yI78D|6musMPe@Ckt=7z2%k=QXO=U>YJR)fDY? z(#t4kS7W2>6$v{p|I{8hsmF`>?M7B3$s~dzkZ~yWQKNv%LKi=1ZrONwQ95KUIQO@J ze`A(}4Wzg_8*H6N)39|+`wLO6Rp4yBYh4al)Tr(Dwc=}kuE>8Arm{5VeO6of@)<;|byd=P?yF9^#i1%f=};PN;;xEwSt-Ao{Y zNVFP6=u^TR{5^u}x;Q85m$hP(TqEuVOS-QBy)m2dOjt50AK^6q;g57bmi^6EAM1 zb+ci#@<-_T3m~v}mO*D=>Ba1#flhmebjZ_uHNx8ZSWA(r?Pp#cX|$x#ISK0Pnpfa& z&pY`0*MTzbL(ve8#Cb{^imPh~QcweuVb60=ahr`z;_JOYB9kc;6pVDt#1?auDQ1J- zVF-Zx0WO2#Mlltch(D#JIQ6}}ZL>D~mN%}D$;PJ(0rGAf9 z&nh-t^F-K{*nPgbx?%HE2pjx3tS7|DnE>r0)*8f#0fB}`&cTB~+4+jx7t{Q1BFfOg zE?2b}NQ8t4l6oqF1lFUJDa+R?Bx&*P{+M0aQt#WFiiwTu4Ndd4h!TR!AmZia;;Qg~ z@=4-%C))9_X=vlDU3bJkkIWTgu`e$b!&2+6q;v7k%x~iVa7Fk9g_Q;QlY&bDB}|Ia zd*t-=llY^9n!I4o8?~gPqfZxjhJFnG6}3cin7V$w)OvcVE~GR8^uMWUn~f-aC$bNj zUu+JbX^B}n4oHI~`_;i740MqH4Iz&foqUm(ytt*|+TEvv&U_3qqe1HOO1QFvTiEP$ z^WIb?VRU%UeQ>F>w(cBZ8^ogbQsmAZXRvH~;U_?8DOVod5@HJdwOv%E_FSg>>tffs zplf%V`)O6NV@RbK@c}Ka?YYE8)?Y1peZEcC;e!*T5BjPGB4Jlw?&_ZniHQG^ys2v0 ztGI7`Jc`phtdoB3&tW6GW@7fcY&jut+S>u5iUM%v8XNp)scvdnQ-rigoCbelwU;JC zzCPtQCjb1pe_9%__Fl9me|RQO6~(plUACx~JDNCrCU;U70l>Dc6Vj0U&@5KNMO|dkwk_IkF0@nq;$x7wY_%t3 z@>!)Lc1DoO4I!A$pp-ad&sY*oFPv`GE z)3xMwJ1dx*zQCKmBuE?}tsxUIhS47+*%Y@R&$`%nnNIuy898xdG&=y3zSls9dR5WM zfhP?IN}b;x%#0dYIuA0NI-FvAYC2E&8P=LStbf>%`D^m}f;WTx0Xj>gt%T`E_l~c& zP&$7@wnO}b1CC+%5(0w2a*&_hD6|H@UoWq?q+~E`@ z9g?pUTQM81K+mpxx7IVzaP0lzzjvOEnQYnyTS*^Sp;STFRbc2Z#|K&-t7b;#Kg@64 zoGv&jIpZmV(Qe<2S-NkWbpNCQRu%C5C0`Sr9J=Vi8g$mK{%NFZO6ugBGU$K0BmNg$ z4ct8iQ|zd3?!AM|Gw&b&b+N>{=lP~__1fFj9M9&xg9JvoqQX<-P5H3%)yj%%4sZwi zYKNpATqgfPM|_{l%cS0aZ|(Cf{sz_;UEq*$}oll+O2!jt+c-sH9LsnT5sv;&Q2V zgWuc*l}qh)Fg}1NPB}vomUK1*N*y^1!OtxM87y5mwA6y%Fhwj`86Le zdwn5KE*fLFq>5J|TcU4EZy0#lKM{)vOGwjyjaEg%N`3!W(#N)7i1fq@(6%(cfnk`r zA|W!V*N~ariT9_ZR*PPSVBUNyXCC-4T5BmRhsOldr_@38_uzp8X;%(_Mk<@%4D=74 z4kO^c%2$VJm~iaj2EtCXcoVa6Zd-QXuh2FIL!@bAF&bKZ1 zR;&n*@ci=eh%$d{o!54!ucoU{*Caxl|L26?VfhcoxT>7Ga_^f-C71cb;_-CHb)at#+tVv(_4ONBYI<3n8lN z^^79=S|BN5hjN?*%k2TuK}=(qWjUBQw~b>;W+!Jgk+;tF`^`>eZOraNZw3w`0dx>l z!25wW0Bo5Ry9%4RvcbxnzhN2s&M`4D1Rc9@oNmX}A&eJ%Y@ENTJ$`;}@7Eprq4(>| z&C^12+T<>4FOF>}jFJrfy8AkP=Xw5LY+vb*qYu`t{zUwAfq--@OVp7zM{wC?LK@)2W>IkP%L`=>PkU{0 zO1|=ajR$u3@%U_O(Nvhj)J_?_fdm`Jwv{P@XD17ud>e*#BMu{0K~t!1TATVEr+)AJ z(2Wg|CTPzQNO`-g(JhrT&2U7qeq{B=^YNXb6|}qUuE-q!Ioj>#am??;NCPJL4X;dkWpZ_ z3P;qe=e4#JDm_pOHijk)#&qtyyo7qOK=U8pG_eG*101nGc?GY31nR14q72N{e)Y*Y zILxr#3Gn=sauy6Q^+GiPP=N3iI_fc)3eY8r}qIC)sq=@693o%2j~;M<9kZ!?r?+*OTjdvYsDB{RDZ#tg>trs5UJjH&pp>Gt!zjdmBWqyXwzejv9I{Um^> zX!nmStM$ra+onG>W1cxLL%5+S2w?a?@(mjutewGN?o9v*ZHRkggHw7;j}kwc9WNEz zPN$RVk%fhSDuB=2e~N)dI<|b?JZqRA$%I={~%}upVjYeRyr=kS1 zbntcCE9djc11WKAYMjF zk$XrW^ggS)KWfnT>OUR*nB=*Zg^_CK0}NCHDQ~*^)fyyp>#8~P!Qdw22`G~j(c`kK zU6zl`Kf)kK`6IaKeYqgVqIkhBe>X3%sMWd^v6rUXa6l1%GF93Z`{l)6GGk%Mg$hX) z;5U-MS%X$<>-^h!(NrAs1GKeKDf^0J3Y+F5Qw{Z@UBx3O#DOf^O)t1-4LNy+XW%)s z);r^}p~G1dImSYN!Q<|&{OicO9 zf4UWs*=3E1CKlv>My&aLi2}Z!MQk8)bqFv}qaAT>)CyQjs{+QZgVFiuIuH;`y#IZ! z_-wN1o&2RDv>QNCqwF1AK(KCF0>JyNDBsozgFNZyFyHsVo+oRe_G;{cRLBW23p3`$ zhs+yLq3q@ONHj&pOPOQ{Kjp-vR(;fcTKGu!8)NxZyrH7ulMPso!{c zsg2o>n|Q;3taJX#v+|Dm0R49U=*Xg86PoOD(ZV8{6|{MI#4*cr;8hBhrFcuiBQ)M& zhNlxhVPg~4?UjI)blOjl{AS>)*R|lrIi+6?l9V*raw&5vsQ#!in={gi%zP#q`DxdnI1jccb4I)oS*fa3e;l|w{Xh=)<*Hu zzNK^$PzKc4%+chan!H|EVeZm6Af{c4HphAKep8{{_6$a=x#Q{4O<`HkRsa>B5c2sb z7zm^X23=mt)fVkYtcrlOR#=|wrL@hv#(v)JnyYvDy$hAF(YHAzyzYq3cUiN3ii>K? zzb57qUMpEdM3Y5grDGi(6{CXs5NF^L$M=6G6I`_V*Hb^6DXz@LD{M0|C08gZ+W}$N zyls}c7MLZ%vJd>pHAof2+0Ient2IzJHg+)|qsq+QFXAO|V)^e{^0d~|7o)bnU+I;; zs-NWsIL8)0;l^BmZ&mJI+^h%NF$YM)=aIPCNNd4*`Fuux#JJt7-UtsfBNPIoP9BU> zXOB#uja_j08!PK}bt0McPg+ovbvN?M-*C#37Y3^LbUw*|E3cipI@+9+K(A#Nwk~jY z4xKYL&Msqw_PL&zxLA;F_xY^e&THw$>}|oDRU7#lhNBQL-_<-*f(tIimgW7t)SgNP zjnahV?Yt>=Rvl|0QR`7`M)kCis1_5dhVYH1O&m%)kn z3F{R%tu;hA8ZVaFPwO=zynnH3^=m{ANec^QV4mbKzSzrQ}Iu)nIy455GDLo?5 zp23`ZsY@fn$yZkU$&}0UbJ32eY&KeA0|WW>bv!lUKY?4U*=uzyR#)n8=MRKCv?jyP z(6JWz?2?Cv#oa$I9TV~eQZtP&&|SXs0IyaHAd1<(gC85f<9Di>dzc`R9|>(YN^vG- zJd-_^_CSI8%#_~{4zi=D<^J|2F+Cbcdn-`QZ)v|D;EsG9vb~3Z^nq8*OKHEE0gz#~ za4=7yDFC5s&W1g^tOV7lruKjSc}9=P=0&e4BmLf?IwUYOh3~1;*QYog6i0iZ ze4BgKE5tDicHSRZ76w*EYrtm-0W*Jg9@zqb>C%U`)ERO91C8t^0mJu!rae^#q(`fx zCio-jH9B@dBB#G{ag#TXa-3nukhaJ!D}NuKa&9aIK>~ZAG$lASO#-f}&0L!_-at!A zYwq`7o^YzD#}&6~v%(AI7m751FT}Hi=>nhB4G0qW6N1JHvKgSgfcF!)0T4K8F~kGL z9T^v&!&1DlEBFhW0;Z>#G#v$j7ij^_`@iu9aC~O>E(x5I^;&bPW>thHRwa`j>v#XD zz6e4(h-ZBJc~(I{i8uBJz(P!Rx--A-4h>i#eC4f7!2(@sm3NS=BqVBNviwK3DjSpN z35!nNd2=+q@IzPc$kCq`-yS=UDGw=w2QV(x#SuF~|1lZu7W+4do5*6jY3F}F@NVE)X8q3UyMu4R zSx~$aQ&*z0+O+;IySvU$5;**yoizy07*0O27FxAKuiZ%s_6t|5X_ec?2B&Tqe2*l4 z`bYXdRb9S!)oNOL-$W$SIqnpKjlApca3X(c4Li{kbjDJX08kE6YEd>rJso+m?p@J7 zP2w@7kFhaf2?IG@9N;!rqh7J|zKjbQ{o9YVb=X=YU+WN=nID7wo`Umq-9Ike$$cIR57P)R44Vv~Id@eJ z*p?^i0BBi=CkcN$a6TE1jRk`FkeilH!V9I9_U0Hd2&==5`j$4p8mTVKZqw!6y85WU z0Uy2Z_=(HF!JCrsILUalm(sF?H_FSJUzKo243J=RNGsPS&`G198L7c=GV zojb*6>6zb7RH}*V{G?VNM>VmFf6az$Ivy0NXM+#OvY^^QYPYGw;yIH8L#5`&X4RAlvgR3nLj&D;Yi(+kJZNg8swg(CKkRpimban#HO8+g=xlWU`_%Wx9w@ebYk^i= zd-qfwa`d0dT?r%Vc$cN-PVWzVE}paIP{fDO?>$!44XCA#TW(v}Jin?u7Q4SovhUH} z%~!HvRu%t6o!;tu*hN?z{d29(g7Wdx)?NC@%86w^?jQGC&)i^nIq!(`{XUnCCA$oD zQUAFAoP9WOdTGvZyp&tNcjZ-2Bo4|JX|iF6I5UuUisx`}RmS5?|?hLgBmwXICpN>XN)^)8J) z=Zh9Qx@&E-8`j9i9@KA$=VR@?QyWRGdPl=g;mICDo7g7rkk^GZ?EOjsa;}AjM@njI zWaiqnCuApl@!Q+%a!J353OuaypRC2_lsuQu8~Lc2ANULU^Pgz&88S(>(2^%w(YM-7 zV=1A-(g1WWf96vo+D~w{w-4C41NsEsZ-a!zq+6fn2Jap25JI`yK8)>eq^1BQo5EgwHl^+ZtZrxi}nik zS=C-cb3>U=h`C(&6YqtyCzFHwmIOG!u_^b63Tmt0n;ufAJTTdB^39|^)ROq9A|a?` zkoJ%Z>6clj%-hO=_Byq$k6mSZ&353m){_BxFqDR2g2XlSYDID~xp2+?u!8S|nbSQ6 zu(eR)b3|-R0#)eOx#jJ~{a?)m%NOdkfK`rQkVhLt>9od2)MzraDInVotWr8Wuvrcv zwgM+AVPqBuXailzzz|Z57wv#()yW>n%*MY7m~~4#_HMHnkdq@SWCnxZp#Gp`WX=|s zbwkjCK$Z^6zitf4wo0Jo_ZLNjA`)wNpxEuCv7YzYIWHp{8`=1B~;JxA0iN4Q6WS_r9+@2W(~b zEAp(Rc0B>R=P_PT{yEbl@o>Z_OkzQr!WmAnHu2FqYU^bBj{0&ZvDd z#Ufq@)(Vgbj1go-y5(@1!8N1+zGBKi-QE5DVBMx`I(CT)vR1YpJCW%81@)SLEWUPg z8M7ax;0Yzwr5ItQziNtEiW&*~;rHdg-Az<)h~jjZJJXlin(fs)5`kL9DGnPm@S@rG zh=x1c|Dw03_-O!iTavLWpgi@S%O(Wc#$wwR45&KJ#tP3oggkB0?;TcFD zeD0y13gm2CZtxzCLxb~4`G>msxs8;_dNVG6x@MKaK^+U~}O@&P0zmcth%) zZt}Rn<-%(E-O>iw`dg<>zwTr%h);*2v2=b4B&!s=G5d6=;OrmPqU|N5-d_I#RyaN?Z~~r(nM?`@Q*juV$*huxbmdeKAHVt6(MJpW{#KRBG_(vc zJ+wK35lOygYW6tyP|yA&x}!Hyrj1!3AO8y4gD}Sa&hoe#S_TxW9OP;0=vDdE9!%L= z#>3;}i`Qa@U$6A)@lIySV)qi)bvUiR_vz}sU$yGGdC1fm$H}3wRA2o<1Hku~3%_rjV5Sha};j@eBCs0qT zqMv`9KKIdhS>%g1*U%kV7!2f~@v^*)@7LHM7J(Gg-_ZZaa*!mOQwv!)G{bfbT|w+k30=u*iPU$B?$1X7A6fk-%yUOUg&HoWL&wM3M{zioP@w3%`;cp zJO36}{J~-^?Qt!M??IRcTF|x;;a09khJ1F49rL z_>EzlV&$NyFH5vqOj2`y7_l)eBYX2TCsdCGr+a@v34x6fW`jUzb2Jy6?*Wk|$^(iF z+r>hqmL5E^03c0$Qb%Sq!uF)UhL539eM7R?SdnHz2y(TLwDkHUE3?Vv(dxzP7FgzFaw@8WsKS z2jZYxGL^)Z6o$o|*^MC!gqY256rG<#JPQp?eIs#M;o(x?MAesC{*S5^UB0mWbR!&$ zPZj3Ck022L_9L33K(@{v17sW`w{IjKUM_%6B_yzrLMFf3bc50(;#bL!Rgnt=D1(u~ zkXdP3hI079VeQ3yzeVG$Eoet)2*A4|aL+EC9T_j|BhqldfzAo+(9PRZW&Eaz-1h6* z_DREnsvVXo7vC>^dwu_9AyjGjZg?Vo+IHlL->shIl*<-2IvAXH1jmG9qC^4}BW>}dTwM?!a~qd(&>nU~aRG?>-g$=+)OZj;4EY?2 znh;(UHAKvMC^gtv;F43Ldw~G5$^kfYybvg`4<_`L%Xo|lN0gfBCmZy=F;LIs}PjtX|J+YcmpCMoA6>X#a z=|Lwku;s&jY@9bl|8bC-D8gj+H}p!RtIV2rDsull9_QwjW#bQ$9Tr+|!#BXUg{lPk zlV68KR-auBvf<|V+|DmmkO?1IL*Dcy&+7#I=-vQp$iDNh@tQ^f58y4lO)CI7(HkMHLz_YlqMcH$Sq>PvE<^&; z1H|;89u-M~{16ue7U@YLl-ZzCn=F{OZ9H$4%_*!AGBdNSjh}X{WG168ZZ=?z=%ZGe zK&w<;d;>VdSP2#9)&46yjQ%t+lR!+-w2cbZ}&uBLG&F_TEG98 zPCH(Qd6iTfGyK7#(*NhY6f`cjU>G{Q-ALd-B*AV;59+WVhlUNa(r59K$@+^{BhuMy^Vc_E|*kdSp9v&h6Y5Ye?MuWsmXO7u>a_;4C^kZ?%J4Sg2FJXtg z!3%+DFyq7NAx#z0?lY&`M&BbLea+RKPv3yve)Vh#vuwn-O4vF3KK=;siJ%v-5)g9$89* zt^CNo^U^M8x0Vo4(!c3qwn@xnZ|YF-R+8P9N0c&EgELbZbkO+6;ah#%add@bikm5o z-2Chc^o8!w(XZR28RK;zJr-FKf_%`uo|%)*74Pb-Kbi|COGv@ub0yrV!qOr=-sN#W z<#y0pKQ;{~S%U!^&HkSdWh&^+fp}KY^yKj=*4R{aDVs9-rtF>t!Jn=Ig#LCUZ6-sHmJ4UL4>~TKz=1;Z?BDx0!?~ zqBpMVeaHT2x4DK5f4_Wx;TuS#X?XHe9PI4ysXB}^AxZ@(gXD(4SpMHm3{3U?y7&se zwQ?50Fe52=f3lELR~(=+fyF^me^jP|>TQh4I+;-xvL5fd(h!<(myfbfWjpNVW@9Aw zthpeb{kzR1kEC6Z(ns8kTNe5)d)tg^Sl;{LAz_XI)Fw7RRURSm4mvb@M|tt|>2bhJ z7fF`0NHg628Sw`XTpiZ_DuwLvxT_gO0Ye3ro&tx+W62P?0NN~{>jaDP?$>x>nD0lG zXSoLy#kj96dR+#5_xszg5e&4G5z1X5u;-P|Q`)Jc$!I5`pS-nAQ0|N{{$n;=5pY@x zc$y}WDO6%tuc(;!>T6oBZgOI)dSqt}#qRv;k241{v(@H@Oy-O6u$hkN6tHqu3BfU% zh$e$WX0DDC9u7p7)=ZEHAx!Dayu4Aq@^j>n2rs4Bj^V_nYja9zL4b)XF>5|~h!0Y) z1YsixV)r)AqM*i+-N5tc419b(p;Kxz*t-tf?Mgk@v)LAYz}N#&#&e)qb@QNNDxr~R zOV!c=rBe)OVwfI0e7W-uPkGP`bYuQi6}_c%3*xzxH476!QLaYz5VnpSPkeK!p8uob zC*c1!`#$Y+QOKeLDUN{8L34szDBXN; zeJuAoK=dM~P_yY>A~yTC!||-jDz@qruszkr_FsDWYnu`&z<4cI35qBv=LQOR6UhjR zMl`lA99STYRdt1+Nn~h7>wy=R1)2#3nTJUqs~yuh+4=9X-+#v81EQeSrptdYRRuFg z0#G|6CA9;cHuVue1Ln`DO+oxf?N>0gFC=jbu|hooE={H^m{07zXbMj z`(xIbU2pI0`J49V&9w^)`sNB_i`5KhE_0rm!9HWGK65(sUJ|uMVVGF)TF6<+DZ(!Q zdFk|ln4=*dekrYAFYmuM_O=9e!cAevNA-^xQ9d{+BBk!FtAk2LKI>-%}Q z76X$yH0=x1{I9Um)-R~Q9%lr{MPEWA591UisWUqD_a-KxB+ya3_i4Fn;qJ4iHre^w zDm@$Drid7*znWnD?I5ikAS^zS{w-Ga!>+qEV*ybXbaRuNCxE1?(IJtP3fAp;z;=UA z`9lO%u3e}J(1bM38+(*D8m-%|-0#;jU1iFqFg84%o0afNvq?LrkN592znRu-VGP0A z87J1UHv}u!ms?#-I|J=5kuKzf-rZQB=1D<+0=J1e6^0Z-H(`(6HukRUf!^D;^6K`- z?JoDFXU7xb$8Jhpp`0Jj%XNL~G=p^X9t_$!dX}pxSUZ!XSr_)A#x3!PNi^^sLfo{~ z)pV^rFYc0LGcMbNTHvZH@CS$#oy7lFqKgcs;!boqI|9dX6EzF%2)v-JfPoDXW)Scr zKVWmx-Y8p*FuaMRahc^2lGg3Q9d5>nYAjOY4-}IkWpfWmUqgCuP1vi-vqS<3(GjSf zx3NM{K5B%ecHgat#@f5-9C)#^bT4Et$l=gkVajGXUgGacfSG4b13^7MNG61g+ZhSC zMXIsfb62-C@SFOUF~!FjAs()ujBRp0=?+;r=Om&&rojO`r>!AU3R<6OXIr_DU(rjr z`#Oi~i&v<%Sx%`@$^JR$0-~I33U#*DZ4N=6Iz8xo*s#=*AZ#f#@JG7m7qxP0HfZev z4<(OF{yIN8lAA$z;FUOc$zunj0b0!y3&5cTEt!#XLK2YC`{7 zkiV!TwS!Flc}T&Zm%CUO7o5C@zqdE_UxN&KO~KgoQY%bZ`oSY+@Z(Va_OHj>&(v8u zXUf3SRTgwzQoFh?aHiz(c$Rkmw%o|Fot1iFdEITxD3aaQ!qMR+8EbD?J@3A_pa1fK zUR929@lhn5EMLv317(5I@2@bcXibaz1ZMq1({ zYm<|mdYv0?rnn#Z`M$7r`&}t>M3rp@j@e%)RRxJwCxfpX&@No^c{Iaxe{x|;4F0R( z=48+zRCALj6PGRQ=PwDvqxP&QI$e(8)7|E5l5IQ|@Jib3t0J3v1Scmmtlj%M=4paQ z2yamt{zbi z0_so;q6YKLi-SFx)<;KYUSn2>h_y{@*n9fj#@d=oHRG6H=W7b#3D^E~heON}MNR&? z%{YJ%%0pRO8Pul@9d4g2?tZ-XVsvJXG*8IBJMi68Bx97?*7=#Gq^e}^lP%914os=m z|8;uFGM>1*jCoa?A1cW*-Q1RUtS8L!>(#b2kZ$vE{gXOM+Yrk9@1;I%KfHo(;GLeF zZJ+7#8yePy^7eme3z+LVawc%N@v`q4{+Byjf6BgeIDzRIQ>n9c)s`REaUb&@+585vSiy}`nLiDhc% zTgG3+5>dy>nVqotuhtu$7BRQI{o>YJD_=fcSch9 z|G#IW-A>HiA9l=aH_z?!w;^|}o884q59{kS-+>7wt4Vc*|G&V=^5XgKr!k#xuHQ_T@;cNnT_;oA~xQSRz_@cE9 zm9GY+9AL8`u{Uv6r2pYH!8=SaN%ROoo5uJ&;!Z7P9HaiYKY4op@tc2M_SbT-ZB2NS zJz-uUNad1a`Y0VZx6@Lh3=gr_M$6AQPu6V9g%*H8qYHK_QBntxz3hfQmZ)?pRHE7I}6UCE!C^XzOg3CD4AVVD|e!^tFG zx47Z;G&xAj`8({7I3l-QzvoVuwg1ATYS^15T%{wcq*-Ov9CcLsQ8)U??^e5>=(`o8 zi>f_US68|(j@8<`kXVtMo(Ksg)5QM28-j4y?=^9hJ01ByS8pVv_UkjbG zw6=~q5}L6$4HV7gPqqvU3)~Ke08{i8EOQNol*_bY?(HA6hNn+4lbFLTLJK7iRQnl& zwh6ujahPF>1pwYIOWLujU{lc|9MnkIm<0j2jZ`Q|bo!+YFjh{}B#4ICr?ytIWQ1{-M0ssrEF8f(*`#h_n5HiAB3eMudK_q52Wz z@rc{={&nBL_Ql&t06AbmYVM?3g))*nd){92-b67db@kz(QLxy%Y*f7e>s_MSQl4Ms z9?t?-OjR3ieX0qhN9}`y3Mw4|hta0G8gFW}!K#C*1)cGt61AIt4K{P~sp1qDlm_3- zzodides6gu5}1#h!nE`Dhyz89LsujY#Kv9)zi()q{u1EN=+B~GxHF1_GM@}b9{ZYn zC0h9C9mz>Eg~EajW5wvutn;!SPnjjR+ap*rAq zcd-LToP#b3SmP2nUCJg;U*c=_tR>EAYvFNb%KYP&^!u+yIfJIqXBFq}nM8$9aCCj7 zBv}*p#QVNM_hjS!6H&B6#+I@?yft$Vt>{z(?4Yiuq)p|4Tkuzyuc~(VnA`I!X265z zwC5~{-hO08&&Q=$r|s=tC}kF@4mgqmsZWOh*ryNWfYD7+w(T0wK z$mg3uvr{>|eY~cvh=MRG1LRB6DLgUCjfR6}0YWUVyR?obRivMBkrIj7$M_eYJ4!zN zJC&^dxzUa&56U{du*sU|fkgtl29_aMFpN=71;=Kl$>&FKoJ7|C?`WViYA-xZjLVMcR{e3WK{ zF=R%UHFQ*S(r-|CRR8C|pAXHTN=h4OKm)iAJ~~IZg_=n|5$TCD1TY&S~-#vU+)3R-_{&dJWKlK-||euog8&WMqj0v#GrqDHQ-m7Wrb6zvqQc&9k_93;ed) zN0vGOH+yCs*2p5^c-$JW$hhxW2vTdKN-ymi!Ga%`Y~rmr%|UFIrzTWGJwBrfwf*+5-iOAG#)#-=y6ssG7ga4IoVW z@g11H=HdKQH;Or?`3`PArBY39^KMLV2)y9a&)Poa*XcEZRxc!@_$?0|`U79*-C?X( z&-hHYoow=V`(pSv(Kor2Yk7KW_qt{C|2VzXGxG4}Ki4yTRdbMKx+g0F=Pvr>8ag#H z8}e$gtQ2K>b?@FwD{FeYkZm?TKNc2o3C^y$kU?y6VI#4@c^vk%?}weR+!2=**ms(F ze^Q|N z6x9Rr1W)E@fZbp=)K3pHXvR$I7pEop?fQPk-N^%xpRy#}jj|nsJC01tW`6!Fdq76C zDDSjkI3;igSMUB`O?};VAseLns1bXNbHjsH1GWG90_WK`DbyTj1v^se0wUAOxn+Kw zg-oBJC{L%KQ{2+Cy<;?TXUq8+hL%;tt$6-j@7FuB92%EXvi~A5|E`zP(2qlq&w2B0 zFhW(Os&X?a(koOU`W%20@cG^P@QA%)NdQobha!Xmt}xjeXeaf-Dv zhaBQ$gp)}hs}vKol1bjvJ39(H79h40wkkTEqeRaO4y1WU@_VHfNz8lb-q9t;E-9KR zh(@O{JOOpKGbq=Plg_q)C*TTWRRvsp|Sr`G23Z4wLhK@sC#1T|wiozbl*|;>AEZwLX)X zd}ydbI0u}@S`iuT8QP#1dLZf-tXw#?v2t0^eRZk z8y_77jZ2$=gTA3rNtkGSH*;&pwKJblC+CtTRcB+bZ;@(EFBTo{$cilQ-zoNx)SU@m zul)6@gR=bA4dpUacG9g}JYTW!-^^m=#DLlCRTI@HXd-8AwD7u`k}Y1ASl>q+Lk>u9 zvncn?W!Wn(KCMP?0Nct|4?KJG^Iicn{BOX6xGLZ<5OoVsFBjb?@)NMAz&nh=QKr!z zt|Xk{OnTDB1dfzDUH%Ea^z+1GpcETH)(9N5_Cnqo9gGPaj;tIf>leyE%-!rL$eH4+ z3ofgwj)zX%XLA5tg~*5)@(3}@ZD2$!06PzbsUn0?%;eN$eg$7)882VGB7ImWkTJQB z>Acn=+DfKqy1)2v>yvlqHMDbtQAyM>*(X=+*jt!Uj(Ll`r|#$8X|So z+pZ%60e%*V?MG6bj6m%Vh;T-ubs9+HvLLY;3D;24g^?0mEc7p337C-_J-yTRX8Xp# z6_%5CK#upUJUOCJ>vWKcntShBb5BYt0#aIpw2}Aqx=f8X zG~A|VAY1GI8&cgOh(HY`qAgpBiseY?lWn}w4C%!?OYeTPZ)ciT**mlB{)t!jn`2hPdKZ=*C(PP@KAMWGXImaL2AJzkrwI z+>4I5b%#Q2()=3>#fqsn$KHHme_6hd9f?<<-v`6E;ZVN9&=0g=D~gjh?&S) zb;;3ggqtv_WJz|s<@q05*5^8=(*#9aoR@bL{A}>S%fC8*B|_WF7(dp6HEwHLV;xp` z3G`xmBVbJd4kolr-Ca&82dL=f?$LI^CXnS}YXn57s&P*9bcq3ED29P3{DX0)Y34Ws zub=7pr`~-S0fsCo)(e0gplEQ7rOH_jBT-G3q=y)nykLr(AO2h1#R>%(4)H<+{hy)R zetv|sA9!!1GXvUU+P%})k?g1pOP{d+@0-ZNSVQPM0J9dq$ZRY7(Ks|kqtz{f8H4N% zBAq%CXMAq!mg!T8HjAHbekgsM;jvJ3zH4JA*2?tywZ98}h9Zl@3s%%=tpf6%Wwa=h z1_xgED}(-%J?d&r^ngW9V!6EWEGd~2hxdd-6K z@|WiF9^7$HlVh1J{Q*Cc=VXtOGADeG|6Q@Eg!zZ}-WQ#}Gmh3_(tUZxHdj2dqd+5q zTL0kWoF^|B`uiuKueIT&30l>M`0q3(;pW_sA#0F{;&tNh_ z-P_JGw}mt^(_Lo^AyEzk73=7fER|z&H{MC1!N&qX%*aGxY^pjB*FE_p6tupVNHoI( z*%e|)Ops6XZIVwGpHRy1IG5o~9=MJF&225XSPF(f&K z85#Hh*b1J?t1~x(x+MxMzWMSgaKd-zdBoYOV^!`#L%-vjkIGrDMV`#%Lf>Rsg4wYX zwIIhVF!QYRxp9~+>#4Yd`}HtGUKU(>=J^~85>9BAc@=z%Jas7dFO`l* z+Bx0_gOy2w(k>OG&0Eb~>*q&&n;?mPqVf4&=@1UMyZ+XM#IwFEMxz6WrJ za9Hq00v#lM0LLkmm;h<$V^Nzm>KZx&b>+(eRjsK0S)g!O!v9R(hcR+17CFWy>-~MxA`=@R7_pe6vch#^ zaFK8Q&rh$!7aO%Qz%IQl4Wr?10zDpP!7vA%7yUEb1S)knb#|GJQb_La_SecRghk7U zWw>^J(s}Owtkk(%lEWC5Y**m7Vrf`Fz3C8n5EX?nq8-@mE9R-6H>-DU1-h9;ICmv`rq16h@gD}hWr!S$OPSehJAth#8ggF1QTpiIVA;a0 zb6(@AJtl=L4GHG-&94t+&E^zIAQP%k29$#9j3igOOd_VU^!~ zX8)~J7GK>)l+#lD0h}dHSyhXdCe)`ml(9#H&2H(yk1*LXP3{e5l=xE2Ia8lorhpO3 z%d|>cv`DAC$-ofcEt0ct&VQKG+*Z}CNyFziZQ1-0~x)8+oY@U(mtj5$?Bsvh7PHYS9 zREAqdSP!7uk00L<+YJCglpWmls`%WPbD!(Ad51D^!0{aVm?b@YcxidD(os6Kak`*V zS&FU9l{)2lKT$kLqG;Hy`Y}7H&h=NY$9!vfKDg9LAie_n1Hdh|4Hk4z^Hdt{3W)wd zEVOv3#09`f;FiIwYk3B?;Fw$Ui+`qz>pIf80KW;E{y0NmTPX*>aZfb~9^h4d>3O4#aW~AcQy!e_oxuiZr=%9<7hyU_AWzD_e zYM_5jV}OTslP7W-AGV7jh#l{`V55TqTUU~5OAA;P0%iL&c-emwlnC;W;9GUx~eG=AEuPO6;WnmUU7wk*V|OAgP4sx} z?+3RZ6)=r(=Rggs6L|K1mZk+?MfC!EUnX#sjM>XkK`5d(H+6-1#^cj)$TX3yFx3}G zA2&h`e$v*anNt7kz3_$pCAH6|Lit;XacKa`{kDhy4UQ<-jRU;w{2{!C~1SU>qnP<1?{hVCjsO6%(s8vkIE7{>ux_q8gCy8I8r>MpY-Y#bZK( zIXto}@$oLK8;8|eyt%R)Z&7^nJ(jx7+Z!?=$K##r_dBmBL8wT$#iXO*Fz$@LOD0?S zd!wxv;qc(XEd+2TupFDLw#GwkeI7z)lKGyMOuzL%eYASBWR1sQeY~1>K)+-}s)#i2 zn3a{DdzoRrpFZ_wJm&9>k)s{*NBf(6mO_QoeV}3KE;u^7WdU{QraG@Q1x0 zUFHm^=9+Cp<$W`M4Vz=?{imRInW>{@R{x0^Q}lMtdds?kk;dUd7D|x!Yp*f?++7fQ z!6^&4as$2==oRQ+-?!Llyo%m64=0#l&T-<(gHGMIjPUGog}Wk`lFB|VUmJH)_w2iT zU=SgZ;TE(V2=_B9R)bytdE2;cq3*0ZeaTX~DR{tcfJ|aw(S>T--oLc_SP|aY;Wa71qoOroRkh>DlE!Hs0`}-zE95|;j z;MG6kx9OXsj}Vwr_e3}5)o(S%?KSnmtUTUS>Pz-WU0EiErpz!5?aG+>hxTg|DNnXf z9htqi51As#!UN$r@L_2t-(3c&In{SpSikV(d2N<4?D5 zCIUyAk;a2Y^ey!)vnLX*w?7BI|5&G^_x_L&Z^ZmSJD}wN@j;;D<9PQ3w~zW?xc0DS->_A@?rZM&oAwL zD;LhW6=M6$I2|0)uodsQsOR>Ef{h2(*6H~>4l@`4>5_xPSQ?AzxQU<{##((wsBr

SK7)sr)6WX+9{XK> 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

@UX)rCW-BJ?#O#68A| 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 y{7`sshdA7AVqNM8VK1jt|+joPO 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 z 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

B3vGp9x1;q68@ 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

{flagged} {escape(obj.name)}
{obj.timezone}
" - ) + return mark_safe(f"
{escape(obj.name)}
{obj.plan}
") def derive_queryset(self, **kwargs): qs = super().derive_queryset(**kwargs).filter(is_active=True) @@ -2049,8 +2119,11 @@ def derive_queryset(self, **kwargs): qs = qs.filter(is_flagged=True) elif obj_filter == "suspended": qs = qs.filter(is_suspended=True) + elif obj_filter == "verified": + # this is not my favorite + qs = qs.filter(config__icontains='"verified": True') elif obj_filter and obj_filter != "all": - qs = qs.filter(name__icontains=obj_filter) + qs = qs.filter(Q(plan=obj_filter) | Q(name__icontains=obj_filter)) return qs.annotate(credits=Sum("topups__credits")).annotate(paid=Sum("topups__price")) @@ -2069,7 +2142,7 @@ def lookup_field_link(self, context, field, obj): def get_created_by(self, obj): # pragma: needs cover return "%s %s - %s" % (obj.created_by.first_name, obj.created_by.last_name, obj.created_by.email) - class Update(ComponentFormMixin, ContentMenuMixin, SmartUpdateView): + class Update(StaffMixin, SpaMixin, ModalMixin, ComponentFormMixin, SmartUpdateView): class Form(forms.ModelForm): parent = forms.IntegerField(required=False) plan_end = forms.DateTimeField(required=False) @@ -2100,7 +2173,12 @@ def clean(self): def add_limits_fields(self, org: Org): for limit_type in settings.ORG_LIMIT_DEFAULTS.keys(): initial = org.limits.get(limit_type) - limit_field = forms.IntegerField(required=False, initial=initial) + limit_field = forms.IntegerField( + label=limit_type.capitalize(), + required=False, + initial=initial, + widget=forms.TextInput(attrs={"placeholder": _("Limit")}), + ) field_key = f"{limit_type}_limit" self.fields.update(OrderedDict([(field_key, limit_field)])) @@ -2119,59 +2197,21 @@ class Meta: "is_multi_user", "is_multi_org", "is_suspended", + "is_flagged", ) form_class = Form + def derive_title(self): + return None + def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["org"] = self.get_object() return kwargs def get_success_url(self): - return reverse("orgs.org_update", args=[self.get_object().pk]) - - def build_content_menu(self, menu): - if not self.object.is_active: - return - - menu.add_url_post( - _("Service"), - f'{reverse("orgs.org_service")}?organization={self.object.id}&redirect_url={reverse("msgs.msg_inbox", args=[])}', - ) - menu.add_link(_("Topups"), f"{reverse('orgs.topup_manage')}?org={self.object.id}") - - if self.object.is_flagged: - menu.add_url_post(_("Unflag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=unflag") - else: # pragma: needs cover - menu.add_url_post(_("Flag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=flag") - - if not self.object.is_verified(): - menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=verify") - - if self.request.user.has_perm("orgs.org_delete"): - menu.add_modax( - _("Delete"), - "delete-org", - reverse("orgs.org_delete", args=[self.object.id]), - title=_("Delete Workspace"), - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - org = self.get_object() - - users_roles = [] - - for role in OrgRole: - role_users = list(org.get_users(roles=[role]).values("id", "email")) - if role_users: - users_roles.append(dict(role_display=role.display_plural, users=role_users)) - - context["users_roles"] = users_roles - - return context + return reverse("orgs.org_read", args=[self.get_object().pk]) def post(self, request, *args, **kwargs): if "action" in request.POST: @@ -2193,7 +2233,7 @@ def pre_save(self, obj): obj.limits = cleaned_data["limits"] return obj - class Delete(ModalMixin, SmartDeleteView): + class Delete(StaffMixin, SpaMixin, ModalMixin, SmartDeleteView): cancel_url = "id@orgs.org_update" success_url = "id@orgs.org_update" fields = ("id",) @@ -2478,7 +2518,7 @@ def get_success_url(self): # pragma: needs cover org_id = self.request.GET.get("org") return "%s?org=%s" % (reverse("orgs.org_manage_accounts_sub_org"), org_id) - class Service(SmartFormView): + class Service(StaffMixin, SmartFormView): class ServiceForm(forms.Form): organization = TembaChoiceField(queryset=Org.objects.all(), empty_label=None) redirect_url = forms.CharField(required=False) @@ -3850,7 +3890,7 @@ def post_save(self, obj): apply_topups_task.delay(obj.org.id) return obj - class Manage(SmartListView): + class Manage(SpaMixin, SmartListView): """ This is only for root to be able to manage topups on an account """ diff --git a/temba/utils/templatetags/temba.py b/temba/utils/templatetags/temba.py index 43b61d4e98f..8224862bab2 100644 --- a/temba/utils/templatetags/temba.py +++ b/temba/utils/templatetags/temba.py @@ -79,6 +79,11 @@ def icon(o): return "" +@register.filter +def deslug(str): + return str.replace("_", " ").title() + + @register.filter def object_url(o): assert type(o) in OBJECT_URLS diff --git a/templates/contacts/contact_read_spa.haml b/templates/contacts/contact_read_spa.haml index 8d16545ac0e..53acdf413bb 100644 --- a/templates/contacts/contact_read_spa.haml +++ b/templates/contacts/contact_read_spa.haml @@ -89,7 +89,7 @@ -block subtitle .summary.-mt-2 - %temba-contact-groups(contact="{{object.uuid}}") + %temba-contact-badges(contact="{{object.uuid}}") -block content diff --git a/templates/frame.haml b/templates/frame.haml index e50126ceed5..08e9aeca3cf 100644 --- a/templates/frame.haml +++ b/templates/frame.haml @@ -309,7 +309,8 @@ } function handlePosterize(ele) { - posterize(ele.getAttribute('href')); + console.log(ele.getAttribute('href') || ele.dataset.href); + posterize(ele.getAttribute('href') || ele.dataset.href); } function removalConfirmation(removal, buttonName) { diff --git a/templates/includes/nav.haml b/templates/includes/nav.haml index 0776232fcda..26e01f40bcd 100644 --- a/templates/includes/nav.haml +++ b/templates/includes/nav.haml @@ -183,7 +183,7 @@ .title -trans "channels" - -if request.user.is_superuser or perms.orgs.user_list + -if request.user.is_superuser or request.user.is_staff -if not user_org %a{href:"{% url 'orgs.user_list' %}", class:"{% active request 'users' %}"} .circle @@ -191,7 +191,7 @@ .title -trans "users" - -if request.user.is_superuser or perms.orgs.org_manage + -if request.user.is_superuser or request.user.is_staff -if not user_org %a{href:"{% url 'orgs.org_manage' %}", class:"{% active request 'org' %}"} .circle @@ -221,7 +221,7 @@ -block loggedin-submenu - -if request.user.is_superuser or perms.orgs.user_list + -if request.user.is_superuser or request.user.is_staff -if user_org %a{href:"{% url 'orgs.user_list' %}", class:"{% active request 'users' %}"} .circle @@ -229,7 +229,7 @@ .title -trans "users" - -if request.user.is_superuser or perms.orgs.org_manage + -if request.user.is_superuser or request.user.is_staff -if user_org %a{href:"{% url 'orgs.org_manage' %}", class:"{% active request 'org' %}"} .circle diff --git a/templates/msgs/message_box_spa.haml b/templates/msgs/message_box_spa.haml index 92ef3027dc1..fe9ffbb1694 100644 --- a/templates/msgs/message_box_spa.haml +++ b/templates/msgs/message_box_spa.haml @@ -12,7 +12,7 @@ .flex.flex-col %form#search-form(method="get") %temba-textinput.w-full(placeholder='{% trans "Search" %}' name="search" value="{{search}}") - %input.hide(type="submit") + %input.hidden(type="submit" value="Submit") .mt-4.shadow.rounded-lg.rounded-bl-none.rounded-br-none.bg-white diff --git a/templates/orgs/org_manage.haml b/templates/orgs/org_manage.haml index ff10f000544..6284a1d2b85 100644 --- a/templates/orgs/org_manage.haml +++ b/templates/orgs/org_manage.haml @@ -26,8 +26,14 @@ {{block.super}} :css - .org-timezone, .owner-email { + .org-timezone, .owner-email, .org-plan { font-size: 80%; + color: #999; + } + + a:hover, a:hover * { + text-decoration: none; + color: var(--color-link-primary); } .plan-name { diff --git a/templates/orgs/org_manage_spa.haml b/templates/orgs/org_manage_spa.haml new file mode 100644 index 00000000000..767a06a5b8d --- /dev/null +++ b/templates/orgs/org_manage_spa.haml @@ -0,0 +1,11 @@ +-extends "orgs/org_manage.haml" +-load i18n + +-block page-header + +-block pre-table + .flex.mb-4.items-center + .search-box.flex-grow + %form#search-form(method='get') + %temba-textinput(name='search' value='{{ search }}' placeholder="Search Workspaces") + %input.hidden(type="submit" value="Submit") diff --git a/templates/orgs/org_read.haml b/templates/orgs/org_read.haml new file mode 100644 index 00000000000..9eeda822b0a --- /dev/null +++ b/templates/orgs/org_read.haml @@ -0,0 +1,37 @@ +-extends 'smartmin/read.html' +-load i18n + +-block content + .flex + -if org.is_active + -if org.is_anon + %temba-label.mr-2(icon="help-circle" backgroundcolor="#eee" textcolor="#999") + -trans "Anonymous" + + -if org.is_suspended + %temba-label.mr-2(icon="slash" backgroundcolor="#eee" textcolor="#999") + -trans "Suspended" + + -if org.is_flagged + %temba-label.mr-2(icon="flag" backgroundcolor="#eee" textcolor="#999") + -trans "Flagged" + + -if org.is_verified + %temba-label.mr-2(icon="check" backgroundcolor="rgb(136 193 122)" textcolor="white") + -trans "Verified" + + -else + %temba-label.mr-2(icon="trash" backgroundcolor="#eee" textcolor="#999") + -trans "Deleted" + + .card + -for user_role in users_roles + .my-1 + .cap-label + {{user_role.role_display}} + + .flex.flex-col + -for user in user_role.users + .user + %a(href='{% url "orgs.user_update" user.id %}')< + {{user.email}} diff --git a/templates/orgs/org_read_spa.haml b/templates/orgs/org_read_spa.haml new file mode 100644 index 00000000000..ab12c58c9f6 --- /dev/null +++ b/templates/orgs/org_read_spa.haml @@ -0,0 +1 @@ +-extends 'orgs/org_read.haml' \ No newline at end of file diff --git a/templates/orgs/org_update.haml b/templates/orgs/org_update.haml index d9f22fd5700..c4e60ae3fbe 100644 --- a/templates/orgs/org_update.haml +++ b/templates/orgs/org_update.haml @@ -32,3 +32,4 @@ -for user in user_role.users %a{href:'{% url "orgs.user_update" user.id %}'} {{user.email}} + diff --git a/templates/orgs/org_update_spa.haml b/templates/orgs/org_update_spa.haml new file mode 100644 index 00000000000..1d1974a8512 --- /dev/null +++ b/templates/orgs/org_update_spa.haml @@ -0,0 +1,2 @@ +-extends "smartmin/form.html" +-load i18n smartmin diff --git a/templates/orgs/user_account.haml b/templates/orgs/user_account.haml index 67287b89e2b..afc593696e1 100644 --- a/templates/orgs/user_account.haml +++ b/templates/orgs/user_account.haml @@ -20,14 +20,13 @@ -block page-header - -if user_orgs|length > 1 + -if user_orgs|length > 1 or request.user.is_staff .text-xl.w-full.mb-4 %temba-select.w-full(onchange="handleWorkspaceChanged(event)") - -for org in user_orgs - -if org.id == user_org.id - %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}" selected="true") - -else - %temba-option(name='{{ org.name|escapejs }}' value="{{org.id}}") + %temba-option(name='{{ user_org.name|escapejs }}' value="{{user_org.id}}" selected="true") + -for other_org in user_orgs + -if other_org.id != user_org.id + %temba-option(name='{{ other_org.name|escapejs }}' value="{{other_org.id}}") - else {{block.super}} diff --git a/templates/orgs/user_list.haml b/templates/orgs/user_list.haml index eaa131843d9..f83ec0f3fd0 100644 --- a/templates/orgs/user_list.haml +++ b/templates/orgs/user_list.haml @@ -21,3 +21,4 @@ %form#search-form(method='get') %input(type="hidden" name="filter" value='{{ filter }}') %temba-textinput(name='search' value='{{ search }}') + %input.hidden(type="submit" value="Submit") diff --git a/templates/orgs/user_list_spa.haml b/templates/orgs/user_list_spa.haml new file mode 100644 index 00000000000..caf04e8a91f --- /dev/null +++ b/templates/orgs/user_list_spa.haml @@ -0,0 +1,11 @@ +-extends "orgs/user_list.haml" +-load i18n + +-block page-header + +-block pre-table + %form#search-form(method='get') + .flex.mb-4.items-center + .search-box.flex-grow + %temba-textinput(name='search' value='{{ search }}' placeholder="Search Users") + %input.hidden(type="submit" value="Submit") diff --git a/templates/smartmin/base.html b/templates/smartmin/base.html index 85785a49a36..f7540e0676f 100644 --- a/templates/smartmin/base.html +++ b/templates/smartmin/base.html @@ -9,15 +9,6 @@ {% block extra-script %} + :javascript + $(function(){ + prettyPrint(); + }); + + :javascript + $('document').ready(function(){ + $('.summary :first').click(); + }); + + $('.summary').on('click', function() { + var top = $(this).parent('.log') + var ele = top.find(".details"); + if (ele.is(':visible')) { + ele.slideUp(); + top.removeClass('expanded'); + } else { + ele.slideDown(); + top.addClass('expanded') + } + }); + +-block extra-style + {{ block.super }} + + :css + .page-content { + max-width: 100%; + } + +-block extra-less + {{block.super}} + -compress css inline + {% lessblock %} + :plain + table.list { + tbody { + tr:first-child { + td { + padding: 1.5rem; + } + } + } + } + + pre.prettyprint { + margin: 0; + border: 0; + max-height: none !important; + padding: 1.5rem; + + &.request { + background: #f7f7f9 + 111; + } + } + {% endlessblock %} diff --git a/templates/channels/channellog_read.haml b/templates/channels/channellog_read.haml index 48cfe5c39e4..79e1d5bcc91 100644 --- a/templates/channels/channellog_read.haml +++ b/templates/channels/channellog_read.haml @@ -5,47 +5,12 @@ -trans "Channel Event" -block title - -trans "Message Log" + -trans "Channel Log" -block subtitle {{ object.channel.get_channel_type_display }} -block content - .card.flex.mt-0.flex-shrink-0 - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Recipient" - -block log-recipient - -if object.msg - %temba-anchor(href='{% url "contacts.contact_read" object.msg.contact.uuid %}') - {{ object.msg.contact_urn.get_display }} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Direction" - -block log-direction - {{ object.msg.get_direction_display }} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Date" - {% format_datetime object.created_on seconds=True %} - - -if object.duration - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Duration" - {{ object.get_duration|delta }} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Status" - -block log-status - -if object.is_error - -trans "Error" - -else - {{ object.msg.get_status_display }} - -for log in http_logs -include "includes/http_log.haml" with log=log diff --git a/templates/includes/http_log.haml b/templates/includes/http_log.haml index cf1cdd09338..46c80ca8cb4 100644 --- a/templates/includes/http_log.haml +++ b/templates/includes/http_log.haml @@ -27,4 +27,4 @@ %tr %td(colspan="4" style="padding:0;") %pre.prettyprint.response< - {% if object.response%}{{ log.response }}{% else %}{% trans "Connection Error" %}{% endif %} + {% if log.response%}{{ log.response }}{% else %}{% trans "Connection Error" %}{% endif %} diff --git a/templates/msgs/tags/channel_log_link.haml b/templates/msgs/tags/channel_log_link.haml index 28fc69bd032..92e553318f5 100644 --- a/templates/msgs/tags/channel_log_link.haml +++ b/templates/msgs/tags/channel_log_link.haml @@ -1,3 +1,3 @@ -if log - .hover-linked{onclick:"goto(event)", href:"{% url 'channels.channellog_read' log.channel.uuid log.id %}"} + .hover-linked{onclick:"goto(event)", href:"{% url 'channels.channellog_read' log.id %}"} .icon-docs-2.pointer-events-none From 0e716f10853d7ca885dc27b1fbc6e61861ffc934 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 13:37:42 -0500 Subject: [PATCH 146/630] Simplify ChannelLogCRUDL urls --- temba/channels/views.py | 1 + temba/mailroom/tests.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/temba/channels/views.py b/temba/channels/views.py index a1210b5bc38..a9f76cb7cc1 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1438,6 +1438,7 @@ def get_context_data(self, *args, **kwargs): class ChannelLogCRUDL(SmartCRUDL): model = ChannelLog + path = "log" # urls like /channels/log/ actions = ("list", "read", "msg", "call") class List(SpaMixin, OrgPermsMixin, ContentMenuMixin, SmartListView): diff --git a/temba/mailroom/tests.py b/temba/mailroom/tests.py index 944ab9b7481..9356ea533d9 100644 --- a/temba/mailroom/tests.py +++ b/temba/mailroom/tests.py @@ -881,7 +881,7 @@ def test_from_msg(self): "quick_replies": ["yes", "no"], }, "status": "E", - "logs_url": f"/channels/channellog/msg/{msg_out.id}/", + "logs_url": f"/channels/log/msg/{msg_out.id}/", }, Event.from_msg(self.org, self.admin, msg_out), ) @@ -1133,7 +1133,7 @@ def test_from_ivr_call(self): "status": "E", "status_display": "Errored (Busy)", "created_on": matchers.ISODate(), - "logs_url": f"/channels/channellog/call/{call2.id}/", + "logs_url": f"/channels/log/call/{call2.id}/", }, Event.from_ivr_call(self.org, self.admin, call2), ) From 3b7c675e67431d00390b2efd382f360eda3ea453 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 14:10:01 -0500 Subject: [PATCH 147/630] Fix tests --- temba/channels/models.py | 3 +- templates/channels/channellog_call.haml | 27 +++++ templates/channels/channellog_connection.haml | 15 --- templates/channels/channellog_group_base.haml | 69 +++++++++++ templates/channels/channellog_msg.haml | 110 ++++-------------- 5 files changed, 120 insertions(+), 104 deletions(-) create mode 100644 templates/channels/channellog_call.haml delete mode 100644 templates/channels/channellog_connection.haml create mode 100644 templates/channels/channellog_group_base.haml diff --git a/temba/channels/models.py b/temba/channels/models.py index f4fb8874768..f918e8870d4 100644 --- a/temba/channels/models.py +++ b/temba/channels/models.py @@ -1758,8 +1758,7 @@ def get_session(self): return None def release(self): - for log in self.channel_logs.all(): - log.release() + self.channel_logs.all().delete() session = self.get_session() if session: diff --git a/templates/channels/channellog_call.haml b/templates/channels/channellog_call.haml new file mode 100644 index 00000000000..3a5fc76a3ba --- /dev/null +++ b/templates/channels/channellog_call.haml @@ -0,0 +1,27 @@ +-extends "smartmin/list.html" +-load i18n + +-block title + -trans "Call Log" + +-block group_object + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Recipient" + %temba-anchor(href='{% url "contacts.contact_read" call.contact.uuid %}') + {{ call.contact_urn.get_display }} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Duration" + {{ call.get_duration }} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Date" + {% format_datetime call.created_on seconds=True %} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Status" + {{ call.get_status_display }} diff --git a/templates/channels/channellog_connection.haml b/templates/channels/channellog_connection.haml deleted file mode 100644 index da56c6b9751..00000000000 --- a/templates/channels/channellog_connection.haml +++ /dev/null @@ -1,15 +0,0 @@ --extends "channels/channellog_read.html" --load i18n - --block title - -trans "Call Log" - --block log-recipient - %a(href='{% url "contacts.contact_read" object.contact.uuid %}') - {{ object.contact_urn.path }} - --block log-direction - {{ object.get_direction_display }} - --block log-status - {{ object.status_display }} diff --git a/templates/channels/channellog_group_base.haml b/templates/channels/channellog_group_base.haml new file mode 100644 index 00000000000..5aa0d25efdb --- /dev/null +++ b/templates/channels/channellog_group_base.haml @@ -0,0 +1,69 @@ +-extends "smartmin/list.html" +-load i18n compress + +-block content + .card.flex.mt-0.flex-shrink-0 + -block group_object + + -for log in http_logs + -include "includes/http_log.haml" with log=log + +-block extra-script + {{ block.super }} + + :javascript + $(function(){ + prettyPrint(); + }); + + :javascript + $('document').ready(function(){ + $('.summary :first').click(); + }); + + $('.summary').on('click', function() { + var top = $(this).parent('.log') + var ele = top.find(".details"); + if (ele.is(':visible')) { + ele.slideUp(); + top.removeClass('expanded'); + } else { + ele.slideDown(); + top.addClass('expanded') + } + }); + +-block extra-style + {{ block.super }} + + :css + .page-content { + max-width: 100%; + } + +-block extra-less + {{block.super}} + -compress css inline + {% lessblock %} + :plain + table.list { + tbody { + tr:first-child { + td { + padding: 1.5rem; + } + } + } + } + + pre.prettyprint { + margin: 0; + border: 0; + max-height: none !important; + padding: 1.5rem; + + &.request { + background: #f7f7f9 + 111; + } + } + {% endlessblock %} diff --git a/templates/channels/channellog_msg.haml b/templates/channels/channellog_msg.haml index a940882767c..b0a7e919968 100644 --- a/templates/channels/channellog_msg.haml +++ b/templates/channels/channellog_msg.haml @@ -1,91 +1,27 @@ --extends "smartmin/list.html" --load i18n compress +-extends "channels/channellog_group_base.haml" +-load i18n -block title -trans "Message Log" --block content - .card.flex.mt-0.flex-shrink-0 - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Recipient" - %temba-anchor(href='{% url "contacts.contact_read" msg.contact.uuid %}') - {{ msg.contact_urn.get_display }} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Direction" - {{ msg.get_direction_display }} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Date" - {% format_datetime msg.created_on seconds=True %} - - .inline-flex.mr-8 - .font-normal.mr-2 - -trans "Status" - {{ msg.get_status_display }} - - -for log in http_logs - -include "includes/http_log.haml" with log=log - --block extra-script - {{ block.super }} - - :javascript - $(function(){ - prettyPrint(); - }); - - :javascript - $('document').ready(function(){ - $('.summary :first').click(); - }); - - $('.summary').on('click', function() { - var top = $(this).parent('.log') - var ele = top.find(".details"); - if (ele.is(':visible')) { - ele.slideUp(); - top.removeClass('expanded'); - } else { - ele.slideDown(); - top.addClass('expanded') - } - }); - --block extra-style - {{ block.super }} - - :css - .page-content { - max-width: 100%; - } - --block extra-less - {{block.super}} - -compress css inline - {% lessblock %} - :plain - table.list { - tbody { - tr:first-child { - td { - padding: 1.5rem; - } - } - } - } - - pre.prettyprint { - margin: 0; - border: 0; - max-height: none !important; - padding: 1.5rem; - - &.request { - background: #f7f7f9 + 111; - } - } - {% endlessblock %} +-block group_object + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Recipient" + %temba-anchor(href='{% url "contacts.contact_read" msg.contact.uuid %}') + {{ msg.contact_urn.get_display }} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Direction" + {{ msg.get_direction_display }} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Date" + {% format_datetime msg.created_on seconds=True %} + + .inline-flex.mr-8 + .font-normal.mr-2 + -trans "Status" + {{ msg.get_status_display }} From 09caf348347e2b175dc1224a9136503b7b1209b0 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 14:35:09 -0500 Subject: [PATCH 148/630] Fix tests --- temba/contacts/tests.py | 8 +++----- temba/mailroom/events.py | 2 +- temba/msgs/models.py | 9 --------- temba/msgs/templatetags/sms.py | 2 +- temba/msgs/tests.py | 16 ++++++++++------ templates/msgs/tags/channel_log_link.haml | 4 ++-- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index de8f0f0b9f3..7f7bff23289 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -2372,9 +2372,7 @@ def test_history(self): failed = Msg.objects.filter(direction="O", contact=self.joe).last() failed.status = "F" failed.save(update_fields=("status",)) - log = ChannelLog.objects.create( - channel=failed.channel, msg=failed, is_error=True, description="It didn't send!!" - ) + ChannelLog.objects.create(channel=failed.channel, msg=failed, is_error=True, description="It didn't send!!") # create an airtime transfer transfer = AirtimeTransfer.objects.create( @@ -2450,7 +2448,7 @@ def test_history(self): # fetch our contact history self.login(self.admin) with patch("temba.utils.s3.s3.client", return_value=self.mock_s3): - with self.assertNumQueries(35): + with self.assertNumQueries(34): response = self.client.get(url + "?limit=100") # history should include all messages in the last 90 days, the channel event, the call, and the flow run @@ -2492,7 +2490,7 @@ def assertHistoryEvent(events, index, expected_type, **kwargs): response, "http://www.openstreetmap.org/?mlat=47.5414799&mlon=-122.6359908#map=18/47.5414799/-122.6359908", ) - self.assertContains(response, reverse("channels.channellog_read", args=[log.id])) + self.assertContains(response, reverse("channels.channellog_msg", args=[failed.id])) self.assertContains(response, reverse("channels.channellog_call", args=[call.id])) self.assertContains(response, "Transferred 100.00 RWF of airtime") self.assertContains(response, reverse("airtime.airtimetransfer_read", args=[transfer.id])) diff --git a/temba/mailroom/events.py b/temba/mailroom/events.py index d97d134391b..411e5309028 100644 --- a/temba/mailroom/events.py +++ b/temba/mailroom/events.py @@ -79,7 +79,7 @@ def from_msg(cls, org: Org, user: User, obj: Msg) -> dict: """ logs_url = None - if obj.get_last_log(): + if obj.channel_logs.exists(): logs_url = _url_for_user( org, user, "channels.channellog_msg", args=[obj.id], perm="channels.channellog_read" ) diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 245c9c87ce4..afe8b38188f 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -661,15 +661,6 @@ def get_attachments(self): """ return Attachment.parse_all(self.attachments) - def get_last_log(self): - """ - Gets the last channel log for this message. Performs sorting in Python to ease pre-fetching. - """ - sorted_logs = None - if self.channel and self.channel.is_active: - sorted_logs = sorted(self.channel_logs.all(), key=lambda l: l.created_on, reverse=True) - return sorted_logs[0] if sorted_logs else None - def update(self, cmd): """ Updates our message according to the provided client command diff --git a/temba/msgs/templatetags/sms.py b/temba/msgs/templatetags/sms.py index 7f88561801c..878de1b8673 100644 --- a/temba/msgs/templatetags/sms.py +++ b/temba/msgs/templatetags/sms.py @@ -139,4 +139,4 @@ def attachment_button(attachment: str) -> dict: @register.inclusion_tag("msgs/tags/channel_log_link.haml") def channel_log_link(msg): - return {"log": msg.get_last_log()} + return {"msg": msg, "has_logs": msg.channel_logs.exists()} diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 9cce548fd16..aff2cbcefe8 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -1795,11 +1795,15 @@ def test_sent(self): # check query count self.login(self.admin) - with self.assertNumQueries(33): + with self.assertNumQueries(28): self.client.get(sent_url) # messages sorted by sent_on - self.assertListFetch(sent_url, allow_viewers=True, allow_editors=True, context_objects=[msg1, msg3, msg2]) + response = self.assertListFetch( + sent_url, allow_viewers=True, allow_editors=True, context_objects=[msg1, msg3, msg2] + ) + + self.assertContains(response, reverse("channels.channellog_msg", args=[msg1.id])) response = self.client.get(sent_url + "?search=joe") self.assertEqual([msg1, msg2], list(response.context_data["object_list"])) @@ -1808,7 +1812,7 @@ def test_sent(self): def test_failed(self, mock_msg_resend): contact1 = self.create_contact("Joe Blow", phone="+250788000001") msg1 = self.create_outgoing_msg(contact1, "message number 1", status="F") - log = ChannelLog.objects.create(channel=msg1.channel, msg=msg1, is_error=True, description="Failed") + ChannelLog.objects.create(channel=msg1.channel, msg=msg1, is_error=True, description="Failed") failed_url = reverse("msgs.msg_failed") @@ -1822,7 +1826,7 @@ def test_failed(self, mock_msg_resend): # check query count self.login(self.admin) - with self.assertNumQueries(32): + with self.assertNumQueries(28): self.client.get(failed_url) response = self.assertListFetch( @@ -1830,12 +1834,12 @@ def test_failed(self, mock_msg_resend): ) self.assertEqual(("resend",), response.context["actions"]) - self.assertContains(response, reverse("channels.channellog_read", args=[log.id])) + self.assertContains(response, reverse("channels.channellog_msg", args=[msg1.id])) # make the org anonymous with AnonymousOrg(self.org): response = self.requestView(failed_url, self.admin) - self.assertNotContains(response, reverse("channels.channellog_read", args=[log.id])) + self.assertNotContains(response, reverse("channels.channellog_msg", args=[msg1.id])) # resend some messages self.client.post(failed_url, {"action": "resend", "objects": [msg2.id]}) diff --git a/templates/msgs/tags/channel_log_link.haml b/templates/msgs/tags/channel_log_link.haml index 92e553318f5..4f2c9c7e4ec 100644 --- a/templates/msgs/tags/channel_log_link.haml +++ b/templates/msgs/tags/channel_log_link.haml @@ -1,3 +1,3 @@ --if log - .hover-linked{onclick:"goto(event)", href:"{% url 'channels.channellog_read' log.id %}"} +-if has_logs + .hover-linked{onclick:"goto(event)", href:"{% url 'channels.channellog_msg' msg.id %}"} .icon-docs-2.pointer-events-none From b3bd265e982864499acdacf3dab2941cf02c7e05 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 14:39:44 -0500 Subject: [PATCH 149/630] Remove model changes which can go in another PR --- ...g_elapsed_ms_channellog_errors_and_more.py | 45 ------------------- temba/channels/models.py | 37 +-------------- temba/mailroom/events.py | 2 +- temba/msgs/models.py | 3 +- temba/msgs/tests.py | 2 +- 5 files changed, 5 insertions(+), 84 deletions(-) delete mode 100644 temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py diff --git a/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py b/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py deleted file mode 100644 index a3c9972316f..00000000000 --- a/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 4.0.7 on 2022-08-16 15:04 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("channels", "0139_channel_is_system"), - ] - - operations = [ - migrations.AddField( - model_name="channellog", - name="elapsed_ms", - field=models.IntegerField(null=True), - ), - migrations.AddField( - model_name="channellog", - name="errors", - field=models.JSONField(null=True), - ), - migrations.AddField( - model_name="channellog", - name="http_logs", - field=models.JSONField(null=True), - ), - migrations.AddField( - model_name="channellog", - name="log_type", - field=models.CharField( - choices=[ - ("msg_send", "Message Send"), - ("msg_update", "Message Update"), - ("msg_receive", "Message Receive"), - ("ivr_start", "IVR Start"), - ("ivr_callback", "IVR Callback"), - ("contact_update", "Contact Update"), - ("token_refresh", "Token Refresh"), - ], - max_length=16, - null=True, - ), - ), - ] diff --git a/temba/channels/models.py b/temba/channels/models.py index f918e8870d4..dc576e92b49 100644 --- a/temba/channels/models.py +++ b/temba/channels/models.py @@ -1185,44 +1185,20 @@ class ChannelLog(models.Model): A log of an interaction with a channel """ - LOG_TYPE_MSG_SEND = "msg_send" - LOG_TYPE_MSG_UPDATE = "msg_update" - LOG_TYPE_MSG_RECEIVE = "msg_receive" - LOG_TYPE_IVR_START = "ivr_start" - LOG_TYPE_IVR_CALLBACK = "ivr_callback" - LOG_TYPE_CONTACT_UPDATE = "contact_update" - LOG_TYPE_TOKEN_REFRESH = "token_refresh" - LOG_TYPE_CHOICES = ( - (LOG_TYPE_MSG_SEND, _("Message Send")), - (LOG_TYPE_MSG_UPDATE, _("Message Update")), - (LOG_TYPE_MSG_RECEIVE, _("Message Receive")), - (LOG_TYPE_IVR_START, _("IVR Start")), - (LOG_TYPE_IVR_CALLBACK, _("IVR Callback")), - (LOG_TYPE_CONTACT_UPDATE, _("Contact Update")), - (LOG_TYPE_TOKEN_REFRESH, _("Token Refresh")), - ) - id = models.BigAutoField(primary_key=True) channel = models.ForeignKey(Channel, on_delete=models.PROTECT, related_name="logs") msg = models.ForeignKey("msgs.Msg", on_delete=models.PROTECT, related_name="channel_logs", null=True) connection = models.ForeignKey( "channels.ChannelConnection", on_delete=models.PROTECT, related_name="channel_logs", null=True ) - - log_type = models.CharField(max_length=16, choices=LOG_TYPE_CHOICES, null=True) - http_logs = models.JSONField(null=True) - errors = models.JSONField(null=True) - is_error = models.BooleanField(default=False) - elapsed_ms = models.IntegerField(null=True) - created_on = models.DateTimeField(default=timezone.now) - - # TODO deprecated description = models.CharField(max_length=255) + is_error = models.BooleanField(default=False) url = models.TextField(null=True) method = models.CharField(max_length=16, null=True) request = models.TextField(null=True) response = models.TextField(null=True) response_status = models.IntegerField(null=True) + created_on = models.DateTimeField(default=timezone.now) request_time = models.IntegerField(null=True) @classmethod @@ -1309,9 +1285,6 @@ def get_display(self, user) -> dict: "created_on": self.created_on, } - def get_duration(self) -> int: - return self.elapsed_ms or self.request_time - class Meta: indexes = [ models.Index( @@ -1720,12 +1693,6 @@ def __init__(self, *args, **kwargs): self.__class__ = IVRCall - def has_logs(self): - """ - Returns whether this connection has any channel logs - """ - return self.channel.is_active and self.channel_logs.count() > 0 - def get_duration(self): """ Either gets the set duration as reported by provider, or tries to calculate it diff --git a/temba/mailroom/events.py b/temba/mailroom/events.py index 411e5309028..9216f16ea65 100644 --- a/temba/mailroom/events.py +++ b/temba/mailroom/events.py @@ -156,7 +156,7 @@ def from_flow_exit(cls, org: Org, user: User, obj: FlowExit) -> dict: @classmethod def from_ivr_call(cls, org: Org, user: User, obj: IVRCall) -> dict: logs_url = None - if obj.has_logs(): + if obj.channel_logs.exists(): logs_url = _url_for_user( org, user, "channels.channellog_call", args=[obj.id], perm="channels.channellog_read" ) diff --git a/temba/msgs/models.py b/temba/msgs/models.py index afe8b38188f..6524ad09811 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -780,8 +780,7 @@ def delete(self, soft: bool = False): self.visibility = Msg.VISIBILITY_DELETED_BY_USER self.save(update_fields=("text", "attachments", "visibility")) else: - for log in self.channel_logs.all(): - log.release() + self.channel_logs.all().delete() super().delete() diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index aff2cbcefe8..c721429dc85 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -1733,7 +1733,7 @@ def test_outbox(self): # check query count self.login(self.admin) - with self.assertNumQueries(31): + with self.assertNumQueries(30): self.client.get(outbox_url) # messages sorted by created_on From 0c65bcf3aeb10377313673b8264fdf5282db01d0 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Wed, 17 Aug 2022 12:48:23 +0200 Subject: [PATCH 150/630] Update the links for line developers console on the line claim page --- templates/channels/types/line/claim.haml | 34 +++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/templates/channels/types/line/claim.haml b/templates/channels/types/line/claim.haml index 1922e4c1d61..b2461dacb62 100644 --- a/templates/channels/types/line/claim.haml +++ b/templates/channels/types/line/claim.haml @@ -3,15 +3,17 @@ -block pre-form -blocktrans trimmed with name=brand.name - You can connect a LINE Bot to your {{ name }} workspace + You can connect a LINE Bot to your {{ name }} workspace to automate sending and receiving LINE messages. -blocktrans trimmed - To start creating a LINE bot, go to Getting started with the Messaging API. + To start creating a LINE bot, go to Getting started with the Messaging API. %ol.steps.card + + %li -blocktrans trimmed - Access the LINE Channels page and add a new Channel. + Access the LINE Developers Console page. %li -blocktrans trimmed @@ -27,16 +29,20 @@ %li -blocktrans trimmed - Create a new business account Line (With Messaging API enabled) + Create a new account on LINE Developers Console (With Messaging API enabled) + + %li + -blocktrans trimmed + Follow the steps on Creating a channel on the LINE Developers Console %ol %li -blocktrans trimmed - In LINE Business Center, select Messaging API in Services + Log in to the LINE Developers Console %li -blocktrans trimmed - Select Start using Messaging API + Register as a developer (only on first login) %li -blocktrans trimmed @@ -45,12 +51,20 @@ .important %p -blocktrans trimmed - Note: At this time you must create a LINE business account and some information, for example, address, + Note: At this time you must create a LINE Developers Console account and some information, for example, address, phone, etc., will be requested. %li -blocktrans trimmed - After the creation process of the LINE business account, you will see the page to add a new channel of + Create a new provider + + %li + -blocktrans trimmed + Create a channel + + %li + -blocktrans trimmed + After the creation process of the LINE Developers Console account, you will see the page to add a new channel of communication Messaging API. Enter the name and select the appropriate category and click OK. %li @@ -72,11 +86,11 @@ %ol %li -blocktrans trimmed - Click on the menu "Accounts" at the top of the page at the link https://business.line.me + Click on the menu "Accounts" at the top of the page at the link https://developers.line.biz/console/ %li -blocktrans trimmed - In the communication channel of your choice, click on the LINE Developers button, accept the terms, + In the communication channel of your choice, click on the LINE Developers Console button, accept the terms, and it will direct you to a page with the information needed to fill out in the form below (Channel ID, Channel Name, Channel Secret and Channel Access Token). From 9dc3d9ace3045a0d20eadf169f736477db2ae28b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 09:02:28 -0500 Subject: [PATCH 151/630] Update CHANGELOG.md for v7.5.20 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b913e42754a..923edad5073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.20 +---------- + * Update the links for line developers console on the line claim page + * Rework channel log details views into one generic one, one for messages, one for calls + v7.5.19 ---------- * Rework channel log rendering to use common HTTPLog template diff --git a/pyproject.toml b/pyproject.toml index 3de2df9fbf9..a09a3b70c7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.19" +version = "7.5.20" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 43678859f20aadf35be6df2822e9b3af9f7b3b7c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 16 Aug 2022 15:34:49 -0500 Subject: [PATCH 152/630] Replace all permission checking against Customer Support group with is_staff check on user --- temba/apks/tests.py | 47 ++++---------------- temba/apks/views.py | 11 +++-- temba/campaigns/tests.py | 1 + temba/channels/models.py | 2 +- temba/channels/tests.py | 10 ++--- temba/flows/tests.py | 8 +--- temba/flows/views.py | 5 +-- temba/msgs/views.py | 4 +- temba/orgs/models.py | 10 ++--- temba/orgs/tests.py | 27 ++++-------- temba/orgs/views.py | 51 ++++++++++------------ temba/policies/views.py | 15 ++++--- temba/settings_common.py | 31 +------------ temba/tests/base.py | 4 +- temba/tests/crudl.py | 2 +- temba/utils/management/commands/test_db.py | 5 +-- temba/utils/views.py | 9 ++++ templates/msgs/message_box.haml | 2 +- templates/msgs/message_box_spa.haml | 2 +- templates/msgs/msg_outbox.haml | 2 +- templates/msgs/msg_outbox_spa.haml | 2 +- 21 files changed, 90 insertions(+), 160 deletions(-) diff --git a/temba/apks/tests.py b/temba/apks/tests.py index be057c688c7..a019c102e1e 100644 --- a/temba/apks/tests.py +++ b/temba/apks/tests.py @@ -3,12 +3,12 @@ from django.core.files import File from django.urls import reverse -from temba.tests import TembaTest +from temba.tests import CRUDLTestMixin, TembaTest from .models import Apk -class ApkTest(TembaTest): +class ApkCRUDLTest(CRUDLTestMixin, TembaTest): def setUp(self): super().setUp() apk_file_mock = MagicMock(spec=File) @@ -27,51 +27,20 @@ def test_claim_android(self): self.assertContains(response, "
  • has new things
  • ") def test_list(self): - url = reverse("apks.apk_list") + list_url = reverse("apks.apk_list") - self.login(self.admin) - response = self.client.get(url) - self.assertLoginRedirect(response) - - self.login(self.customer_support) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) + response = self.assertStaffOnly(list_url) - self.login(self.superuser) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) self.assertContains(response, "Relayer Application APK") def test_create(self): - url = reverse("apks.apk_create") - - self.login(self.admin) - response = self.client.get(url) - self.assertLoginRedirect(response) + create_url = reverse("apks.apk_create") - self.login(self.customer_support) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - self.login(self.superuser) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) + self.assertStaffOnly(create_url) def test_update(self): - url = reverse("apks.apk_update", args=[self.apk.id]) - - response = self.client.get(url) - self.assertLoginRedirect(response) - - self.login(self.admin) - response = self.client.get(url) - self.assertLoginRedirect(response) + update_url = reverse("apks.apk_update", args=[self.apk.id]) - self.login(self.customer_support) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) + response = self.assertStaffOnly(update_url) - self.login(self.superuser) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) self.assertContains(response, "Relayer Application APK") diff --git a/temba/apks/views.py b/temba/apks/views.py index 3aae577261a..316c2b6a777 100644 --- a/temba/apks/views.py +++ b/temba/apks/views.py @@ -1,4 +1,6 @@ -from smartmin.views import SmartCreateView, SmartCRUDL, SmartListView +from smartmin.views import SmartCreateView, SmartCRUDL, SmartListView, SmartUpdateView + +from temba.utils.views import StaffOnlyMixin from .models import Apk @@ -8,10 +10,13 @@ class ApkCRUDL(SmartCRUDL): permissions = True actions = ("create", "update", "list") - class Create(SmartCreateView): + class Create(StaffOnlyMixin, SmartCreateView): fields = ("apk_type", "version", "pack", "apk_file", "description") - class List(SmartListView): + class Update(StaffOnlyMixin, SmartUpdateView): + pass + + class List(StaffOnlyMixin, SmartListView): fields = ("apk_type", "version", "pack", "apk_file", "created_on") def get_apk_type(self, obj): diff --git a/temba/campaigns/tests.py b/temba/campaigns/tests.py index 38008d9a924..275f9a481d2 100644 --- a/temba/campaigns/tests.py +++ b/temba/campaigns/tests.py @@ -667,6 +667,7 @@ def test_view_campaign_read_with_customer_support(self): campaign = Campaign.create(self.org, self.admin, "Perform the rain dance", self.farmers) response = self.client.get(reverse("campaigns.campaign_read", args=[campaign.uuid])) + self.assertEqual( [ { diff --git a/temba/channels/models.py b/temba/channels/models.py index 352f05e9aca..0a1fa928e22 100644 --- a/temba/channels/models.py +++ b/temba/channels/models.py @@ -1256,7 +1256,7 @@ def _get_display_value(self, user, original, mask, redact_keys=(), redact_values for secret_val in redact_values: original = redact.text(original, secret_val, mask) - if not self.channel.org.is_anon or user.has_org_perm(self.channel.org, "contacts.contact_break_anon"): + if not self.channel.org.is_anon or user.is_staff: return original # if this log doesn't have a msg then we don't know what to redact, so redact completely diff --git a/temba/channels/tests.py b/temba/channels/tests.py index b74dce4611f..ce53d8627fc 100644 --- a/temba/channels/tests.py +++ b/temba/channels/tests.py @@ -2186,7 +2186,7 @@ def test_redaction_for_telegram(self): with AnonymousOrg(self.org): response = self.client.get(read_url) # contact_urn is still masked on the read page, it uses contacts.models.Contact.get_display - # Contact.get_display does not check if user has `contacts.contact_break_anon` permission + # Contact.get_display does not check if user is staff self.assertContains(response, "3527065", count=2) self.assertContains(response, "Nic", count=2) self.assertContains(response, "Pottier", count=1) @@ -2347,7 +2347,7 @@ def test_redaction_for_twitter(self): with AnonymousOrg(self.org): response = self.client.get(read_url) # contact_urn is still masked on the read page, it uses contacts.models.Contact.get_display - # Contact.get_display does not check if user has `contacts.contact_break_anon` permission + # Contact.get_display does not check if user is staff self.assertContains(response, "767659860", count=4) self.assertContains(response, "Aaron Tumukunde", count=1) self.assertContains(response, "tumaaron", count=2) @@ -2463,7 +2463,7 @@ def test_redaction_for_facebook(self): with AnonymousOrg(self.org): response = self.client.get(read_url) # contact_urn is still masked on the read page, it uses contacts.models.Contact.get_display - # Contact.get_display does not check if user has `contacts.contact_break_anon` permission + # Contact.get_display does not check if user is staff self.assertContains(response, "2150393045080607", count=2) self.assertContains(response, "facebook:", count=1) @@ -2527,7 +2527,7 @@ def test_redaction_for_facebook_when_no_match(self): self.assertContains(response, "There is no contact identifying information", count=3) # contact_urn is still masked on the read page, it uses contacts.models.Contact.get_display - # Contact.get_display does not check if user has `contacts.contact_break_anon` permission + # Contact.get_display does not check if user is staff self.assertContains(response, HTTPLog.REDACT_MASK, count=1) def test_redaction_for_twilio(self): @@ -2595,7 +2595,7 @@ def test_redaction_for_twilio(self): with AnonymousOrg(self.org): response = self.client.get(read_url) # contact_urn is still masked on the read page, it uses contacts.models.Contact.get_display - # Contact.get_display does not check if user has `contacts.contact_break_anon` permission + # Contact.get_display does not check if user is staff self.assertContains(response, "097 909 9111", count=0) self.assertContains(response, "979099111", count=1) self.assertContains(response, "Quito", count=1) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 328fd64554b..cf7a1adfe31 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -11,7 +11,6 @@ from openpyxl import load_workbook from django.conf import settings -from django.contrib.auth.models import Group from django.db.models.functions import TruncDate from django.test.utils import override_settings from django.urls import reverse @@ -264,12 +263,7 @@ def test_editor(self): self.assertContains(response, "id='rp-flow-editor'") # customer service gets a service button - csrep = self.create_user("csrep") - csrep.groups.add(Group.objects.get(name="Customer Support")) - csrep.is_staff = True - csrep.save() - - self.login(csrep) + self.login(self.customer_support) response = self.client.get(reverse("flows.flow_editor", args=[flow.uuid])) self.assertContains(response, "Service") diff --git a/temba/flows/views.py b/temba/flows/views.py index 94ef3d52b9a..4a81cfa3a8e 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -62,7 +62,7 @@ TembaChoiceField, ) from temba.utils.text import slugify_with -from temba.utils.views import BulkActionMixin, ContentMenuMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ContentMenuMixin, SpaMixin, StaffOnlyMixin from .models import ( ExportFlowResultsTask, @@ -157,9 +157,8 @@ class FlowSessionCRUDL(SmartCRUDL): actions = ("json",) model = FlowSession - class Json(SmartReadView): + class Json(StaffOnlyMixin, SmartReadView): slug_url_kwarg = "uuid" - permission = "flows.flowsession_json" def get(self, request, *args, **kwargs): session = self.get_object() diff --git a/temba/msgs/views.py b/temba/msgs/views.py index fbf2758899f..4cc9eebae2f 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -50,7 +50,7 @@ TembaChoiceField, ) from temba.utils.models import patch_queryset_count -from temba.utils.views import BulkActionMixin, ComponentFormMixin, ContentMenuMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ComponentFormMixin, ContentMenuMixin, SpaMixin, StaffOnlyMixin from .models import Broadcast, ExportMessagesTask, Label, LabelCount, Media, Msg, Schedule, SystemLabel from .tasks import export_messages_task @@ -1011,5 +1011,5 @@ def post(self, request, *args, **kwargs): } ) - class List(OrgPermsMixin, SmartListView): + class List(StaffOnlyMixin, OrgPermsMixin, SmartListView): fields = ("name", "content_type", "size", "created_by", "created_on") diff --git a/temba/orgs/models.py b/temba/orgs/models.py index 5caa5d7cc25..e17e1b6c35a 100644 --- a/temba/orgs/models.py +++ b/temba/orgs/models.py @@ -243,10 +243,6 @@ def is_alpha(self) -> bool: def is_beta(self) -> bool: return self.groups.filter(name="Beta").exists() - @cached_property - def is_support(self) -> bool: - return self.groups.filter(name="Customer Support").exists() - def get_org(self): """ Gets the request org cached on the user. This should only be used where request.org can't be. @@ -260,13 +256,13 @@ def has_org_perm(self, org, permission: str) -> bool: """ Determines if a user has the given permission in the given org. """ - if self.is_superuser: + if self.is_staff: return True if self.is_anonymous: # pragma: needs cover return False - # has it innately? (e.g. customer support) + # has it innately? if self.has_perm(permission): return True @@ -1119,7 +1115,7 @@ def get_admins(self): def has_user(self, user: User) -> bool: """ - Returns whether the given user has a role in this org (only explicit roles, so doesn't include customer support) + Returns whether the given user has a role in this org (only explicit roles, so doesn't include staff) """ return self.users.filter(id=user.id).exists() diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 410b063a850..33b6c5b491f 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -124,7 +124,6 @@ def test_model(self): self.assertEqual("Jim McFlow", user.name) self.assertFalse(user.is_alpha) self.assertFalse(user.is_beta) - self.assertFalse(user.is_support) self.assertEqual({"email": "jim@rapidpro.io", "name": "Jim McFlow"}, user.as_engine_ref()) self.assertEqual([self.org, self.org2], list(user.get_orgs().order_by("id"))) self.assertEqual([], list(user.get_orgs(roles=[OrgRole.ADMINISTRATOR]).order_by("id"))) @@ -137,9 +136,6 @@ def test_model(self): self.assertEqual({"email": "jim@rapidpro.io", "name": "Jim"}, user.as_engine_ref()) def test_has_org_perm(self): - self.customer_support.is_staff = True - self.customer_support.save(update_fields=("is_staff",)) - tests = ( ( self.org, @@ -187,7 +183,7 @@ def test_has_org_perm(self): ), ( self.org, - "apks.apk_create", + "orgs.org_grant", { self.agent: False, self.user: False, @@ -204,7 +200,7 @@ def test_has_org_perm(self): self.user: False, self.admin: False, self.admin2: False, - self.customer_support: False, + self.customer_support: True, # staff have implicit all perm access }, ), ) @@ -4011,9 +4007,8 @@ def test_choose(self): response = self.client.get("/users/login/") self.assertContains(response, "No organizations for this account, please contact your administrator.") - # unless they are Customer Support - Group.objects.get(name="Customer Support").user_set.add(self.non_org_user) - self.assertRedirect(self.requestView(choose_url, self.non_org_user), "/org/manage/") + # unless they are staff + self.assertRedirect(self.requestView(choose_url, self.customer_support), "/org/manage/") # superusers are sent to the manage orgs page self.assertRedirect(self.requestView(choose_url, self.superuser), "/org/manage/") @@ -4339,27 +4334,21 @@ def test_login_case_not_sensitive(self): @mock_mailroom def test_org_service(self, mr_mocks): - # create a customer service user - self.csrep = self.create_user("csrep") - self.csrep.groups.add(Group.objects.get(name="Customer Support")) - self.csrep.is_staff = True - self.csrep.save() - service_url = reverse("orgs.org_service") # without logging in, try to service our main org response = self.client.post(service_url, dict(organization=self.org.id)) - self.assertRedirect(response, "/users/login/") + self.assertLoginRedirect(response) # try logging in with a normal user self.login(self.admin) # same thing, no permission response = self.client.post(service_url, dict(organization=self.org.id)) - self.assertRedirect(response, "/users/login/") + self.assertLoginRedirect(response) # ok, log in as our cs rep - self.login(self.csrep) + self.login(self.customer_support) # then service our org response = self.client.post(service_url, dict(organization=self.org.id)) @@ -4377,7 +4366,7 @@ def test_org_service(self, mr_mocks): # make sure that contact's created on is our cs rep contact = Contact.objects.get(urns__path="+250788123123", org=self.org) - self.assertEqual(self.csrep, contact.created_by) + self.assertEqual(self.customer_support, contact.created_by) # make sure we can manage topups as well TopUp.objects.create( diff --git a/temba/orgs/views.py b/temba/orgs/views.py index fbc86946ff5..d68ecee9f0d 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -73,7 +73,14 @@ ) from temba.utils.http import http_headers from temba.utils.timezones import TimeZoneFormField -from temba.utils.views import ComponentFormMixin, ContentMenuMixin, NonAtomicMixin, RequireRecentAuthMixin, SpaMixin +from temba.utils.views import ( + ComponentFormMixin, + ContentMenuMixin, + NonAtomicMixin, + RequireRecentAuthMixin, + SpaMixin, + StaffOnlyMixin, +) from .models import ( BackupToken, @@ -108,15 +115,6 @@ def check_login(request): return HttpResponseRedirect(settings.LOGIN_URL) -class StaffMixin: - """ - Views that only staff should be able to access - """ - - def has_permission(self, request, *args, **kwargs): - return self.request.user.is_staff - - class OrgPermsMixin: """ Get the organization and the user within the inheriting view so that it be come easy to decide @@ -164,7 +162,7 @@ def dispatch(self, request, *args, **kwargs): # non admin authenticated users without orgs get the org chooser user = self.get_user() - if user.is_authenticated and not (user.is_superuser or user.is_staff): + if user.is_authenticated and not user.is_staff: if not self.derive_org(): return HttpResponseRedirect(reverse("orgs.org_choose")) @@ -173,7 +171,7 @@ def dispatch(self, request, *args, **kwargs): class OrgFilterMixin: """ - Simple mixin to filter a view's queryset by the user's org + Simple mixin to filter a view's queryset by the request org """ def derive_queryset(self, *args, **kwargs): @@ -182,7 +180,7 @@ def derive_queryset(self, *args, **kwargs): if not self.request.user.is_authenticated: return queryset.none() # pragma: no cover else: - return queryset.filter(org=self.request.user.get_org()) + return queryset.filter(org=self.request.org) class AnonMixin(OrgPermsMixin): @@ -194,7 +192,7 @@ def has_permission(self, request, *args, **kwargs): org = self.derive_org() # can this user break anonymity? then we are fine - if self.get_user().has_perm("contacts.contact_break_anon"): + if self.request.user.is_staff: return True # otherwise if this org is anon, no go @@ -714,7 +712,7 @@ class UserCRUDL(SmartCRUDL): "account", ) - class List(StaffMixin, SpaMixin, SmartListView): + class List(StaffOnlyMixin, SpaMixin, SmartListView): fields = ("email", "name", "orgs", "date_joined") ordering = ("-date_joined",) search_fields = ("email", "first_name", "last_name") @@ -756,7 +754,7 @@ def get_context_data(self, **kwargs): context["filters"] = self.filters return context - class Update(StaffMixin, SpaMixin, ComponentFormMixin, ContentMenuMixin, SmartUpdateView): + class Update(StaffOnlyMixin, SpaMixin, ComponentFormMixin, ContentMenuMixin, SmartUpdateView): class Form(UserUpdateForm): groups = forms.ModelMultipleChoiceField( widget=SelectMultipleWidget( @@ -800,7 +798,7 @@ def post_save(self, obj): return obj - class Delete(StaffMixin, SpaMixin, ModalMixin, SmartDeleteView): + class Delete(StaffOnlyMixin, SpaMixin, ModalMixin, SmartDeleteView): fields = ("id",) permission = "orgs.user_update" submit_button_name = _("Delete") @@ -2019,7 +2017,7 @@ def get_context_data(self, **kwargs): context["from_email_custom"] = from_email_custom return context - class Read(StaffMixin, SpaMixin, ContentMenuMixin, SmartReadView): + class Read(StaffOnlyMixin, SpaMixin, ContentMenuMixin, SmartReadView): def build_content_menu(self, menu): if not self.object.is_active: return @@ -2079,7 +2077,7 @@ def get_context_data(self, **kwargs): return context - class Manage(StaffMixin, SpaMixin, SmartListView): + class Manage(StaffOnlyMixin, SpaMixin, SmartListView): fields = ("name", "owner", "created_on", "service") field_config = {"service": {"label": ""}} default_order = ("-credits", "-created_on") @@ -2168,7 +2166,7 @@ def lookup_field_link(self, context, field, obj): def get_created_by(self, obj): # pragma: needs cover return "%s %s - %s" % (obj.created_by.first_name, obj.created_by.last_name, obj.created_by.email) - class Update(StaffMixin, SpaMixin, ModalMixin, ComponentFormMixin, SmartUpdateView): + class Update(StaffOnlyMixin, SpaMixin, ModalMixin, ComponentFormMixin, SmartUpdateView): class Form(forms.ModelForm): parent = forms.IntegerField(required=False) plan_end = forms.DateTimeField(required=False) @@ -2259,7 +2257,7 @@ def pre_save(self, obj): obj.limits = cleaned_data["limits"] return obj - class Delete(StaffMixin, SpaMixin, ModalMixin, SmartDeleteView): + class Delete(StaffOnlyMixin, SpaMixin, ModalMixin, SmartDeleteView): cancel_url = "id@orgs.org_update" success_url = "id@orgs.org_update" fields = ("id",) @@ -2544,7 +2542,7 @@ def get_success_url(self): # pragma: needs cover org_id = self.request.GET.get("org") return "%s?org=%s" % (reverse("orgs.org_manage_accounts_sub_org"), org_id) - class Service(StaffMixin, SmartFormView): + class Service(StaffOnlyMixin, SmartFormView): class ServiceForm(forms.Form): organization = TembaChoiceField(queryset=Org.objects.all(), empty_label=None) redirect_url = forms.CharField(required=False) @@ -2717,7 +2715,7 @@ def pre_process(self, request, *args, **kwargs): return HttpResponseRedirect(self.get_success_url()) elif user_orgs.count() == 0: - if user.is_support: + if user.is_staff: return HttpResponseRedirect(reverse("orgs.org_manage")) # for regular users, if there's no orgs, log them out with a message @@ -3082,7 +3080,6 @@ class Grant(NonAtomicMixin, SmartCreateView): fields = ("first_name", "last_name", "email", "password", "name", "timezone", "credits") success_message = "Workspace successfully created." submit_button_name = _("Create") - permission = "orgs.org_grant" success_url = "@orgs.org_grant" def get_or_create_user(self, email, first_name, last_name, password, language): @@ -3878,7 +3875,7 @@ def get_template_names(self): else: return super().get_template_names() - class Create(ComponentFormMixin, SmartCreateView): + class Create(StaffOnlyMixin, ComponentFormMixin, SmartCreateView): """ This is only for root to be able to credit accounts. """ @@ -3897,7 +3894,7 @@ def post_save(self, obj): apply_topups_task.delay(obj.org.id) return obj - class Update(ComponentFormMixin, SmartUpdateView): + class Update(StaffOnlyMixin, ComponentFormMixin, SmartUpdateView): fields = ("is_active", "price", "credits", "expires_on") def get_success_url(self): @@ -3908,7 +3905,7 @@ def post_save(self, obj): apply_topups_task.delay(obj.org.id) return obj - class Manage(SpaMixin, SmartListView): + class Manage(StaffOnlyMixin, SpaMixin, SmartListView): """ This is only for root to be able to manage topups on an account """ diff --git a/temba/policies/views.py b/temba/policies/views.py index 7dec1a596ee..f63f3fdc82e 100644 --- a/temba/policies/views.py +++ b/temba/policies/views.py @@ -10,7 +10,7 @@ from temba.orgs.views import OrgPermsMixin from temba.utils import analytics -from temba.utils.views import ComponentFormMixin, ContentMenuMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin, StaffOnlyMixin from .models import Consent, Policy @@ -20,7 +20,7 @@ class PolicyCRUDL(SmartCRUDL): model = Policy permissions = True - class Admin(ContentMenuMixin, SmartListView): + class Admin(StaffOnlyMixin, ContentMenuMixin, SmartListView): ordering = ("-created_on",) link_fields = ("policy_type",) title = "Policies" @@ -38,10 +38,10 @@ def get_context_data(self, **kwargs): context["active_policies"] = Policy.objects.filter(is_active=True).order_by(*self.ordering) return context - class Update(ComponentFormMixin, SmartUpdateView): + class Update(StaffOnlyMixin, ComponentFormMixin, SmartUpdateView): pass - class Create(ComponentFormMixin, SmartCreateView): + class Create(StaffOnlyMixin, ComponentFormMixin, SmartCreateView): # make sure we only have one active policy at a time def post_save(self, obj): @@ -50,11 +50,11 @@ def post_save(self, obj): ) return obj - class History(SmartReadView): + class History(StaffOnlyMixin, SmartReadView): def derive_title(self): return self.get_object().get_policy_type_display() - class Read(History): + class Read(SmartReadView): permission = None @classmethod @@ -62,6 +62,9 @@ def derive_url_pattern(cls, path, action): archive_types = (choice[0] for choice in Policy.TYPE_CHOICES) return r"^%s/(%s)/$" % (path, "|".join(archive_types)) + def derive_title(self): + return self.get_object().get_policy_type_display() + def get_requested_policy_type(self): return self.request.path.split("/")[-2] diff --git a/temba/settings_common.py b/temba/settings_common.py index dd50e9a37b3..21845753fde 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -532,40 +532,13 @@ "orgs.org_spa", "orgs.org_surveyor", ), - "Granters": ("orgs.org_grant",), "Customer Support": ( - "apks.apk_create", - "apks.apk_list", - "apks.apk_update", - "campaigns.campaign_read", - "channels.channel_configuration", + "campaigns.campaign_read", # anywhere we allow servicing still needs these "channels.channel_read", - "channels.channellog_read", - "contacts.contact_break_anon", "contacts.contact_read", "flows.flow_editor", - "flows.flow_revisions", - "flows.flowrun_delete", - "flows.flowsession_json", - "msgs.media_list", - "notifications.log_list", - "orgs.org_dashboard", - "orgs.org_delete", - "orgs.org_grant", - "orgs.org_manage", - "orgs.org_service", - "orgs.org_spa", - "orgs.org_update", - "orgs.topup_create", - "orgs.topup_manage", - "orgs.topup_update", - "orgs.user_list", - "orgs.user_update", - "policies.policy_admin", - "policies.policy_create", - "policies.policy_history", - "policies.policy_update", ), + "Granters": ("orgs.org_grant",), "Administrators": ( "airtime.airtimetransfer_list", "airtime.airtimetransfer_read", diff --git a/temba/tests/base.py b/temba/tests/base.py index 0f706f42f50..004f503f783 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -60,9 +60,7 @@ def setUpOrgs(self): self.user = self.create_user("viewer@nyaruka.com") self.agent = self.create_user("agent@nyaruka.com", first_name="Agnes") self.surveyor = self.create_user("surveyor@nyaruka.com") - self.customer_support = self.create_user( - "support@nyaruka.com", group_names=("Customer Support",), is_staff=True - ) + self.customer_support = self.create_user("support@nyaruka.com", is_staff=True) self.org = Org.objects.create( name="Nyaruka", diff --git a/temba/tests/crudl.py b/temba/tests/crudl.py index c77ce6dd437..6439be8a6bf 100644 --- a/temba/tests/crudl.py +++ b/temba/tests/crudl.py @@ -225,7 +225,7 @@ def assertStaffOnly(self, url): self.requestView(url, admin, checks=[LoginRedirect()]) self.requestView(url, self.superuser, checks=[StatusCode(200)]) - self.requestView(url, self.customer_support, checks=[StatusCode(200)]) + return self.requestView(url, self.customer_support, checks=[StatusCode(200)]) class BaseCheck: diff --git a/temba/utils/management/commands/test_db.py b/temba/utils/management/commands/test_db.py index 13f56b7eba9..2479309028a 100644 --- a/temba/utils/management/commands/test_db.py +++ b/temba/utils/management/commands/test_db.py @@ -13,7 +13,6 @@ from django_redis import get_redis_connection from django.conf import settings -from django.contrib.auth.models import Group from django.core.management import BaseCommand, CommandError from django.db import connection from django.utils import timezone @@ -174,9 +173,7 @@ def handle_generate(self, num_orgs, num_contacts, seed, password): # create root user and a customer support user superuser = User.objects.create_superuser("root", "root@nyaruka.com", password) - - support = User.objects.create_user("support@nyaruka.com", "support@nyaruka.com", password, is_staff=True) - support.groups.add(Group.objects.get(name="Customer Support")) + User.objects.create_user("support@nyaruka.com", "support@nyaruka.com", password, is_staff=True) country, locations = self.load_locations(LOCATIONS_DUMP) orgs = self.create_orgs(superuser, country, num_orgs) diff --git a/temba/utils/views.py b/temba/utils/views.py index 02ec75e0dca..00365defd6a 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -96,6 +96,15 @@ def customize_form_field(self, name, field): return field +class StaffOnlyMixin: + """ + Views that only staff should be able to access + """ + + def has_permission(self, request, *args, **kwargs): + return self.request.user.is_staff + + class PostOnlyMixin(View): """ Utility mixin to make a class based view be POST only diff --git a/templates/msgs/message_box.haml b/templates/msgs/message_box.haml index 948085834d1..9893f3c6ed4 100644 --- a/templates/msgs/message_box.haml +++ b/templates/msgs/message_box.haml @@ -202,7 +202,7 @@ -block message_time {% short_datetime object.created_on %} - -if show_channel_logs and not user_org.is_anon or perms.contacts.contact_break_anon + -if show_channel_logs and not user_org.is_anon or user.is_staff .inline-block.text-gray-400.linked.ml-3 {% channel_log_link object %} diff --git a/templates/msgs/message_box_spa.haml b/templates/msgs/message_box_spa.haml index fe9ffbb1694..f5472458c68 100644 --- a/templates/msgs/message_box_spa.haml +++ b/templates/msgs/message_box_spa.haml @@ -52,7 +52,7 @@ -block message_time {% short_datetime object.created_on %} - -if show_channel_logs and not user_org.is_anon or perms.contacts.contact_break_anon + -if show_channel_logs and not user_org.is_anon or user.is_staff .inline-block.text-gray-400.linked.ml-3 {% channel_log_link object %} diff --git a/templates/msgs/msg_outbox.haml b/templates/msgs/msg_outbox.haml index 9e8c1d1f63d..42bd629aba8 100644 --- a/templates/msgs/msg_outbox.haml +++ b/templates/msgs/msg_outbox.haml @@ -44,7 +44,7 @@ %span.time {% short_datetime object.created_on %} - -if show_channel_logs and not user_org.is_anon or perms.contacts.contact_break_anon + -if show_channel_logs and not user_org.is_anon or user.is_staff .inline-block.text-gray-400.linked {% channel_log_link object %} diff --git a/templates/msgs/msg_outbox_spa.haml b/templates/msgs/msg_outbox_spa.haml index c5ba1335fa2..a703fd1069e 100644 --- a/templates/msgs/msg_outbox_spa.haml +++ b/templates/msgs/msg_outbox_spa.haml @@ -44,7 +44,7 @@ %span.time {% short_datetime object.created_on %} - -if show_channel_logs and not user_org.is_anon or perms.contacts.contact_break_anon + -if show_channel_logs and not user_org.is_anon or user.is_staff .inline-block.text-gray-400.linked {% channel_log_link object %} From a55f10ec9547cf5fb820231172964566c435dfbb Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 10:26:53 -0500 Subject: [PATCH 153/630] Remove unused policies.policy_read perm --- temba/settings_common.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/temba/settings_common.py b/temba/settings_common.py index 21845753fde..4435a62d72e 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -667,7 +667,6 @@ "orgs.topup_read", "policies.policy_give_consent", "policies.policy_list", - "policies.policy_read", "request_logs.httplog_list", "request_logs.httplog_read", "request_logs.httplog_webhooks", @@ -781,7 +780,6 @@ "orgs.topup_read", "policies.policy_give_consent", "policies.policy_list", - "policies.policy_read", "request_logs.httplog_webhooks", "schedules.schedule.*", "templates.template_api", @@ -871,7 +869,6 @@ "orgs.topup_read", "policies.policy_give_consent", "policies.policy_list", - "policies.policy_read", "tickets.ticketer_api", "tickets.topic_api", "triggers.trigger_archived", From 63ad8a7a97162ea0019666138f978e6e8c2c75bf Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 10:56:59 -0500 Subject: [PATCH 154/630] Test support user still needs to be in Customer Support group --- temba/settings_common.py | 1 + temba/tests/base.py | 4 +++- temba/utils/management/commands/test_db.py | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/temba/settings_common.py b/temba/settings_common.py index ce268f82503..6db384a8bc8 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -535,6 +535,7 @@ "Customer Support": ( "campaigns.campaign_read", # anywhere we allow servicing still needs these "channels.channel_read", + "channels.channellog_read", "contacts.contact_read", "flows.flow_editor", ), diff --git a/temba/tests/base.py b/temba/tests/base.py index 004f503f783..0f706f42f50 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -60,7 +60,9 @@ def setUpOrgs(self): self.user = self.create_user("viewer@nyaruka.com") self.agent = self.create_user("agent@nyaruka.com", first_name="Agnes") self.surveyor = self.create_user("surveyor@nyaruka.com") - self.customer_support = self.create_user("support@nyaruka.com", is_staff=True) + self.customer_support = self.create_user( + "support@nyaruka.com", group_names=("Customer Support",), is_staff=True + ) self.org = Org.objects.create( name="Nyaruka", diff --git a/temba/utils/management/commands/test_db.py b/temba/utils/management/commands/test_db.py index 2479309028a..d32952b655f 100644 --- a/temba/utils/management/commands/test_db.py +++ b/temba/utils/management/commands/test_db.py @@ -13,6 +13,7 @@ from django_redis import get_redis_connection from django.conf import settings +from django.contrib.auth.models import Group from django.core.management import BaseCommand, CommandError from django.db import connection from django.utils import timezone @@ -173,7 +174,8 @@ def handle_generate(self, num_orgs, num_contacts, seed, password): # create root user and a customer support user superuser = User.objects.create_superuser("root", "root@nyaruka.com", password) - User.objects.create_user("support@nyaruka.com", "support@nyaruka.com", password, is_staff=True) + support = User.objects.create_user("support@nyaruka.com", "support@nyaruka.com", password, is_staff=True) + support.groups.add(Group.objects.get(name="Customer Support")) country, locations = self.load_locations(LOCATIONS_DUMP) orgs = self.create_orgs(superuser, country, num_orgs) From e509e30405d5be5c8be0e01beb715bd4c113dfe8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 11:46:16 -0500 Subject: [PATCH 155/630] Fix missing coverage and remove another unused policy perm --- temba/orgs/models.py | 2 +- temba/orgs/tests.py | 14 +++++++++ temba/orgs/views.py | 2 +- temba/policies/tests.py | 63 +++++++++++++++++++--------------------- temba/settings_common.py | 3 -- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/temba/orgs/models.py b/temba/orgs/models.py index e17e1b6c35a..a18fc3c0179 100644 --- a/temba/orgs/models.py +++ b/temba/orgs/models.py @@ -262,7 +262,7 @@ def has_org_perm(self, org, permission: str) -> bool: if self.is_anonymous: # pragma: needs cover return False - # has it innately? + # has it innately? e.g. Granter group if self.has_perm(permission): return True diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 33b6c5b491f..4032f6ab7e5 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -136,6 +136,8 @@ def test_model(self): self.assertEqual({"email": "jim@rapidpro.io", "name": "Jim"}, user.as_engine_ref()) def test_has_org_perm(self): + granter = self.create_user("jim@rapidpro.io", group_names=("Granters",)) + tests = ( ( self.org, @@ -159,6 +161,17 @@ def test_has_org_perm(self): self.customer_support: True, }, ), + ( + self.org2, + "contacts.contact_read", + { + self.agent: False, + self.user: False, + self.admin: False, + self.admin2: True, + self.customer_support: True, # needed for servicing + }, + ), ( self.org, "orgs.org_edit", @@ -190,6 +203,7 @@ def test_has_org_perm(self): self.admin: False, self.admin2: False, self.customer_support: True, + granter: True, }, ), ( diff --git a/temba/orgs/views.py b/temba/orgs/views.py index d68ecee9f0d..a6fe396e8ea 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -2045,7 +2045,7 @@ def build_content_menu(self, menu): if not self.object.is_verified(): menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=verify") - if self.request.user.has_perm("orgs.org_delete"): + if self.request.user.is_staff: menu.add_modax( _("Delete"), "delete-org", diff --git a/temba/policies/tests.py b/temba/policies/tests.py index 117343ee866..6648a703346 100644 --- a/temba/policies/tests.py +++ b/temba/policies/tests.py @@ -1,15 +1,15 @@ from django.urls import reverse -from temba.tests import TembaTest +from temba.tests import CRUDLTestMixin, TembaTest from .models import Policy -class PolicyViewTest(TembaTest): +class PolicyCRUDLTest(CRUDLTestMixin, TembaTest): def setUp(self): super().setUp() - Policy.objects.create( + self.privacy = Policy.objects.create( policy_type=Policy.TYPE_PRIVACY, body="Privacy matters", summary="Summary", @@ -36,65 +36,62 @@ def setUp(self): modified_by=self.admin, ) - def test_policy_list(self): + def test_list(self): + list_url = reverse("policies.policy_list") - # non logged in users can visit - response = self.client.get(reverse("policies.policy_list")) + # anybody including non-logged-in users can list our policies + response = self.client.get(list_url) self.assertEqual(3, response.context["object_list"].count()) self.assertNotIn("needs_consent", response.context) # logged in users consent details for the two that require it self.login(self.admin) - response = self.client.get(reverse("policies.policy_list")) + response = self.client.get(list_url) self.assertEqual(3, response.context["object_list"].count()) self.assertEqual(2, response.context["needs_consent"].count()) self.assertNotIn("consent_date", response.context) # give our consent self.client.post(reverse("policies.policy_give_consent"), dict(consent=True)) - response = self.client.get(reverse("policies.policy_list")) + response = self.client.get(list_url) self.assertEqual(0, response.context["needs_consent"].count()) self.assertIsNotNone(response.context["consent_date"]) # now revoke it self.client.post(reverse("policies.policy_give_consent"), dict(consent=False)) - response = self.client.get(reverse("policies.policy_list")) + response = self.client.get(list_url) self.assertEqual(2, response.context["needs_consent"].count()) self.assertNotIn("consent_date", response.context) def test_read(self): - # anybody can read our policies - response = self.client.get(reverse("policies.policy_read", args=["privacy"])) + privacy_url = reverse("policies.policy_read", args=["privacy"]) + + # anybody including non-logged-in users can read our policies + response = self.client.get(privacy_url) self.assertContains(response, "Privacy matters") - def test_admin(self): + def test_history(self): + privacy_url = reverse("policies.policy_history", args=[self.privacy.id]) - # have to be logged in - response = self.client.get(reverse("policies.policy_admin")) - self.assertRedirect(response, reverse("users.user_login")) + self.assertStaffOnly(privacy_url) - # logged in admins cant see it either - self.login(self.admin) - response = self.client.get(reverse("policies.policy_admin")) - self.assertRedirect(response, reverse("users.user_login")) + def test_admin(self): + admin_url = reverse("policies.policy_admin") - # but customer service users can manage policies - self.login(self.customer_support) - response = self.client.get(reverse("policies.policy_admin")) - self.assertEqual(200, response.status_code) + response = self.assertStaffOnly(admin_url) self.assertEqual(3, response.context["active_policies"].count()) # publishing a new policy should deactivate the previous one - post_data = dict( - policy_type="privacy", body="My privacy policy update", summary="the summary", requires_consent=True + self.client.post( + reverse("policies.policy_create"), + { + "policy_type": "privacy", + "body": "My privacy policy update", + "summary": "the summary", + "requires_consent": True, + }, ) - self.client.post(reverse("policies.policy_create"), post_data) - response = self.client.get(reverse("policies.policy_admin")) + + response = self.client.get(admin_url) self.assertEqual(3, response.context["active_policies"].count()) self.assertEqual(1, response.context["object_list"].count()) - - # def test_consent_middleware(self): - # middleware should reroute to ask for consent - # self.login(self.admin) - # response = self.client.get(reverse('msgs.msg_inbox')) - # self.assertRedirect(response, reverse('policies.policy_list')) diff --git a/temba/settings_common.py b/temba/settings_common.py index 6db384a8bc8..675d46d1860 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -666,7 +666,6 @@ "orgs.topup_list", "orgs.topup_read", "policies.policy_give_consent", - "policies.policy_list", "request_logs.httplog_list", "request_logs.httplog_read", "request_logs.httplog_webhooks", @@ -779,7 +778,6 @@ "orgs.topup_list", "orgs.topup_read", "policies.policy_give_consent", - "policies.policy_list", "request_logs.httplog_webhooks", "schedules.schedule.*", "templates.template_api", @@ -868,7 +866,6 @@ "orgs.topup_list", "orgs.topup_read", "policies.policy_give_consent", - "policies.policy_list", "tickets.ticketer_api", "tickets.topic_api", "triggers.trigger_archived", From b2cd4278102c9739d3ba34b5460f2ec944b658f7 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 14:27:13 -0500 Subject: [PATCH 156/630] Add new fields to channel log model and start reading from them if they're set --- ...g_elapsed_ms_channellog_errors_and_more.py | 45 +++++ temba/channels/models.py | 119 +++++++---- temba/channels/tests.py | 184 +++++++++++++++++- temba/channels/views.py | 6 +- temba/request_logs/models.py | 2 +- templates/channels/channellog.haml | 11 ++ templates/channels/channellog_group_base.haml | 6 +- templates/channels/channellog_read.haml | 5 +- templates/includes/http_log.haml | 4 +- 9 files changed, 335 insertions(+), 47 deletions(-) create mode 100644 temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py create mode 100644 templates/channels/channellog.haml diff --git a/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py b/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py new file mode 100644 index 00000000000..bb4074143c4 --- /dev/null +++ b/temba/channels/migrations/0140_channellog_elapsed_ms_channellog_errors_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.0.7 on 2022-08-17 15:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("channels", "0139_channel_is_system"), + ] + + operations = [ + migrations.AddField( + model_name="channellog", + name="elapsed_ms", + field=models.IntegerField(null=True), + ), + migrations.AddField( + model_name="channellog", + name="errors", + field=models.JSONField(null=True), + ), + migrations.AddField( + model_name="channellog", + name="http_logs", + field=models.JSONField(null=True), + ), + migrations.AddField( + model_name="channellog", + name="log_type", + field=models.CharField( + choices=[ + ("msg_send", "Message Send"), + ("msg_update", "Message Update"), + ("msg_receive", "Message Receive"), + ("ivr_start", "IVR Start"), + ("ivr_callback", "IVR Callback"), + ("contact_update", "Contact Update"), + ("token_refresh", "Token Refresh"), + ], + max_length=16, + null=True, + ), + ), + ] diff --git a/temba/channels/models.py b/temba/channels/models.py index dc576e92b49..6152b90b381 100644 --- a/temba/channels/models.py +++ b/temba/channels/models.py @@ -1185,20 +1185,44 @@ class ChannelLog(models.Model): A log of an interaction with a channel """ + LOG_TYPE_MSG_SEND = "msg_send" + LOG_TYPE_MSG_UPDATE = "msg_update" + LOG_TYPE_MSG_RECEIVE = "msg_receive" + LOG_TYPE_IVR_START = "ivr_start" + LOG_TYPE_IVR_CALLBACK = "ivr_callback" + LOG_TYPE_CONTACT_UPDATE = "contact_update" + LOG_TYPE_TOKEN_REFRESH = "token_refresh" + LOG_TYPE_CHOICES = ( + (LOG_TYPE_MSG_SEND, _("Message Send")), + (LOG_TYPE_MSG_UPDATE, _("Message Update")), + (LOG_TYPE_MSG_RECEIVE, _("Message Receive")), + (LOG_TYPE_IVR_START, _("IVR Start")), + (LOG_TYPE_IVR_CALLBACK, _("IVR Callback")), + (LOG_TYPE_CONTACT_UPDATE, _("Contact Update")), + (LOG_TYPE_TOKEN_REFRESH, _("Token Refresh")), + ) + id = models.BigAutoField(primary_key=True) channel = models.ForeignKey(Channel, on_delete=models.PROTECT, related_name="logs") msg = models.ForeignKey("msgs.Msg", on_delete=models.PROTECT, related_name="channel_logs", null=True) connection = models.ForeignKey( "channels.ChannelConnection", on_delete=models.PROTECT, related_name="channel_logs", null=True ) - description = models.CharField(max_length=255) + + log_type = models.CharField(max_length=16, choices=LOG_TYPE_CHOICES, null=True) + http_logs = models.JSONField(null=True) + errors = models.JSONField(null=True) is_error = models.BooleanField(default=False) + elapsed_ms = models.IntegerField(null=True) + created_on = models.DateTimeField(default=timezone.now) + + # TODO deprecated + description = models.CharField(max_length=255) url = models.TextField(null=True) method = models.CharField(max_length=16, null=True) request = models.TextField(null=True) response = models.TextField(null=True) response_status = models.IntegerField(null=True) - created_on = models.DateTimeField(default=timezone.now) request_time = models.IntegerField(null=True) @classmethod @@ -1218,32 +1242,6 @@ def log_channel_request(cls, channel_id, description, event, start, is_error=Fal request_time=request_time_ms, ) - def _get_url_display(self, user, value): - """ - Gets the URL as it should be displayed to the given user - """ - redact_values = Channel.get_type_from_code(self.channel.channel_type).redact_values - - return self._get_display_value(user, value, redact_values=redact_values) - - def _get_request_display(self, user, value): - """ - Gets the request trace as it should be displayed to the given user - """ - redact_keys = Channel.get_type_from_code(self.channel.channel_type).redact_request_keys - redact_values = Channel.get_type_from_code(self.channel.channel_type).redact_values - - return self._get_display_value(user, value, redact_keys=redact_keys, redact_values=redact_values) - - def _get_response_display(self, user, value): - """ - Gets the response trace as it should be displayed to the given user - """ - redact_keys = Channel.get_type_from_code(self.channel.channel_type).redact_response_keys - redact_values = Channel.get_type_from_code(self.channel.channel_type).redact_values - - return self._get_display_value(user, value, redact_keys=redact_keys, redact_values=redact_values) - def _get_display_value(self, user, original, redact_keys=(), redact_values=()): """ Get a part of the log which may or may not have to be redacted to hide sensitive information in anon orgs @@ -1275,16 +1273,69 @@ def _get_display_value(self, user, original, redact_keys=(), redact_values=()): return redacted def get_display(self, user) -> dict: + redact_values = self.channel.type.redact_values + redact_request_keys = self.channel.type.redact_request_keys + redact_response_keys = self.channel.type.redact_response_keys + + http_logs, errors = self._get_logs_and_errors() + + def redact_http(log: dict) -> dict: + return { + "url": self._get_display_value(user, log["url"], redact_values=redact_values), + "status_code": log["status_code"], + "request": self._get_display_value( + user, log["request"], redact_keys=redact_request_keys, redact_values=redact_values + ), + "response": self._get_display_value( + user, log["response"], redact_keys=redact_response_keys, redact_values=redact_values + ), + "elapsed_ms": log["elapsed_ms"], + "retries": log["retries"], + "created_on": log["created_on"], + } + + def redact_error(err: dict) -> dict: + return { + "message": self._get_display_value(user, err["message"], redact_values=redact_values), + "code": err["code"], + } + return { - "url": self._get_url_display(user, self.url), - "status_code": self.response_status or 0, - "request": self._get_request_display(user, self.request), - "response": self._get_response_display(user, self.response), - "elapsed_ms": self.request_time, - "retries": 0, + "description": self.get_description(), + "http_logs": [redact_http(h) for h in http_logs], + "errors": [redact_error(e) for e in errors], "created_on": self.created_on, } + def get_description(self) -> str: + return self.description or self.get_log_type_display() + + def _get_logs_and_errors(self) -> tuple: + # if this is a legacy style log, create from deprecated fields + if not self.http_logs and not self.errors: + # legacy logs append error messages to response traces + resp_parts = self.response.split("\n\nError: ", maxsplit=2) + response, error = resp_parts if len(resp_parts) == 2 else (resp_parts[0], None) + logs = [] + if self.request: + logs.append( + { + "url": self.url, + "status_code": self.response_status or 0, + "request": self.request, + "response": response, + "elapsed_ms": self.request_time, + "retries": 0, + "created_on": self.created_on.isoformat(), + } + ) + return ( + logs, + [{"message": error, "code": ""}] if error else [], + ) + + return self.http_logs or [], self.errors or [] + class Meta: indexes = [ models.Index( diff --git a/temba/channels/tests.py b/temba/channels/tests.py index 3c0e91b75ed..40920cbd165 100644 --- a/temba/channels/tests.py +++ b/temba/channels/tests.py @@ -1951,6 +1951,188 @@ def test_daily_counts(self): class ChannelLogTest(TembaTest): + def test_get_display_success_legacy(self): + channel = self.create_channel("TG", "Telegram", "mybot") + contact = self.create_contact("Fred Jones", urns=["telegram:74747474"]) + msg_out = self.create_outgoing_msg(contact, "Working", channel=channel, status="S") + log = ChannelLog.objects.create( + channel=channel, + msg=msg_out, + description="Message Sent", + is_error=False, + url="https://telegram.com/send?to=74747474", + response_status=200, + request='POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + response='HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}', + request_time=263, + ) + + expected_unredacted = { + "description": "Message Sent", + "http_logs": [ + { + "url": "https://telegram.com/send?to=74747474", + "status_code": 200, + "request": 'POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": matchers.ISODate(), + } + ], + "errors": [], + "created_on": matchers.Datetime(), + } + + expected_redacted = { + "description": "Message Sent", + "http_logs": [ + { + "url": "https://telegram.com/send?to=********", + "status_code": 200, + "request": 'POST https://telegram.com/send?to=******** HTTP/1.1\r\n\r\n{"to":"********"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to": "********", "first_name": "********"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": matchers.ISODate(), + } + ], + "errors": [], + "created_on": matchers.Datetime(), + } + + self.assertEqual(expected_unredacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + with AnonymousOrg(self.org): + self.assertEqual(expected_redacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + def test_get_display_error_legacy(self): + channel = self.create_channel("TG", "Telegram", "mybot") + contact = self.create_contact("Fred Jones", urns=["telegram:74747474"]) + msg_out = self.create_outgoing_msg(contact, "Working", channel=channel, status="S") + log = ChannelLog.objects.create( + channel=channel, + msg=msg_out, + description="Message Send Error", + is_error=True, + url="https://telegram.com/send?to=74747474", + response_status=400, + request='POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + response='HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}\n\nError: response not right', + request_time=263, + ) + + expected_unredacted = { + "description": "Message Send Error", + "http_logs": [ + { + "url": "https://telegram.com/send?to=74747474", + "status_code": 400, + "request": 'POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": matchers.ISODate(), + } + ], + "errors": [{"message": "response not right", "code": ""}], + "created_on": matchers.Datetime(), + } + + expected_redacted = { + "description": "Message Send Error", + "http_logs": [ + { + "url": "https://telegram.com/send?to=********", + "status_code": 400, + "request": 'POST https://telegram.com/send?to=******** HTTP/1.1\r\n\r\n{"to":"********"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to": "********", "first_name": "********"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": matchers.ISODate(), + } + ], + "errors": [{"message": "response n********", "code": ""}], + "created_on": matchers.Datetime(), + } + + self.assertEqual(expected_unredacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + with AnonymousOrg(self.org): + self.assertEqual(expected_redacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + def test_get_display_error(self): + channel = self.create_channel("TG", "Telegram", "mybot") + contact = self.create_contact("Fred Jones", urns=["telegram:74747474"]) + msg_out = self.create_outgoing_msg(contact, "Working", channel=channel, status="S") + log = ChannelLog.objects.create( + channel=channel, + msg=msg_out, + log_type=ChannelLog.LOG_TYPE_MSG_SEND, + is_error=True, + http_logs=[ + { + "url": "https://telegram.com/send?to=74747474", + "status_code": 400, + "request": 'POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": "2022-08-17T14:07:30Z", + } + ], + errors=[{"message": "response not right", "code": ""}], + ) + + expected_unredacted = { + "description": "Message Send", + "http_logs": [ + { + "url": "https://telegram.com/send?to=74747474", + "status_code": 400, + "request": 'POST https://telegram.com/send?to=74747474 HTTP/1.1\r\n\r\n{"to":"74747474"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to":"74747474","first_name":"Fred"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": "2022-08-17T14:07:30Z", + } + ], + "errors": [{"message": "response not right", "code": ""}], + "created_on": matchers.Datetime(), + } + + expected_redacted = { + "description": "Message Send", + "http_logs": [ + { + "url": "https://telegram.com/send?to=********", + "status_code": 400, + "request": 'POST https://telegram.com/send?to=******** HTTP/1.1\r\n\r\n{"to":"********"}', + "response": 'HTTP/2.0 200 OK\r\n\r\n{"to": "********", "first_name": "********"}', + "elapsed_ms": 263, + "retries": 0, + "created_on": "2022-08-17T14:07:30Z", + } + ], + "errors": [{"message": "response n********", "code": ""}], + "created_on": matchers.Datetime(), + } + + self.maxDiff = None + + self.assertEqual(expected_unredacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + with AnonymousOrg(self.org): + self.assertEqual(expected_redacted, log.get_display(self.admin)) + self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) + + +class ChannelLogCRUDLTest(TembaTest): def test_views(self): self.channel.role = "CASR" self.channel.save(update_fields=("role",)) @@ -2682,7 +2864,7 @@ def test_channellog_anonymous_org_no_msg(self): self.assertContains(response, tw_urn, count=0) # when we can't identify the contact, url, request and response objects are completely masked - self.assertContains(response, HTTPLog.REDACT_MASK, count=3) + self.assertContains(response, HTTPLog.REDACT_MASK, count=4) def test_trim_task(self): contact = self.create_contact("Fred Jones", phone="12345") diff --git a/temba/channels/views.py b/temba/channels/views.py index a9f76cb7cc1..df8bcf79f23 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1536,7 +1536,7 @@ def get_object_org(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["http_logs"] = [self.object.get_display(self.request.user)] + context["log"] = self.object.get_display(self.request.user) return context class Msg(SpaMixin, OrgPermsMixin, ContentMenuMixin, SmartListView): @@ -1563,7 +1563,7 @@ def derive_queryset(self, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["msg"] = self.msg - context["http_logs"] = [log.get_display(self.request.user) for log in context["object_list"]] + context["logs"] = [log.get_display(self.request.user) for log in context["object_list"]] return context class Call(AnonMixin, ContentMenuMixin, SmartListView): @@ -1590,5 +1590,5 @@ def build_content_menu(self, menu): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["call"] = self.call - context["http_logs"] = [log.get_display(self.request.user) for log in context["object_list"]] + context["logs"] = [log.get_display(self.request.user) for log in context["object_list"]] return context diff --git a/temba/request_logs/models.py b/temba/request_logs/models.py index 0e69e7a92ac..af4ac842743 100644 --- a/temba/request_logs/models.py +++ b/temba/request_logs/models.py @@ -167,7 +167,7 @@ def get_display(self) -> dict: "response": self._get_display_value(self.response or ""), "elapsed_ms": self.request_time, "retries": self.num_retries, - "created_on": self.created_on, + "created_on": self.created_on.isoformat(), } class Meta: diff --git a/templates/channels/channellog.haml b/templates/channels/channellog.haml new file mode 100644 index 00000000000..2f9add93b94 --- /dev/null +++ b/templates/channels/channellog.haml @@ -0,0 +1,11 @@ +-for http_log in log.http_logs + -include "includes/http_log.haml" with log=http_log +-if log.errors + %table.list.mb-8 + %tbody + -for err in log.errors + %tr.border-b.warning + %td(width="32") + .icon-warning + %td + {{ err.message }} \ No newline at end of file diff --git a/templates/channels/channellog_group_base.haml b/templates/channels/channellog_group_base.haml index 5aa0d25efdb..a5e50372213 100644 --- a/templates/channels/channellog_group_base.haml +++ b/templates/channels/channellog_group_base.haml @@ -5,8 +5,8 @@ .card.flex.mt-0.flex-shrink-0 -block group_object - -for log in http_logs - -include "includes/http_log.haml" with log=log + -for log in logs + -include "channels/channellog.haml" with log=log -block extra-script {{ block.super }} @@ -46,7 +46,7 @@ -compress css inline {% lessblock %} :plain - table.list { + table.http-log { tbody { tr:first-child { td { diff --git a/templates/channels/channellog_read.haml b/templates/channels/channellog_read.haml index 79e1d5bcc91..4068863c97b 100644 --- a/templates/channels/channellog_read.haml +++ b/templates/channels/channellog_read.haml @@ -11,8 +11,7 @@ {{ object.channel.get_channel_type_display }} -block content - -for log in http_logs - -include "includes/http_log.haml" with log=log + -include "channels/channellog.haml" with log=log -block extra-script {{ block.super }} @@ -52,7 +51,7 @@ -compress css inline {% lessblock %} :plain - table.list { + table.http-log { tbody { tr:first-child { td { diff --git a/templates/includes/http_log.haml b/templates/includes/http_log.haml index 46c80ca8cb4..dd6634ecdcd 100644 --- a/templates/includes/http_log.haml +++ b/templates/includes/http_log.haml @@ -1,6 +1,6 @@ -load i18n humanize temba -%table.list +%table.list.http-log.mb-8 %tbody %tr.border-b(class="{% if log.status_code < 200 or log.status_code >= 400 or log.elapsed_ms > 5000 %}warning{% endif %}") %td(style="width: 30px;") @@ -19,7 +19,7 @@ ({{ log.retries }} retries) %td .text-right.whitespace-nowrap - {% format_datetime log.created_on seconds=True %} + {% format_datetime log.created_on|parse_isodate seconds=True %} %tr %td(colspan="99" style="padding:0;") %pre.prettyprint.request< From dcd2a4c72c3ed5bb2c3a66da7924a232b1c6125b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 17 Aug 2022 20:16:56 -0500 Subject: [PATCH 157/630] Allow views with ContentMenuMixin to be fetched as JSON menu items using a header --- temba/contacts/tests.py | 23 +++++++----- temba/contacts/views.py | 34 +++++++++--------- temba/orgs/tests.py | 80 ++++++++++++++++------------------------- temba/orgs/views.py | 21 +++++------ temba/tests/base.py | 13 ------- temba/tests/crudl.py | 24 ++++++++++--- temba/utils/views.py | 13 +++++-- 7 files changed, 103 insertions(+), 105 deletions(-) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 7f7bff23289..7f209b1c710 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -476,26 +476,33 @@ def test_read(self, mr_mocks): response = self.client.get(read_url) self.assertLoginRedirect(response) + self.assertContentMenu(read_url, self.user, []) + self.assertContentMenu( + read_url, + self.editor, + ["Send Message", "Start Flow", "Open Ticket", "Edit", "Custom Fields", "Block", "Archive"], + ) + self.assertContentMenu( + read_url, + self.admin, + ["Send Message", "Start Flow", "Open Ticket", "Edit", "Custom Fields", "Block", "Archive"], + ) + # login as viewer self.login(self.user) response = self.client.get(read_url) self.assertContains(response, "Joe") - # make sure the block link is not present - self.assertNotContains(response, block_url) - # login as admin self.login(self.admin) - # make sure the block link is present now - response = self.client.get(read_url) - self.assertContains(response, block_url) - - # and that it works + # block the contact self.client.post(block_url, dict(id=joe.id)) self.assertTrue(Contact.objects.get(pk=joe.id, status="B")) + self.assertContentMenu(read_url, self.admin, ["Edit", "Custom Fields", "Activate", "Archive"]) + # try unblocking now response = self.client.get(read_url) restore_url = reverse("contacts.contact_restore", args=[joe.id]) diff --git a/temba/contacts/views.py b/temba/contacts/views.py index d436ac5e343..36b6c31b09c 100644 --- a/temba/contacts/views.py +++ b/temba/contacts/views.py @@ -864,30 +864,30 @@ def post(self, request, *args, **kwargs): return HttpResponse("unknown action", status=400) # pragma: no cover def build_content_menu(self, menu): - if self.object.status == Contact.STATUS_ACTIVE: + obj = self.get_object() + + if obj.status == Contact.STATUS_ACTIVE: if not self.is_spa() and self.has_org_perm("msgs.broadcast_send"): menu.add_modax( _("Send Message"), "send-message", - f"{reverse('msgs.broadcast_send')}?c={self.object.uuid}", + f"{reverse('msgs.broadcast_send')}?c={obj.uuid}", primary=True, ) if self.has_org_perm("flows.flow_broadcast"): - menu.add_modax( - _("Start Flow"), "start-flow", f"{reverse('flows.flow_broadcast')}?c={self.object.uuid}" - ) + menu.add_modax(_("Start Flow"), "start-flow", f"{reverse('flows.flow_broadcast')}?c={obj.uuid}") if self.has_org_perm("contacts.contact_open_ticket"): menu.add_modax( - _("Open Ticket"), "open-ticket", reverse("contacts.contact_open_ticket", args=[self.object.id]) + _("Open Ticket"), "open-ticket", reverse("contacts.contact_open_ticket", args=[obj.id]) ) - if self.has_org_perm("contacts.contact_interrupt") and self.object.current_flow: - menu.add_url_post(_("Interrupt"), reverse("contacts.contact_interrupt", args=(self.object.id,))) + if self.has_org_perm("contacts.contact_interrupt") and obj.current_flow: + menu.add_url_post(_("Interrupt"), reverse("contacts.contact_interrupt", args=(obj.id,))) if self.has_org_perm("contacts.contact_update"): menu.add_modax( _("Edit"), "edit-contact", - f"{reverse('contacts.contact_update', args=[self.object.id])}", + f"{reverse('contacts.contact_update', args=[obj.id])}", title=_("Edit Contact"), on_submit="contactUpdated()", ) @@ -896,21 +896,21 @@ def build_content_menu(self, menu): menu.add_modax( _("Custom Fields"), "update-custom-fields", - f"{reverse('contacts.contact_update_fields', args=[self.object.id])}", + f"{reverse('contacts.contact_update_fields', args=[obj.id])}", on_submit="contactUpdated()", ) - if self.object.status != Contact.STATUS_ACTIVE and self.has_org_perm("contacts.contact_restore"): - menu.add_url_post(_("Activate"), reverse("contacts.contact_restore", args=(self.object.id,))) - if self.object.status != Contact.STATUS_BLOCKED and self.has_org_perm("contacts.contact_block"): - menu.add_url_post(_("Block"), reverse("contacts.contact_block", args=(self.object.id,))) - if self.object.status != Contact.STATUS_ARCHIVED and self.has_org_perm("contacts.contact_archive"): - menu.add_url_post(_("Archive"), reverse("contacts.contact_archive", args=(self.object.id,))) + if obj.status != Contact.STATUS_ACTIVE and self.has_org_perm("contacts.contact_restore"): + menu.add_url_post(_("Activate"), reverse("contacts.contact_restore", args=(obj.id,))) + if obj.status != Contact.STATUS_BLOCKED and self.has_org_perm("contacts.contact_block"): + menu.add_url_post(_("Block"), reverse("contacts.contact_block", args=(obj.id,))) + if obj.status != Contact.STATUS_ARCHIVED and self.has_org_perm("contacts.contact_archive"): + menu.add_url_post(_("Archive"), reverse("contacts.contact_archive", args=(obj.id,))) if self.request.user.is_superuser or self.request.user.is_staff: menu.add_url_post( _("Service"), - f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("contacts.contact_read", args=[self.object.uuid])}', + f'{reverse("orgs.org_service")}?organization={obj.org_id}&redirect_url={reverse("contacts.contact_read", args=[obj.uuid])}', ) class Scheduled(OrgObjPermsMixin, SmartReadView): diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 410b063a850..86d60a26ac4 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -3525,6 +3525,36 @@ def test_menu(self): self.assertEqual("Workspaces", menu[0]["name"]) self.assertEqual("Users", menu[1]["name"]) + def test_read(self): + read_url = reverse("orgs.org_read", args=[self.org.id]) + + # make our second org a child + self.org2.parent = self.org + self.org2.save() + + response = self.assertStaffOnly(read_url) + + # we should have a child in our context + self.assertEqual(1, len(response.context["children"])) + + # we should have an option to flag + self.assertContentMenu( + read_url, self.customer_support, ["Service", "Edit", "Topups", "Flag", "Verify", "Delete"] + ) + + # flag and content menu option should be inverted + self.org.flag() + response = self.client.get(read_url) + self.assertContentMenu( + read_url, self.customer_support, ["Service", "Edit", "Topups", "Unflag", "Verify", "Delete"] + ) + + # no menu for inactive orgs + self.org.is_active = False + self.org.save() + response = self.client.get(read_url) + self.assertEquals([], response.context["content_menu"]) + def test_workspace(self): response = self.assertListFetch( reverse("orgs.org_workspace"), allow_viewers=True, allow_editors=True, allow_agents=False @@ -5703,53 +5733,3 @@ def test_model(self): self.assertEqual(10, len(new_admin_tokens)) self.assertNotEqual([t.token for t in admin_tokens], [t.token for t in new_admin_tokens]) self.assertEqual(10, self.admin.backup_tokens.count()) - - -class TestSpa(TembaTest): - def test_menu(self): - - # our admin gets a full menu - self.login(self.admin) - response = self.client.get(reverse("orgs.org_menu")) - self.assertGreater(len(response.json()["results"]), 5) - - # customer support has no org, so they just see staff menu - self.login(self.customer_support) - response = self.client.get(reverse("orgs.org_menu")) - self.assertEqual(len(response.json()["results"]), 1) - - def test_staff(self): - - # admin can't see org manage page - self.login(self.admin) - response = self.client.get(reverse("orgs.org_read", args=[self.org.id])) - self.assertRedirect(response, reverse("users.user_login")) - - # but staff members can manage orgs - self.login(self.customer_support) - - # make our second org a child - self.org2.parent = self.org - self.org2.save() - - response = self.client.get(reverse("orgs.org_read", args=[self.org.id])) - self.assertEqual(200, response.status_code) - - # we should have a child in our context - self.assertEqual(1, len(response.context["children"])) - - # we should have an option to flag - self.assertContentMenuContains(response.context["content_menu"], "Flag") - self.assertContentMenuExcludes(response.context["content_menu"], "Unflag") - - # flag and content menu option should be inverted - self.org.flag() - response = self.client.get(reverse("orgs.org_read", args=[self.org.id])) - self.assertContentMenuContains(response.context["content_menu"], "Unflag") - self.assertContentMenuExcludes(response.context["content_menu"], "Flag") - - # no menu for inactive orgs - self.org.is_active = False - self.org.save() - response = self.client.get(reverse("orgs.org_read", args=[self.org.id])) - self.assertEquals([], response.context["content_menu"]) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index fbc86946ff5..1966d9b609d 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -2021,37 +2021,38 @@ def get_context_data(self, **kwargs): class Read(StaffMixin, SpaMixin, ContentMenuMixin, SmartReadView): def build_content_menu(self, menu): - if not self.object.is_active: + obj = self.get_object() + if not obj.is_active: return menu.add_url_post( _("Service"), - f'{reverse("orgs.org_service")}?organization={self.object.id}&redirect_url={reverse("msgs.msg_inbox", args=[])}', + f'{reverse("orgs.org_service")}?organization={obj.id}&redirect_url={reverse("msgs.msg_inbox", args=[])}', ) if self.request.user.is_staff: menu.add_modax( _("Edit"), "update-workspace", - reverse("orgs.org_update", args=[self.object.id]), + reverse("orgs.org_update", args=[obj.id]), title=_("Edit Workspace"), ) - menu.add_link(_("Topups"), f"{reverse('orgs.topup_manage')}?org={self.object.id}") + menu.add_link(_("Topups"), f"{reverse('orgs.topup_manage')}?org={obj.id}") - if self.object.is_flagged: - menu.add_url_post(_("Unflag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=unflag") + if obj.is_flagged: + menu.add_url_post(_("Unflag"), f"{reverse('orgs.org_update', args=[obj.id])}?action=unflag") else: # pragma: needs cover - menu.add_url_post(_("Flag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=flag") + menu.add_url_post(_("Flag"), f"{reverse('orgs.org_update', args=[obj.id])}?action=flag") - if not self.object.is_verified(): - menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=verify") + if not obj.is_verified(): + menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[obj.id])}?action=verify") if self.request.user.has_perm("orgs.org_delete"): menu.add_modax( _("Delete"), "delete-org", - reverse("orgs.org_delete", args=[self.object.id]), + reverse("orgs.org_delete", args=[obj.id]), title=_("Delete Workspace"), ) diff --git a/temba/tests/base.py b/temba/tests/base.py index 0f706f42f50..a79445545e2 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -751,19 +751,6 @@ def assertResponseError(self, response, field, message, status_code=400): self.assertTrue(message, isinstance(body[field], (list, tuple))) self.assertIn(message, body[field]) - def getContentMenuItem(self, menu, label): - for item in menu: - if item.get("label", None) == label: - return item - - def assertContentMenuContains(self, menu, label): - if not self.getContentMenuItem(menu, label): - raise AssertionError(f"No content menu item for '{label}'") - - def assertContentMenuExcludes(self, menu, label): - if self.getContentMenuItem(menu, label): - raise AssertionError(f"Found content menu item for '{label}'") - class TembaTest(TembaTestMixin, SmartminTest): """ diff --git a/temba/tests/crudl.py b/temba/tests/crudl.py index c77ce6dd437..e3cd4f639e1 100644 --- a/temba/tests/crudl.py +++ b/temba/tests/crudl.py @@ -7,7 +7,7 @@ class CRUDLTestMixin: def get_test_users(self): return self.user, self.editor, self.agent, self.admin, self.admin2 - def requestView(self, url, user, *, post_data=None, checks=()): + def requestView(self, url, user, *, post_data=None, checks=(), **kwargs): """ Requests the given URL as a specific user and runs a set of checks """ @@ -24,7 +24,7 @@ def requestView(self, url, user, *, post_data=None, checks=()): for check in checks: check.pre_check(self, pre_msg_prefix) - response = self.client.post(url, post_data) if method == "POST" else self.client.get(url) + response = self.client.post(url, post_data, **kwargs) if method == "POST" else self.client.get(url, **kwargs) for check in checks: check.check(self, response, msg_prefix) @@ -225,7 +225,13 @@ def assertStaffOnly(self, url): self.requestView(url, admin, checks=[LoginRedirect()]) self.requestView(url, self.superuser, checks=[StatusCode(200)]) - self.requestView(url, self.customer_support, checks=[StatusCode(200)]) + return self.requestView(url, self.customer_support, checks=[StatusCode(200)]) + + def assertContentMenu(self, url, user, labels: list): + response = self.requestView( + url, user, checks=[StatusCode(200), ContentType("application/json")], HTTP_TEMBA_CONTENT_MENU=1 + ) + self.assertEqual(labels, [i["label"] for i in response.json()["items"]]) class BaseCheck: @@ -380,13 +386,23 @@ def check(self, test_cls, response, msg_prefix): class StatusCode(BaseCheck): - def __init__(self, status): + def __init__(self, status: int): self.status = status def check(self, test_cls, response, msg_prefix): test_cls.assertEqual(self.status, response.status_code, msg=f"{msg_prefix}: status code mismatch") +class ContentType(BaseCheck): + def __init__(self, content_type: str): + self.content_type = content_type + + def check(self, test_cls, response, msg_prefix): + test_cls.assertEqual( + self.content_type, response.headers["content-type"], msg=f"{msg_prefix}: content type mismatch" + ) + + class LoginRedirectOr404(BaseCheck): def check(self, test_cls, response, msg_prefix): if response.status_code == 302: diff --git a/temba/utils/views.py b/temba/utils/views.py index 02ec75e0dca..ba50dc5f1bb 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -3,7 +3,7 @@ from django import forms from django.db import transaction -from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect, JsonResponse from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property @@ -30,8 +30,7 @@ def spa_referrer_path(self) -> tuple: return tuple(s for s in self.request.META.get("HTTP_TEMBA_REFERER_PATH", "").split("/") if s) def is_spa(self): - is_spa = "HTTP_TEMBA_SPA" in self.request.META - return is_spa + return "HTTP_TEMBA_SPA" in self.request.META def get_template_names(self): templates = super().get_template_names() @@ -357,3 +356,11 @@ def get_context_data(self, **kwargs): def build_content_menu(self, menu: ContentMenu): # pragma: no cover pass + + def get(self, request, *args, **kwargs): + if "HTTP_TEMBA_CONTENT_MENU" in self.request.META: + menu = ContentMenu() + self.build_content_menu(menu) + return JsonResponse({"items": menu.as_items()}) + + return super().get(request, *args, **kwargs) From 7e68b3885eb3e7b015d69b118f8f8c270c0a6ea3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 09:35:17 -0500 Subject: [PATCH 158/630] Fix more content menus so that they can be fetched as JSON and add more tests --- temba/archives/tests.py | 9 +- temba/campaigns/tests.py | 125 ++++++++++-------------- temba/campaigns/views.py | 32 +++--- temba/channels/tests.py | 24 ++--- temba/channels/types/dialog360/tests.py | 11 +-- temba/channels/types/whatsapp/tests.py | 11 +-- temba/channels/views.py | 52 +++++----- temba/classifiers/tests.py | 2 + temba/classifiers/views.py | 10 +- temba/contacts/tests.py | 58 +++++------ temba/orgs/tests.py | 3 +- temba/tests/crudl.py | 4 + temba/utils/views.py | 18 ++-- 13 files changed, 162 insertions(+), 197 deletions(-) diff --git a/temba/archives/tests.py b/temba/archives/tests.py index f9359cb965a..5bab73cc3d8 100644 --- a/temba/archives/tests.py +++ b/temba/archives/tests.py @@ -237,15 +237,18 @@ def test_archive_type_filter(self): # create archive for other org self.create_archive(Archive.TYPE_MSG, "D", date(2020, 7, 31), [{"id": 1}], org=self.org2) - response = self.assertListFetch( - reverse("archives.archive_run"), allow_viewers=False, allow_editors=True, context_objects=[d3] - ) + runs_url = reverse("archives.archive_run") + msgs_url = reverse("archives.archive_message") + + response = self.assertListFetch(runs_url, allow_viewers=False, allow_editors=True, context_objects=[d3]) self.assertContains(response, "jsonl.gz") + self.assertContentMenu(runs_url, self.admin, ["Message Archives"]) response = self.assertListFetch( reverse("archives.archive_message"), allow_viewers=False, allow_editors=True, context_objects=[d2, m1] ) self.assertContains(response, "jsonl.gz") + self.assertContentMenu(msgs_url, self.admin, ["Run Archives"]) def test_read(self): archive = self.create_archive(Archive.TYPE_MSG, "D", date(2020, 7, 31), [{"id": 1}, {"id": 2}]) diff --git a/temba/campaigns/tests.py b/temba/campaigns/tests.py index 38008d9a924..656120d9287 100644 --- a/temba/campaigns/tests.py +++ b/temba/campaigns/tests.py @@ -661,48 +661,6 @@ def test_view_campaign_cant_modify_inactive_or_archive(self): # we should get 404 for the inactive campaign self.assertEqual(response.status_code, 404) - def test_view_campaign_read_with_customer_support(self): - self.login(self.customer_support) - - campaign = Campaign.create(self.org, self.admin, "Perform the rain dance", self.farmers) - - response = self.client.get(reverse("campaigns.campaign_read", args=[campaign.uuid])) - self.assertEqual( - [ - { - "type": "url_post", - "label": "Service", - "url": f"/org/service/?organization={campaign.org_id}&redirect_url=/campaign/read/{campaign.uuid}/", - } - ], - response.context["content_menu"], - ) - - def test_view_campaign_read_archived(self): - self.login(self.admin) - - campaign = Campaign.create(self.org, self.admin, "Perform the rain dance", self.farmers) - - response = self.client.get(reverse("campaigns.campaign_read", args=[campaign.uuid])) - - # page title and main content title should NOT contain (Archived) - self.assertContains(response, "Perform the rain dance", count=2) - self.assertContains(response, "Archived", count=0) - self.assertListEqual( - ["New Event", "Export", "Edit", "Archive"], [i["label"] for i in response.context["content_menu"]] - ) - - # archive the campaign - campaign.is_archived = True - campaign.save() - - response = self.client.get(reverse("campaigns.campaign_read", args=[campaign.uuid])) - - # page title and main content title should contain (Archived) - self.assertContains(response, "Perform the rain dance", count=2) - self.assertContains(response, "Archived", count=2) - self.assertListEqual(["Activate", "Export"], [i["label"] for i in response.context["content_menu"]]) - def test_view_campaign_archive(self): self.login(self.admin) @@ -735,35 +693,6 @@ def test_view_campaign_activate(self): campaign.refresh_from_db() self.assertFalse(campaign.is_archived) - def test_view_campaignevent_read_on_archived_campaign(self): - self.login(self.admin) - - campaign = Campaign.create(self.org, self.admin, "Perform the rain dance", self.farmers) - - # create a reminder for our first planting event - event = CampaignEvent.create_flow_event( - self.org, self.admin, campaign, relative_to=self.planting_date, offset=3, unit="D", flow=self.reminder_flow - ) - - response = self.client.get(reverse("campaigns.campaignevent_read", args=[event.campaign.uuid, event.pk])) - - # page title and main content title should NOT contain Archived - self.assertContains(response, "Perform the rain dance", count=1) - self.assertContains(response, "Archived", count=0) - self.assertListEqual(["Edit", "Delete"], [i["label"] for i in response.context["content_menu"]]) - - # archive the campaign - campaign.is_archived = True - campaign.save() - - response = self.client.get(reverse("campaigns.campaignevent_read", args=[event.campaign.uuid, event.pk])) - - # page title and main content title should contain Archived - self.assertContains(response, "Perform the rain dance", count=1) - self.assertContains(response, "Archived", count=1) - - self.assertListEqual(["Delete"], [i["label"] for i in response.context["content_menu"]]) - def test_view_campaignevent_update_on_archived_campaign(self): self.login(self.admin) @@ -1280,13 +1209,43 @@ def test_create(self): def test_read(self): group = self.create_group("Reporters", contacts=[]) campaign = self.create_campaign(self.org, "Welcomes", group) - read_url = reverse("campaigns.campaign_read", args=[campaign.uuid]) response = self.assertReadFetch(read_url, allow_viewers=True, allow_editors=True, context_object=campaign) self.assertContains(response, "Welcomes") self.assertContains(response, "Registered") + def test_read_archived(self): + group = self.create_group("Reporters", contacts=[]) + campaign = self.create_campaign(self.org, "Welcomes", group) + read_url = reverse("campaigns.campaign_read", args=[campaign.uuid]) + + response = self.requestView(read_url, self.admin) + + # page title and main content title should NOT contain (Archived) + self.assertContains(response, "Welcomes", count=3) + self.assertContains(response, "Archived", count=0) + self.assertContentMenu(read_url, self.admin, ["New Event", "Export", "Edit", "Archive"]) + + # archive the campaign + campaign.is_archived = True + campaign.save() + + response = self.client.get(read_url) + + # page title and main content title should contain (Archived) + self.assertContains(response, "Welcomes", count=3) + self.assertContains(response, "Archived", count=2) + self.assertContentMenu(read_url, self.admin, ["Activate", "Export"]) + + def test_read_as_customer_support(self): + group = self.create_group("Reporters", contacts=[]) + campaign = Campaign.create(self.org, self.admin, "Reminders", group) + read_url = reverse("campaigns.campaign_read", args=[campaign.uuid]) + + # should see service button + self.assertContentMenu(read_url, self.customer_support, ["Service"]) + def test_archive_and_activate(self): group = self.create_group("Reporters", contacts=[]) campaign = self.create_campaign(self.org, "Welcomes", group) @@ -1420,6 +1379,28 @@ def test_read(self): self.assertContains(response, "1 week after") self.assertContains(response, "Registered") + def test_read_on_archived_campaign(self): + event = self.campaign1.events.order_by("id").first() + read_url = reverse("campaigns.campaignevent_read", args=[event.campaign.uuid, event.id]) + + response = self.requestView(read_url, self.admin) + + # page title and main content title should NOT contain Archived + self.assertContains(response, "Welcomes", count=2) + self.assertContains(response, "Archived", count=0) + self.assertContentMenu(read_url, self.admin, ["Edit", "Delete"]) + + # archive the campaign + event.campaign.is_archived = True + event.campaign.save() + + response = self.requestView(read_url, self.admin) + + # page title and main content title should contain Archived + self.assertContains(response, "Welcomes", count=2) + self.assertContains(response, "Archived", count=1) + self.assertContentMenu(read_url, self.admin, ["Delete"]) + def test_create(self): farmer1 = self.create_contact("Rob Jasper", phone="+250788111111") farmer2 = self.create_contact("Mike Gordon", phone="+250788222222", language="spa") diff --git a/temba/campaigns/views.py b/temba/campaigns/views.py index bcc19bb38a0..0d46e68ef2f 100644 --- a/temba/campaigns/views.py +++ b/temba/campaigns/views.py @@ -130,38 +130,40 @@ def derive_title(self): return self.object.name def build_content_menu(self, menu): - if self.object.is_archived: + obj = self.get_object() + + if obj.is_archived: if self.has_org_perm("campaigns.campaign_activate"): - menu.add_url_post(_("Activate"), reverse("campaigns.campaign_activate", args=[self.object.id])) + menu.add_url_post(_("Activate"), reverse("campaigns.campaign_activate", args=[obj.id])) if self.has_org_perm("orgs.org_export"): - menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={self.object.id}&archived=1") + menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={obj.id}&archived=1") else: if self.has_org_perm("campaigns.campaignevent_create"): menu.add_modax( _("New Event"), "event-add", - f"{reverse('campaigns.campaignevent_create')}?campaign={self.object.id}", + f"{reverse('campaigns.campaignevent_create')}?campaign={obj.id}", ) if self.has_org_perm("orgs.org_export"): - menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={self.object.id}") + menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={obj.id}") if self.has_org_perm("campaigns.campaign_update"): menu.add_modax( _("Edit"), "campaign-update", - reverse("campaigns.campaign_update", args=[self.object.id]), + reverse("campaigns.campaign_update", args=[obj.id]), title=_("Edit Campaign"), ) if self.has_org_perm("campaigns.campaign_archive"): - menu.add_url_post(_("Archive"), reverse("campaigns.campaign_archive", args=[self.object.id])) + menu.add_url_post(_("Archive"), reverse("campaigns.campaign_archive", args=[obj.id])) if self.request.user.is_staff: menu.add_url_post( _("Service"), - f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("campaigns.campaign_read", args=[self.object.uuid])}', + f'{reverse("orgs.org_service")}?organization={obj.org_id}&redirect_url={reverse("campaigns.campaign_read", args=[obj.uuid])}', ) class Create(OrgPermsMixin, ModalMixin, SmartCreateView): @@ -172,7 +174,7 @@ class Create(OrgPermsMixin, ModalMixin, SmartCreateView): def pre_save(self, obj): obj = super().pre_save(obj) - obj.org = self.request.user.get_org() + obj.org = self.request.org return obj def get_form_kwargs(self): @@ -187,14 +189,14 @@ class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartLi def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["org_has_campaigns"] = Campaign.objects.filter(org=self.request.user.get_org()).count() + context["org_has_campaigns"] = Campaign.objects.filter(org=self.request.org).count() if not self.is_spa(): context["folders"] = self.get_folders() context["request_url"] = self.request.path return context def get_folders(self): - org = self.request.user.get_org() + org = self.request.org folders = [] folders.append( dict( @@ -541,11 +543,13 @@ def get_context_data(self, **kwargs): return context def build_content_menu(self, menu): - if self.has_org_perm("campaigns.campaignevent_update") and not self.object.campaign.is_archived: + obj = self.get_object() + + if self.has_org_perm("campaigns.campaignevent_update") and not obj.campaign.is_archived: menu.add_modax( _("Edit"), "event-update", - reverse("campaigns.campaignevent_update", args=[self.object.id]), + reverse("campaigns.campaignevent_update", args=[obj.id]), title=_("Edit Event"), ) @@ -553,7 +557,7 @@ def build_content_menu(self, menu): menu.add_modax( _("Delete"), "event-delete", - reverse("campaigns.campaignevent_delete", args=[self.object.id]), + reverse("campaigns.campaignevent_delete", args=[obj.id]), title=_("Delete Event"), ) diff --git a/temba/channels/tests.py b/temba/channels/tests.py index 40920cbd165..1b54d3cc1fa 100644 --- a/temba/channels/tests.py +++ b/temba/channels/tests.py @@ -110,21 +110,6 @@ def assertHasCommand(self, cmd_name, response): raise Exception("Did not find '%s' cmd in response: '%s'" % (cmd_name, response.content)) - def test_channel_read_with_customer_support(self): - self.login(self.customer_support) - - response = self.client.get(reverse("channels.channel_read", args=[self.tel_channel.uuid])) - self.assertEqual( - [ - { - "type": "url_post", - "label": "Service", - "url": f"/org/service/?organization={self.tel_channel.org_id}&redirect_url=/channels/channel/read/{self.tel_channel.uuid}/", - } - ], - response.context["content_menu"], - ) - def test_deactivate(self): self.login(self.admin) self.tel_channel.is_active = False @@ -1428,6 +1413,12 @@ def setUp(self): config={"send_url": "http://send.com"}, ) + def test_channel_read_as_customer_support(self): + read_url = reverse("channels.channel_read", args=[self.ex_channel.uuid]) + + # should see service button + self.assertContentMenu(read_url, self.customer_support, ["Settings", "Channel Log", "Service"]) + def test_configuration(self): config_url = reverse("channels.channel_configuration", args=[self.ex_channel.uuid]) @@ -2132,7 +2123,7 @@ def test_get_display_error(self): self.assertEqual(expected_unredacted, log.get_display(self.customer_support)) -class ChannelLogCRUDLTest(TembaTest): +class ChannelLogCRUDLTest(CRUDLTestMixin, TembaTest): def test_views(self): self.channel.role = "CASR" self.channel.save(update_fields=("role",)) @@ -2247,6 +2238,7 @@ def test_views(self): # view success alone response = self.client.get(reverse("channels.channellog_read", args=[success_log.id])) self.assertContains(response, "POST https://foo.bar/send?msg=failed+message") + self.assertContentMenu(reverse("channels.channellog_read", args=[success_log.id]), self.admin, ["Channel Log"]) self.assertEqual(self.channel.get_success_log_count(), 2) self.assertEqual(self.channel.get_error_log_count(), 4) # error log count always includes IVR logs diff --git a/temba/channels/types/dialog360/tests.py b/temba/channels/types/dialog360/tests.py index 1a7d4887fc5..104197b75a9 100644 --- a/temba/channels/types/dialog360/tests.py +++ b/temba/channels/types/dialog360/tests.py @@ -216,16 +216,7 @@ def test_message_templates_and_logs_views(self): # check if message templates link are in sync_logs view response = self.client.get(reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) - self.assertEqual( - [ - { - "type": "link", - "label": "Message Templates", - "url": reverse("channels.types.dialog360.templates", args=[channel.uuid]), - } - ], - response.context["content_menu"], - ) + self.assertContains(response, reverse("channels.types.dialog360.templates", args=[channel.uuid])) # sync logs not accessible by user from other org self.login(self.admin2) diff --git a/temba/channels/types/whatsapp/tests.py b/temba/channels/types/whatsapp/tests.py index f32ffeef44e..e1a749beed9 100644 --- a/temba/channels/types/whatsapp/tests.py +++ b/temba/channels/types/whatsapp/tests.py @@ -492,16 +492,7 @@ def test_message_templates_and_logs_views(self): # check if message templates link are in sync_logs view response = self.client.get(reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid])) - self.assertEqual( - [ - { - "type": "link", - "label": "Message Templates", - "url": reverse("channels.types.whatsapp.templates", args=[channel.uuid]), - } - ], - response.context["content_menu"], - ) + self.assertContains(response, reverse("channels.types.whatsapp.templates", args=[channel.uuid])) # sync logs and message templates not accessible by user from other org self.login(self.admin2) diff --git a/temba/channels/views.py b/temba/channels/views.py index df8bcf79f23..d55ccb90d73 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -790,23 +790,25 @@ def get_queryset(self): return Channel.objects.filter(is_active=True) def build_content_menu(self, menu): - for extra in self.object.type.extra_links or (): - menu.add_link(extra["label"], reverse(extra["view_name"], args=[self.object.uuid])) + obj = self.get_object() - if self.object.parent: - menu.add_link(_("Android Channel"), reverse("channels.channel_read", args=[self.object.parent.uuid])) + for extra in obj.type.extra_links or (): + menu.add_link(extra["label"], reverse(extra["view_name"], args=[obj.uuid])) - if self.object.type.show_config_page: - menu.add_link(_("Settings"), reverse("channels.channel_configuration", args=[self.object.uuid])) + if obj.parent: + menu.add_link(_("Android Channel"), reverse("channels.channel_read", args=[obj.parent.uuid])) - if not self.object.is_android(): - sender = self.object.get_sender() - caller = self.object.get_caller() + if obj.type.show_config_page: + menu.add_link(_("Settings"), reverse("channels.channel_configuration", args=[obj.uuid])) + + if not obj.is_android(): + sender = obj.get_sender() + caller = obj.get_caller() if sender: menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[sender.uuid])) - elif Channel.ROLE_RECEIVE in self.object.role: - menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[self.object.uuid])) + elif Channel.ROLE_RECEIVE in obj.role: + menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[obj.uuid])) if caller and caller != sender: menu.add_link( @@ -817,12 +819,12 @@ def build_content_menu(self, menu): menu.add_modax( _("Edit"), "update-channel", - reverse("channels.channel_update", args=[self.object.id]), + reverse("channels.channel_update", args=[obj.id]), title=_("Edit Channel"), ) - if self.object.is_android() or (self.object.parent and self.object.parent.is_android()): - sender = self.object.get_sender() + if obj.is_android() or (obj.parent and obj.parent.is_android()): + sender = obj.get_sender() if sender and sender.is_delegate_sender(): menu.add_modax( @@ -830,13 +832,13 @@ def build_content_menu(self, menu): "disable-sender", reverse("channels.channel_delete", args=[sender.uuid]), ) - elif self.object.is_android(): + elif obj.is_android(): menu.add_link( _("Enable Bulk Sending"), - f"{reverse('channels.channel_bulk_sender_options')}?channel={self.object.id}", + f"{reverse('channels.channel_bulk_sender_options')}?channel={obj.id}", ) - caller = self.object.get_caller() + caller = obj.get_caller() if caller and caller.is_delegate_caller(): menu.add_modax( @@ -844,28 +846,28 @@ def build_content_menu(self, menu): "disable-voice", reverse("channels.channel_delete", args=[caller.uuid]), ) - elif self.object.org.is_connected_to_twilio(): + elif obj.org.is_connected_to_twilio(): menu.add_url_post( _("Enable Voice Calling"), - f"{reverse('channels.channel_create_caller')}?channel={self.object.id}", + f"{reverse('channels.channel_create_caller')}?channel={obj.id}", ) if self.has_org_perm("channels.channel_delete"): menu.add_modax( - _("Delete Channel"), "delete-channel", reverse("channels.channel_delete", args=[self.object.uuid]) + _("Delete Channel"), "delete-channel", reverse("channels.channel_delete", args=[obj.uuid]) ) - if self.object.channel_type == "FB" and self.has_org_perm("channels.channel_facebook_whitelist"): + if obj.channel_type == "FB" and self.has_org_perm("channels.channel_facebook_whitelist"): menu.add_modax( _("Whitelist Domain"), "fb-whitelist", - reverse("channels.channel_facebook_whitelist", args=[self.object.uuid]), + reverse("channels.channel_facebook_whitelist", args=[obj.uuid]), ) if self.request.user.is_staff: menu.add_url_post( _("Service"), - f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("channels.channel_read", args=[self.object.uuid])}', + f'{reverse("orgs.org_service")}?organization={obj.org_id}&redirect_url={reverse("channels.channel_read", args=[obj.uuid])}', ) def get_context_data(self, **kwargs): @@ -1529,7 +1531,9 @@ class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): fields = ("description", "created_on") def build_content_menu(self, menu): - menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[self.object.channel.uuid])) + obj = self.get_object() + + menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[obj.channel.uuid])) def get_object_org(self): return self.get_object().channel.org diff --git a/temba/classifiers/tests.py b/temba/classifiers/tests.py index d0903a99e8e..c7723fe9828 100644 --- a/temba/classifiers/tests.py +++ b/temba/classifiers/tests.py @@ -172,6 +172,8 @@ def test_read(self): self.assertNotContains(response, "book_hotel") self.assertContains(response, "book_car") + self.assertContentMenu(read_url, self.admin, ["Log", "Sync", "Delete"]) + def test_delete(self): delete_url = reverse("classifiers.classifier_delete", args=[self.c2.uuid]) diff --git a/temba/classifiers/views.py b/temba/classifiers/views.py index da7833c039d..9c08f5dc07f 100644 --- a/temba/classifiers/views.py +++ b/temba/classifiers/views.py @@ -78,22 +78,24 @@ class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): exclude = ("id", "is_active", "created_by", "modified_by", "modified_on") def build_content_menu(self, menu): - menu.add_link(_("Log"), reverse("request_logs.httplog_classifier", args=[self.object.uuid])) + obj = self.get_object() + + menu.add_link(_("Log"), reverse("request_logs.httplog_classifier", args=[obj.uuid])) if self.has_org_perm("classifiers.classifier_sync"): - menu.add_url_post(_("Sync"), reverse("classifiers.classifier_sync", args=[self.object.id])) + menu.add_url_post(_("Sync"), reverse("classifiers.classifier_sync", args=[obj.id])) if self.has_org_perm("classifiers.classifier_delete"): menu.add_modax( _("Delete"), "classifier-delete", - reverse("classifiers.classifier_delete", args=[self.object.uuid]), + reverse("classifiers.classifier_delete", args=[obj.uuid]), title=_("Delete Classifier"), ) def get_queryset(self, **kwargs): queryset = super().get_queryset(**kwargs) - return queryset.filter(org=self.request.user.get_org(), is_active=True) + return queryset.filter(org=self.request.org, is_active=True) class Sync(OrgObjPermsMixin, SmartUpdateView): fields = () diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 7f209b1c710..3614f670778 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -563,6 +563,32 @@ def test_read(self, mr_mocks): response = self.client.get(reverse("contacts.contact_read", args=["invalid-uuid"])) self.assertEqual(response.status_code, 404) + def test_read_as_customer_support(self): + joe = self.create_contact("Joe", phone="123") + read_url = reverse("contacts.contact_read", args=[joe.uuid]) + + # should see service button + self.assertContentMenu(read_url, self.customer_support, ["Service"]) + + def test_read_language(self): + joe = self.create_contact("Joe", phone="123") + read_url = reverse("contacts.contact_read", args=[joe.uuid]) + + # this is a bogus + joe.language = "zzz" + joe.save(update_fields=("language",)) + response = self.requestView(read_url, self.admin) + + # should just show the language code instead of the language name + self.assertContains(response, "zzz") + + joe.language = "fra" + joe.save(update_fields=("language",)) + response = self.requestView(read_url, self.admin) + + # with a proper code, we should see the language + self.assertContains(response, "French") + def test_scheduled(self): contact1 = self.create_contact("Joe", phone="+1234567890") contact2 = self.create_contact("Frank", phone="+1204567802") @@ -2960,38 +2986,6 @@ def test_read(self, mr_mocks): ) self.assertEqual(response.status_code, 200) - def test_read_with_customer_support(self): - self.login(self.customer_support) - - response = self.client.get(reverse("contacts.contact_read", args=[self.joe.uuid])) - self.assertEqual( - [ - { - "type": "url_post", - "label": "Service", - "url": f"/org/service/?organization={self.org.id}&redirect_url=/contact/read/{self.joe.uuid}/", - } - ], - response.context["content_menu"], - ) - - def test_read_language(self): - - # this is a bogus - self.joe.language = "zzz" - self.joe.save(update_fields=("language",)) - response = self.fetch_protected(reverse("contacts.contact_read", args=[self.joe.uuid]), self.admin) - - # should just show the language code instead of the language name - self.assertContains(response, "zzz") - - self.joe.language = "fra" - self.joe.save(update_fields=("language",)) - response = self.fetch_protected(reverse("contacts.contact_read", args=[self.joe.uuid]), self.admin) - - # with a proper code, we should see the language - self.assertContains(response, "French") - @mock_mailroom def test_contacts_search(self, mr_mocks): search_url = reverse("contacts.contact_search") diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index 86d60a26ac4..942861dd26e 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -3552,8 +3552,7 @@ def test_read(self): # no menu for inactive orgs self.org.is_active = False self.org.save() - response = self.client.get(read_url) - self.assertEquals([], response.context["content_menu"]) + self.assertContentMenu(read_url, self.customer_support, []) def test_workspace(self): response = self.assertListFetch( diff --git a/temba/tests/crudl.py b/temba/tests/crudl.py index e3cd4f639e1..1b67077977c 100644 --- a/temba/tests/crudl.py +++ b/temba/tests/crudl.py @@ -233,6 +233,10 @@ def assertContentMenu(self, url, user, labels: list): ) self.assertEqual(labels, [i["label"] for i in response.json()["items"]]) + # for now menu is also stuffed into context in old gear links format + response = self.requestView(url, user, checks=[StatusCode(200)]) + self.assertEqual(labels, [i["title"] for i in response.context["gear_links"]]) + class BaseCheck: def pre_check(self, test_cls, desc): diff --git a/temba/utils/views.py b/temba/utils/views.py index ba50dc5f1bb..4cb3b9ae646 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -325,7 +325,7 @@ class ContentMenuMixin: """ Mixin for views that have a content menu (hamburger icon with dropdown items) - TODO: rework legacy gear-link templates to use `content_menu` instead of `gear_links` + TODO: use component to read menu as JSON and then can stop putting menu (in legacy gear-links format) in context """ # renderers to convert menu items to the legacy "gear-links" format @@ -345,22 +345,20 @@ class ContentMenuMixin: } def get_context_data(self, **kwargs): - menu = ContentMenu() - self.build_content_menu(menu) - menu_items = menu.as_items() - context = super().get_context_data(**kwargs) - context["content_menu"] = menu_items - context["gear_links"] = [self.gear_link_renderers[i["type"]](i) for i in menu_items] + context["gear_links"] = [self.gear_link_renderers[i["type"]](i) for i in self._get_content_menu()] return context + def _get_content_menu(self): + menu = ContentMenu() + self.build_content_menu(menu) + return menu.as_items() + def build_content_menu(self, menu: ContentMenu): # pragma: no cover pass def get(self, request, *args, **kwargs): if "HTTP_TEMBA_CONTENT_MENU" in self.request.META: - menu = ContentMenu() - self.build_content_menu(menu) - return JsonResponse({"items": menu.as_items()}) + return JsonResponse({"items": self._get_content_menu()}) return super().get(request, *args, **kwargs) From 91829fcfc8f759e5ceb7b5fc5c467652c8998cc2 Mon Sep 17 00:00:00 2001 From: Sandro Meireles Date: Thu, 18 Aug 2022 11:53:15 -0300 Subject: [PATCH 159/630] fix: Improve `trim_http_logs_task` performance by splitting the query --- temba/request_logs/tasks.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/temba/request_logs/tasks.py b/temba/request_logs/tasks.py index b33e34e0b78..d929e9b0908 100644 --- a/temba/request_logs/tasks.py +++ b/temba/request_logs/tasks.py @@ -1,15 +1,35 @@ +import logging + from django.conf import settings from django.utils import timezone +from django.utils.timesince import timesince -from temba.utils import chunk_list from temba.utils.celery import nonoverlapping_task from .models import HTTPLog +logger = logging.getLogger(__name__) + + @nonoverlapping_task(track_started=True, name="trim_http_logs_task") def trim_http_logs_task(): trim_before = timezone.now() - settings.RETENTION_PERIODS["httplog"] - ids = HTTPLog.objects.filter(created_on__lte=trim_before).values_list("id", flat=True) - for chunk in chunk_list(ids, 1000): - HTTPLog.objects.filter(id__in=chunk).delete() + num_deleted = 0 + start = timezone.now() + + logger.info(f"Deleting http logs which ended before {trim_before.isoformat()}...") + + while True: + http_log_ids = HTTPLog.objects.filter(created_on__lte=trim_before).values_list("id", flat=True)[:1000] + + if not http_log_ids: + break + + HTTPLog.objects.filter(id__in=http_log_ids).delete() + num_deleted += len(http_log_ids) + + if num_deleted % 10000 == 0: # pragma: no cover + print(f" > Deleted {num_deleted} http logs") + + logger.info(f"Deleted {num_deleted} http logs in {timesince(start)}") From 8dee122a2446d85acebdfd11ada11f2712b805ef Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 10:37:01 -0500 Subject: [PATCH 160/630] Update CHANGELOG.md for v7.5.21 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 923edad5073..2c77d53ecb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.21 +---------- + * Allow views with ContentMenuMixin to be fetched as JSON menu items using a header + * Add new fields to channel log model and start reading from them if they're set + v7.5.20 ---------- * Update the links for line developers console on the line claim page diff --git a/pyproject.toml b/pyproject.toml index a09a3b70c7b..9f5462b33b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.20" +version = "7.5.21" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From ebbbba414cf3448f578fcd661f7e0b6e4dcf713f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 11:30:48 -0500 Subject: [PATCH 161/630] Use more assertContentMenu --- temba/channels/types/dialog360/tests.py | 21 ++++++++++++--------- temba/channels/types/whatsapp/tests.py | 22 ++++++++++++---------- temba/utils/whatsapp/views.py | 15 +++++++-------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/temba/channels/types/dialog360/tests.py b/temba/channels/types/dialog360/tests.py index 104197b75a9..b482f2ae857 100644 --- a/temba/channels/types/dialog360/tests.py +++ b/temba/channels/types/dialog360/tests.py @@ -8,14 +8,14 @@ from temba.request_logs.models import HTTPLog from temba.templates.models import TemplateTranslation -from temba.tests import MockResponse, TembaTest +from temba.tests import CRUDLTestMixin, MockResponse, TembaTest from temba.utils.whatsapp.tasks import refresh_whatsapp_templates from ...models import Channel from .type import Dialog360Type -class Dialog360TypeTest(TembaTest): +class Dialog360TypeTest(CRUDLTestMixin, TembaTest): @patch("temba.channels.types.dialog360.Dialog360Type.check_health") def test_claim(self, mock_health): mock_health.return_value = MockResponse(200, '{"meta": {"api_status": "stable", "version": "2.35.4"}}') @@ -207,23 +207,26 @@ def test_message_templates_and_logs_views(self): "foo_namespace", ) + sync_url = reverse("channels.types.dialog360.sync_logs", args=[channel.uuid]) + templates_url = reverse("channels.types.dialog360.templates", args=[channel.uuid]) + self.login(self.admin) - # hit our template page - response = self.client.get(reverse("channels.types.dialog360.templates", args=[channel.uuid])) + response = self.client.get(templates_url) + # should have our template translations self.assertContains(response, "Hello") - self.assertContains(response, reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) + self.assertContains(response, sync_url) + self.assertContentMenu(templates_url, self.admin, ["Sync Logs"]) # check if message templates link are in sync_logs view - response = self.client.get(reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) - self.assertContains(response, reverse("channels.types.dialog360.templates", args=[channel.uuid])) + self.assertContentMenu(sync_url, self.admin, ["Message Templates"]) # sync logs not accessible by user from other org self.login(self.admin2) - response = self.client.get(reverse("channels.types.dialog360.templates", args=[channel.uuid])) + response = self.client.get(templates_url) self.assertEqual(404, response.status_code) - response = self.client.get(reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) + response = self.client.get(sync_url) self.assertEqual(404, response.status_code) def test_check_health(self): diff --git a/temba/channels/types/whatsapp/tests.py b/temba/channels/types/whatsapp/tests.py index e1a749beed9..b42911cef8d 100644 --- a/temba/channels/types/whatsapp/tests.py +++ b/temba/channels/types/whatsapp/tests.py @@ -8,7 +8,7 @@ from temba.request_logs.models import HTTPLog from temba.templates.models import TemplateTranslation -from temba.tests import MockResponse, TembaTest +from temba.tests import CRUDLTestMixin, MockResponse, TembaTest from temba.utils.whatsapp.tasks import refresh_whatsapp_contacts, refresh_whatsapp_templates from ...models import Channel @@ -23,7 +23,7 @@ ) -class WhatsAppTypeTest(TembaTest): +class WhatsAppTypeTest(CRUDLTestMixin, TembaTest): @patch("temba.channels.types.whatsapp.WhatsAppType.check_health") def test_claim(self, mock_health): mock_health.return_value = MockResponse(200, '{"meta": {"api_status": "stable", "version": "v2.35.2"}}') @@ -474,31 +474,33 @@ def test_message_templates_and_logs_views(self): "foo_namespace", ) + sync_url = reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid]) + templates_url = reverse("channels.types.whatsapp.templates", args=[channel.uuid]) + self.login(self.admin) - # hit our template page - response = self.client.get(reverse("channels.types.whatsapp.templates", args=[channel.uuid])) + response = self.client.get(templates_url) + # should have our template translations self.assertContains(response, "Hello") self.assertContains(response, "Hi") - self.assertContains(response, reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid])) + self.assertContentMenu(templates_url, self.admin, ["Sync Logs"]) foo.is_active = False foo.save() - response = self.client.get(reverse("channels.types.whatsapp.templates", args=[channel.uuid])) + response = self.client.get(templates_url) # should have our template translations self.assertContains(response, "Hello") self.assertNotContains(response, "Hi") # check if message templates link are in sync_logs view - response = self.client.get(reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid])) - self.assertContains(response, reverse("channels.types.whatsapp.templates", args=[channel.uuid])) + self.assertContentMenu(sync_url, self.admin, ["Message Templates"]) # sync logs and message templates not accessible by user from other org self.login(self.admin2) - response = self.client.get(reverse("channels.types.whatsapp.templates", args=[channel.uuid])) + response = self.client.get(templates_url) self.assertEqual(404, response.status_code) - response = self.client.get(reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid])) + response = self.client.get(sync_url) self.assertEqual(404, response.status_code) def test_check_health(self): diff --git a/temba/utils/whatsapp/views.py b/temba/utils/whatsapp/views.py index 9e78bd61606..5c382c17e9c 100644 --- a/temba/utils/whatsapp/views.py +++ b/temba/utils/whatsapp/views.py @@ -45,9 +45,9 @@ class TemplatesView(ContentMenuMixin, OrgPermsMixin, SmartReadView): template_name = "utils/whatsapp/templates.html" def build_content_menu(self, menu): - menu.add_link( - _("Sync Logs"), reverse(f"channels.types.{self.object.type.slug}.sync_logs", args=[self.object.uuid]) - ) + obj = self.get_object() + + menu.add_link(_("Sync Logs"), reverse(f"channels.types.{obj.type.slug}.sync_logs", args=[obj.uuid])) def get_queryset(self): queryset = super().get_queryset() @@ -75,14 +75,13 @@ class SyncLogsView(ContentMenuMixin, OrgPermsMixin, SmartReadView): template_name = "utils/whatsapp/sync_logs.html" def build_content_menu(self, menu): - menu.add_link( - _("Message Templates"), - reverse(f"channels.types.{self.object.type.slug}.templates", args=[self.object.uuid]), - ) + obj = self.get_object() + + menu.add_link(_("Message Templates"), reverse(f"channels.types.{obj.type.slug}.templates", args=[obj.uuid])) def get_queryset(self): queryset = super().get_queryset() - return queryset.filter(org=self.get_user().get_org()) + return queryset.filter(org=self.request.org) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) From 585d32b70b1e730d423888aea067978bb3510400 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 18 Aug 2022 10:48:16 -0700 Subject: [PATCH 162/630] Update CHANGELOG.md for v7.5.22 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c77d53ecb4..53031db4b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.22 +---------- + * Remove unused policies.policy_read perm + * Replace all permission checking against Customer Support group with is_staff check on user + v7.5.21 ---------- * Allow views with ContentMenuMixin to be fetched as JSON menu items using a header diff --git a/pyproject.toml b/pyproject.toml index 9f5462b33b3..73b228ff489 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.21" +version = "7.5.22" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 390d598f56463cf46a9dc216aa3f9d084983b95f Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 14:12:32 -0500 Subject: [PATCH 163/630] Add new ChannelLog log type choices and make description nullable --- temba/channels/models.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/temba/channels/models.py b/temba/channels/models.py index 24916458349..6bdf0116710 100644 --- a/temba/channels/models.py +++ b/temba/channels/models.py @@ -1186,18 +1186,24 @@ class ChannelLog(models.Model): """ LOG_TYPE_MSG_SEND = "msg_send" - LOG_TYPE_MSG_UPDATE = "msg_update" + LOG_TYPE_MSG_STATUS = "msg_status" LOG_TYPE_MSG_RECEIVE = "msg_receive" LOG_TYPE_IVR_START = "ivr_start" + LOG_TYPE_IVR_INCOMING = "ivr_incoming" LOG_TYPE_IVR_CALLBACK = "ivr_callback" + LOG_TYPE_IVR_STATUS = "ivr_status" + LOG_TYPE_IVR_HANGUP = "ivr_hangup" LOG_TYPE_CONTACT_UPDATE = "contact_update" LOG_TYPE_TOKEN_REFRESH = "token_refresh" LOG_TYPE_CHOICES = ( (LOG_TYPE_MSG_SEND, _("Message Send")), - (LOG_TYPE_MSG_UPDATE, _("Message Update")), + (LOG_TYPE_MSG_STATUS, _("Message Status")), (LOG_TYPE_MSG_RECEIVE, _("Message Receive")), (LOG_TYPE_IVR_START, _("IVR Start")), + (LOG_TYPE_IVR_INCOMING, _("IVR Incoming")), (LOG_TYPE_IVR_CALLBACK, _("IVR Callback")), + (LOG_TYPE_IVR_STATUS, _("IVR Status")), + (LOG_TYPE_IVR_HANGUP, _("IVR Hangup")), (LOG_TYPE_CONTACT_UPDATE, _("Contact Update")), (LOG_TYPE_TOKEN_REFRESH, _("Token Refresh")), ) @@ -1217,7 +1223,7 @@ class ChannelLog(models.Model): created_on = models.DateTimeField(default=timezone.now) # TODO deprecated - description = models.CharField(max_length=255) + description = models.CharField(max_length=255, null=True) url = models.TextField(null=True) method = models.CharField(max_length=16, null=True) request = models.TextField(null=True) From 240f87115e24ae250a7270de793c206194d6f142 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 14:13:36 -0500 Subject: [PATCH 164/630] Update to latest floweditor --- package-lock.json | 15 ++++++++------- package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6a1383b6132..cc45c0bb014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,10 +4,11 @@ "requires": true, "packages": { "": { + "name": "rapidpro", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { - "@nyaruka/flow-editor": "1.17.2", + "@nyaruka/flow-editor": "1.17.3", "@nyaruka/temba-components": "0.29.3", "colorette": "1.2.2", "fa-icons": "0.2.0", @@ -80,9 +81,9 @@ "integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==" }, "node_modules/@nyaruka/flow-editor": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.2.tgz", - "integrity": "sha512-SncrhTt0w+SR3kAwl9P5xGFICTNuSyBZ/FveMKkFd3RHpumhmeVI2UnegYaa6qw8k3VdaeumMWqQcF/CF1HNnQ==", + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.3.tgz", + "integrity": "sha512-Aa2r5S3S3Xo+16kt2tegKW5+y6YroWP1plTJ4J+TNB/bUl9jUmI4G7poKkX4QNJsNX23JDWsGOqEx0Yt1jbLGQ==", "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6" @@ -2479,9 +2480,9 @@ "integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==" }, "@nyaruka/flow-editor": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.2.tgz", - "integrity": "sha512-SncrhTt0w+SR3kAwl9P5xGFICTNuSyBZ/FveMKkFd3RHpumhmeVI2UnegYaa6qw8k3VdaeumMWqQcF/CF1HNnQ==", + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.3.tgz", + "integrity": "sha512-Aa2r5S3S3Xo+16kt2tegKW5+y6YroWP1plTJ4J+TNB/bUl9jUmI4G7poKkX4QNJsNX23JDWsGOqEx0Yt1jbLGQ==", "requires": { "react": "^16.8.6", "react-dom": "^16.8.6" diff --git a/package.json b/package.json index 7ab1227b4be..f1827e5ea3f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ ] }, "dependencies": { - "@nyaruka/flow-editor": "1.17.2", + "@nyaruka/flow-editor": "1.17.3", "@nyaruka/temba-components": "0.29.3", "colorette": "1.2.2", "fa-icons": "0.2.0", From 56a2758e3df3387e8b61ee88fc253823aa068919 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 18 Aug 2022 15:19:57 -0500 Subject: [PATCH 165/630] Tweak more build_content_menu methods --- temba/channels/types/whatsapp_cloud/views.py | 8 ++- temba/contacts/tests.py | 7 ++- temba/flows/tests.py | 16 ++++- temba/flows/views.py | 65 ++++++++++---------- temba/msgs/tests.py | 17 ++--- temba/msgs/views.py | 33 ++++++---- temba/tests/crudl.py | 10 +-- 7 files changed, 88 insertions(+), 68 deletions(-) diff --git a/temba/channels/types/whatsapp_cloud/views.py b/temba/channels/types/whatsapp_cloud/views.py index 1691f0e7381..7679d3bdb06 100644 --- a/temba/channels/types/whatsapp_cloud/views.py +++ b/temba/channels/types/whatsapp_cloud/views.py @@ -260,7 +260,9 @@ def get_success_url(self): return reverse("channels.types.whatsapp_cloud.verify_code", args=[self.object.uuid]) def build_content_menu(self, menu): - menu.add_link(_("Channel"), reverse("channels.channel_read", args=[self.object.uuid])) + obj = self.get_object() + + menu.add_link(_("Channel"), reverse("channels.channel_read", args=[obj.uuid])) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -316,7 +318,9 @@ class Form(forms.Form): submit_button_name = _("Verify Number") def build_content_menu(self, menu): - menu.add_link(_("Channel"), reverse("channels.channel_read", args=[self.object.uuid])) + obj = self.get_object() + + menu.add_link(_("Channel"), reverse("channels.channel_read", args=[obj.uuid])) def get_queryset(self): return Channel.objects.filter(is_active=True, org=self.request.org, channel_type="WAC") diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 3614f670778..0d7608aa8fe 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -101,14 +101,13 @@ def test_list(self, mr_mocks): self.assertEqual([frank, joe], list(response.context["object_list"])) self.assertIsNone(response.context["search_error"]) self.assertEqual([], list(response.context["actions"])) + self.assertContentMenu(list_url, self.user, ["Export"]) active_contacts = self.org.active_contacts_group open_tickets = self.org.groups.get(name="Open Tickets") survey_audience = self.org.groups.get(name="Survey Audience") unsatisfied = self.org.groups.get(name="Unsatisfied Customers") - self.maxDiff = None - self.assertEqual( [ {"id": self.org.groups.get(group_type="A").id, "name": "Active", "count": 2, "url": "/contact/"}, @@ -228,6 +227,7 @@ def test_list(self, mr_mocks): response = self.client.get(list_url) self.assertEqual([frank, joe], list(response.context["object_list"])) self.assertEqual(["block", "archive", "send"], list(response.context["actions"])) + self.assertContentMenu(list_url, self.admin, ["Manage Fields", "Export"]) # TODO: group labeling as a feature is on probation # self.client.post(list_url, {"action": "label", "objects": frank.id, "label": survey_audience.id}) @@ -437,6 +437,9 @@ def test_filter(self, mr_mocks): self.assertEqual(["block", "unlabel"], list(response.context["actions"])) self.assertContains(response, "Edit Group") self.assertContains(response, "Delete Group") + self.assertContentMenu( + group1_url, self.admin, ["Manage Fields", "Edit Group", "Export", "Usages", "Delete Group"] + ) response = self.assertReadFetch(group2_url, allow_viewers=True, allow_editors=True) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index cf7a1adfe31..6d7f11d726f 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -1916,7 +1916,21 @@ def test_views(self): # make sure we don't get a start flow button for Android Surveys response = self.client.get(reverse("flows.flow_editor", args=[flow2.uuid])) - self.assertNotContains(response, "broadcast-rulesflow btn-primary") + self.assertContentMenu( + reverse("flows.flow_editor", args=[flow2.uuid]), + self.admin, + [ + "Results", + "-", + "Edit", + "Copy", + "Delete", + "-", + "Export Definition", + "Export Translation", + "Import Translation", + ], + ) # create a new voice flow response = self.client.post( diff --git a/temba/flows/views.py b/temba/flows/views.py index 4a81cfa3a8e..ff8d9c47acc 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -874,51 +874,49 @@ class Filter(BaseList, OrgObjPermsMixin): slug_url_kwarg = "uuid" def build_content_menu(self, menu): - label = FlowLabel.objects.get(uuid=self.kwargs["uuid"]) - if self.has_org_perm("flows.flow_update"): menu.add_modax( _("Edit"), "update-label", - f"{reverse('flows.flowlabel_update', args=[label.pk])}", + f"{reverse('flows.flowlabel_update', args=[self.label.id])}", title=_("Edit Label"), primary=True, ) if self.has_org_perm("flows.flow_delete"): menu.add_modax( - _("Delete Label"), "delete-label", f"{reverse('flows.flowlabel_delete', args=[label.pk])}" + _("Delete Label"), "delete-label", f"{reverse('flows.flowlabel_delete', args=[self.label.id])}" ) def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) - context["current_label"] = self.derive_label() + context["current_label"] = self.label return context @classmethod def derive_url_pattern(cls, path, action): - return r"^%s/%s/(?P[0-9a-f-]+)/$" % (path, action) + return r"^%s/%s/(?P[0-9a-f-]+)/$" % (path, action) def derive_title(self, *args, **kwargs): - return self.derive_label().name + return self.label.name def get_object_org(self): - return FlowLabel.objects.get(uuid=self.kwargs["uuid"]).org + return self.label.org - def derive_label(self): - return FlowLabel.objects.get(uuid=self.kwargs["uuid"], org=self.request.user.get_org()) + @cached_property + def label(self): + return FlowLabel.objects.get(uuid=self.kwargs["label_uuid"], org=self.request.org) def get_label_filter(self): - label = FlowLabel.objects.get(uuid=self.kwargs["uuid"]) - children = label.children.all() + children = self.label.children.all() if children: # pragma: needs cover - return [lb for lb in FlowLabel.objects.filter(parent=label)] + [label] + return [lb for lb in FlowLabel.objects.filter(parent=self.label)] + [self.label] else: - return [label] + return [self.label] def get_queryset(self, **kwargs): qs = super().get_queryset(**kwargs) - qs = qs.filter(org=self.request.user.get_org()).order_by("-created_on") + qs = qs.filter(org=self.request.org).order_by("-created_on") qs = qs.filter(labels__in=self.get_label_filter(), is_archived=False).distinct() return qs @@ -1007,65 +1005,62 @@ def get_features(self, org) -> list: return features def build_content_menu(self, menu): - flow = self.object - if ( - flow.flow_type != Flow.TYPE_SURVEY - and self.has_org_perm("flows.flow_broadcast") - and not flow.is_archived - ): + obj = self.get_object() + + if obj.flow_type != Flow.TYPE_SURVEY and self.has_org_perm("flows.flow_broadcast") and not obj.is_archived: menu.add_modax( _("Start Flow"), "start-flow", - f"{reverse('flows.flow_broadcast', args=[])}?flow={self.object.id}", + f"{reverse('flows.flow_broadcast', args=[])}?flow={obj.id}", primary=True, ) if self.has_org_perm("flows.flow_results"): - menu.add_link(_("Results"), reverse("flows.flow_results", args=[flow.uuid])) + menu.add_link(_("Results"), reverse("flows.flow_results", args=[obj.uuid])) menu.new_group() - if self.has_org_perm("flows.flow_update") and not flow.is_archived: + if self.has_org_perm("flows.flow_update") and not obj.is_archived: menu.add_modax( _("Edit"), "edit-flow", - f"{reverse('flows.flow_update', args=[self.object.pk])}", + f"{reverse('flows.flow_update', args=[obj.id])}", title=_("Edit Flow"), ) if self.has_org_perm("flows.flow_copy"): - menu.add_url_post(_("Copy"), reverse("flows.flow_copy", args=[flow.id])) + menu.add_url_post(_("Copy"), reverse("flows.flow_copy", args=[obj.id])) if self.has_org_perm("flows.flow_delete"): menu.add_modax( _("Delete"), "delete-flow", - reverse("flows.flow_delete", args=[self.object.uuid]), + reverse("flows.flow_delete", args=[obj.uuid]), title=_("Delete Flow"), ) menu.new_group() if self.has_org_perm("orgs.org_export"): - menu.add_link(_("Export Definition"), f"{reverse('orgs.org_export')}?flow={flow.id}") + menu.add_link(_("Export Definition"), f"{reverse('orgs.org_export')}?flow={obj.id}") # limit PO export/import to non-archived flows since mailroom doesn't know about archived flows - if not self.object.is_archived: + if not obj.is_archived: if self.has_org_perm("flows.flow_export_translation"): menu.add_modax( _("Export Translation"), "export-translation", - reverse("flows.flow_export_translation", args=[self.object.pk]), + reverse("flows.flow_export_translation", args=[obj.id]), ) if self.has_org_perm("flows.flow_import_translation"): - menu.add_link(_("Import Translation"), reverse("flows.flow_import_translation", args=[flow.id])) + menu.add_link(_("Import Translation"), reverse("flows.flow_import_translation", args=[obj.id])) user = self.get_user() if user.is_superuser or user.is_staff: menu.add_url_post( _("Service"), - f'{reverse("orgs.org_service")}?organization={flow.org_id}&redirect_url={reverse("flows.flow_editor", args=[flow.uuid])}', + f'{reverse("orgs.org_service")}?organization={obj.org_id}&redirect_url={reverse("flows.flow_editor", args=[obj.uuid])}', ) class ChangeLanguage(OrgObjPermsMixin, SmartUpdateView): @@ -1596,16 +1591,18 @@ class Results(SpaMixin, AllowOnlyActiveFlowMixin, OrgObjPermsMixin, ContentMenuM slug_url_kwarg = "uuid" def build_content_menu(self, menu): + obj = self.get_object() + if self.has_org_perm("flows.flow_update"): menu.add_modax( _("Download"), "download-results", - f"{reverse('flows.flow_export_results')}?ids={self.get_object().pk}", + f"{reverse('flows.flow_export_results')}?ids={obj.id}", title=_("Download Results"), ) if self.has_org_perm("flows.flow_editor"): - menu.add_link(_("Edit Flow"), reverse("flows.flow_editor", args=[self.get_object().uuid])) + menu.add_link(_("Edit Flow"), reverse("flows.flow_editor", args=[obj.uuid])) def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index c721429dc85..971849160d4 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -1891,18 +1891,16 @@ def test_filter(self): response = self.requestView(label3_url, self.user) self.assertEqual(200, response.status_code) self.assertEqual(("label",), response.context["actions"]) - self.assertNotContains(response, reverse("msgs.label_update", args=[label3.id])) # can't update label - self.assertNotContains(response, reverse("msgs.label_delete", args=[label3.id])) # can't delete label + self.assertContentMenu(label3_url, self.user, ["Download", "Usages"]) # no update or delete # check that test and non-visible messages are excluded, and messages and ordered newest to oldest self.assertEqual([msg6, msg3, msg2, msg1], list(response.context["object_list"])) # check viewing a folder - response = self.client.get(reverse("msgs.msg_filter", args=[folder.uuid])) + response = self.client.get(folder_url) self.assertEqual(200, response.status_code) self.assertEqual(("label",), response.context["actions"]) - self.assertNotContains(response, reverse("msgs.label_update", args=[folder.id])) # can't update folder - self.assertNotContains(response, reverse("msgs.label_delete", args=[folder.id])) # can't delete folder + self.assertContentMenu(folder_url, self.user, ["Download", "Usages"]) # no update or delete # messages from contained labels are rolled up without duplicates self.assertEqual([msg3, msg2, msg1], list(response.context["object_list"])) @@ -1916,13 +1914,8 @@ def test_filter(self): self.assertEqual({msg1, msg6}, set(response.context_data["object_list"])) # check admin users see edit and delete options for labels and folders - response = self.requestView(folder_url, self.admin) - self.assertContains(response, reverse("msgs.label_update", args=[folder.id])) - self.assertContains(response, reverse("msgs.label_delete", args=[folder.id])) - - response = self.requestView(label1_url, self.admin) - self.assertContains(response, reverse("msgs.label_update", args=[label1.id])) - self.assertContains(response, reverse("msgs.label_delete", args=[label1.id])) + self.assertContentMenu(folder_url, self.admin, ["Edit Folder", "Download", "Usages", "Delete Folder"]) + self.assertContentMenu(label1_url, self.admin, ["Edit Label", "Download", "Usages", "Delete Label"]) class BroadcastTest(TembaTest): diff --git a/temba/msgs/views.py b/temba/msgs/views.py index 4cc9eebae2f..6bf071279f9 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -1,4 +1,5 @@ from datetime import date, timedelta +from functools import cached_property from urllib.parse import quote_plus from smartmin.views import ( @@ -793,43 +794,49 @@ class Filter(InboxView): bulk_actions = ("label",) def derive_title(self, *args, **kwargs): - return self.derive_label().name + return self.label.name def build_content_menu(self, menu): - label = self.derive_label() - if self.has_org_perm("msgs.msg_update"): - if label.is_folder(): - menu.add_modax(_("Edit Folder"), "update-folder", reverse("msgs.label_update", args=[label.id])) + if self.label.is_folder(): + menu.add_modax( + _("Edit Folder"), "update-folder", reverse("msgs.label_update", args=[self.label.id]) + ) else: - menu.add_modax(_("Edit Label"), "update-label", reverse("msgs.label_update", args=[label.id])) + menu.add_modax(_("Edit Label"), "update-label", reverse("msgs.label_update", args=[self.label.id])) if self.has_org_perm("msgs.msg_export"): menu.add_modax( _("Download"), "export-messages", self.derive_export_url(), title=_("Download Messages") ) - menu.add_modax(_("Usages"), "label-usages", reverse("msgs.label_usages", args=[label.uuid])) + menu.add_modax(_("Usages"), "label-usages", reverse("msgs.label_usages", args=[self.label.uuid])) - if label.is_folder(): + if self.label.is_folder(): if self.has_org_perm("msgs.label_delete_folder"): menu.add_modax( - _("Delete Folder"), "delete-folder", reverse("msgs.label_delete_folder", args=[label.id]) + _("Delete Folder"), "delete-folder", reverse("msgs.label_delete_folder", args=[self.label.id]) ) else: if self.has_org_perm("msgs.label_delete"): - menu.add_modax(_("Delete Label"), "delete-label", reverse("msgs.label_delete", args=[label.uuid])) + menu.add_modax( + _("Delete Label"), "delete-label", reverse("msgs.label_delete", args=[self.label.uuid]) + ) @classmethod def derive_url_pattern(cls, path, action): - return r"^%s/%s/(?P

    m< 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 z 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 Q4k-z|96y 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 diff --git a/media/test_media/synth.mp3 b/media/test_media/synth.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..23c2e3aaa31e160505bc427651b25807cc69262f GIT binary patch literal 52079 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 str: """ - Creates a new audio version of the given media file + Creates a new audio version of the given audio media """ def transform(in_name, out_name): ffmpeg.input(in_name).output(out_name, acodec=codec).overwrite_output().run() - return _create_new_media(original, file, transform, new_extension) + return _create_alternate(original, file, transform, new_content_type, new_extension, duration=original.duration) -def _create_new_video_thumbnail(media: str, file) -> str: +def _create_video_thumbnail(original: Media, file) -> str: """ - Creates a new thumbnail for the given video file + Creates a new thumbnail for the given video media """ def transform(in_name, out_name): - ffmpeg.input(in_name, ss="00:00:00").filter("scale", "640", -1).output( - out_name, vframes=1 - ).overwrite_output().run() + ffmpeg.input(in_name, ss="00:00:00").output(out_name, vframes=1).overwrite_output().run() - return _create_new_media(media, file, transform, "jpg") + return _create_alternate( + original, file, transform, "image/jpeg", "jpg", width=original.width, height=original.height + ) -def _create_new_media(original: Media, file, transform, new_content_type: str, new_extension: str) -> Media: +def _create_alternate(original: Media, file, transform, new_content_type: str, new_extension: str, **kwargs) -> Media: """ Creates a new media instance by transforming an original with an ffmpeg pipeline """ - new_path = _change_extension(original.path, new_extension) + new_name = _change_extension(original.name, new_extension) with NamedTemporaryFile(suffix="." + new_extension, delete=True) as temp: transform(file.name, temp.name) - public_file_storage.save(new_path, temp) - - return Media.objects.create( - uuid=uuid4(), - org=original.org, - url=public_file_storage.url(new_path), - name=file.name, - content_type=new_content_type, - path=new_path, - original=original, - created_by=original.created_by, - ) - - -def _get_duration(file) -> int: - """ - Uses ffprobe to get the duration of the audio or video file - """ - output = ffmpeg.probe(file.name) - return int(float(output["format"]["duration"]) * 1000) + return Media.create_alternate(original, new_name, new_content_type, temp, **kwargs) def _change_extension(filename: str, extension: str) -> str: diff --git a/temba/msgs/models.py b/temba/msgs/models.py index cd26062ebaf..bb25a187e2e 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -52,10 +52,10 @@ class Media(models.Model): name = models.CharField(max_length=255) # filename including extension content_type = models.CharField(max_length=255) path = models.CharField(max_length=2048) + size = models.IntegerField(default=0) # bytes original = models.ForeignKey("self", null=True, on_delete=models.CASCADE, related_name="alternates") # fields that will be set after upload by a processing task - size = models.IntegerField(default=0) # bytes duration = models.IntegerField(default=0) # milliseconds width = models.IntegerField(default=0) # pixels height = models.IntegerField(default=0) # pixels @@ -76,33 +76,61 @@ def get_storage_path(cls, org, uuid, filename): return f"{settings.STORAGE_ROOT_DIR}/{org.id}/media/{str(uuid)[0:4]}/{uuid}/{filename}" @classmethod - def from_upload(cls, org, user, file): - from .tasks import process_media_upload + def from_upload(cls, org, user, file, process=True): + """ + Creates a new media instance from a file upload. + """ - uuid = uuid4() + from .tasks import process_media_upload # browsers might send m4a files but correct MIME type is audio/mp4 extension = file.name.split(".")[-1] if extension == "m4a": file.content_type = "audio/mp4" - path = cls.get_storage_path(org, uuid, file.name) - path = public_file_storage.save(path, file) # storage classes can rewrite saved paths + media = cls._create(org, user, file.name, file.content_type, file) + + if process: + on_transaction_commit(lambda: process_media_upload.delay(media.id)) + + return media + + @classmethod + def create_alternate(cls, original, name: str, content_type: str, file, **kwargs): + """ + Creates a new alternate media instance for the given original. + """ + + return cls._create( + original.org, + original.created_by, + name, + content_type, + file, + original=original, + is_ready=True, + **kwargs, + ) + + @classmethod + def _create(cls, org, user, name: str, content_type: str, file, **kwargs): + uuid = uuid4() + path = cls.get_storage_path(org, uuid, name) + path = public_file_storage.save(path, file) + size = public_file_storage.size(path) - media = cls.objects.create( + return cls.objects.create( uuid=uuid, org=org, url=public_file_storage.url(path), - name=file.name, - content_type=file.content_type, + name=name, + content_type=content_type, path=path, + size=size, created_by=user, + **kwargs, ) - on_transaction_commit(lambda: process_media_upload.delay(media.id)) - - return media - def process_upload(self): from .media import process_upload diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 8cd73cf2a19..400e2eae8fc 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -36,12 +36,14 @@ class MediaTest(TembaTest): @patch("temba.msgs.models.uuid4") - def test_model(self, mock_uuid): + def test_from_upload(self, mock_uuid): mock_uuid.side_effect = [UUID("6a65f14f-b762-4485-b860-96a322292775")] + media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "image/jpeg"), + process=False, ) self.assertEqual("6a65f14f-b762-4485-b860-96a322292775", str(media.uuid)) @@ -58,66 +60,128 @@ def test_model(self, mock_uuid): self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) - def test_process_audio_wav(self): - flow = self.create_flow("Color") + @patch("temba.msgs.models.uuid4") + def test_process_audio_wav(self, mock_uuid): + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("23184249-7c8f-437b-8123-e12c190abf7e"), + UUID("fe6cb59a-0a79-4b01-babf-dc97fe70d3e7"), + ] + media = Media.from_upload( - self.org, - self.admin, - self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav"), - flow=flow, + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav"), process=False ) media.process_upload() + media.refresh_from_db() - self.assertTrue(media.is_ready) + self.assertEqual(81818, media.size) self.assertEqual(5110, media.duration) + self.assertEqual(0, media.width) + self.assertEqual(0, media.height) + self.assertTrue(media.is_ready) + + alt1, alt2 = list(media.alternates.order_by("id")) + + self.assertEqual(self.org, alt1.org) self.assertEqual( - { - "audio/wav": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.wav", - "audio/mp3": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.mp3", - "audio/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/allo.m4a", - }, - media.paths, + f"/media/test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/allo.mp3", alt1.url + ) + self.assertEqual("allo.mp3", alt1.name) + self.assertEqual("audio/mp3", alt1.content_type) + self.assertEqual( + f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/allo.mp3", alt1.path + ) + self.assertEqual(5517, alt1.size) + self.assertEqual(5110, alt1.duration) + self.assertEqual(0, alt1.width) + self.assertEqual(0, alt2.height) + self.assertTrue(alt1.is_ready) + + self.assertEqual(self.org, alt2.org) + self.assertEqual( + f"/media/test_orgs/{self.org.id}/media/fe6c/fe6cb59a-0a79-4b01-babf-dc97fe70d3e7/allo.m4a", alt2.url + ) + self.assertEqual("allo.m4a", alt2.name) + self.assertEqual("audio/mp4", alt2.content_type) + self.assertEqual( + f"test_orgs/{self.org.id}/media/fe6c/fe6cb59a-0a79-4b01-babf-dc97fe70d3e7/allo.m4a", alt2.path ) + self.assertEqual(20552, alt2.size) + self.assertEqual(5110, alt2.duration) + self.assertEqual(0, alt2.width) + self.assertEqual(0, alt2.height) + self.assertTrue(alt2.is_ready) + + @patch("temba.msgs.models.uuid4") + def test_process_audio_m4a(self, mock_uuid): + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("23184249-7c8f-437b-8123-e12c190abf7e"), + ] - def test_process_audio_m4a(self): - flow = self.create_flow("Color") media = Media.from_upload( self.org, self.admin, - self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.m4a", "audio/mp4"), - flow=flow, + self.upload(f"{settings.MEDIA_ROOT}/test_media/bubbles.m4a", "audio/mp4"), + process=False, ) media.process_upload() + self.assertEqual(46468, media.size) + self.assertEqual(10216, media.duration) + self.assertEqual(0, media.width) + self.assertEqual(0, media.height) self.assertTrue(media.is_ready) - self.assertEqual(3809, media.duration) + + alt = media.alternates.get() + + self.assertEqual(self.org, alt.org) self.assertEqual( - { - "audio/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.m4a", - "audio/mp3": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.mp3", - }, - media.paths, + f"/media/test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/bubbles.mp3", alt.url + ) + self.assertEqual("bubbles.mp3", alt.name) + self.assertEqual("audio/mp3", alt.content_type) + self.assertEqual( + f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/bubbles.mp3", alt.path ) + self.assertEqual(41493, alt.size) + self.assertEqual(10216, alt.duration) + self.assertEqual(0, alt.width) + self.assertEqual(0, alt.height) + self.assertTrue(alt.is_ready) + + @patch("temba.msgs.models.uuid4") + def test_process_video_mp4(self, mock_uuid): + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("23184249-7c8f-437b-8123-e12c190abf7e"), + ] - def test_process_video_mp4(self): - flow = self.create_flow("Color") media = Media.from_upload( - self.org, - self.admin, - self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4"), - flow=flow, + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4"), process=False ) media.process_upload() + self.assertEqual(684558, media.size) + self.assertEqual(3536, media.duration) + self.assertEqual(640, media.width) + self.assertEqual(480, media.height) self.assertTrue(media.is_ready) - self.assertEqual(3809, media.duration) + + alt = media.alternates.get() + + self.assertEqual(self.org, alt.org) self.assertEqual( - { - "video/mp4": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.mp4", - "image/jpg": f"attachments/{self.org.id}/{flow.id}/steps/{media.uuid}/snow.jpg", - }, - media.paths, - ) + f"/media/test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/snow.jpg", alt.url + ) + self.assertEqual("snow.jpg", alt.name) + self.assertEqual("image/jpeg", alt.content_type) + self.assertEqual(f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/snow.jpg", alt.path) + self.assertEqual(37613, alt.size) + self.assertEqual(0, alt.duration) + self.assertEqual(640, alt.width) + self.assertEqual(480, alt.height) + self.assertTrue(alt.is_ready) class MsgTest(TembaTest): From 316e9b5684a8550ba7e5c82497a08219f3134846 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 18:11:23 -0500 Subject: [PATCH 074/630] Get image media dimensions when processing too --- media/test_media/klab.png | Bin 0 -> 371425 bytes temba/msgs/media.py | 4 +++- temba/msgs/tests.py | 34 +++++++++++++++++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 media/test_media/klab.png diff --git a/media/test_media/klab.png b/media/test_media/klab.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7c42c9e5b1450eb24c622d57877f9dbf5f46ba GIT binary patch literal 371425 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 literal 0 HcmV?d00001 diff --git a/temba/msgs/media.py b/temba/msgs/media.py index 556397ef388..abe88a35bec 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -33,7 +33,9 @@ def process_upload(media: Media): def _process_image_upload(media: Media, sub_type: str, file): - pass + probe = ffmpeg.probe(file.name, select_streams="v:0") + media.width = probe["streams"][0]["width"] + media.height = probe["streams"][0]["height"] def _process_audio_upload(media: Media, sub_type: str, file): diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 400e2eae8fc..b6076747af5 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -60,6 +60,26 @@ def test_from_upload(self, mock_uuid): self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) + @patch("temba.msgs.models.uuid4") + def test_process_image_png(self, mock_uuid): + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("23184249-7c8f-437b-8123-e12c190abf7e"), + ] + + media = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/klab.png", "image/png"), + ) + media.refresh_from_db() + + self.assertEqual(371425, media.size) + self.assertEqual(0, media.duration) + self.assertEqual(480, media.width) + self.assertEqual(360, media.height) + self.assertTrue(media.is_ready) + @patch("temba.msgs.models.uuid4") def test_process_audio_wav(self, mock_uuid): mock_uuid.side_effect = [ @@ -69,9 +89,8 @@ def test_process_audio_wav(self, mock_uuid): ] media = Media.from_upload( - self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav"), process=False + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/allo.wav", "audio/wav") ) - media.process_upload() media.refresh_from_db() self.assertEqual(81818, media.size) @@ -120,12 +139,9 @@ def test_process_audio_m4a(self, mock_uuid): ] media = Media.from_upload( - self.org, - self.admin, - self.upload(f"{settings.MEDIA_ROOT}/test_media/bubbles.m4a", "audio/mp4"), - process=False, + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/bubbles.m4a", "audio/mp4") ) - media.process_upload() + media.refresh_from_db() self.assertEqual(46468, media.size) self.assertEqual(10216, media.duration) @@ -158,9 +174,9 @@ def test_process_video_mp4(self, mock_uuid): ] media = Media.from_upload( - self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4"), process=False + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "video/mp4") ) - media.process_upload() + media.refresh_from_db() self.assertEqual(684558, media.size) self.assertEqual(3536, media.duration) From b69978ac3d218d59df6c1aefdc803ed116dcf700 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 18:42:58 -0500 Subject: [PATCH 075/630] Cleanup media upload filenames --- temba/msgs/media.py | 26 +++++++++++++++++--------- temba/msgs/models.py | 16 +++++++++++++--- temba/msgs/tests.py | 23 ++++++++++++++++++++++- temba/tests/base.py | 4 ++-- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/temba/msgs/media.py b/temba/msgs/media.py index abe88a35bec..599def45751 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -33,14 +33,14 @@ def process_upload(media: Media): def _process_image_upload(media: Media, sub_type: str, file): - probe = ffmpeg.probe(file.name, select_streams="v:0") - media.width = probe["streams"][0]["width"] - media.height = probe["streams"][0]["height"] + stream_info = _get_stream_info(file.name, "v:0") + media.width = stream_info.get("width", 0) + media.height = stream_info.get("height", 0) def _process_audio_upload(media: Media, sub_type: str, file): - probe = ffmpeg.probe(file.name, select_streams="a:0") - media.duration = int(float(probe["streams"][0]["duration"]) * 1000) + stream_info = _get_stream_info(file.name, "a:0") + media.duration = int(float(stream_info.get("duration", 0)) * 1000) if sub_type != "mp3": _create_alternate_audio(media, file, "audio/mp3", "mp3", codec="libmp3lame") @@ -49,10 +49,10 @@ def _process_audio_upload(media: Media, sub_type: str, file): def _process_video_upload(media: Media, sub_type: str, file): - probe = ffmpeg.probe(file.name, select_streams="v:0") - media.duration = int(float(probe["streams"][0]["duration"]) * 1000) - media.width = probe["streams"][0]["width"] - media.height = probe["streams"][0]["height"] + stream_info = _get_stream_info(file.name, "v:0") + media.duration = int(float(stream_info.get("duration", 0)) * 1000) + media.width = stream_info.get("width", 0) + media.height = stream_info.get("height", 0) _create_video_thumbnail(media, file) @@ -94,6 +94,14 @@ def _create_alternate(original: Media, file, transform, new_content_type: str, n return Media.create_alternate(original, new_name, new_content_type, temp, **kwargs) +def _get_stream_info(filename: str, stream_id: str) -> dict: + """ + Probes a file for a given stream type + """ + probe = ffmpeg.probe(filename, select_streams=stream_id) + return probe["streams"][0] if probe["streams"] else {} + + def _change_extension(filename: str, extension: str) -> str: """ Changes the extension of a filename diff --git a/temba/msgs/models.py b/temba/msgs/models.py index bb25a187e2e..731fa6802cd 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -1,4 +1,7 @@ import logging +import mimetypes +import os +import re import time from array import array from datetime import datetime, timedelta @@ -83,12 +86,19 @@ def from_upload(cls, org, user, file, process=True): from .tasks import process_media_upload + base_name, extension = os.path.splitext(file.name) + + # cleanup file name + base_name = re.sub(r"[^a-zA-Z0-9_ ]", "", base_name).strip() or "file" + + if not extension: + extension = mimetypes.guess_extension(file.content_type) or ".bin" + # browsers might send m4a files but correct MIME type is audio/mp4 - extension = file.name.split(".")[-1] - if extension == "m4a": + if extension == ".m4a": file.content_type = "audio/mp4" - media = cls._create(org, user, file.name, file.content_type, file) + media = cls._create(org, user, base_name + extension, file.content_type, file) if process: on_transaction_commit(lambda: process_media_upload.delay(media.id)) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index b6076747af5..b7bd1ee96d7 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -35,9 +35,17 @@ class MediaTest(TembaTest): + def tearDown(self): + self.clear_storage() + + return super().tearDown() + @patch("temba.msgs.models.uuid4") def test_from_upload(self, mock_uuid): - mock_uuid.side_effect = [UUID("6a65f14f-b762-4485-b860-96a322292775")] + mock_uuid.side_effect = [ + UUID("6a65f14f-b762-4485-b860-96a322292775"), + UUID("23184249-7c8f-437b-8123-e12c190abf7e"), + ] media = Media.from_upload( self.org, @@ -60,6 +68,19 @@ def test_from_upload(self, mock_uuid): self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) + # check that our filename is cleaned + media = Media.from_upload( + self.org, + self.admin, + self.upload(f"{settings.MEDIA_ROOT}/test_media/klab.png", "image/png", name="../../../etc/passwd"), + process=False, + ) + + self.assertEqual("passwd.png", media.name) + self.assertEqual( + f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/passwd.png", media.path + ) + @patch("temba.msgs.models.uuid4") def test_process_image_png(self, mock_uuid): mock_uuid.side_effect = [ diff --git a/temba/tests/base.py b/temba/tests/base.py index 18678a6e9a1..88fa48e3377 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -771,9 +771,9 @@ def tearDown(self): def mockReadOnly(self, assert_models: set = None): return MockReadOnly(self, assert_models=assert_models) - def upload(self, path: str, content_type="text/plain"): + def upload(self, path: str, content_type="text/plain", name=None): with open(path, "rb") as f: - return SimpleUploadedFile(path, content=f.read(), content_type=content_type) + return SimpleUploadedFile(name or path, content=f.read(), content_type=content_type) class TembaNonAtomicTest(TembaTestMixin, SmartminTestMixin, TransactionTestCase): From 223e8246d987f7e4c5be15bb8a2e39bd8e069934 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 28 Jul 2022 18:48:26 -0500 Subject: [PATCH 076/630] Use self.assertAlmostEqual when testing transcoded media size --- temba/msgs/models.py | 2 +- temba/msgs/tests.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 731fa6802cd..d81d7193168 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -89,7 +89,7 @@ def from_upload(cls, org, user, file, process=True): base_name, extension = os.path.splitext(file.name) # cleanup file name - base_name = re.sub(r"[^a-zA-Z0-9_ ]", "", base_name).strip() or "file" + base_name = re.sub(r"[^a-zA-Z0-9_ ]", "", base_name).strip()[:255] or "file" if not extension: extension = mimetypes.guess_extension(file.content_type) or ".bin" diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index b7bd1ee96d7..237dbdd674d 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -131,7 +131,7 @@ def test_process_audio_wav(self, mock_uuid): self.assertEqual( f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/allo.mp3", alt1.path ) - self.assertEqual(5517, alt1.size) + self.assertAlmostEqual(5517, alt1.size, delta=1000) self.assertEqual(5110, alt1.duration) self.assertEqual(0, alt1.width) self.assertEqual(0, alt2.height) @@ -146,7 +146,7 @@ def test_process_audio_wav(self, mock_uuid): self.assertEqual( f"test_orgs/{self.org.id}/media/fe6c/fe6cb59a-0a79-4b01-babf-dc97fe70d3e7/allo.m4a", alt2.path ) - self.assertEqual(20552, alt2.size) + self.assertAlmostEqual(20552, alt2.size, delta=7500) self.assertEqual(5110, alt2.duration) self.assertEqual(0, alt2.width) self.assertEqual(0, alt2.height) @@ -181,7 +181,7 @@ def test_process_audio_m4a(self, mock_uuid): self.assertEqual( f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/bubbles.mp3", alt.path ) - self.assertEqual(41493, alt.size) + self.assertAlmostEqual(41493, alt.size, delta=1000) self.assertEqual(10216, alt.duration) self.assertEqual(0, alt.width) self.assertEqual(0, alt.height) @@ -214,7 +214,7 @@ def test_process_video_mp4(self, mock_uuid): self.assertEqual("snow.jpg", alt.name) self.assertEqual("image/jpeg", alt.content_type) self.assertEqual(f"test_orgs/{self.org.id}/media/2318/23184249-7c8f-437b-8123-e12c190abf7e/snow.jpg", alt.path) - self.assertEqual(37613, alt.size) + self.assertAlmostEqual(37613, alt.size, delta=1000) self.assertEqual(0, alt.duration) self.assertEqual(640, alt.width) self.assertEqual(480, alt.height) From df938d613b46560f592d448d557f2ced63c8e8b8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 29 Jul 2022 09:12:26 -0500 Subject: [PATCH 077/630] Add decorator to mock uuid generation in tests --- temba/flows/tests.py | 30 ++++++++++++++++-------------- temba/msgs/tests.py | 14 ++++++-------- temba/tests/base.py | 26 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index 6481200e950..8c45ea11f27 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -28,13 +28,22 @@ from temba.mailroom import FlowValidationException from temba.orgs.integrations.dtone import DTOneType from temba.templates.models import Template, TemplateTranslation -from temba.tests import AnonymousOrg, CRUDLTestMixin, MigrationTest, MockResponse, TembaTest, matchers, mock_mailroom +from temba.tests import ( + AnonymousOrg, + CRUDLTestMixin, + MigrationTest, + MockResponse, + TembaTest, + matchers, + mock_mailroom, + mock_uuids, +) from temba.tests.engine import MockSessionWriter from temba.tests.s3 import MockS3Client, jsonlgz_encode from temba.tickets.models import Ticketer from temba.triggers.models import Trigger from temba.utils import json -from temba.utils.uuid import UUID, uuid4 +from temba.utils.uuid import uuid4 from .checks import mailroom_url from .models import ( @@ -2973,8 +2982,8 @@ def test_broadcast_background_flow(self, mr_mocks): self.assertTrue(start.include_active) self.assertEqual('name ~ "frank"', start.query) - @patch("temba.msgs.models.uuid4") - def test_upload_media(self, mock_uuid): + @mock_uuids + def test_upload_media(self): flow = self.create_flow("Test") other_org_flow = self.create_flow("Test", org=self.org2) @@ -2989,19 +2998,12 @@ def assert_upload(user, filename, expected_json): self.assertEqual(response.status_code, 200) self.assertEqual(expected_json, response.json()) - mock_uuid.side_effect = [ - UUID("6a65f14f-b762-4485-b860-96a322292775"), - UUID("2f42e913-6a19-44c5-90ee-cdf7b14ad5c0"), - UUID("f661c405-524e-4bd7-83e2-c93ffe35aa60"), - UUID("67ec31c7-a85f-4834-9da2-dee2c7b56576"), - ] - assert_upload( self.admin, f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", { "type": "image/jpeg", - "url": f"/media/test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", + "url": f"/media/test_orgs/{self.org.id}/media/3618/361838c4-2866-495a-8990-9f3c222a7604/steve%20marten.jpg", }, ) assert_upload( @@ -3009,7 +3011,7 @@ def assert_upload(user, filename, expected_json): f"{settings.MEDIA_ROOT}/test_media/snow.mp4", { "type": "video/mp4", - "url": f"/media/test_orgs/{self.org.id}/media/2f42/2f42e913-6a19-44c5-90ee-cdf7b14ad5c0/snow.mp4", + "url": f"/media/test_orgs/{self.org.id}/media/606d/606de307-a799-47fc-8802-edc9301e0e04/snow.mp4", }, ) assert_upload( @@ -3017,7 +3019,7 @@ def assert_upload(user, filename, expected_json): f"{settings.MEDIA_ROOT}/test_media/snow.m4a", { "type": "audio/mp4", - "url": f"/media/test_orgs/{self.org.id}/media/f661/f661c405-524e-4bd7-83e2-c93ffe35aa60/snow.m4a", + "url": f"/media/test_orgs/{self.org.id}/media/5349/53499958-0a0a-48a5-bb5f-8f9f4d8af77b/snow.m4a", }, ) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 25e7ca92f75..42fdb703db5 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -25,35 +25,33 @@ SystemLabelCount, ) from temba.schedules.models import Schedule -from temba.tests import AnonymousOrg, CRUDLTestMixin, TembaTest +from temba.tests import AnonymousOrg, CRUDLTestMixin, TembaTest, mock_uuids from temba.tests.engine import MockSessionWriter from temba.tests.s3 import MockS3Client, jsonlgz_encode -from temba.utils.uuid import UUID from .tasks import squash_msgcounts from .templatetags.sms import as_icon class MediaTest(TembaTest): - @patch("temba.msgs.models.uuid4") - def test_model(self, mock_uuid): - mock_uuid.side_effect = [UUID("6a65f14f-b762-4485-b860-96a322292775")] + @mock_uuids + def test_model(self): media = Media.from_upload( self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "image/jpeg"), ) - self.assertEqual("6a65f14f-b762-4485-b860-96a322292775", str(media.uuid)) + self.assertEqual("b97f69f7-5edf-45c7-9fda-d37066eae91d", str(media.uuid)) self.assertEqual(self.org, media.org) self.assertEqual( - f"/media/test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve%20marten.jpg", + f"/media/test_orgs/{self.org.id}/media/b97f/b97f69f7-5edf-45c7-9fda-d37066eae91d/steve%20marten.jpg", media.url, ) self.assertEqual("steve marten.jpg", media.name) self.assertEqual("image/jpeg", media.content_type) self.assertEqual( - f"test_orgs/{self.org.id}/media/6a65/6a65f14f-b762-4485-b860-96a322292775/steve marten.jpg", media.path + f"test_orgs/{self.org.id}/media/b97f/b97f69f7-5edf-45c7-9fda-d37066eae91d/steve marten.jpg", media.path ) self.assertEqual(self.admin, media.created_by) self.assertFalse(media.is_ready) diff --git a/temba/tests/base.py b/temba/tests/base.py index 18678a6e9a1..f923c8f4411 100644 --- a/temba/tests/base.py +++ b/temba/tests/base.py @@ -1,5 +1,6 @@ import shutil from datetime import datetime +from functools import wraps from pathlib import Path from unittest.mock import patch @@ -861,3 +862,28 @@ def setUp(self): def setUpBeforeMigration(self, apps): pass + + +def mock_uuids(method=None, *, seed=1234): + """ + Convenience decorator to override UUID generation in a test. + """ + + from temba.utils import uuid + + def _wrap_test_method(f, instance, *args, **kwargs): + try: + uuid.default_generator = uuid.seeded_generator(seed) + + return f(instance, *args, **kwargs) + finally: + uuid.default_generator = uuid.real_uuid4 + + def actual_decorator(f): + @wraps(f) + def wrapper(instance, *args, **kwargs): + _wrap_test_method(f, instance, *args, **kwargs) + + return wrapper + + return actual_decorator(method) if method else actual_decorator From bf7a50c899d9a6ff924f01c127885e4f48370787 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 29 Jul 2022 11:45:06 -0500 Subject: [PATCH 078/630] Convert more views to use ContentMenuMixin --- temba/archives/views.py | 17 +- temba/campaigns/views.py | 110 ++++--------- temba/channels/types/dialog360/type.py | 2 +- temba/channels/types/facebookapp/type.py | 2 +- temba/channels/types/instagram/type.py | 4 +- temba/channels/types/whatsapp/type.py | 2 +- temba/channels/types/whatsapp_cloud/type.py | 4 +- temba/channels/views.py | 173 +++++++------------- temba/classifiers/views.py | 32 ++-- temba/flows/views.py | 169 +++++++------------ temba/locations/views.py | 7 +- temba/utils/views.py | 30 +++- 12 files changed, 197 insertions(+), 355 deletions(-) diff --git a/temba/archives/views.py b/temba/archives/views.py index 30a38d61f6b..9f5baf4e9e2 100644 --- a/temba/archives/views.py +++ b/temba/archives/views.py @@ -7,7 +7,7 @@ from django.urls import reverse from temba.orgs.views import OrgObjPermsMixin, OrgPermsMixin -from temba.utils.views import SpaMixin +from temba.utils.views import ContentMenuMixin, SpaMixin from .models import Archive @@ -18,27 +18,18 @@ class ArchiveCRUDL(SmartCRUDL): actions = ("read", "run", "message") permissions = True - class BaseList(SpaMixin, OrgPermsMixin, SmartListView): + class BaseList(SpaMixin, OrgPermsMixin, ContentMenuMixin, SmartListView): title = _("Archive") fields = ("url", "start_date", "period", "record_count", "size") default_order = ("-start_date", "-period", "archive_type") paginate_by = 250 - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): if not self.is_spa(): archive_type = self.get_archive_type() for choice in Archive.TYPE_CHOICES: if archive_type != choice[0]: - links.append( - dict( - title=f"{choice[1]} {_('Archives')}", - style="button-light", - href=f"{reverse(f'archives.archive_{choice[0]}')}", - ) - ) - return links + menu.add_link(f"{choice[1]} {_('Archives')}", reverse(f"archives.archive_{choice[0]}")) def get_queryset(self, **kwargs): queryset = super().get_queryset(**kwargs) diff --git a/temba/campaigns/views.py b/temba/campaigns/views.py index 83b0861a821..bcc19bb38a0 100644 --- a/temba/campaigns/views.py +++ b/temba/campaigns/views.py @@ -21,7 +21,7 @@ from temba.orgs.views import MenuMixin, ModalMixin, OrgFilterMixin, OrgObjPermsMixin, OrgPermsMixin from temba.utils import languages from temba.utils.fields import CompletionTextarea, InputWidget, SelectWidget, TembaChoiceField -from temba.utils.views import BulkActionMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ContentMenuMixin, SpaMixin from .models import Campaign, CampaignEvent @@ -123,79 +123,47 @@ def form_valid(self, form): return self.render_modal_response(form) - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" def derive_title(self): return self.object.name - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): if self.object.is_archived: if self.has_org_perm("campaigns.campaign_activate"): - links.append( - dict( - title="Activate", - js_class="posterize activate-campaign", - href=reverse("campaigns.campaign_activate", args=[self.object.id]), - ) - ) + menu.add_url_post(_("Activate"), reverse("campaigns.campaign_activate", args=[self.object.id])) if self.has_org_perm("orgs.org_export"): - links.append( - dict( - title=_("Export"), - href=f"{reverse('orgs.org_export')}?campaign={self.object.id}&archived=1", - ) - ) - + menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={self.object.id}&archived=1") else: if self.has_org_perm("campaigns.campaignevent_create"): - links.append( - dict( - id="event-add", - title=_("New Event"), - href=f"{reverse('campaigns.campaignevent_create')}?campaign={self.object.pk}", - modax=_("New Event"), - ) + menu.add_modax( + _("New Event"), + "event-add", + f"{reverse('campaigns.campaignevent_create')}?campaign={self.object.id}", ) + if self.has_org_perm("orgs.org_export"): - links.append( - dict(title=_("Export"), href=f"{reverse('orgs.org_export')}?campaign={self.object.id}") - ) + menu.add_link(_("Export"), f"{reverse('orgs.org_export')}?campaign={self.object.id}") if self.has_org_perm("campaigns.campaign_update"): - links.append( - dict( - id="campaign-update", - title=_("Edit"), - href=reverse("campaigns.campaign_update", args=[self.object.pk]), - modax=_("Edit Campaign"), - ) + menu.add_modax( + _("Edit"), + "campaign-update", + reverse("campaigns.campaign_update", args=[self.object.id]), + title=_("Edit Campaign"), ) if self.has_org_perm("campaigns.campaign_archive"): - links.append( - dict( - title="Archive", - js_class="posterize archive-campaign", - href=reverse("campaigns.campaign_archive", args=[self.object.id]), - ) - ) + menu.add_url_post(_("Archive"), reverse("campaigns.campaign_archive", args=[self.object.id])) - user = self.get_user() - if user.is_superuser or user.is_staff: - links.append( - dict( - title=_("Service"), - posterize=True, - href=f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("campaigns.campaign_read", args=[self.object.uuid])}', - ) + if self.request.user.is_staff: + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("campaigns.campaign_read", args=[self.object.uuid])}', ) - return links - class Create(OrgPermsMixin, ModalMixin, SmartCreateView): fields = ("name", "group") form_class = CampaignForm @@ -538,7 +506,7 @@ class CampaignEventCRUDL(SmartCRUDL): "This is a background flow. When it triggers, it will run it for all contacts without interruption." ) - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): @classmethod def derive_url_pattern(cls, path, action): return r"^%s/%s/(?P[0-9a-f-]+)/(?P\d+)/$" % (path, action) @@ -572,33 +540,23 @@ def get_context_data(self, **kwargs): return context - def get_gear_links(self): - links = [] - - campaign_event = self.get_object() - - if self.has_org_perm("campaigns.campaignevent_update") and not campaign_event.campaign.is_archived: - links.append( - dict( - id="event-update", - title=_("Edit"), - href=reverse("campaigns.campaignevent_update", args=[campaign_event.pk]), - modax=_("Edit Event"), - ) + def build_content_menu(self, menu): + if self.has_org_perm("campaigns.campaignevent_update") and not self.object.campaign.is_archived: + menu.add_modax( + _("Edit"), + "event-update", + reverse("campaigns.campaignevent_update", args=[self.object.id]), + title=_("Edit Event"), ) if self.has_org_perm("campaigns.campaignevent_delete"): - links.append( - dict( - id="event-delete", - title="Delete", - href=reverse("campaigns.campaignevent_delete", args=[campaign_event.id]), - modax=_("Delete Event"), - ) + menu.add_modax( + _("Delete"), + "event-delete", + reverse("campaigns.campaignevent_delete", args=[self.object.id]), + title=_("Delete Event"), ) - return links - class Delete(ModalMixin, OrgObjPermsMixin, SmartDeleteView): default_template = "smartmin/delete_confirm.html" diff --git a/temba/channels/types/dialog360/type.py b/temba/channels/types/dialog360/type.py index 8e1f932c8e0..a92f4509ced 100644 --- a/temba/channels/types/dialog360/type.py +++ b/temba/channels/types/dialog360/type.py @@ -20,7 +20,7 @@ class Dialog360Type(ChannelType): A 360 Dialog Channel Type """ - extra_links = [dict(name=_("Message Templates"), link="channels.types.dialog360.templates")] + extra_links = [dict(label=_("Message Templates"), view_name="channels.types.dialog360.templates")] code = "D3" category = ChannelType.Category.SOCIAL_MEDIA diff --git a/temba/channels/types/facebookapp/type.py b/temba/channels/types/facebookapp/type.py index d9a040ffd32..4930b00ada8 100644 --- a/temba/channels/types/facebookapp/type.py +++ b/temba/channels/types/facebookapp/type.py @@ -15,7 +15,7 @@ class FacebookAppType(ChannelType): A Facebook channel """ - extra_links = [dict(name=_("Reconnect Facebook Page"), link="channels.types.facebookapp.refresh_token")] + extra_links = [dict(label=_("Reconnect Facebook Page"), view_name="channels.types.facebookapp.refresh_token")] code = "FBA" category = ChannelType.Category.SOCIAL_MEDIA diff --git a/temba/channels/types/instagram/type.py b/temba/channels/types/instagram/type.py index 0e918cd7706..fe2a5f5dac3 100644 --- a/temba/channels/types/instagram/type.py +++ b/temba/channels/types/instagram/type.py @@ -16,8 +16,8 @@ class InstagramType(ChannelType): extra_links = [ dict( - name=_("Reconnect Instagram Business Account"), - link="channels.types.instagram.refresh_token", + label=_("Reconnect Instagram Business Account"), + view_name="channels.types.instagram.refresh_token", ) ] diff --git a/temba/channels/types/whatsapp/type.py b/temba/channels/types/whatsapp/type.py index 83a82d1e492..ac34698d8f3 100644 --- a/temba/channels/types/whatsapp/type.py +++ b/temba/channels/types/whatsapp/type.py @@ -29,7 +29,7 @@ class WhatsAppType(ChannelType): A WhatsApp Channel Type """ - extra_links = [dict(name=_("Message Templates"), link="channels.types.whatsapp.templates")] + extra_links = [dict(label=_("Message Templates"), view_name="channels.types.whatsapp.templates")] code = "WA" category = ChannelType.Category.SOCIAL_MEDIA diff --git a/temba/channels/types/whatsapp_cloud/type.py b/temba/channels/types/whatsapp_cloud/type.py index 3d141a1f34a..46037fb8449 100644 --- a/temba/channels/types/whatsapp_cloud/type.py +++ b/temba/channels/types/whatsapp_cloud/type.py @@ -20,8 +20,8 @@ class WhatsAppCloudType(ChannelType): """ extra_links = [ - dict(name=_("Message Templates"), link="channels.types.whatsapp_cloud.templates"), - dict(name=_("Verify Number"), link="channels.types.whatsapp_cloud.request_code"), + dict(label=_("Message Templates"), view_name="channels.types.whatsapp_cloud.templates"), + dict(label=_("Verify Number"), view_name="channels.types.whatsapp_cloud.request_code"), ] code = "WAC" diff --git a/temba/channels/views.py b/temba/channels/views.py index 868e876cb78..2a42beb8dd0 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -44,7 +44,7 @@ from temba.utils import analytics, countries, json from temba.utils.fields import SelectWidget from temba.utils.models import patch_queryset_count -from temba.utils.views import ComponentFormMixin, SpaMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin, SpaMixin from .models import ( Alert, @@ -781,139 +781,92 @@ def derive_menu(self): return menu - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" exclude = ("id", "is_active", "created_by", "modified_by", "modified_on") def get_queryset(self): return Channel.objects.filter(is_active=True) - def get_gear_links(self): - links = [] - - extra_links = self.object.type.extra_links - if extra_links: - for extra in extra_links: - links.append(dict(title=extra["name"], href=reverse(extra["link"], args=[self.object.uuid]))) + def build_content_menu(self, menu): + for extra in self.object.type.extra_links or (): + menu.add_link(extra["label"], reverse(extra["view_name"], args=[self.object.uuid])) if self.object.parent: - links.append( - dict( - title=_("Android Channel"), - style="button-primary", - href=reverse("channels.channel_read", args=[self.object.parent.uuid]), - ) - ) + menu.add_link(_("Android Channel"), reverse("channels.channel_read", args=[self.object.parent.uuid])) if self.object.type.show_config_page: - links.append( - dict(title=_("Settings"), href=reverse("channels.channel_configuration", args=[self.object.uuid])) - ) + menu.add_link(_("Settings"), reverse("channels.channel_configuration", args=[self.object.uuid])) if not self.object.is_android(): sender = self.object.get_sender() caller = self.object.get_caller() if sender: - links.append( - dict(title=_("Channel Log"), href=reverse("channels.channellog_list", args=[sender.uuid])) - ) + menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[sender.uuid])) elif Channel.ROLE_RECEIVE in self.object.role: - links.append( - dict(title=_("Channel Log"), href=reverse("channels.channellog_list", args=[self.object.uuid])) - ) + menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[self.object.uuid])) if caller and caller != sender: - links.append( - dict( - title=_("Call Log"), - href=f"{reverse('channels.channellog_list', args=[caller.uuid])}?sessions=1", - ) + menu.add_link( + _("Call Log"), f"{reverse('channels.channellog_list', args=[caller.uuid])}?sessions=1" ) if self.has_org_perm("channels.channel_update"): - links.append( - dict( - id="update-channel", - title=_("Edit"), - href=reverse("channels.channel_update", args=[self.object.id]), - modax=_("Edit Channel"), - ) + menu.add_modax( + _("Edit"), + "update-channel", + reverse("channels.channel_update", args=[self.object.id]), + title=_("Edit Channel"), ) if self.object.is_android() or (self.object.parent and self.object.parent.is_android()): - sender = self.object.get_sender() + if sender and sender.is_delegate_sender(): - links.append( - dict( - id="disable-sender", - title=_("Disable Bulk Sending"), - modax=_("Disable Bulk Sending"), - href=reverse("channels.channel_delete", args=[sender.uuid]), - ) + menu.add_modax( + _("Disable Bulk Sending"), + "disable-sender", + reverse("channels.channel_delete", args=[sender.uuid]), ) elif self.object.is_android(): - links.append( - dict( - title=_("Enable Bulk Sending"), - href="%s?channel=%d" - % (reverse("channels.channel_bulk_sender_options"), self.object.id), - ) + menu.add_link( + _("Enable Bulk Sending"), + f"{reverse('channels.channel_bulk_sender_options')}?channel={self.object.id}", ) caller = self.object.get_caller() + if caller and caller.is_delegate_caller(): - links.append( - dict( - id="disable-voice", - title=_("Disable Voice Calling"), - modax=_("Disable Voice Calling"), - href=reverse("channels.channel_delete", args=[caller.uuid]), - ) + menu.add_modax( + _("Disable Voice Calling"), + "disable-voice", + reverse("channels.channel_delete", args=[caller.uuid]), ) elif self.object.org.is_connected_to_twilio(): - links.append( - dict( - id="enable-voice", - title=_("Enable Voice Calling"), - js_class="posterize", - href=f"{reverse('channels.channel_create_caller')}?channel={self.object.id}", - ) + menu.add_url_post( + _("Enable Voice Calling"), + f"{reverse('channels.channel_create_caller')}?channel={self.object.id}", ) if self.has_org_perm("channels.channel_delete"): - links.append( - dict( - id="delete-channel", - title=_("Delete Channel"), - modax=_("Delete Channel"), - href=reverse("channels.channel_delete", args=[self.object.uuid]), - ) + menu.add_modax( + _("Delete Channel"), "delete-channel", reverse("channels.channel_delete", args=[self.object.uuid]) ) if self.object.channel_type == "FB" and self.has_org_perm("channels.channel_facebook_whitelist"): - links.append( - dict( - id="fb-whitelist", - title=_("Whitelist Domain"), - modax=_("Whitelist Domain"), - href=reverse("channels.channel_facebook_whitelist", args=[self.object.uuid]), - ) + menu.add_modax( + _("Whitelist Domain"), + "fb-whitelist", + reverse("channels.channel_facebook_whitelist", args=[self.object.uuid]), ) - user = self.get_user() - if user.is_superuser or user.is_staff: - links.append( - dict( - title=_("Service"), - posterize=True, - href=f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("channels.channel_read", args=[self.object.uuid])}', - ) + if self.request.user.is_staff: + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={self.object.org_id}&redirect_url={reverse("channels.channel_read", args=[self.object.uuid])}', ) - return links - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) channel = self.object @@ -1483,7 +1436,7 @@ class ChannelLogCRUDL(SmartCRUDL): model = ChannelLog actions = ("list", "read", "connection") - class List(SpaMixin, OrgPermsMixin, SmartListView): + class List(SpaMixin, OrgPermsMixin, ContentMenuMixin, SmartListView): fields = ("channel", "description", "created_on") link_fields = ("channel", "description", "created_on") paginate_by = 50 @@ -1504,20 +1457,17 @@ def folder(self) -> str: else: return self.FOLDER_MESSAGES - def get_gear_links(self): + def build_content_menu(self, menu): list_url = reverse("channels.channellog_list", args=[self.channel.uuid]) - links = [] if self.folder != self.FOLDER_MESSAGES: - links.append(dict(title=_("Messages"), href=list_url)) + menu.add_link(_("Messages"), list_url) if self.folder != self.FOLDER_CALLS and self.channel.supports_ivr(): - links.append(dict(title=_("Calls"), href=f"{list_url}?calls=1")) + menu.add_link(_("Calls"), f"{list_url}?calls=1") if self.folder != self.FOLDER_OTHERS: - links.append(dict(title=_("Other Interactions"), href=f"{list_url}?others=1")) + menu.add_link(_("Other Interactions"), f"{list_url}?others=1") if self.folder != self.FOLDER_ERRORS: - links.append(dict(title=_("Errors"), href=f"{list_url}?errors=1")) - - return links + menu.add_link(_("Errors"), f"{list_url}?errors=1") @classmethod def derive_url_pattern(cls, path, action): @@ -1566,19 +1516,16 @@ def get_context_data(self, **kwargs): context["channel"] = self.channel return context - class Connection(AnonMixin, SmartReadView): + class Connection(AnonMixin, ContentMenuMixin, SmartReadView): model = ChannelConnection - def get_gear_links(self): - return [ - dict( - title=_("More Calls"), - style="button-light", - href=reverse("channels.channellog_list", args=[self.get_object().channel.uuid]) + "?connections=1", - ) - ] + def build_content_menu(self, menu): + menu.add_link( + _("More Calls"), + reverse("channels.channellog_list", args=[self.get_object().channel.uuid]) + "?connections=1", + ) - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): fields = ("description", "created_on") slug_url_kwarg = "pk" @@ -1586,14 +1533,8 @@ class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): def derive_url_pattern(cls, path, action): return r"^%s/%s/(?P[0-9a-f-]+)/(?P\d+)/$" % (path, action) - def get_gear_links(self): - return [ - dict( - title=_("Channel Log"), - style="button-light", - href=reverse("channels.channellog_list", args=[self.get_object().channel.uuid]), - ) - ] + def build_content_menu(self, menu): + menu.add_link(_("Channel Log"), reverse("channels.channellog_list", args=[self.get_object().channel.uuid])) def get_object_org(self): return self.get_object().channel.org diff --git a/temba/classifiers/views.py b/temba/classifiers/views.py index cb358dbb35c..840994e7528 100644 --- a/temba/classifiers/views.py +++ b/temba/classifiers/views.py @@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _ from temba.orgs.views import DependencyDeleteModal, MenuMixin, OrgObjPermsMixin, OrgPermsMixin -from temba.utils.views import ComponentFormMixin, SpaMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin, SpaMixin from .models import Classifier @@ -73,34 +73,24 @@ class Delete(DependencyDeleteModal): success_url = "@orgs.org_home" success_message = _("Your classifier has been deleted.") - class Read(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Read(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" exclude = ("id", "is_active", "created_by", "modified_by", "modified_on") - def get_gear_links(self): - links = [dict(title=_("Log"), href=reverse("request_logs.httplog_classifier", args=[self.object.uuid]))] + def build_content_menu(self, menu): + menu.add_link(_("Log"), reverse("request_logs.httplog_classifier", args=[self.object.uuid])) if self.has_org_perm("classifiers.classifier_sync"): - links.append( - dict( - title=_("Sync"), - style="btn-secondary", - posterize=True, - href=reverse("classifiers.classifier_sync", args=[self.object.id]), - ) - ) + menu.add_url_post(_("Sync"), reverse("classifiers.classifier_sync", args=[self.object.id])) + if self.has_org_perm("classifiers.classifier_delete"): - links.append( - dict( - id="ticketer-delete", - title=_("Delete"), - modax=_("Delete Classifier"), - href=reverse("classifiers.classifier_delete", args=[self.object.uuid]), - ) + menu.add_modax( + _("Delete"), + "classifier-delete", + reverse("classifiers.classifier_delete", args=[self.object.uuid]), + title=_("Delete Classifier"), ) - return links - def get_queryset(self, **kwargs): queryset = super().get_queryset(**kwargs) return queryset.filter(org=self.request.user.get_org(), is_active=True) diff --git a/temba/flows/views.py b/temba/flows/views.py index b88e3fd0000..034f3eb50bc 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -63,7 +63,7 @@ TembaChoiceField, ) from temba.utils.text import slugify_with -from temba.utils.views import BulkActionMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ContentMenuMixin, SpaMixin from .models import ( ExportFlowResultsTask, @@ -708,7 +708,7 @@ def post(self, request, *args, **kwargs): media = Media.from_upload(self.request.org, self.request.user, self.request.FILES["file"]) return JsonResponse({"type": media.content_type, "url": media.url}) - class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, SmartListView): + class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, ContentMenuMixin, SmartListView): title = _("Flows") refresh = 10000 fields = ("name", "modified_on") @@ -816,16 +816,11 @@ def get_folders(self): ), ] - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): if self.has_org_perm("orgs.org_import"): - links.append(dict(title=_("Import"), href=reverse("orgs.org_import"))) - + menu.add_link(_("Import"), reverse("orgs.org_import")) if self.has_org_perm("orgs.org_export"): - links.append(dict(title=_("Export"), href=reverse("orgs.org_export"))) - - return links + menu.add_link(_("Export"), reverse("orgs.org_export")) class Archived(BaseList): title = _("Archived Flows") @@ -888,36 +883,23 @@ class Filter(BaseList, OrgObjPermsMixin): bulk_actions = ("label",) slug_url_kwarg = "uuid" - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): label = FlowLabel.objects.get(uuid=self.kwargs["uuid"]) if self.has_org_perm("flows.flow_update"): - # links.append(dict(title=_("Edit"), href="#", js_class="label-update-btn")) - - links.append( - dict( - id="update-label", - title=_("Edit"), - style="button-primary", - href=f"{reverse('flows.flowlabel_update', args=[label.pk])}", - modax=_("Edit Label"), - ) + menu.add_modax( + _("Edit"), + "update-label", + f"{reverse('flows.flowlabel_update', args=[label.pk])}", + title=_("Edit Label"), + primary=True, ) if self.has_org_perm("flows.flow_delete"): - links.append( - dict( - id="delete-label", - title=_("Delete Label"), - href=f"{reverse('flows.flowlabel_delete', args=[label.pk])}", - modax=_("Delete Label"), - ) + menu.add_modax( + _("Delete Label"), "delete-label", f"{reverse('flows.flowlabel_delete', args=[label.pk])}" ) - return links - def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context["current_label"] = self.derive_label() @@ -951,7 +933,7 @@ def get_queryset(self, **kwargs): return qs - class Editor(SpaMixin, OrgObjPermsMixin, SmartReadView): + class Editor(SpaMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" def derive_title(self): @@ -1034,95 +1016,68 @@ def get_features(self, org) -> list: return features - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): flow = self.object if ( flow.flow_type != Flow.TYPE_SURVEY and self.has_org_perm("flows.flow_broadcast") and not flow.is_archived ): - links.append( - dict( - id="start-flow", - title=_("Start Flow"), - style="button-primary", - href=f"{reverse('flows.flow_broadcast', args=[])}?flow={self.object.id}", - modax=_("Start Flow"), - ) + menu.add_modax( + _("Start Flow"), + "start-flow", + f"{reverse('flows.flow_broadcast', args=[])}?flow={self.object.id}", + primary=True, ) if self.has_org_perm("flows.flow_results"): - links.append( - dict( - title=_("Results"), - style="button-primary", - href=reverse("flows.flow_results", args=[flow.uuid]), - ) - ) - if len(links) > 1: - links.append(dict(divider=True)) + menu.add_link(_("Results"), reverse("flows.flow_results", args=[flow.uuid])) + + menu.new_group() if self.has_org_perm("flows.flow_update") and not flow.is_archived: - links.append( - dict( - id="edit-flow", - title=_("Edit"), - href=f"{reverse('flows.flow_update', args=[self.object.pk])}", - modax=_("Edit Flow"), - ) + menu.add_modax( + _("Edit"), + "edit-flow", + f"{reverse('flows.flow_update', args=[self.object.pk])}", + title=_("Edit Flow"), ) if self.has_org_perm("flows.flow_copy"): - links.append(dict(title=_("Copy"), posterize=True, href=reverse("flows.flow_copy", args=[flow.id]))) + menu.add_url_post(_("Copy"), reverse("flows.flow_copy", args=[flow.id])) if self.has_org_perm("flows.flow_delete"): - links.append( - dict( - id="delete-flow", - title=_("Delete"), - href=f"{reverse('flows.flow_delete', args=[self.object.uuid])}", - modax=_("Delete Flow"), - ) + menu.add_modax( + _("Delete"), + "delete-flow", + reverse("flows.flow_delete", args=[self.object.uuid]), + title=_("Delete Flow"), ) - links.append(dict(divider=True)), + menu.new_group() if self.has_org_perm("orgs.org_export"): - links.append(dict(title=_("Export Definition"), href=f"{reverse('orgs.org_export')}?flow={flow.id}")) + menu.add_link(_("Export Definition"), f"{reverse('orgs.org_export')}?flow={flow.id}") # limit PO export/import to non-archived flows since mailroom doesn't know about archived flows if not self.object.is_archived: if self.has_org_perm("flows.flow_export_translation"): - links.append( - dict( - id="export-translation", - title=_("Export Translation"), - href=f"{reverse('flows.flow_export_translation', args=[self.object.pk])}", - modax=_("Export Translation"), - ) + menu.add_modax( + _("Export Translation"), + "export-translation", + reverse("flows.flow_export_translation", args=[self.object.pk]), ) if self.has_org_perm("flows.flow_import_translation"): - links.append( - dict( - title=_("Import Translation"), - href=reverse("flows.flow_import_translation", args=[flow.id]), - ) - ) + menu.add_link(_("Import Translation"), reverse("flows.flow_import_translation", args=[flow.id])) user = self.get_user() if user.is_superuser or user.is_staff: - links.append( - dict( - title=_("Service"), - posterize=True, - href=f'{reverse("orgs.org_service")}?organization={flow.org_id}&redirect_url={reverse("flows.flow_editor", args=[flow.uuid])}', - ) + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={flow.org_id}&redirect_url={reverse("flows.flow_editor", args=[flow.uuid])}', ) - return links - class ChangeLanguage(OrgObjPermsMixin, SmartUpdateView): class Form(forms.Form): language = forms.CharField(required=True) @@ -1647,32 +1602,20 @@ class CategoryCounts(AllowOnlyActiveFlowMixin, OrgObjPermsMixin, SmartReadView): def render_to_response(self, context, **response_kwargs): return JsonResponse(self.get_object().get_category_counts()) - class Results(SpaMixin, AllowOnlyActiveFlowMixin, OrgObjPermsMixin, SmartReadView): + class Results(SpaMixin, AllowOnlyActiveFlowMixin, OrgObjPermsMixin, ContentMenuMixin, SmartReadView): slug_url_kwarg = "uuid" - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): if self.has_org_perm("flows.flow_update"): - links.append( - dict( - id="download-results", - title=_("Download"), - modax=_("Download Results"), - href=f"{reverse('flows.flow_export_results')}?ids={self.get_object().pk}", - ) + menu.add_modax( + _("Download"), + "download-results", + f"{reverse('flows.flow_export_results')}?ids={self.get_object().pk}", + title=_("Download Results"), ) if self.has_org_perm("flows.flow_editor"): - links.append( - dict( - title=_("Edit Flow"), - style="button-primary", - href=reverse("flows.flow_editor", args=[self.get_object().uuid]), - ) - ) - - return links + menu.add_link(_("Edit Flow"), reverse("flows.flow_editor", args=[self.get_object().uuid])) def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) @@ -2182,14 +2125,14 @@ class FlowStartCRUDL(SmartCRUDL): model = FlowStart actions = ("list",) - class List(OrgFilterMixin, OrgPermsMixin, SmartListView): + class List(OrgFilterMixin, OrgPermsMixin, ContentMenuMixin, SmartListView): title = _("Flow Start Log") ordering = ("-created_on",) select_related = ("flow", "created_by") paginate_by = 25 - def get_gear_links(self): - return [dict(title=_("Flows"), style="button-light", href=reverse("flows.flow_list"))] + def build_content_menu(self, menu): + menu.add_link(_("Flows"), reverse("flows.flow_list")) def derive_queryset(self, *args, **kwargs): qs = super().derive_queryset(*args, **kwargs) diff --git a/temba/locations/views.py b/temba/locations/views.py index 5cd57d27dbf..239ca1adc86 100644 --- a/temba/locations/views.py +++ b/temba/locations/views.py @@ -10,21 +10,22 @@ from temba.locations.models import AdminBoundary, BoundaryAlias from temba.orgs.views import OrgPermsMixin from temba.utils import json +from temba.utils.views import ContentMenuMixin class BoundaryCRUDL(SmartCRUDL): actions = ("alias", "geometry", "boundaries") model = AdminBoundary - class Alias(OrgPermsMixin, SmartReadView): + class Alias(OrgPermsMixin, ContentMenuMixin, SmartReadView): @classmethod def derive_url_pattern(cls, path, action): # though we are a read view, we don't actually need an id passed # in, that is derived return r"^%s/%s/$" % (path, action) - def get_gear_links(self): - return [dict(title=_("Home"), style="button-light", href=reverse("orgs.org_home"))] + def build_content_menu(self, menu): + menu.add_link(_("Home"), reverse("orgs.org_home")) def pre_process(self, request, *args, **kwargs): response = super().pre_process(self, request, *args, **kwargs) diff --git a/temba/utils/views.py b/temba/utils/views.py index fb8455b5163..5b8b771fac2 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -279,21 +279,24 @@ class ContentMenu: """ def __init__(self): - self.items = [] + self.groups = [[]] + + def new_group(self): + self.groups.append([]) def add_link(self, label: str, url: str): - self.items.append({"title": label, "href": url}) + self.groups[-1].append({"title": label, "href": url}) def add_js(self, label: str, on_click: str, link_class: str): - self.items.append({"title": label, "on_click": on_click, "js_class": link_class, "href": "#"}) + self.groups[-1].append({"title": label, "on_click": on_click, "js_class": link_class, "href": "#"}) def add_url_post(self, label: str, url: str): - self.items.append({"title": label, "href": url, "js_class": "posterize"}) + self.groups[-1].append({"title": label, "href": url, "js_class": "posterize"}) def add_modax( self, label: str, modal_id: str, url: str, *, title: str = None, on_submit: str = None, primary: bool = False ): - self.items.append( + self.groups[-1].append( { "id": modal_id, "title": label, @@ -304,6 +307,21 @@ def add_modax( } ) + def as_items(self): + """ + Reduce groups to a flat list of items separated by a divider. + """ + items = [] + for group in self.groups: + if not group: + continue + if items: + items.append({"divider": True}) + + items.extend(group) + + return items + class ContentMenuMixin: """ @@ -313,7 +331,7 @@ class ContentMenuMixin: def get_gear_links(self): menu = ContentMenu() self.build_content_menu(menu) - return menu.items + return menu.as_items() def build_content_menu(self, menu: ContentMenu): # pragma: no cover pass From 488e97e42f03d2f8974dadd35f4c4458ae43106b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 29 Jul 2022 12:24:39 -0500 Subject: [PATCH 079/630] Remove unneeded call to view.get_gear_links --- templates/contacts/contact_list.haml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/templates/contacts/contact_list.haml b/templates/contacts/contact_list.haml index 6dd60c063f6..70060ed15ad 100644 --- a/templates/contacts/contact_list.haml +++ b/templates/contacts/contact_list.haml @@ -200,9 +200,8 @@ {{current_group.name}} -else {{title}} - -if view.get_gear_links - .gear-links - -include "gear_links_include.haml" + .gear-links + -include "gear_links_include.haml" .subtitle.ml-1.w-full -block subtitle From 8ae74abc3da008b2bf6317c945df0b24bf2012b8 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 29 Jul 2022 14:18:32 -0500 Subject: [PATCH 080/630] Replace get_gear_links on all remaining views --- temba/channels/types/whatsapp_cloud/views.py | 23 +- temba/msgs/views.py | 78 ++----- temba/orgs/views.py | 224 ++++++------------- temba/policies/views.py | 10 +- temba/request_logs/views.py | 22 +- temba/tickets/types/zendesk/views.py | 10 +- temba/tickets/views.py | 8 +- temba/utils/whatsapp/views.py | 29 +-- 8 files changed, 123 insertions(+), 281 deletions(-) diff --git a/temba/channels/types/whatsapp_cloud/views.py b/temba/channels/types/whatsapp_cloud/views.py index f9b8a8a49fc..1691f0e7381 100644 --- a/temba/channels/types/whatsapp_cloud/views.py +++ b/temba/channels/types/whatsapp_cloud/views.py @@ -11,6 +11,7 @@ from temba.orgs.views import ModalMixin, OrgObjPermsMixin, OrgPermsMixin from temba.utils.fields import InputWidget +from temba.utils.views import ContentMenuMixin from ...models import Channel from ...views import ClaimViewMixin @@ -239,7 +240,7 @@ def render_to_response(self, context, **response_kwargs): return JsonResponse({}) -class RequestCode(ModalMixin, OrgObjPermsMixin, SmartModelActionView): +class RequestCode(ModalMixin, ContentMenuMixin, OrgObjPermsMixin, SmartModelActionView): class Form(forms.Form): pass @@ -258,13 +259,8 @@ def get_queryset(self): def get_success_url(self): return reverse("channels.types.whatsapp_cloud.verify_code", args=[self.object.uuid]) - def get_gear_links(self): - return [ - dict( - title=_("Channel"), - href=reverse("channels.channel_read", args=[self.object.uuid]), - ) - ] + def build_content_menu(self, menu): + menu.add_link(_("Channel"), reverse("channels.channel_read", args=[self.object.uuid])) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -304,7 +300,7 @@ def execute_action(self): ) -class VerifyCode(ModalMixin, OrgObjPermsMixin, SmartModelActionView): +class VerifyCode(ModalMixin, ContentMenuMixin, OrgObjPermsMixin, SmartModelActionView): class Form(forms.Form): code = forms.CharField( min_length=6, required=True, help_text=_("The 6-digits number verification code"), widget=InputWidget() @@ -319,13 +315,8 @@ class Form(forms.Form): title = _("Verify Number") submit_button_name = _("Verify Number") - def get_gear_links(self): - return [ - dict( - title=_("Channel"), - href=reverse("channels.channel_read", args=[self.object.uuid]), - ) - ] + def build_content_menu(self, menu): + menu.add_link(_("Channel"), reverse("channels.channel_read", args=[self.object.uuid])) def get_queryset(self): return Channel.objects.filter(is_active=True, org=self.request.org, channel_type="WAC") diff --git a/temba/msgs/views.py b/temba/msgs/views.py index d963a754a85..e2910982cd3 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -50,7 +50,7 @@ TembaChoiceField, ) from temba.utils.models import patch_queryset_count -from temba.utils.views import BulkActionMixin, ComponentFormMixin, SpaMixin +from temba.utils.views import BulkActionMixin, ComponentFormMixin, ContentMenuMixin, SpaMixin from .models import Broadcast, ExportMessagesTask, Label, LabelCount, Msg, Schedule, SystemLabel from .tasks import export_messages_task @@ -106,7 +106,7 @@ def clean(self): return cleaned -class InboxView(SpaMixin, OrgPermsMixin, BulkActionMixin, SmartListView): +class InboxView(SpaMixin, ContentMenuMixin, OrgPermsMixin, BulkActionMixin, SmartListView): """ Base class for inbox views with message folders and labels listed by the side """ @@ -210,18 +210,9 @@ def get_context_data(self, **kwargs): return context - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): if self.allow_export and self.has_org_perm("msgs.msg_export"): - links.append( - dict( - id="export-messages", - title=_("Download"), - href=self.derive_export_url(), - modax=_("Download Messages"), - ) - ) - return links + menu.add_modax(_("Download"), "export-messages", self.derive_export_url(), title=_("Download Messages")) class BroadcastForm(forms.ModelForm): @@ -804,71 +795,30 @@ class Filter(InboxView): def derive_title(self, *args, **kwargs): return self.derive_label().name - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): label = self.derive_label() + if self.has_org_perm("msgs.msg_update"): if label.is_folder(): - links.append( - dict( - id="update-label", - title=_("Edit Folder"), - href=reverse("msgs.label_update", args=[label.pk]), - modax=_("Edit Folder"), - ) - ) + menu.add_modax(_("Edit Folder"), "update-folder", reverse("msgs.label_update", args=[label.id])) else: - links.append( - dict( - id="update-label", - title=_("Edit Label"), - href=reverse("msgs.label_update", args=[label.pk]), - modax=_("Edit Label"), - ) - ) + menu.add_modax(_("Edit Label"), "update-label", reverse("msgs.label_update", args=[label.id])) if self.has_org_perm("msgs.msg_export"): - links.append( - dict( - id="export-messages", - title=_("Download"), - href=self.derive_export_url(), - modax=_("Download Messages"), - ) + menu.add_modax( + _("Download"), "export-messages", self.derive_export_url(), title=_("Download Messages") ) - links.append( - dict( - id="label-usages", - title=_("Usages"), - modax=_("Usages"), - href=reverse("msgs.label_usages", args=[label.uuid]), - ) - ) + menu.add_modax(_("Usages"), "label-usages", reverse("msgs.label_usages", args=[label.uuid])) if label.is_folder(): if self.has_org_perm("msgs.label_delete_folder"): - links.append( - dict( - id="delete-folder", - title=_("Delete Folder"), - href=reverse("msgs.label_delete_folder", args=[label.id]), - modax=_("Delete Folder"), - ) + menu.add_modax( + _("Delete Folder"), "delete-folder", reverse("msgs.label_delete_folder", args=[label.id]) ) else: if self.has_org_perm("msgs.label_delete"): - links.append( - dict( - id="delete-label", - title=_("Delete Label"), - href=reverse("msgs.label_delete", args=[label.uuid]), - modax=_("Delete Label"), - ) - ) - - return links + menu.add_modax(_("Delete Label"), "delete-label", reverse("msgs.label_delete", args=[label.uuid])) @classmethod def derive_url_pattern(cls, path, action): diff --git a/temba/orgs/views.py b/temba/orgs/views.py index bef60c5d144..a38fccac8bc 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -73,7 +73,7 @@ ) from temba.utils.http import http_headers from temba.utils.timezones import TimeZoneFormField -from temba.utils.views import ComponentFormMixin, NonAtomicMixin, RequireRecentAuthMixin, SpaMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin, NonAtomicMixin, RequireRecentAuthMixin, SpaMixin from .models import ( BackupToken, @@ -744,7 +744,7 @@ def get_context_data(self, **kwargs): context["filters"] = self.filters return context - class Update(ComponentFormMixin, SmartUpdateView): + class Update(ComponentFormMixin, ContentMenuMixin, SmartUpdateView): class Form(UserUpdateForm): groups = forms.ModelMultipleChoiceField( widget=SelectMultipleWidget( @@ -763,15 +763,10 @@ class Meta: success_message = "User updated successfully." title = "Update" - def get_gear_links(self): - return [ - dict( - id="user-delete", - title=_("Delete"), - modax=_("Delete User"), - href=reverse("orgs.user_delete", args=[self.object.id]), - ) - ] + def build_content_menu(self, menu): + menu.add_modax( + _("Delete"), "user-delete", reverse("orgs.user_delete", args=[self.object.id]), title=_("Delete User") + ) def pre_save(self, obj): obj.username = obj.email @@ -1052,7 +1047,9 @@ def form_valid(self, form): return super().form_valid(form) - class TwoFactorTokens(SpaMixin, RequireRecentAuthMixin, InferOrgMixin, OrgPermsMixin, SmartTemplateView): + class TwoFactorTokens( + SpaMixin, RequireRecentAuthMixin, InferOrgMixin, ContentMenuMixin, OrgPermsMixin, SmartTemplateView + ): permission = "orgs.org_two_factor" title = _("Two-factor Authentication") @@ -1069,10 +1066,9 @@ def post(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) - def get_gear_links(self): - if self.is_spa(): - return [] - return [dict(title=_("Home"), style="button-light", href=reverse("orgs.org_home"))] + def build_content_menu(self, menu): + if not self.is_spa(): + menu.add_link(_("Home"), reverse("orgs.org_home")) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -2073,7 +2069,7 @@ def lookup_field_link(self, context, field, obj): def get_created_by(self, obj): # pragma: needs cover return "%s %s - %s" % (obj.created_by.first_name, obj.created_by.last_name, obj.created_by.email) - class Update(ComponentFormMixin, SmartUpdateView): + class Update(ComponentFormMixin, ContentMenuMixin, SmartUpdateView): class Form(forms.ModelForm): parent = forms.IntegerField(required=False) plan_end = forms.DateTimeField(required=False) @@ -2135,68 +2131,32 @@ def get_form_kwargs(self): def get_success_url(self): return reverse("orgs.org_update", args=[self.get_object().pk]) - def get_gear_links(self): - links = [] - - org = self.get_object() - - if org.is_active: - links.append( - dict( - title=_("Service"), - posterize=True, - href=f'{reverse("orgs.org_service")}?organization={org.pk}&redirect_url={reverse("msgs.msg_inbox", args=[])}', - ) - ) + def build_content_menu(self, menu): + if not self.object.is_active: + return - links.append( - dict( - title=_("Topups"), - style="button-primary", - href="%s?org=%d" % (reverse("orgs.topup_manage"), org.pk), - ) + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={self.object.id}&redirect_url={reverse("msgs.msg_inbox", args=[])}', + ) + menu.add_link(_("Topups"), f"{reverse('orgs.topup_manage')}?org={self.object.id}") + + if self.object.is_flagged: + menu.add_url_post(_("Unflag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=unflag") + else: # pragma: needs cover + menu.add_url_post(_("Flag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=flag") + + if not self.object.is_verified(): + menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=verify") + + if self.request.user.has_perm("orgs.org_delete"): + menu.add_modax( + _("Delete"), + "delete-org", + reverse("orgs.org_delete", args=[self.object.id]), + title=_("Delete Workspace"), ) - if org.is_flagged: - links.append( - dict( - title=_("Unflag"), - style="button-secondary", - posterize=True, - href="%s?action=unflag" % reverse("orgs.org_update", args=[org.pk]), - ) - ) - else: # pragma: needs cover - links.append( - dict( - title=_("Flag"), - style="button-secondary", - posterize=True, - href="%s?action=flag" % reverse("orgs.org_update", args=[org.pk]), - ) - ) - - if not org.is_verified(): - links.append( - dict( - title=_("Verify"), - style="button-secondary", - posterize=True, - href="%s?action=verify" % reverse("orgs.org_update", args=[org.pk]), - ) - ) - - if self.request.user.has_perm("orgs.org_delete"): - links.append( - dict( - id="delete-org", - title=_("Delete"), - href=reverse("orgs.org_delete", args=[org.id]), - modax=_("Delete Workspace"), - ) - ) - return links - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -2288,7 +2248,7 @@ def get_context_data(self, **kwargs): context["role_summary"] = role_summary return context - class ManageAccounts(SpaMixin, InferOrgMixin, OrgPermsMixin, SmartUpdateView): + class ManageAccounts(SpaMixin, ContentMenuMixin, InferOrgMixin, OrgPermsMixin, SmartUpdateView): class AccountsForm(forms.ModelForm): invite_emails = forms.CharField( required=False, widget=InputWidget(attrs={"widget_only": True, "placeholder": _("Email Address")}) @@ -2430,23 +2390,22 @@ class Meta: submit_button_name = _("Save Changes") title = _("Manage Logins") - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): + other_org = self.request.org.id != self.get_object().id + if self.is_spa(): - if self.request.user.get_org().id != self.get_object().id: - links.append( - dict( - title=_("Edit"), - modax=_("Edit Workspace"), - href=f"{reverse('orgs.org_edit_sub_org')}?org={self.object.pk}", - ) + if other_org: + menu.add_modax( + _("Edit"), + "edit-workspace", + f"{reverse('orgs.org_edit_sub_org')}?org={self.object.id}", + title=_("Edit Workspace"), ) - else: - if self.request.user.get_org().id != self.get_object().id: - links.append(dict(title=_("Workspaces"), style="button-light", href=reverse("orgs.org_sub_orgs"))) - links.append(dict(title=_("Home"), style="button-light", href=reverse("orgs.org_home"))) - return links + if other_org: + menu.add_link(_("Workspaces"), reverse("orgs.org_sub_orgs")) + + menu.add_link(_("Home"), reverse("orgs.org_home")) def get_form_kwargs(self): kwargs = super().get_form_kwargs() @@ -2539,7 +2498,7 @@ def form_invalid(self, form): self.request.session["org_id"] = None return HttpResponseRedirect(reverse("orgs.org_manage")) - class SubOrgs(SpaMixin, MultiOrgMixin, InferOrgMixin, SmartListView): + class SubOrgs(SpaMixin, ContentMenuMixin, MultiOrgMixin, InferOrgMixin, SmartListView): link_fields = () title = _("Workspaces") @@ -2549,33 +2508,15 @@ def derive_fields(self): else: return "name", "contacts", "manage", "created_on" - def get_gear_links(self): - links = [] - + def build_content_menu(self, menu): if self.has_org_perm("orgs.org_dashboard"): - links.append(dict(title=_("Dashboard"), href=reverse("dashboard.dashboard_home"))) + menu.add_link(_("Dashboard"), reverse("dashboard.dashboard_home")) if self.has_org_perm("orgs.org_create_sub_org"): - links.append( - dict( - title=_("New Workspace"), - href=reverse("orgs.org_create_sub_org"), - modax=_("New Workspace"), - id="new-workspace", - ) - ) + menu.add_modax(_("New Workspace"), "new-workspace", reverse("orgs.org_create_sub_org")) if self.has_org_perm("orgs.org_transfer_credits") and self.get_object().uses_topups: - links.append( - dict( - title=_("Transfer Credits"), - href=reverse("orgs.org_transfer_credits"), - modax=_("Transfer Credits"), - id="transfer-credits", - ) - ) - - return links + menu.add_modax(_("Transfer Credits"), "transfer-credits", reverse("orgs.org_transfer_credits")) def get_manage(self, obj): # pragma: needs cover if obj == self.get_object(): @@ -3283,11 +3224,10 @@ def get_context_data(self, **kwargs): def get_token(self, org): return APIToken.objects.filter(is_active=True, org=org, role=Group.objects.get(name="Prometheus")).first() - class Workspace(SpaMixin, FormaxMixin, InferOrgMixin, OrgPermsMixin, SmartReadView): + class Workspace(SpaMixin, FormaxMixin, ContentMenuMixin, InferOrgMixin, OrgPermsMixin, SmartReadView): title = _("Workspace") - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): org = self.get_object() if ( @@ -3295,15 +3235,7 @@ def get_gear_links(self): and org.uses_topups and Org.objects.filter(parent=org, is_active=True).exists() ): - links.append( - dict( - title=_("Transfer Credits"), - href=reverse("orgs.org_transfer_credits"), - modax=_("Transfer Credits"), - id="transfer-credits", - ) - ) - return links + menu.add_modax(_("Transfer Credits"), "transfer-credits", reverse("orgs.org_transfer_credits")) def derive_formax_sections(self, formax, context): org = self.request.org @@ -3336,49 +3268,33 @@ def derive_formax_sections(self, formax, context): if self.has_org_perm("orgs.org_plan"): # pragma: needs cover formax.add_section("plan", reverse("orgs.org_plan"), icon="icon-credit", action="summary") - class Home(SpaMixin, FormaxMixin, InferOrgMixin, OrgPermsMixin, SmartReadView): + class Home(SpaMixin, FormaxMixin, ContentMenuMixin, InferOrgMixin, OrgPermsMixin, SmartReadView): title = _("Your Account") - def get_gear_links(self): + def build_content_menu(self, menu): org = self.request.org - links = [] if self.has_org_perm("channels.channel_claim"): - links.append(dict(title=_("Add Channel"), href=reverse("channels.channel_claim"))) - + menu.add_link(_("Add Channel"), reverse("channels.channel_claim")) if self.has_org_perm("classifiers.classifier_connect"): - links.append(dict(title=_("Add Classifier"), href=reverse("classifiers.classifier_connect"))) - + menu.add_link(_("Add Classifier"), reverse("classifiers.classifier_connect")) if self.has_org_perm("tickets.ticketer_connect") and "ticketers" in org.get_branding().get("features", []): - links.append(dict(title=_("Add Ticketing Service"), href=reverse("tickets.ticketer_connect"))) + menu.add_link(_("Add Ticketing Service"), reverse("tickets.ticketer_connect")) - if len(links) > 0: - links.append(dict(divider=True)) + menu.new_group() if self.has_org_perm("orgs.org_export"): - links.append(dict(title=_("Export"), href=reverse("orgs.org_export"))) + menu.add_link(_("Export"), reverse("orgs.org_export")) if self.has_org_perm("orgs.org_import"): - links.append(dict(title=_("Import"), href=reverse("orgs.org_import"))) + menu.add_link(_("Import"), reverse("orgs.org_import")) if settings.HELP_URL: # pragma: needs cover - if len(links) > 1: - links.append(dict(divider=True)) - - links.append(dict(title=_("Help"), href=settings.HELP_URL)) - - if len(links) > 1: - links.append(dict(divider=True)) - - links.append( - dict( - title=_("Sign Out"), - style="button-light", - href=f"{reverse('users.user_logout')}?next={reverse('users.user_login')}", - ) - ) + menu.new_group() + menu.add_link(_("Help"), settings.HELP_URL) - return links + menu.new_group() + menu.add_link(_("Sign Out"), f"{reverse('users.user_logout')}?next={reverse('users.user_login')}") def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) diff --git a/temba/policies/views.py b/temba/policies/views.py index aa79d0f088f..7dec1a596ee 100644 --- a/temba/policies/views.py +++ b/temba/policies/views.py @@ -10,7 +10,7 @@ from temba.orgs.views import OrgPermsMixin from temba.utils import analytics -from temba.utils.views import ComponentFormMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin from .models import Consent, Policy @@ -20,15 +20,14 @@ class PolicyCRUDL(SmartCRUDL): model = Policy permissions = True - class Admin(SmartListView): + class Admin(ContentMenuMixin, SmartListView): ordering = ("-created_on",) link_fields = ("policy_type",) title = "Policies" paginate_by = 500 - def get_gear_links(self): - links = [dict(title=_("New Policy"), href=reverse("policies.policy_create"))] - return links + def build_content_menu(self, menu): + menu.add_link(_("New Policy"), reverse("policies.policy_create")) def get_queryset(self, **kwargs): queryset = super().get_queryset(**kwargs) @@ -37,7 +36,6 @@ def get_queryset(self, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["active_policies"] = Policy.objects.filter(is_active=True).order_by(*self.ordering) - context["gear_links"] = self.get_gear_links() return context class Update(ComponentFormMixin, SmartUpdateView): diff --git a/temba/request_logs/views.py b/temba/request_logs/views.py index 503dc90282c..4c1c6ad41a3 100644 --- a/temba/request_logs/views.py +++ b/temba/request_logs/views.py @@ -8,6 +8,7 @@ from temba.classifiers.models import Classifier from temba.orgs.views import OrgObjPermsMixin, OrgPermsMixin from temba.tickets.models import Ticketer +from temba.utils.views import ContentMenuMixin from .models import HTTPLog @@ -55,15 +56,14 @@ class HTTPLogCRUDL(SmartCRUDL): model = HTTPLog actions = ("webhooks", "classifier", "ticketer", "read") - class Webhooks(OrgPermsMixin, SmartListView): + class Webhooks(ContentMenuMixin, OrgPermsMixin, SmartListView): title = _("Webhook Calls") default_order = ("-created_on",) select_related = ("flow",) - fields = ("flow", "url", "status_code", "request_time", "created_on") - def get_gear_links(self): - return [dict(title=_("Flows"), style="button-light", href=reverse("flows.flow_list"))] + def build_content_menu(self, menu): + menu.add_link(_("Flows"), reverse("flows.flow_list")) def get_queryset(self, **kwargs): return super().get_queryset(**kwargs).filter(org=self.request.org, flow__isnull=False) @@ -84,21 +84,15 @@ class Ticketer(BaseObjLogsView): def get_source(self, uuid): return Ticketer.objects.filter(uuid=uuid, is_active=True) - class Read(OrgObjPermsMixin, SmartReadView): + class Read(ContentMenuMixin, OrgObjPermsMixin, SmartReadView): fields = ("description", "created_on") @property def permission(self): return "request_logs.httplog_webhooks" if self.get_object().flow else "request_logs.httplog_read" - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): if self.object.classifier: - links.append( - dict( - title=_("Classifier Log"), - style="button-light", - href=reverse("request_logs.httplog_classifier", args=[self.object.classifier.uuid]), - ) + menu.add_link( + _("Classifier Log"), reverse("request_logs.httplog_classifier", args=[self.object.classifier.uuid]) ) - return links diff --git a/temba/tickets/types/zendesk/views.py b/temba/tickets/types/zendesk/views.py index bd0d681c153..b7577e515e2 100644 --- a/temba/tickets/types/zendesk/views.py +++ b/temba/tickets/types/zendesk/views.py @@ -20,7 +20,7 @@ from temba.utils import json from temba.utils.s3 import public_file_storage from temba.utils.text import random_string -from temba.utils.views import ComponentFormMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin from ...models import Ticketer from ...views import BaseConnectView @@ -116,7 +116,7 @@ def handle_code_granted(self, request, *args, **kwargs): return HttpResponseRedirect(self.get_success_url()) -class ConfigureView(ComponentFormMixin, OrgPermsMixin, SmartReadView): +class ConfigureView(ComponentFormMixin, ContentMenuMixin, OrgPermsMixin, SmartReadView): model = Ticketer fields = () permission = "tickets.ticketer_configure" @@ -127,11 +127,9 @@ def get_queryset(self): queryset = super().get_queryset() return queryset.filter(org=self.get_user().get_org()) - def get_gear_links(self): - links = [] + def build_content_menu(self, menu): if self.has_org_perm("tickets.ticket_list"): - links.append(dict(title=_("Tickets"), href=reverse("tickets.ticket_list"))) - return links + menu.add_link(_("Tickets"), reverse("tickets.ticket_list")) def get_context_data(self, **kwargs): from .type import ZendeskType diff --git a/temba/tickets/views.py b/temba/tickets/views.py index 48cdc4c4849..a92fba3df40 100644 --- a/temba/tickets/views.py +++ b/temba/tickets/views.py @@ -18,7 +18,7 @@ from temba.utils.dates import datetime_to_timestamp, timestamp_to_datetime from temba.utils.export import response_from_workbook from temba.utils.fields import InputWidget, SelectWidget -from temba.utils.views import ComponentFormMixin, SpaMixin +from temba.utils.views import ComponentFormMixin, ContentMenuMixin, SpaMixin from .models import ( AllFolder, @@ -399,9 +399,9 @@ class TicketerCRUDL(SmartCRUDL): model = Ticketer actions = ("connect", "read", "delete") - class Connect(OrgPermsMixin, SmartTemplateView): - def get_gear_links(self): - return [dict(title=_("Home"), style="button-light", href=reverse("orgs.org_home"))] + class Connect(ContentMenuMixin, OrgPermsMixin, SmartTemplateView): + def build_content_menu(self, menu): + menu.add_link(_("Home"), reverse("orgs.org_home")) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) diff --git a/temba/utils/whatsapp/views.py b/temba/utils/whatsapp/views.py index e6c1cf667c2..9e78bd61606 100644 --- a/temba/utils/whatsapp/views.py +++ b/temba/utils/whatsapp/views.py @@ -7,7 +7,7 @@ from temba.orgs.views import OrgPermsMixin from temba.request_logs.models import HTTPLog from temba.templates.models import TemplateTranslation -from temba.utils.views import PostOnlyMixin +from temba.utils.views import ContentMenuMixin, PostOnlyMixin from .tasks import refresh_whatsapp_contacts @@ -33,7 +33,7 @@ def post_save(self, obj): return obj -class TemplatesView(OrgPermsMixin, SmartReadView): +class TemplatesView(ContentMenuMixin, OrgPermsMixin, SmartReadView): """ Displays a simple table of all the templates synced on this whatsapp channel """ @@ -44,13 +44,10 @@ class TemplatesView(OrgPermsMixin, SmartReadView): slug_url_kwarg = "uuid" template_name = "utils/whatsapp/templates.html" - def get_gear_links(self): - return [ - dict( - title=_("Sync Logs"), - href=reverse(f"channels.types.{self.object.type.slug}.sync_logs", args=[self.object.uuid]), - ) - ] + def build_content_menu(self, menu): + menu.add_link( + _("Sync Logs"), reverse(f"channels.types.{self.object.type.slug}.sync_logs", args=[self.object.uuid]) + ) def get_queryset(self): queryset = super().get_queryset() @@ -66,7 +63,7 @@ def get_context_data(self, **kwargs): return context -class SyncLogsView(OrgPermsMixin, SmartReadView): +class SyncLogsView(ContentMenuMixin, OrgPermsMixin, SmartReadView): """ Displays a simple table of the WhatsApp Templates Synced requests for this channel """ @@ -77,13 +74,11 @@ class SyncLogsView(OrgPermsMixin, SmartReadView): slug_url_kwarg = "uuid" template_name = "utils/whatsapp/sync_logs.html" - def get_gear_links(self): - return [ - dict( - title=_("Message Templates"), - href=reverse(f"channels.types.{self.object.type.slug}.templates", args=[self.object.uuid]), - ) - ] + def build_content_menu(self, menu): + menu.add_link( + _("Message Templates"), + reverse(f"channels.types.{self.object.type.slug}.templates", args=[self.object.uuid]), + ) def get_queryset(self): queryset = super().get_queryset() From 18e0f6ea5e53b443e71157026465628f2db857ec Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 29 Jul 2022 15:16:49 -0500 Subject: [PATCH 081/630] Rework ContentMenuMixin to put the menu in the context, and include new and legacy formats --- temba/campaigns/tests.py | 30 +++-- temba/channels/tests.py | 13 +- temba/channels/types/dialog360/tests.py | 15 ++- temba/channels/types/whatsapp/tests.py | 15 ++- temba/contacts/tests.py | 13 +- temba/utils/views.py | 50 +++++--- templates/gear_links_include.haml | 159 ++++++++++++------------ templates/spa.haml | 30 +++-- templates/spa_page_menu.haml | 34 +++-- 9 files changed, 197 insertions(+), 162 deletions(-) diff --git a/temba/campaigns/tests.py b/temba/campaigns/tests.py index b0eb99f787c..38008d9a924 100644 --- a/temba/campaigns/tests.py +++ b/temba/campaigns/tests.py @@ -667,12 +667,15 @@ def test_view_campaign_read_with_customer_support(self): campaign = Campaign.create(self.org, self.admin, "Perform the rain dance", self.farmers) response = self.client.get(reverse("campaigns.campaign_read", args=[campaign.uuid])) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Service"]) self.assertEqual( - gear_links[-1]["href"], - f"/org/service/?organization={campaign.org_id}&redirect_url=/campaign/read/{campaign.uuid}/", + [ + { + "type": "url_post", + "label": "Service", + "url": f"/org/service/?organization={campaign.org_id}&redirect_url=/campaign/read/{campaign.uuid}/", + } + ], + response.context["content_menu"], ) def test_view_campaign_read_archived(self): @@ -685,9 +688,9 @@ def test_view_campaign_read_archived(self): # page title and main content title should NOT contain (Archived) self.assertContains(response, "Perform the rain dance", count=2) self.assertContains(response, "Archived", count=0) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["New Event", "Export", "Edit", "Archive"]) + self.assertListEqual( + ["New Event", "Export", "Edit", "Archive"], [i["label"] for i in response.context["content_menu"]] + ) # archive the campaign campaign.is_archived = True @@ -698,9 +701,7 @@ def test_view_campaign_read_archived(self): # page title and main content title should contain (Archived) self.assertContains(response, "Perform the rain dance", count=2) self.assertContains(response, "Archived", count=2) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Activate", "Export"]) + self.assertListEqual(["Activate", "Export"], [i["label"] for i in response.context["content_menu"]]) def test_view_campaign_archive(self): self.login(self.admin) @@ -749,9 +750,7 @@ def test_view_campaignevent_read_on_archived_campaign(self): # page title and main content title should NOT contain Archived self.assertContains(response, "Perform the rain dance", count=1) self.assertContains(response, "Archived", count=0) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Edit", "Delete"]) + self.assertListEqual(["Edit", "Delete"], [i["label"] for i in response.context["content_menu"]]) # archive the campaign campaign.is_archived = True @@ -763,8 +762,7 @@ def test_view_campaignevent_read_on_archived_campaign(self): self.assertContains(response, "Perform the rain dance", count=1) self.assertContains(response, "Archived", count=1) - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Delete"]) + self.assertListEqual(["Delete"], [i["label"] for i in response.context["content_menu"]]) def test_view_campaignevent_update_on_archived_campaign(self): self.login(self.admin) diff --git a/temba/channels/tests.py b/temba/channels/tests.py index 37c8fd661f0..381fdc47978 100644 --- a/temba/channels/tests.py +++ b/temba/channels/tests.py @@ -113,12 +113,15 @@ def test_channel_read_with_customer_support(self): self.login(self.customer_support) response = self.client.get(reverse("channels.channel_read", args=[self.tel_channel.uuid])) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Service"]) self.assertEqual( - gear_links[-1]["href"], - f"/org/service/?organization={self.tel_channel.org_id}&redirect_url=/channels/channel/read/{self.tel_channel.uuid}/", + [ + { + "type": "url_post", + "label": "Service", + "url": f"/org/service/?organization={self.tel_channel.org_id}&redirect_url=/channels/channel/read/{self.tel_channel.uuid}/", + } + ], + response.context["content_menu"], ) def test_deactivate(self): diff --git a/temba/channels/types/dialog360/tests.py b/temba/channels/types/dialog360/tests.py index c3671ce494f..1a7d4887fc5 100644 --- a/temba/channels/types/dialog360/tests.py +++ b/temba/channels/types/dialog360/tests.py @@ -214,11 +214,18 @@ def test_message_templates_and_logs_views(self): self.assertContains(response, "Hello") self.assertContains(response, reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) - # Check if message templates link are in sync_logs view + # check if message templates link are in sync_logs view response = self.client.get(reverse("channels.types.dialog360.sync_logs", args=[channel.uuid])) - gear_links = response.context["view"].get_gear_links() - self.assertEqual(gear_links[-1]["title"], "Message Templates") - self.assertEqual(gear_links[-1]["href"], reverse("channels.types.dialog360.templates", args=[channel.uuid])) + self.assertEqual( + [ + { + "type": "link", + "label": "Message Templates", + "url": reverse("channels.types.dialog360.templates", args=[channel.uuid]), + } + ], + response.context["content_menu"], + ) # sync logs not accessible by user from other org self.login(self.admin2) diff --git a/temba/channels/types/whatsapp/tests.py b/temba/channels/types/whatsapp/tests.py index 5dd424830a3..f32ffeef44e 100644 --- a/temba/channels/types/whatsapp/tests.py +++ b/temba/channels/types/whatsapp/tests.py @@ -490,11 +490,18 @@ def test_message_templates_and_logs_views(self): self.assertContains(response, "Hello") self.assertNotContains(response, "Hi") - # Check if message templates link are in sync_logs view + # check if message templates link are in sync_logs view response = self.client.get(reverse("channels.types.whatsapp.sync_logs", args=[channel.uuid])) - gear_links = response.context["view"].get_gear_links() - self.assertEqual(gear_links[-1]["title"], "Message Templates") - self.assertEqual(gear_links[-1]["href"], reverse("channels.types.whatsapp.templates", args=[channel.uuid])) + self.assertEqual( + [ + { + "type": "link", + "label": "Message Templates", + "url": reverse("channels.types.whatsapp.templates", args=[channel.uuid]), + } + ], + response.context["content_menu"], + ) # sync logs and message templates not accessible by user from other org self.login(self.admin2) diff --git a/temba/contacts/tests.py b/temba/contacts/tests.py index 1be3a8f1a7c..db97290798c 100644 --- a/temba/contacts/tests.py +++ b/temba/contacts/tests.py @@ -2959,12 +2959,15 @@ def test_read_with_customer_support(self): self.login(self.customer_support) response = self.client.get(reverse("contacts.contact_read", args=[self.joe.uuid])) - - gear_links = response.context["view"].get_gear_links() - self.assertListEqual([gl["title"] for gl in gear_links], ["Service"]) self.assertEqual( - gear_links[-1]["href"], - f"/org/service/?organization={self.joe.org_id}&redirect_url=/contact/read/{self.joe.uuid}/", + [ + { + "type": "url_post", + "label": "Service", + "url": f"/org/service/?organization={self.org.id}&redirect_url=/contact/read/{self.joe.uuid}/", + } + ], + response.context["content_menu"], ) def test_read_language(self): diff --git a/temba/utils/views.py b/temba/utils/views.py index 5b8b771fac2..02ec75e0dca 100644 --- a/temba/utils/views.py +++ b/temba/utils/views.py @@ -285,53 +285,75 @@ def new_group(self): self.groups.append([]) def add_link(self, label: str, url: str): - self.groups[-1].append({"title": label, "href": url}) + self.groups[-1].append({"type": "link", "label": label, "url": url}) def add_js(self, label: str, on_click: str, link_class: str): - self.groups[-1].append({"title": label, "on_click": on_click, "js_class": link_class, "href": "#"}) + self.groups[-1].append({"type": "js", "label": label, "on_click": on_click, "link_class": link_class}) def add_url_post(self, label: str, url: str): - self.groups[-1].append({"title": label, "href": url, "js_class": "posterize"}) + self.groups[-1].append({"type": "url_post", "label": label, "url": url}) def add_modax( self, label: str, modal_id: str, url: str, *, title: str = None, on_submit: str = None, primary: bool = False ): self.groups[-1].append( { - "id": modal_id, - "title": label, - "modax": title or label, - "href": url, + "type": "modax", + "label": label, + "url": url, + "modal_id": modal_id, + "title": title or label, "on_submit": on_submit, - "style": "button-primary" if primary else "", + "primary": primary, } ) def as_items(self): """ - Reduce groups to a flat list of items separated by a divider. + Reduce groups to a flat list of items separated by dividers. """ items = [] for group in self.groups: if not group: continue if items: - items.append({"divider": True}) - + items.append({"type": "divider"}) items.extend(group) - return items class ContentMenuMixin: """ Mixin for views that have a content menu (hamburger icon with dropdown items) + + TODO: rework legacy gear-link templates to use `content_menu` instead of `gear_links` """ - def get_gear_links(self): + # renderers to convert menu items to the legacy "gear-links" format + gear_link_renderers = { + "link": lambda i: {"title": i["label"], "href": i["url"]}, + "js": lambda i: {"title": i["label"], "on_click": i["on_click"], "js_class": i["link_class"], "href": "#"}, + "url_post": lambda i: {"title": i["label"], "href": i["url"], "js_class": "posterize"}, + "modax": lambda i: { + "id": i["modal_id"], + "title": i["label"], + "modax": i["title"], + "href": i["url"], + "on_submit": i["on_submit"], + "style": "button-primary" if i["primary"] else "", + }, + "divider": lambda i: {"divider": True}, + } + + def get_context_data(self, **kwargs): menu = ContentMenu() self.build_content_menu(menu) - return menu.as_items() + menu_items = menu.as_items() + + context = super().get_context_data(**kwargs) + context["content_menu"] = menu_items + context["gear_links"] = [self.gear_link_renderers[i["type"]](i) for i in menu_items] + return context def build_content_menu(self, menu: ContentMenu): # pragma: no cover pass diff --git a/templates/gear_links_include.haml b/templates/gear_links_include.haml index 162046fdf04..2d39abb31d7 100644 --- a/templates/gear_links_include.haml +++ b/templates/gear_links_include.haml @@ -13,104 +13,103 @@ margin-left: 1em; } --with gear_links=view.get_gear_links - -if gear_links - - -for link in gear_links - -if link.modax - %temba-modax{ header:'{{link.modax}}', endpoint:"{{link.href}}", id:"{{link.id}}"} - - #gear-container.flex.items-center.text-gray-700 - -if gear_links|length == 1 - -with link=gear_links|first - -if link.modax - .button-light{onclick:'showModax("{{link.id}}")', class:'{{ link|gear_link_classes:True }}'} - {{link.title}} +-if gear_links + + -for link in gear_links + -if link.modax + %temba-modax{ header:'{{link.modax}}', endpoint:"{{link.href}}", id:"{{link.id}}"} + + #gear-container.flex.items-center.text-gray-700 + -if gear_links|length == 1 + -with link=gear_links|first + -if link.modax + .button-light{onclick:'showModax("{{link.id}}")', class:'{{ link|gear_link_classes:True }}'} + {{link.title}} + %span{class:'gear-flag'} + {{link.flag}} + + -else + .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} + {{link.title}} + + - else + -with link=gear_links|first + -if link.modax + .button-light{onclick:'javascript:showModax("{{link.id}}")', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} + {{link.title}} %span{class:'gear-flag'} {{link.flag}} - -else - .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} + -else + -if link.js_class + .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}void(0);{%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} {{link.title}} - - else - -with link=gear_links|first - -if link.modax - .button-light{onclick:'javascript:showModax("{{link.id}}")', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} + -else + .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} {{link.title}} - %span{class:'gear-flag'} - {{link.flag}} - -else - -if link.js_class - .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}void(0);{%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} - {{link.title}} - - -else - .button-light{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}', href:'{{link.href}}', class:'{{ link|gear_link_classes:True }}', data-success-url:'{{ link.success_url }}'} - {{link.title}} - - .btn-group.gear-menu.ml-3 - .button-light.p-icon.dropdown-toggle.text-center{ data-toggle:"dropdown" } - .icon-menu.text-gray-500(style="margin-left:-2px;margin-top:1px") - %ul.dropdown-menu.label-menu.rounded-lg.border-none.px-4.py-3{'role':'menu', 'aria-labelledby':'dlabel'} - -for link in gear_links - -if not forloop.first - -if link.divider - %li.separator.-mx-4.border-b.my-3.border-gray-200 - -else - %li.py-1 - -if link.ngClick - .hover-linked.font-normal{onclick:"goto(event);", href:'{{link.href}}', ng-click:'{{link.ngClick}}', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} + .btn-group.gear-menu.ml-3 + .button-light.p-icon.dropdown-toggle.text-center{ data-toggle:"dropdown" } + .icon-menu.text-gray-500(style="margin-left:-2px;margin-top:1px") + %ul.dropdown-menu.label-menu.rounded-lg.border-none.px-4.py-3{'role':'menu', 'aria-labelledby':'dlabel'} + -for link in gear_links + -if not forloop.first + -if link.divider + %li.separator.-mx-4.border-b.my-3.border-gray-200 + -else + %li.py-1 + -if link.ngClick + .hover-linked.font-normal{onclick:"goto(event);", href:'{{link.href}}', ng-click:'{{link.ngClick}}', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} + {{link.title}} + .gear-flag + {{link.flag}} + -elif link.modax + .hover-linked.font-normal{onclick:'javascript:showModax("{{link.id}}")', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} + {{link.title}} + %span{class:'gear-flag'} + {{link.flag}} + + -else + -if link.js_class + .hover-linked.font-normal{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}void(0);{%endif%}', class:'{{ link|gear_link_classes }}', href:'{{link.href}}', data-success-url:'{{ link.success_url }}'} {{link.title}} - .gear-flag + %span{class:'gear-flag'} {{link.flag}} - -elif link.modax - .hover-linked.font-normal{onclick:'javascript:showModax("{{link.id}}")', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} + -else + .hover-linked.font-normal{onclick:"{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}", href:'{{link.href}}', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} {{link.title}} %span{class:'gear-flag'} {{link.flag}} - -else - -if link.js_class - .hover-linked.font-normal{onclick:'{%if link.on_click%}{{link.on_click}}{% else %}void(0);{%endif%}', class:'{{ link|gear_link_classes }}', href:'{{link.href}}', data-success-url:'{{ link.success_url }}'} - {{link.title}} - %span{class:'gear-flag'} - {{link.flag}} - -else - .hover-linked.font-normal{onclick:"{%if link.on_click%}{{link.on_click}}{% else %}goto(event){%endif%}", href:'{{link.href}}', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}'} - {{link.title}} - %span{class:'gear-flag'} - {{link.flag}} - - - :javascript - function showModax(endpoint) { - const modax = document.querySelector("temba-modax[id='" + endpoint + "']"); - if(modax) { - modax.open = true; - } + + :javascript + function showModax(endpoint) { + const modax = document.querySelector("temba-modax[id='" + endpoint + "']"); + if(modax) { + modax.open = true; } + } - $("#gear-container .gear-delete").on('click', function(e){ - $("#delete-form").attr('href', $(this).attr('href')); - e.stopPropagation(); + $("#gear-container .gear-delete").on('click', function(e){ + $("#delete-form").attr('href', $(this).attr('href')); + e.stopPropagation(); - var modal = new ConfirmationModal($('.deletion > .title').html(), $('.deletion > .body').html()); - modal.addClass('alert'); - modal.setListeners({ onPrimary: function(){ - $('#delete-form').click(); - }}, false); + var modal = new ConfirmationModal($('.deletion > .title').html(), $('.deletion > .body').html()); + modal.addClass('alert'); + modal.setListeners({ onPrimary: function(){ + $('#delete-form').click(); + }}, false); - modal.setPrimaryButton('Remove'); - modal.show(); + modal.setPrimaryButton('Remove'); + modal.show(); - var successUrl = $(this).data('success-url'); - if (successUrl){ - modal.addListener('onSuccess', function(){ document.location.href = successUrl; }); - } + var successUrl = $(this).data('success-url'); + if (successUrl){ + modal.addListener('onSuccess', function(){ document.location.href = successUrl; }); + } - return false; - }); + return false; + }); diff --git a/templates/spa.haml b/templates/spa.haml index 2f7ae505c4c..99bd12f4085 100644 --- a/templates/spa.haml +++ b/templates/spa.haml @@ -27,22 +27,20 @@ -block page-header - -with gear_links=view.get_gear_links - - -if title or gear_links - .spa-title.no-menu.flex.items-center.mb-4 - .text-container.text-2xl.text-gray-700 - .flex.flex-row - -block spa-title - #title-text - {{title}} - .line.flex-grow.mr-2.ml-6 - .h-0.border.border-gray-200 - - -if gear_links - -include "spa_page_menu.haml" - - -block subtitle + -if title or gear_links + .spa-title.no-menu.flex.items-center.mb-4 + .text-container.text-2xl.text-gray-700 + .flex.flex-row + -block spa-title + #title-text + {{title}} + .line.flex-grow.mr-2.ml-6 + .h-0.border.border-gray-200 + + -if gear_links + -include "spa_page_menu.haml" + + -block subtitle -block alert-messages -if user_org.is_suspended diff --git a/templates/spa_page_menu.haml b/templates/spa_page_menu.haml index 5305f1f4326..2f076d69569 100644 --- a/templates/spa_page_menu.haml +++ b/templates/spa_page_menu.haml @@ -104,22 +104,20 @@ } } --with gear_links=view.get_gear_links - - -if gear_links - .flex.h-full.spa-gear-buttons - -with link=gear_links|first - %temba-button.ml-4(name="{{link.title|escapejs}}" onclick="handleMenuClicked(event)" class='{{ link|gear_link_classes }}' data-success-url='{{ link.success_url }}' data-href='{{link.href}}' data-modax='{{link.modax|escapejs}}' data-on-submit='{{link.on_submit|escapejs}}') - - -if gear_links|length > 1 - %temba-dropdown.items-stretch.flex.flex-column(arrowoffset="-12" offsetx="24" offsety="6" arrowsize="8") - .menu-button.items-center.flex.flex-column.py-2.px-2.ml-2(slot="toggle") - %temba-icon( name="menu" size="1.5") - .dropdown.px-6.py-4.text-gray-800.z-50(slot="dropdown" style="min-width:200px") - -for link in gear_links - -if not forloop.first - .whitespace-nowrap.menu-item.hover-linked.font-normal{onclick:'handleMenuClicked(event)', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}', data-href:'{{link.href}}', data-modax: '{{link.modax|escapejs}}', data-on-submit:'{{link.on_submit|escapejs}}'} - {{link.title}} - %span{class:'gear-flag'} - {{link.flag}} +-if gear_links + .flex.h-full.spa-gear-buttons + -with link=gear_links|first + %temba-button.ml-4(name="{{link.title|escapejs}}" onclick="handleMenuClicked(event)" class='{{ link|gear_link_classes }}' data-success-url='{{ link.success_url }}' data-href='{{link.href}}' data-modax='{{link.modax|escapejs}}' data-on-submit='{{link.on_submit|escapejs}}') + + -if gear_links|length > 1 + %temba-dropdown.items-stretch.flex.flex-column(arrowoffset="-12" offsetx="24" offsety="6" arrowsize="8") + .menu-button.items-center.flex.flex-column.py-2.px-2.ml-2(slot="toggle") + %temba-icon( name="menu" size="1.5") + .dropdown.px-6.py-4.text-gray-800.z-50(slot="dropdown" style="min-width:200px") + -for link in gear_links + -if not forloop.first + .whitespace-nowrap.menu-item.hover-linked.font-normal{onclick:'handleMenuClicked(event)', class:'{{ link|gear_link_classes }}', data-success-url:'{{ link.success_url }}', data-href:'{{link.href}}', data-modax: '{{link.modax|escapejs}}', data-on-submit:'{{link.on_submit|escapejs}}'} + {{link.title}} + %span{class:'gear-flag'} + {{link.flag}} From 8b19fcc9f6e87f95062885e0d82347a84b080b98 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Mon, 1 Aug 2022 15:49:17 +0200 Subject: [PATCH 082/630] Remove requiring instagram_basic permission --- templates/channels/types/instagram/claim.haml | 2 +- templates/channels/types/instagram/refresh_token.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/channels/types/instagram/claim.haml b/templates/channels/types/instagram/claim.haml index 70debf298bb..7a445e059fc 100644 --- a/templates/channels/types/instagram/claim.haml +++ b/templates/channels/types/instagram/claim.haml @@ -76,7 +76,7 @@ :javascript $(document).ready(function(){ $(".connect-facebook").click(function(evt){ - location.replace("https://www.facebook.com/v12.0/dialog/oauth?client_id={{ facebook_app_id }}&redirect_uri=" + window.location.origin + window.location.pathname + "&scope=instagram_basic,instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list&response_type=token") + location.replace("https://www.facebook.com/v12.0/dialog/oauth?client_id={{ facebook_app_id }}&redirect_uri=" + window.location.origin + window.location.pathname + "&scope=instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list&response_type=token") }); var hash = window.location.hash.substring(1) diff --git a/templates/channels/types/instagram/refresh_token.haml b/templates/channels/types/instagram/refresh_token.haml index 1e875b3beed..161a6818aaa 100644 --- a/templates/channels/types/instagram/refresh_token.haml +++ b/templates/channels/types/instagram/refresh_token.haml @@ -52,7 +52,7 @@ } }, - {scope: 'instagram_basic,instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list'}); + {scope: 'instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list'}); }) }); \ No newline at end of file From 799fd5aa50ecf918201b98fa411feadc58e51178 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 1 Aug 2022 11:36:39 -0500 Subject: [PATCH 083/630] Update floweditor --- package-lock.json | 15 ++++++++------- package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b429708b72..1c3fa954ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,10 +4,11 @@ "requires": true, "packages": { "": { + "name": "rapidpro", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { - "@nyaruka/flow-editor": "1.17.1", + "@nyaruka/flow-editor": "1.17.2", "@nyaruka/temba-components": "0.29.0", "colorette": "1.2.2", "fa-icons": "0.2.0", @@ -80,9 +81,9 @@ "integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==" }, "node_modules/@nyaruka/flow-editor": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.1.tgz", - "integrity": "sha512-H8pyAaHiIrnpE5GSmSARWSnUKakGTp4M2YsjR9QR1liNUK/uShLpi6FxJbvnKICYN2ytrbTYmPK/JCpXrPLCAA==", + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.2.tgz", + "integrity": "sha512-SncrhTt0w+SR3kAwl9P5xGFICTNuSyBZ/FveMKkFd3RHpumhmeVI2UnegYaa6qw8k3VdaeumMWqQcF/CF1HNnQ==", "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6" @@ -2479,9 +2480,9 @@ "integrity": "sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==" }, "@nyaruka/flow-editor": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.1.tgz", - "integrity": "sha512-H8pyAaHiIrnpE5GSmSARWSnUKakGTp4M2YsjR9QR1liNUK/uShLpi6FxJbvnKICYN2ytrbTYmPK/JCpXrPLCAA==", + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/@nyaruka/flow-editor/-/flow-editor-1.17.2.tgz", + "integrity": "sha512-SncrhTt0w+SR3kAwl9P5xGFICTNuSyBZ/FveMKkFd3RHpumhmeVI2UnegYaa6qw8k3VdaeumMWqQcF/CF1HNnQ==", "requires": { "react": "^16.8.6", "react-dom": "^16.8.6" diff --git a/package.json b/package.json index 76a8daedee6..2fae7778aa4 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ ] }, "dependencies": { - "@nyaruka/flow-editor": "1.17.1", + "@nyaruka/flow-editor": "1.17.2", "@nyaruka/temba-components": "0.29.0", "colorette": "1.2.2", "fa-icons": "0.2.0", From efe84b061d2ebac1e46056e340fc9af0770b10b9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 1 Aug 2022 11:38:38 -0500 Subject: [PATCH 084/630] Update CHANGELOG.md for v7.5.8 --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ffcb3670dd..f47c2f8835c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.8 +---------- + * Update floweditor + * Convert all views to use ContentMenuMixin instead of get_gear_links + * Add decorator to mock uuid generation in tests + * Process media uploads with ffmpeg in celery task + v7.5.7 ---------- * Add constraint to ensure non-waiting/active runs have exited_on set diff --git a/pyproject.toml b/pyproject.toml index 39969997cbd..d86f89fb4d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.7" +version = "7.5.8" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From c9d53b8d218ba18de7400bdba13d662e62429c57 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 1 Aug 2022 13:20:58 -0500 Subject: [PATCH 085/630] Add status field to Media, move primary index to UUID field --- temba/msgs/media.py | 42 +++++++++++-------- ...s_media_status_alter_media_url_and_more.py | 41 ++++++++++++++++++ temba/msgs/models.py | 13 ++++-- temba/msgs/tests.py | 28 +++++++++---- 4 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 temba/msgs/migrations/0180_remove_media_paths_media_status_alter_media_url_and_more.py diff --git a/temba/msgs/media.py b/temba/msgs/media.py index 599def45751..ca7383e2a08 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -1,3 +1,4 @@ +import logging import os from tempfile import NamedTemporaryFile @@ -7,28 +8,35 @@ from .models import Media +logger = logging.getLogger(__name__) + def process_upload(media: Media): media_type, sub_type = media.content_type.split("/") - with public_file_storage.open(media.path, mode="rb") as stream: - # download the media from storage to a local temp file - with NamedTemporaryFile(suffix=media.name, delete=True) as temp: - data = stream.read() - temp.write(data) - temp.flush() - temp.seek(0) - - media.size = len(data) - - if media_type == "image": - _process_image_upload(media, sub_type, temp) - elif media_type == "audio": - _process_audio_upload(media, sub_type, temp) - elif media_type == "video": - _process_video_upload(media, sub_type, temp) + try: + with public_file_storage.open(media.path, mode="rb") as stream: + # download the media from storage to a local temp file + with NamedTemporaryFile(suffix=media.name, delete=True) as temp: + data = stream.read() + temp.write(data) + temp.flush() + temp.seek(0) + + media.size = len(data) + + if media_type == "image": + _process_image_upload(media, sub_type, temp) + elif media_type == "audio": + _process_audio_upload(media, sub_type, temp) + elif media_type == "video": + _process_video_upload(media, sub_type, temp) + + media.status = Media.STATUS_READY + except Exception as e: + media.status = Media.STATUS_FAILED + logger.error("Error processing media upload: %s", e, exc_info=True) - media.is_ready = True media.save() diff --git a/temba/msgs/migrations/0180_remove_media_paths_media_status_alter_media_url_and_more.py b/temba/msgs/migrations/0180_remove_media_paths_media_status_alter_media_url_and_more.py new file mode 100644 index 00000000000..427dbf80122 --- /dev/null +++ b/temba/msgs/migrations/0180_remove_media_paths_media_status_alter_media_url_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 4.0.6 on 2022-08-01 17:31 + +from django.db import migrations, models + +import temba.utils.uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0179_alter_media_content_type_alter_media_path"), + ] + + operations = [ + migrations.RemoveField( + model_name="media", + name="paths", + ), + migrations.AddField( + model_name="media", + name="status", + field=models.CharField( + choices=[("P", "Pending"), ("R", "Ready"), ("F", "Failed")], default="P", max_length=1 + ), + ), + migrations.AlterField( + model_name="media", + name="url", + field=models.URLField(max_length=2048), + ), + migrations.AlterField( + model_name="media", + name="uuid", + field=models.UUIDField(db_index=True, default=temba.utils.uuid.uuid4, unique=True), + ), + migrations.AlterField( + model_name="media", + name="is_ready", + field=models.BooleanField(default=False, null=True), + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index d81d7193168..b64c2918b1e 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -49,26 +49,31 @@ class Media(models.Model): An uploaded media file that can be used as an attachment on messages. """ - uuid = models.UUIDField(default=uuid4) + STATUS_PENDING = "P" + STATUS_READY = "R" + STATUS_FAILED = "F" + STATUS_CHOICES = ((STATUS_PENDING, "Pending"), (STATUS_READY, "Ready"), (STATUS_FAILED, "Failed")) + + uuid = models.UUIDField(default=uuid4, db_index=True, unique=True) org = models.ForeignKey(Org, on_delete=models.PROTECT) - url = models.URLField(max_length=2048, db_index=True, unique=True) + url = models.URLField(max_length=2048) name = models.CharField(max_length=255) # filename including extension content_type = models.CharField(max_length=255) path = models.CharField(max_length=2048) size = models.IntegerField(default=0) # bytes original = models.ForeignKey("self", null=True, on_delete=models.CASCADE, related_name="alternates") + status = models.CharField(max_length=1, default=STATUS_PENDING, choices=STATUS_CHOICES) # fields that will be set after upload by a processing task duration = models.IntegerField(default=0) # milliseconds width = models.IntegerField(default=0) # pixels height = models.IntegerField(default=0) # pixels - is_ready = models.BooleanField(default=False) created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) # TODO remove - paths = models.JSONField(default=dict) + is_ready = models.BooleanField(default=False, null=True) @classmethod def get_storage_path(cls, org, uuid, filename): diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index d91e2be48ef..3a80fef434a 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -60,7 +60,7 @@ def test_from_upload(self): f"test_orgs/{self.org.id}/media/b97f/b97f69f7-5edf-45c7-9fda-d37066eae91d/steve marten.jpg", media.path ) self.assertEqual(self.admin, media.created_by) - self.assertFalse(media.is_ready) + self.assertEqual(Media.STATUS_PENDING, media.status) # check that our filename is cleaned media = Media.from_upload( @@ -88,7 +88,7 @@ def test_process_image_png(self): self.assertEqual(0, media.duration) self.assertEqual(480, media.width) self.assertEqual(360, media.height) - self.assertTrue(media.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) @mock_uuids def test_process_audio_wav(self): @@ -101,7 +101,7 @@ def test_process_audio_wav(self): self.assertEqual(5110, media.duration) self.assertEqual(0, media.width) self.assertEqual(0, media.height) - self.assertTrue(media.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) alt1, alt2 = list(media.alternates.order_by("id")) @@ -118,7 +118,7 @@ def test_process_audio_wav(self): self.assertEqual(5110, alt1.duration) self.assertEqual(0, alt1.width) self.assertEqual(0, alt2.height) - self.assertTrue(alt1.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) self.assertEqual(self.org, alt2.org) self.assertEqual( @@ -133,7 +133,7 @@ def test_process_audio_wav(self): self.assertEqual(5110, alt2.duration) self.assertEqual(0, alt2.width) self.assertEqual(0, alt2.height) - self.assertTrue(alt2.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) @mock_uuids def test_process_audio_m4a(self): @@ -146,7 +146,7 @@ def test_process_audio_m4a(self): self.assertEqual(10216, media.duration) self.assertEqual(0, media.width) self.assertEqual(0, media.height) - self.assertTrue(media.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) alt = media.alternates.get() @@ -163,7 +163,7 @@ def test_process_audio_m4a(self): self.assertEqual(10216, alt.duration) self.assertEqual(0, alt.width) self.assertEqual(0, alt.height) - self.assertTrue(alt.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) @mock_uuids def test_process_video_mp4(self): @@ -176,7 +176,7 @@ def test_process_video_mp4(self): self.assertEqual(3536, media.duration) self.assertEqual(640, media.width) self.assertEqual(480, media.height) - self.assertTrue(media.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) alt = media.alternates.get() @@ -191,7 +191,17 @@ def test_process_video_mp4(self): self.assertEqual(0, alt.duration) self.assertEqual(640, alt.width) self.assertEqual(480, alt.height) - self.assertTrue(alt.is_ready) + self.assertEqual(Media.STATUS_READY, media.status) + + @mock_uuids + def test_process_unsupported(self): + media = Media.from_upload( + self.org, self.admin, self.upload(f"{settings.MEDIA_ROOT}/test_imports/simple.xls", "audio/m4a") + ) + media.refresh_from_db() + + self.assertEqual(19968, media.size) + self.assertEqual(Media.STATUS_FAILED, media.status) class MsgTest(TembaTest): From ea841282240d8e7419fbada9d7409ad51d5b2c9e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 1 Aug 2022 14:26:39 -0500 Subject: [PATCH 086/630] Update CHANGELOG.md for v7.5.9 --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f47c2f8835c..5c8e9da9c88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.9 +---------- + * Add status field to Media, move primary index to UUID field + v7.5.8 ---------- * Update floweditor diff --git a/pyproject.toml b/pyproject.toml index d86f89fb4d0..ac4916401bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.8" +version = "7.5.9" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 13ad032e8e358654492af1f5bee674d4bc29ab69 Mon Sep 17 00:00:00 2001 From: Tyler Britten <1933680+tybritten@users.noreply.github.com> Date: Tue, 2 Aug 2022 12:31:58 -0400 Subject: [PATCH 087/630] remove key/secret hardcoding for boto session --- temba/utils/s3/s3.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/temba/utils/s3/s3.py b/temba/utils/s3/s3.py index 8d0670d44a7..7d1a609cc2c 100644 --- a/temba/utils/s3/s3.py +++ b/temba/utils/s3/s3.py @@ -15,7 +15,9 @@ class PublicFileStorage(DefaultStorage): public_file_storage = PublicFileStorage() public_file_storage.default_acl = "public-read" -public_file_storage.querystring_auth = False # don't include access token in attachment URLs +public_file_storage.querystring_auth = ( + False # don't include access token in attachment URLs +) _s3_client = None @@ -28,10 +30,16 @@ def client(): # pragma: no cover global _s3_client if not _s3_client: - session = boto3.Session( - aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY + if settings.AWS_ACCESS_KEY_ID and settings.AWS_SECRET_ACCESS_KEY: + session = boto3.Session( + aws_access_key_id=settings.AWS_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + ) + else: + session = boto3.Session() + _s3_client = session.client( + "s3", config=Config(retries={"max_attempts": 3}) ) - _s3_client = session.client("s3", config=Config(retries={"max_attempts": 3})) return _s3_client From 9afd53bbe1ca6bc8d50f80255bcc84b59e61080e Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 2 Aug 2022 18:25:49 -0500 Subject: [PATCH 088/630] Remove Media.is_ready, fix setting .status on alternates, add limit for upload size --- temba/flows/tests.py | 11 +++++++++++ temba/flows/views.py | 11 ++++++++++- .../migrations/0181_remove_media_is_ready.py | 17 +++++++++++++++++ temba/msgs/models.py | 18 ++++++++++++++---- temba/msgs/tests.py | 10 +++++----- 5 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 temba/msgs/migrations/0181_remove_media_is_ready.py diff --git a/temba/flows/tests.py b/temba/flows/tests.py index d7798f86879..ba536ed5d54 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -3023,6 +3023,17 @@ def assert_upload(user, filename, expected_json): }, ) + # error message if you upload something unsupported + with open(f"{settings.MEDIA_ROOT}/test_imports/simple.xls", "rb") as data: + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + self.assertEqual({"error": "Unsupported file type"}, response.json()) + + # error message if upload is too big + with patch("temba.msgs.models.Media.MAX_UPLOAD_SIZE", 1024): + with open(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "rb") as data: + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + self.assertEqual({"error": "Limit for file uploads is 0.0009765625 MB"}, response.json()) + # can't upload for flow in other org with open(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "rb") as data: upload_url = reverse("flows.flow_upload_media", args=[other_org_flow.uuid]) diff --git a/temba/flows/views.py b/temba/flows/views.py index 034f3eb50bc..0a5b2c85ab7 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -705,7 +705,16 @@ class UploadMedia(OrgObjPermsMixin, SmartUpdateView): slug_url_kwarg = "uuid" def post(self, request, *args, **kwargs): - media = Media.from_upload(self.request.org, self.request.user, self.request.FILES["file"]) + file = self.request.FILES["file"] + + if not Media.is_allowed_type(file.content_type): + return JsonResponse({"error": _("Unsupported file type")}) + if file.size > Media.MAX_UPLOAD_SIZE: + limit_MB = Media.MAX_UPLOAD_SIZE / (1024 * 1024) + return JsonResponse({"error": _("Limit for file uploads is %s MB") % limit_MB}) + + media = Media.from_upload(self.request.org, self.request.user, file) + return JsonResponse({"type": media.content_type, "url": media.url}) class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, ContentMenuMixin, SmartListView): diff --git a/temba/msgs/migrations/0181_remove_media_is_ready.py b/temba/msgs/migrations/0181_remove_media_is_ready.py new file mode 100644 index 00000000000..029c0973886 --- /dev/null +++ b/temba/msgs/migrations/0181_remove_media_is_ready.py @@ -0,0 +1,17 @@ +# Generated by Django 4.0.6 on 2022-08-02 20:13 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0180_remove_media_paths_media_status_alter_media_url_and_more"), + ] + + operations = [ + migrations.RemoveField( + model_name="media", + name="is_ready", + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index b64c2918b1e..e13cd2c899e 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -5,6 +5,7 @@ import time from array import array from datetime import datetime, timedelta +from fnmatch import fnmatch import iso8601 import pytz @@ -49,6 +50,9 @@ class Media(models.Model): An uploaded media file that can be used as an attachment on messages. """ + ALLOWED_CONTENT_TYPES = ("image/*", "audio/*", "video/*", "application/pdf") + MAX_UPLOAD_SIZE = 1024 * 1024 * 25 # 25MB + STATUS_PENDING = "P" STATUS_READY = "R" STATUS_FAILED = "F" @@ -72,8 +76,12 @@ class Media(models.Model): created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) - # TODO remove - is_ready = models.BooleanField(default=False, null=True) + @classmethod + def is_allowed_type(cls, content_type: str) -> bool: + for allowed_type in cls.ALLOWED_CONTENT_TYPES: + if fnmatch(content_type, allowed_type): + return True + return False @classmethod def get_storage_path(cls, org, uuid, filename): @@ -91,6 +99,8 @@ def from_upload(cls, org, user, file, process=True): from .tasks import process_media_upload + assert cls.is_allowed_type(file.content_type), "unsupported content type" + base_name, extension = os.path.splitext(file.name) # cleanup file name @@ -123,7 +133,7 @@ def create_alternate(cls, original, name: str, content_type: str, file, **kwargs content_type, file, original=original, - is_ready=True, + status=cls.STATUS_READY, **kwargs, ) @@ -149,7 +159,7 @@ def _create(cls, org, user, name: str, content_type: str, file, **kwargs): def process_upload(self): from .media import process_upload - assert not self.is_ready, "media file is already processed" + assert self.status == self.STATUS_PENDING, "media file is already processed" assert not self.original, "only original uploads can be processed" process_upload(self) diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 3a80fef434a..ed421cd5e2f 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -117,8 +117,8 @@ def test_process_audio_wav(self): self.assertAlmostEqual(5517, alt1.size, delta=1000) self.assertEqual(5110, alt1.duration) self.assertEqual(0, alt1.width) - self.assertEqual(0, alt2.height) - self.assertEqual(Media.STATUS_READY, media.status) + self.assertEqual(0, alt1.height) + self.assertEqual(Media.STATUS_READY, alt1.status) self.assertEqual(self.org, alt2.org) self.assertEqual( @@ -133,7 +133,7 @@ def test_process_audio_wav(self): self.assertEqual(5110, alt2.duration) self.assertEqual(0, alt2.width) self.assertEqual(0, alt2.height) - self.assertEqual(Media.STATUS_READY, media.status) + self.assertEqual(Media.STATUS_READY, alt2.status) @mock_uuids def test_process_audio_m4a(self): @@ -163,7 +163,7 @@ def test_process_audio_m4a(self): self.assertEqual(10216, alt.duration) self.assertEqual(0, alt.width) self.assertEqual(0, alt.height) - self.assertEqual(Media.STATUS_READY, media.status) + self.assertEqual(Media.STATUS_READY, alt.status) @mock_uuids def test_process_video_mp4(self): @@ -191,7 +191,7 @@ def test_process_video_mp4(self): self.assertEqual(0, alt.duration) self.assertEqual(640, alt.width) self.assertEqual(480, alt.height) - self.assertEqual(Media.STATUS_READY, media.status) + self.assertEqual(Media.STATUS_READY, alt.status) @mock_uuids def test_process_unsupported(self): From 1bcf48bb6367b47d645646f22aaf1dde52498ea9 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 09:27:18 -0500 Subject: [PATCH 089/630] Update CHANGELOG.md for v7.5.10 --- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c8e9da9c88..77a3e5e9ffd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v7.5.10 +---------- + * Remove Media.is_ready, fix setting .status on alternates, add limit for upload size + * Rework ContentMenuMixin to put the menu in the context, and include new and legacy formats + v7.5.9 ---------- * Add status field to Media, move primary index to UUID field diff --git a/pyproject.toml b/pyproject.toml index ac4916401bb..29bf5d43c37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.9" +version = "7.5.10" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 1e3d2608eb398e767ddfa010d88a9927cb491225 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 10:20:58 -0500 Subject: [PATCH 090/630] Add MediaCRUDL with upload and list endpoints --- temba/flows/views.py | 7 +++- temba/msgs/tests.py | 70 ++++++++++++++++++++++++++++++++ temba/msgs/urls.py | 3 +- temba/msgs/views.py | 35 +++++++++++++++- temba/settings_common.py | 5 ++- templates/flows/flow_editor.haml | 2 +- 6 files changed, 116 insertions(+), 6 deletions(-) diff --git a/temba/flows/views.py b/temba/flows/views.py index 0a5b2c85ab7..2ef946eb535 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -701,7 +701,12 @@ def post_save(self, obj): return obj - class UploadMedia(OrgObjPermsMixin, SmartUpdateView): + class UploadMedia(OrgObjPermsMixin, SmartUpdateView): # pragma: no cover + """ + TODO replace with MediaCRUDL.Upload + """ + + permission = "msgs.media_upload" slug_url_kwarg = "uuid" def post(self, request, *args, **kwargs): diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index ed421cd5e2f..24c4f8698b8 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -2896,3 +2896,73 @@ def test_render(self): # exception if tag not used correctly self.assertRaises(ValueError, self.render_template, "{% load sms %}{% render with bob %}{% endrender %}") self.assertRaises(ValueError, self.render_template, "{% load sms %}{% render as %}{% endrender %}") + + +class MediaCRUDLTest(CRUDLTestMixin, TembaTest): + @mock_uuids + def test_upload(self): + upload_url = reverse("msgs.media_upload") + + def assert_upload(user, filename, expected_json): + self.login(user) + + with open(filename, "rb") as data: + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + + self.assertEqual(response.status_code, 200) + self.assertEqual(expected_json, response.json()) + + assert_upload( + self.admin, + f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", + { + "uuid": "b97f69f7-5edf-45c7-9fda-d37066eae91d", + "content_type": "image/jpeg", + "type": "image/jpeg", + "url": f"/media/test_orgs/{self.org.id}/media/b97f/b97f69f7-5edf-45c7-9fda-d37066eae91d/steve%20marten.jpg", + "name": "steve marten.jpg", + "size": 7461, + }, + ) + assert_upload( + self.editor, + f"{settings.MEDIA_ROOT}/test_media/snow.mp4", + { + "uuid": "14f6ea01-456b-4417-b0b8-35e942f549f1", + "content_type": "video/mp4", + "type": "video/mp4", + "url": f"/media/test_orgs/{self.org.id}/media/14f6/14f6ea01-456b-4417-b0b8-35e942f549f1/snow.mp4", + "name": "snow.mp4", + "size": 684558, + }, + ) + assert_upload( + self.editor, + f"{settings.MEDIA_ROOT}/test_media/bubbles.m4a", + { + "uuid": "9295ebab-5c2d-4eb1-86f9-7c15ed2f3219", + "content_type": "audio/mp4", + "type": "audio/mp4", + "url": f"/media/test_orgs/{self.org.id}/media/9295/9295ebab-5c2d-4eb1-86f9-7c15ed2f3219/bubbles.m4a", + "name": "bubbles.m4a", + "size": 46468, + }, + ) + + # error message if you upload something unsupported + with open(f"{settings.MEDIA_ROOT}/test_imports/simple.xls", "rb") as data: + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + self.assertEqual({"error": "Unsupported file type"}, response.json()) + + # error message if upload is too big + with patch("temba.msgs.models.Media.MAX_UPLOAD_SIZE", 1024): + with open(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "rb") as data: + response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") + self.assertEqual({"error": "Limit for file uploads is 0.0009765625 MB"}, response.json()) + + self.clear_storage() + + def test_list(self): + list_url = reverse("msgs.media_list") + + self.assertStaffOnly(list_url) diff --git a/temba/msgs/urls.py b/temba/msgs/urls.py index 9a5f1e58582..ce1c4e5f77b 100644 --- a/temba/msgs/urls.py +++ b/temba/msgs/urls.py @@ -1,5 +1,6 @@ -from .views import BroadcastCRUDL, LabelCRUDL, MsgCRUDL +from .views import BroadcastCRUDL, LabelCRUDL, MediaCRUDL, MsgCRUDL urlpatterns = MsgCRUDL().as_urlpatterns() urlpatterns += BroadcastCRUDL().as_urlpatterns() urlpatterns += LabelCRUDL().as_urlpatterns() +urlpatterns += MediaCRUDL().as_urlpatterns() diff --git a/temba/msgs/views.py b/temba/msgs/views.py index e2910982cd3..1d24c77fab8 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -17,7 +17,7 @@ from django.contrib import messages from django.db.models.functions.text import Lower from django.forms import Form -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.urls import reverse from django.utils import timezone from django.utils.http import url_has_allowed_host_and_scheme @@ -52,7 +52,7 @@ from temba.utils.models import patch_queryset_count from temba.utils.views import BulkActionMixin, ComponentFormMixin, ContentMenuMixin, SpaMixin -from .models import Broadcast, ExportMessagesTask, Label, LabelCount, Msg, Schedule, SystemLabel +from .models import Broadcast, ExportMessagesTask, Label, LabelCount, Media, Msg, Schedule, SystemLabel from .tasks import export_messages_task @@ -981,3 +981,34 @@ def post(self, request, *args, **kwargs): response = HttpResponse() response["Temba-Success"] = self.get_success_url() return response + + +class MediaCRUDL(SmartCRUDL): + model = Media + actions = ("upload", "list") + + class Upload(OrgPermsMixin, SmartCreateView): + def post(self, request, *args, **kwargs): + file = request.FILES["file"] + + if not Media.is_allowed_type(file.content_type): + return JsonResponse({"error": _("Unsupported file type")}) + if file.size > Media.MAX_UPLOAD_SIZE: + limit_MB = Media.MAX_UPLOAD_SIZE / (1024 * 1024) + return JsonResponse({"error": _("Limit for file uploads is %s MB") % limit_MB}) + + media = Media.from_upload(request.org, request.user, file) + + return JsonResponse( + { + "uuid": str(media.uuid), + "content_type": media.content_type, + "type": media.content_type, # deprecated + "url": media.url, + "name": media.name, + "size": media.size, + } + ) + + class List(OrgPermsMixin, SmartListView): + fields = ("name", "content_type", "size", "created_by", "created_on") diff --git a/temba/settings_common.py b/temba/settings_common.py index c8b69bac9e5..f7ed4f7f811 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -435,7 +435,6 @@ "revisions", "run_table", "simulate", - "upload_media", ), "flows.flowsession": ("json",), "globals.global": ("api", "unused"), @@ -443,6 +442,7 @@ "locations.adminboundary": ("alias", "api", "boundaries", "geometry"), "msgs.broadcast": ("api", "detail", "schedule", "schedule_list", "schedule_read", "send"), "msgs.label": ("api", "delete_folder"), + "msgs.media": ("upload", "list"), "msgs.msg": ( "api", "archive", @@ -547,6 +547,7 @@ "flows.flow_revisions", "flows.flowrun_delete", "flows.flowsession_json", + "msgs.media_list", "notifications.log_list", "orgs.org_dashboard", "orgs.org_delete", @@ -639,6 +640,7 @@ "msgs.broadcast.*", "msgs.broadcastschedule.*", "msgs.label.*", + "msgs.media_upload", "msgs.msg_api", "msgs.msg_archive", "msgs.msg_archived", @@ -772,6 +774,7 @@ "msgs.broadcast.*", "msgs.broadcastschedule.*", "msgs.label.*", + "msgs.media_upload", "msgs.msg_api", "msgs.msg_archive", "msgs.msg_archived", diff --git a/templates/flows/flow_editor.haml b/templates/flows/flow_editor.haml index 74f22a4bb45..6b6d8a23628 100644 --- a/templates/flows/flow_editor.haml +++ b/templates/flows/flow_editor.haml @@ -259,7 +259,7 @@ // TODO: migrate to API? revisions: '/flow/revisions/{{object.uuid}}/', recents: '/flow/recent_contacts/{{object.uuid}}/', - attachments: '/flow/upload_media/{{object.uuid}}/', + attachments: '/media/upload/', languages: base + 'language', environment: base + 'environment', activity: '/flow/activity/{{object.uuid}}/', From bb91bc895aea6e5c56acc66e58bf438774a608b7 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 11:05:35 -0500 Subject: [PATCH 091/630] Rework the undocumented media API endpoint to be more specific to surveyor attachments --- temba/api/v2/tests.py | 61 ++++++++++++++++++++----------------- temba/api/v2/urls.py | 5 +-- temba/api/v2/views.py | 53 ++++++++++++++++---------------- temba/flows/tests.py | 71 +------------------------------------------ temba/orgs/models.py | 50 ------------------------------ 5 files changed, 64 insertions(+), 176 deletions(-) diff --git a/temba/api/v2/tests.py b/temba/api/v2/tests.py index 7572176e359..b4330d2e626 100644 --- a/temba/api/v2/tests.py +++ b/temba/api/v2/tests.py @@ -34,7 +34,7 @@ from temba.msgs.models import Broadcast, Label, Msg from temba.orgs.models import Org, OrgRole, User from temba.templates.models import Template, TemplateTranslation -from temba.tests import AnonymousOrg, TembaTest, matchers, mock_mailroom +from temba.tests import AnonymousOrg, TembaTest, matchers, mock_mailroom, mock_uuids from temba.tests.engine import MockSessionWriter from temba.tickets.models import Ticket, Ticketer, Topic from temba.tickets.types.mailgun import MailgunType @@ -3460,33 +3460,6 @@ def test_workspace(self): }, ) - def test_media(self): - url = reverse("api.v2.media") + ".json" - - self.login(self.admin) - - def assert_media_upload(filename, ext): - with open(filename, "rb") as data: - - post_data = dict(media_file=data, extension=ext, HTTP_X_FORWARDED_HTTPS="https") - response = self.client.post(url, post_data) - - self.assertEqual(response.status_code, 201) - location = response.json().get("location", None) - self.assertIsNotNone(location) - - starts_with = f"{settings.STORAGE_URL}/{settings.STORAGE_ROOT_DIR}/{self.org.id}/media/" - self.assertEqual(starts_with, location[0 : len(starts_with)]) - self.assertEqual(".%s" % ext, location[-4:]) - - assert_media_upload("%s/test_media/steve marten.jpg" % settings.MEDIA_ROOT, "jpg") - assert_media_upload("%s/test_media/snow.mp4" % settings.MEDIA_ROOT, "mp4") - - # missing file - response = self.client.post(url, dict(), HTTP_X_FORWARDED_HTTPS="https") - self.assertEqual(response.status_code, 400) - self.clear_storage() - def test_runs(self): url = reverse("api.v2.runs") @@ -4434,6 +4407,38 @@ def test_templates(self): ], ) + @mock_uuids + def test_surveyor_attachments(self): + endpoint = reverse("api.v2.surveyor_attachments") + ".json" + + self.login(self.admin) + + def assert_media_upload(filename: str, ext: str, location: str): + with open(filename, "rb") as data: + response = self.client.post( + endpoint, {"media_file": data, "extension": ext}, HTTP_X_FORWARDED_HTTPS="https" + ) + + self.assertEqual(response.status_code, 201) + self.assertEqual(location, response.json().get("location", None)) + + assert_media_upload( + f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", + "jpg", + f"/media/test_orgs/{self.org.id}/surveyor_attachments/b97f/b97f69f7-5edf-45c7-9fda-d37066eae91d.jpg", + ) + assert_media_upload( + f"{settings.MEDIA_ROOT}/test_media/snow.mp4", + "mp4", + f"/media/test_orgs/{self.org.id}/surveyor_attachments/14f6/14f6ea01-456b-4417-b0b8-35e942f549f1.mp4", + ) + + # missing file + response = self.client.post(endpoint, dict(), HTTP_X_FORWARDED_HTTPS="https") + self.assertEqual(response.status_code, 400) + + self.clear_storage() + def test_classifiers(self): url = reverse("api.v2.classifiers") self.assertEndpointAccess(url) diff --git a/temba/api/v2/urls.py b/temba/api/v2/urls.py index 9afa51872c0..aa746a70920 100644 --- a/temba/api/v2/urls.py +++ b/temba/api/v2/urls.py @@ -22,7 +22,6 @@ GlobalsEndpoint, GroupsEndpoint, LabelsEndpoint, - MediaEndpoint, MessageActionsEndpoint, MessagesEndpoint, ResthookEventsEndpoint, @@ -30,6 +29,7 @@ ResthookSubscribersEndpoint, RootView, RunsEndpoint, + SurveyorAttachmentsEndpoint, TemplatesEndpoint, TicketActionsEndpoint, TicketersEndpoint, @@ -61,7 +61,6 @@ re_path(r"^globals$", GlobalsEndpoint.as_view(), name="api.v2.globals"), re_path(r"^groups$", GroupsEndpoint.as_view(), name="api.v2.groups"), re_path(r"^labels$", LabelsEndpoint.as_view(), name="api.v2.labels"), - re_path(r"^media$", MediaEndpoint.as_view(), name="api.v2.media"), re_path(r"^messages$", MessagesEndpoint.as_view(), name="api.v2.messages"), re_path(r"^message_actions$", MessageActionsEndpoint.as_view(), name="api.v2.message_actions"), re_path(r"^org$", WorkspaceEndpoint.as_view(), name="api.v2.org"), # deprecated @@ -76,6 +75,8 @@ re_path(r"^topics$", TopicsEndpoint.as_view(), name="api.v2.topics"), re_path(r"^users$", UsersEndpoint.as_view(), name="api.v2.users"), re_path(r"^workspace$", WorkspaceEndpoint.as_view(), name="api.v2.workspace"), + # undocumented + re_path(r"^media$", SurveyorAttachmentsEndpoint.as_view(), name="api.v2.surveyor_attachments"), ] urlpatterns = format_suffix_patterns(urlpatterns, allowed=["json", "api"]) diff --git a/temba/api/v2/views.py b/temba/api/v2/views.py index 585363b3d6a..71509d9c4a0 100644 --- a/temba/api/v2/views.py +++ b/temba/api/v2/views.py @@ -10,6 +10,7 @@ from smartmin.views import SmartFormView, SmartTemplateView from django import forms +from django.conf import settings from django.contrib.auth import authenticate, login from django.db.models import Prefetch, Q from django.http import HttpResponse, JsonResponse @@ -40,7 +41,8 @@ from temba.templates.models import Template, TemplateTranslation from temba.tickets.models import Ticket, Ticketer, Topic from temba.utils import splitting_getlist, str_to_bool -from temba.utils.uuid import is_uuid +from temba.utils.s3 import public_file_storage +from temba.utils.uuid import is_uuid, uuid4 from ..models import SSLPermission from ..support import InvalidQueryError @@ -2403,31 +2405,6 @@ def get_delete_explorer(cls): } -class MediaEndpoint(BaseAPIView): - """ - This endpoint allows you to submit media which can be embedded in flow steps. - - ## Creating Media - - By making a `POST` request to the endpoint you can add a new media files - """ - - parser_classes = (MultiPartParser, FormParser) - permission = "msgs.msg_api" - - def post(self, request, format=None, *args, **kwargs): - - org = self.request.user.get_org() - media_file = request.data.get("media_file", None) - extension = request.data.get("extension", None) - - if media_file and extension: - location = org.save_media(media_file, extension) - return Response(dict(location=location), status=status.HTTP_201_CREATED) - - return Response(dict(), status=status.HTTP_400_BAD_REQUEST) - - class MessagesEndpoint(ListAPIMixin, BaseAPIView): """ This endpoint allows you to list messages in your account. @@ -3784,3 +3761,27 @@ def get_read_explorer(cls): "url": reverse("api.v2.workspace"), "slug": "workspace-read", } + + +class SurveyorAttachmentsEndpoint(BaseAPIView): + """ + Undocumented endpoint used by Surveyor to submit response attachments. + """ + + parser_classes = (MultiPartParser, FormParser) + permission = "msgs.msg_api" + + def post(self, request, format=None, *args, **kwargs): + org = self.request.user.get_org() + file = request.data.get("media_file", None) + extension = request.data.get("extension", None) + + if file and extension: + uuid = uuid4() + path = f"{settings.STORAGE_ROOT_DIR}/{org.id}/surveyor_attachments/{str(uuid)[0:4]}/{uuid}.{extension}" + public_file_storage.save(path, file) + url = public_file_storage.url(path) + + return Response({"location": url}, status=status.HTTP_201_CREATED) + + return Response({}, status=status.HTTP_400_BAD_REQUEST) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index ba536ed5d54..6158b010712 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -28,16 +28,7 @@ from temba.mailroom import FlowValidationException from temba.orgs.integrations.dtone import DTOneType from temba.templates.models import Template, TemplateTranslation -from temba.tests import ( - AnonymousOrg, - CRUDLTestMixin, - MigrationTest, - MockResponse, - TembaTest, - matchers, - mock_mailroom, - mock_uuids, -) +from temba.tests import AnonymousOrg, CRUDLTestMixin, MigrationTest, MockResponse, TembaTest, matchers, mock_mailroom from temba.tests.engine import MockSessionWriter from temba.tests.s3 import MockS3Client, jsonlgz_encode from temba.tickets.models import Ticketer @@ -2982,66 +2973,6 @@ def test_broadcast_background_flow(self, mr_mocks): self.assertTrue(start.include_active) self.assertEqual('name ~ "frank"', start.query) - @mock_uuids - def test_upload_media(self): - flow = self.create_flow("Test") - other_org_flow = self.create_flow("Test", org=self.org2) - - upload_url = reverse("flows.flow_upload_media", args=[flow.uuid]) - - def assert_upload(user, filename, expected_json): - self.login(user) - - with open(filename, "rb") as data: - response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") - - self.assertEqual(response.status_code, 200) - self.assertEqual(expected_json, response.json()) - - assert_upload( - self.admin, - f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", - { - "type": "image/jpeg", - "url": f"/media/test_orgs/{self.org.id}/media/3618/361838c4-2866-495a-8990-9f3c222a7604/steve%20marten.jpg", - }, - ) - assert_upload( - self.editor, - f"{settings.MEDIA_ROOT}/test_media/snow.mp4", - { - "type": "video/mp4", - "url": f"/media/test_orgs/{self.org.id}/media/606d/606de307-a799-47fc-8802-edc9301e0e04/snow.mp4", - }, - ) - assert_upload( - self.editor, - f"{settings.MEDIA_ROOT}/test_media/bubbles.m4a", - { - "type": "audio/mp4", - "url": f"/media/test_orgs/{self.org.id}/media/fd18/fd18a69d-7514-4b76-9fad-072641995e17/bubbles.m4a", - }, - ) - - # error message if you upload something unsupported - with open(f"{settings.MEDIA_ROOT}/test_imports/simple.xls", "rb") as data: - response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") - self.assertEqual({"error": "Unsupported file type"}, response.json()) - - # error message if upload is too big - with patch("temba.msgs.models.Media.MAX_UPLOAD_SIZE", 1024): - with open(f"{settings.MEDIA_ROOT}/test_media/snow.mp4", "rb") as data: - response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") - self.assertEqual({"error": "Limit for file uploads is 0.0009765625 MB"}, response.json()) - - # can't upload for flow in other org - with open(f"{settings.MEDIA_ROOT}/test_media/steve marten.jpg", "rb") as data: - upload_url = reverse("flows.flow_upload_media", args=[other_org_flow.uuid]) - response = self.client.post(upload_url, {"file": data, "action": ""}, HTTP_X_FORWARDED_HTTPS="https") - self.assertLoginRedirect(response) - - self.clear_storage() - def test_copy_view(self): flow = self.get_flow("color") diff --git a/temba/orgs/models.py b/temba/orgs/models.py index 78caf1954dc..abcde74ee9c 100644 --- a/temba/orgs/models.py +++ b/temba/orgs/models.py @@ -15,7 +15,6 @@ import stripe.error from django_redis import get_redis_connection from packaging.version import Version -from requests import Session from smartmin.models import SmartModel from timezone_field import TimeZoneField from twilio.rest import Client as TwilioClient @@ -24,8 +23,6 @@ from django.contrib.auth.models import Group, Permission, User as AuthUser from django.contrib.postgres.fields import ArrayField from django.core.exceptions import ValidationError -from django.core.files import File -from django.core.files.temp import NamedTemporaryFile from django.db import models, transaction from django.db.models import Count, F, Prefetch, Q, Sum from django.utils import timezone @@ -42,7 +39,6 @@ from temba.utils.dates import datetime_to_str from temba.utils.email import send_template_email from temba.utils.models import JSONAsTextField, JSONField, SquashableModel -from temba.utils.s3 import public_file_storage from temba.utils.text import generate_token, random_string from temba.utils.timezones import timezone_to_country_code from temba.utils.uuid import uuid4 @@ -1767,36 +1763,6 @@ def initialize(self, branding=None, topup_size=None, sample_flows=True): if sample_flows: self.create_sample_flows(branding.get("api_link", "")) - def download_and_save_media(self, request, extension=None): # pragma: needs cover - """ - Given an HTTP Request object, downloads the file then saves it as media for the current org. If no extension - is passed it we attempt to extract it from the filename - """ - s = Session() - prepped = s.prepare_request(request) - response = s.send(prepped) - - if response.status_code == 200: - # download the content to a temp file - temp = NamedTemporaryFile(delete=True) - temp.write(response.content) - temp.flush() - - # try to derive our extension from the filename if it wasn't passed in - if not extension: - url_parts = urlparse(request.url) - if url_parts.path: - path_pieces = url_parts.path.rsplit(".") - if len(path_pieces) > 1: - extension = path_pieces[-1] - - else: - raise Exception( - "Received non-200 response (%s) for request: %s" % (response.status_code, response.content) - ) - - return self.save_media(File(temp), extension) - def get_delete_date(self, *, archive_type=Archive.TYPE_MSG): """ Gets the most recent date for which data hasn't been deleted yet or None if no deletion has been done @@ -1806,22 +1772,6 @@ def get_delete_date(self, *, archive_type=Archive.TYPE_MSG): if archive: return archive.get_end_date() - def save_media(self, file, extension): - """ - Saves the given file data with the extension and returns an absolute url to the result - """ - random_file = str(uuid4()) - random_dir = random_file[0:4] - - filename = "%s/%s" % (random_dir, random_file) - if extension: - filename = "%s.%s" % (filename, extension) - - path = "%s/%d/media/%s" % (settings.STORAGE_ROOT_DIR, self.pk, filename) - location = public_file_storage.save(path, file) - - return f"{settings.STORAGE_URL}/{location}" - def release(self, user, *, release_users=True): """ Releases this org, marking it as inactive. Actual deletion of org data won't happen until after 7 days unless From 66305401dbc21540bdbeb05ba648354f9b4b4e67 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 11:38:49 -0500 Subject: [PATCH 092/630] Don't allow creating of labels with parents or editing labels to have a parent --- temba/flows/tests.py | 12 +----------- temba/flows/views.py | 16 +++++++--------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/temba/flows/tests.py b/temba/flows/tests.py index ba536ed5d54..5a2c96a7c0f 100644 --- a/temba/flows/tests.py +++ b/temba/flows/tests.py @@ -5309,9 +5309,7 @@ class FlowLabelCRUDLTest(TembaTest, CRUDLTestMixin): def test_create(self): create_url = reverse("flows.flowlabel_create") - self.assertCreateFetch( - create_url, allow_viewers=False, allow_editors=True, form_fields=("name", "parent", "flows") - ) + self.assertCreateFetch(create_url, allow_viewers=False, allow_editors=True, form_fields=("name", "flows")) # try to submit without a name self.assertCreateSubmit(create_url, {}, form_errors={"name": "This field is required."}) @@ -5326,18 +5324,10 @@ def test_create(self): {"name": "Cool Flows"}, new_obj_query=FlowLabel.objects.filter(org=self.org, name="Cool Flows", parent=None), ) - label1 = FlowLabel.objects.get(name="Cool Flows") # try to create with a name that's already used self.assertCreateSubmit(create_url, {"name": "Cool Flows"}, form_errors={"name": "Must be unique."}) - # create a label with a parent - self.assertCreateSubmit( - create_url, - {"name": "Very Cool Flows", "parent": label1.id}, - new_obj_query=FlowLabel.objects.filter(org=self.org, name="Very Cool Flows", parent=label1), - ) - def test_update(self): parent = FlowLabel.create(self.org, self.admin, "Cool Flows") child = FlowLabel.create(self.org, self.admin, "Very Cool Flows", parent=parent) diff --git a/temba/flows/views.py b/temba/flows/views.py index 0a5b2c85ab7..fe7aa41be86 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -2093,13 +2093,14 @@ def get_form_kwargs(self): return kwargs def derive_fields(self): - if FlowLabel.objects.filter(parent=self.get_object()): # pragma: needs cover + # can't edit parent if this label is already a parent.. or didn't previously have a parent + if self.object.children.exists() or not self.object.parent: return ("name",) else: return ("name", "parent") class Create(ModalMixin, OrgPermsMixin, SmartCreateView): - fields = ("name", "parent", "flows") + fields = ("name", "flows") success_url = "hide" form_class = FlowLabelForm success_message = "" @@ -2107,13 +2108,11 @@ class Create(ModalMixin, OrgPermsMixin, SmartCreateView): def get_form_kwargs(self): kwargs = super().get_form_kwargs() - kwargs["org"] = self.request.user.get_org() + kwargs["org"] = self.request.org return kwargs - def pre_save(self, obj, *args, **kwargs): - obj = super().pre_save(obj, *args, **kwargs) - obj.org = self.request.user.get_org() - return obj + def save(self, obj): + self.object = FlowLabel.create(self.request.org, self.request.user, obj.name) def post_save(self, obj, *args, **kwargs): obj = super().post_save(obj, *args, **kwargs) @@ -2122,8 +2121,7 @@ def post_save(self, obj, *args, **kwargs): if self.form.cleaned_data["flows"]: # pragma: needs cover flow_ids = [int(f) for f in self.form.cleaned_data["flows"].split(",") if f.isdigit()] - flows = Flow.objects.filter(org=obj.org, is_active=True, pk__in=flow_ids) - + flows = obj.org.flows.filter(is_active=True, id__in=flow_ids) if flows: # pragma: needs cover obj.toggle_label(flows, add=True) From dd657c317887de3de452eabd833076d31ae8a964 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 12:04:30 -0500 Subject: [PATCH 093/630] Update CHANGELOG.md for v7.5.11 --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77a3e5e9ffd..3b66ad8a7cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.11 +---------- + * Don't allow creating of labels with parents or editing labels to have a parent + * Rework the undocumented media API endpoint to be more specific to surveyor attachments + * Add MediaCRUDL with upload and list endpoints + * Remove requiring instagram_basic permission + v7.5.10 ---------- * Remove Media.is_ready, fix setting .status on alternates, add limit for upload size diff --git a/pyproject.toml b/pyproject.toml index 29bf5d43c37..2cb6dd8c192 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.10" +version = "7.5.11" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 67d00871a4fc819848c1592185db15374d41b973 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 12:06:11 -0500 Subject: [PATCH 094/630] Remove no longer used FlowCRUDL.UploadMedia --- temba/flows/views.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/temba/flows/views.py b/temba/flows/views.py index 448b2d8d4d8..94ef3d52b9a 100644 --- a/temba/flows/views.py +++ b/temba/flows/views.py @@ -40,7 +40,6 @@ from temba.flows.tasks import export_flow_results_task, update_session_wait_expires from temba.ivr.models import IVRCall from temba.mailroom import FlowValidationException -from temba.msgs.models import Media from temba.orgs.models import IntegrationType, Org from temba.orgs.views import ( DependencyDeleteModal, @@ -212,7 +211,6 @@ class FlowCRUDL(SmartCRUDL): "revisions", "recent_contacts", "assets", - "upload_media", ) model = Flow @@ -701,27 +699,6 @@ def post_save(self, obj): return obj - class UploadMedia(OrgObjPermsMixin, SmartUpdateView): # pragma: no cover - """ - TODO replace with MediaCRUDL.Upload - """ - - permission = "msgs.media_upload" - slug_url_kwarg = "uuid" - - def post(self, request, *args, **kwargs): - file = self.request.FILES["file"] - - if not Media.is_allowed_type(file.content_type): - return JsonResponse({"error": _("Unsupported file type")}) - if file.size > Media.MAX_UPLOAD_SIZE: - limit_MB = Media.MAX_UPLOAD_SIZE / (1024 * 1024) - return JsonResponse({"error": _("Limit for file uploads is %s MB") % limit_MB}) - - media = Media.from_upload(self.request.org, self.request.user, file) - - return JsonResponse({"type": media.content_type, "url": media.url}) - class BaseList(SpaMixin, OrgFilterMixin, OrgPermsMixin, BulkActionMixin, ContentMenuMixin, SmartListView): title = _("Flows") refresh = 10000 From 4c4a8ad28c3191219d21b98874d0985ebf174457 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Wed, 3 Aug 2022 11:53:35 -0500 Subject: [PATCH 095/630] Convert legacy UUID fields on exports and labels --- temba/api/v2/fields.py | 13 +++++++- temba/api/v2/serializers.py | 2 +- temba/api/v2/tests.py | 30 ++++++++++--------- temba/api/v2/views.py | 6 +++- .../0168_alter_exportcontactstask_uuid.py | 20 +++++++++++++ ...ter_exportflowresultstask_uuid_and_more.py | 25 ++++++++++++++++ temba/flows/models.py | 2 +- ...xportmessagestask_uuid_alter_label_uuid.py | 25 ++++++++++++++++ temba/msgs/models.py | 6 ++-- temba/msgs/views.py | 2 +- temba/utils/export.py | 4 +-- 11 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 temba/contacts/migrations/0168_alter_exportcontactstask_uuid.py create mode 100644 temba/flows/migrations/0295_alter_exportflowresultstask_uuid_and_more.py create mode 100644 temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py diff --git a/temba/api/v2/fields.py b/temba/api/v2/fields.py index 100fbd3684e..ba717a69faa 100644 --- a/temba/api/v2/fields.py +++ b/temba/api/v2/fields.py @@ -9,6 +9,7 @@ from temba.flows.models import Flow from temba.msgs.models import Label, Msg from temba.tickets.models import Ticket, Ticketer, Topic +from temba.utils.uuid import is_uuid # default maximum number of items in a posted list or dict DEFAULT_MAX_LIST_ITEMS = 100 @@ -154,8 +155,18 @@ def get_queryset(self): return manager.filter(**kwargs) def get_object(self, value): - query = Q() + # ignore lookup fields that can't be queryed with the given value + lookup_fields = [] for lookup_field in self.lookup_fields: + if lookup_field != "uuid" or is_uuid(value): + lookup_fields.append(lookup_field) + + # if we have no possible lookup fields left, there's no matching object + if not lookup_fields: + return None # pragma: no cover + + query = Q() + for lookup_field in lookup_fields: ignore_case = lookup_field in self.ignore_case_for_fields lookup = "%s__%s" % (lookup_field, "iexact" if ignore_case else "exact") query |= Q(**{lookup: value}) diff --git a/temba/api/v2/serializers.py b/temba/api/v2/serializers.py index 0103501e700..1e545213a3b 100644 --- a/temba/api/v2/serializers.py +++ b/temba/api/v2/serializers.py @@ -889,7 +889,7 @@ def get_type(self, obj): return self.FLOW_TYPES.get(obj.flow_type) def get_labels(self, obj): - return [{"uuid": lb.uuid, "name": lb.name} for lb in obj.labels.all()] + return [{"uuid": str(lb.uuid), "name": lb.name} for lb in obj.labels.all()] def get_runs(self, obj): stats = obj.get_run_stats() diff --git a/temba/api/v2/tests.py b/temba/api/v2/tests.py index 7572176e359..9bb6e19e7f1 100644 --- a/temba/api/v2/tests.py +++ b/temba/api/v2/tests.py @@ -2700,7 +2700,7 @@ def test_flows(self): "name": "Color Flow", "type": "message", "archived": False, - "labels": [{"uuid": reporting.uuid, "name": "Reporting"}], + "labels": [{"uuid": str(reporting.uuid), "name": "Reporting"}], "expires": 10080, "runs": {"active": 0, "completed": 1, "interrupted": 0, "expired": 0}, "results": [ @@ -3165,21 +3165,21 @@ def test_labels(self): self.assertEqual( resp_json["results"], [ - {"uuid": feedback.uuid, "name": "Feedback", "count": 0}, - {"uuid": important.uuid, "name": "Important", "count": 1}, + {"uuid": str(feedback.uuid), "name": "Feedback", "count": 0}, + {"uuid": str(important.uuid), "name": "Important", "count": 1}, ], ) # filter by UUID - response = self.fetchJSON(url, "uuid=%s" % feedback.uuid) - self.assertEqual(response.json()["results"], [{"uuid": feedback.uuid, "name": "Feedback", "count": 0}]) + response = self.fetchJSON(url, f"uuid={feedback.uuid}") + self.assertEqual(response.json()["results"], [{"uuid": str(feedback.uuid), "name": "Feedback", "count": 0}]) # filter by name response = self.fetchJSON(url, "name=important") self.assertResultsByUUID(response, [important]) # try to filter by both - response = self.fetchJSON(url, "uuid=%s&name=important" % important.uuid) + response = self.fetchJSON(url, f"uuid={important.uuid}&name=important") self.assertResponseError(response, None, "You may only specify one of the uuid, name parameters") # try to create empty label @@ -3191,7 +3191,7 @@ def test_labels(self): self.assertEqual(response.status_code, 201) interesting = Label.objects.get(name="Interesting") - self.assertEqual(response.json(), {"uuid": interesting.uuid, "name": "Interesting", "count": 0}) + self.assertEqual(response.json(), {"uuid": str(interesting.uuid), "name": "Interesting", "count": 0}) # try to create another label with same name response = self.postJSON(url, None, {"name": "interesting"}) @@ -3210,14 +3210,14 @@ def test_labels(self): self.assertResponseError(response, "name", "Ensure this field has no more than 64 characters.") # update label by UUID - response = self.postJSON(url, "uuid=%s" % interesting.uuid, {"name": "More Interesting"}) + response = self.postJSON(url, f"uuid={interesting.uuid}", {"name": "More Interesting"}) self.assertEqual(response.status_code, 200) interesting.refresh_from_db() self.assertEqual(interesting.name, "More Interesting") # can't update label from other org - response = self.postJSON(url, "uuid=%s" % spam.uuid, {"name": "Won't work"}) + response = self.postJSON(url, f"uuid={spam.uuid}", {"name": "Won't work"}) self.assert404(response) # try an empty delete request @@ -3225,7 +3225,7 @@ def test_labels(self): self.assertResponseError(response, None, "URL must contain one of the following parameters: uuid") # delete a label by UUID - response = self.deleteJSON(url, "uuid=%s" % interesting.uuid) + response = self.deleteJSON(url, f"uuid={interesting.uuid}") self.assertEqual(response.status_code, 204) interesting.refresh_from_db() @@ -3233,7 +3233,7 @@ def test_labels(self): self.assertFalse(interesting.is_active) # try to delete a label in another org - response = self.deleteJSON(url, "uuid=%s" % spam.uuid) + response = self.deleteJSON(url, f"uuid={spam.uuid}") self.assert404(response) # try creating a new label after reaching the limit on labels @@ -3259,7 +3259,7 @@ def assertMsgEqual(self, msg_json, msg, msg_type, msg_status, msg_visibility): "archived": msg.visibility == "A", "visibility": msg_visibility, "text": msg.text, - "labels": [{"name": lb.name, "uuid": lb.uuid} for lb in msg.labels.all()], + "labels": [{"uuid": str(lb.uuid), "name": lb.name} for lb in msg.labels.all()], "attachments": [{"content_type": a.content_type, "url": a.url} for a in msg.get_attachments()], "created_on": format_datetime(msg.created_on), "sent_on": format_datetime(msg.sent_on), @@ -3810,7 +3810,7 @@ def test_message_actions(self): self.assertEqual(set(label.get_messages()), {msg1, msg2}) # add label by its UUID to message 3 - response = self.postJSON(url, None, {"messages": [msg3.id], "action": "label", "label": label.uuid}) + response = self.postJSON(url, None, {"messages": [msg3.id], "action": "label", "label": str(label.uuid)}) self.assertEqual(response.status_code, 204) self.assertEqual(set(label.get_messages()), {msg1, msg2, msg3}) @@ -3824,7 +3824,9 @@ def test_message_actions(self): self.assertEqual(set(label.get_messages()), {msg1, msg3}) # and remove from messages 1 and 3 by UUID - response = self.postJSON(url, None, {"messages": [msg1.id, msg3.id], "action": "unlabel", "label": label.uuid}) + response = self.postJSON( + url, None, {"messages": [msg1.id, msg3.id], "action": "unlabel", "label": str(label.uuid)} + ) self.assertEqual(response.status_code, 204) self.assertEqual(set(label.get_messages()), set()) diff --git a/temba/api/v2/views.py b/temba/api/v2/views.py index 585363b3d6a..d5a98a1544b 100644 --- a/temba/api/v2/views.py +++ b/temba/api/v2/views.py @@ -2564,7 +2564,11 @@ def filter_queryset(self, queryset): # filter by label name/uuid (optional) label_ref = params.get("label") if label_ref: - label = Label.get_active_for_org(org).filter(Q(name=label_ref) | Q(uuid=label_ref)).first() + label_filter = Q(name=label_ref) + if is_uuid(label_ref): + label_filter |= Q(uuid=label_ref) + + label = Label.get_active_for_org(org).filter(label_filter).first() if label: queryset = queryset.filter(labels=label, visibility=Msg.VISIBILITY_VISIBLE) else: diff --git a/temba/contacts/migrations/0168_alter_exportcontactstask_uuid.py b/temba/contacts/migrations/0168_alter_exportcontactstask_uuid.py new file mode 100644 index 00000000000..58c2ec3fea3 --- /dev/null +++ b/temba/contacts/migrations/0168_alter_exportcontactstask_uuid.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.6 on 2022-08-03 16:53 + +from django.db import migrations, models + +import temba.utils.uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("contacts", "0167_alter_contactgroup_is_system"), + ] + + operations = [ + migrations.AlterField( + model_name="exportcontactstask", + name="uuid", + field=models.UUIDField(default=temba.utils.uuid.uuid4, unique=True), + ), + ] diff --git a/temba/flows/migrations/0295_alter_exportflowresultstask_uuid_and_more.py b/temba/flows/migrations/0295_alter_exportflowresultstask_uuid_and_more.py new file mode 100644 index 00000000000..bbd4a18c974 --- /dev/null +++ b/temba/flows/migrations/0295_alter_exportflowresultstask_uuid_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.6 on 2022-08-03 16:53 + +from django.db import migrations, models + +import temba.utils.uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("flows", "0294_flowrun_flows_run_inactive_has_exited_on_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="exportflowresultstask", + name="uuid", + field=models.UUIDField(default=temba.utils.uuid.uuid4, unique=True), + ), + migrations.AlterField( + model_name="flowlabel", + name="uuid", + field=models.UUIDField(default=temba.utils.uuid.uuid4, unique=True), + ), + ] diff --git a/temba/flows/models.py b/temba/flows/models.py index 807fbfad380..8e93780c549 100644 --- a/temba/flows/models.py +++ b/temba/flows/models.py @@ -2172,7 +2172,7 @@ def bulk_annotate(cls, starts): start.run_count = counts_by_start.get(start.id, 0) -class FlowLabel(LegacyUUIDMixin, TembaModel): +class FlowLabel(TembaModel): """ A label applied to a flow rather than a message """ diff --git a/temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py b/temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py new file mode 100644 index 00000000000..bbcef1d42ea --- /dev/null +++ b/temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.6 on 2022-08-03 16:53 + +from django.db import migrations, models + +import temba.utils.uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0181_remove_media_is_ready"), + ] + + operations = [ + migrations.AlterField( + model_name="exportmessagestask", + name="uuid", + field=models.UUIDField(default=temba.utils.uuid.uuid4, unique=True), + ), + migrations.AlterField( + model_name="label", + name="uuid", + field=models.UUIDField(default=temba.utils.uuid.uuid4, unique=True), + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index e13cd2c899e..647e9ba1592 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -29,7 +29,7 @@ from temba.schedules.models import Schedule from temba.utils import chunk_list, on_transaction_commit from temba.utils.export import BaseExportAssetStore, BaseExportTask -from temba.utils.models import JSONAsTextField, LegacyUUIDMixin, SquashableModel, TembaModel, TranslatableField +from temba.utils.models import JSONAsTextField, SquashableModel, TembaModel, TranslatableField from temba.utils.s3 import public_file_storage from temba.utils.text import clean_string from temba.utils.uuid import uuid4 @@ -580,7 +580,7 @@ def as_archive_json(self): "visibility": MsgReadSerializer.VISIBILITIES.get(self.visibility), "text": self.text, "attachments": [attachment.as_json() for attachment in Attachment.parse_all(self.attachments)], - "labels": [{"uuid": lb.uuid, "name": lb.name} for lb in self.labels.all()], + "labels": [{"uuid": str(lb.uuid), "name": lb.name} for lb in self.labels.all()], "created_on": self.created_on.isoformat(), "sent_on": self.sent_on.isoformat() if self.sent_on else None, } @@ -999,7 +999,7 @@ class Meta: index_together = ("org", "label_type") -class Label(LegacyUUIDMixin, TembaModel, DependencyMixin): +class Label(TembaModel, DependencyMixin): """ Labels represent both user defined labels and folders of labels. User defined labels that can be applied to messages much the same way labels or tags apply to messages in web-based email services. diff --git a/temba/msgs/views.py b/temba/msgs/views.py index e2910982cd3..ae0529ba145 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -902,7 +902,7 @@ def derive_queryset(self, **kwargs): return Label.get_active_for_org(self.request.org).exclude(label_type=Label.TYPE_FOLDER) def render_to_response(self, context, **response_kwargs): - results = [{"id": lb.uuid, "text": lb.name} for lb in context["object_list"]] + results = [{"id": str(lb.uuid), "text": lb.name} for lb in context["object_list"]] return HttpResponse(json.dumps(results), content_type="application/json") class Create(ModalMixin, OrgPermsMixin, SmartCreateView): diff --git a/temba/utils/export.py b/temba/utils/export.py index 19a84204672..ba1a51e3009 100644 --- a/temba/utils/export.py +++ b/temba/utils/export.py @@ -17,7 +17,7 @@ from temba.assets.models import BaseAssetStore, get_asset_store from . import analytics -from .models import LegacyUUIDMixin +from .models import TembaUUIDMixin from .text import clean_string logger = logging.getLogger(__name__) @@ -28,7 +28,7 @@ def is_asset_ready(self, asset): return asset.status == BaseExportTask.STATUS_COMPLETE -class BaseExportTask(LegacyUUIDMixin, SmartModel): +class BaseExportTask(TembaUUIDMixin, SmartModel): """ Base class for export task models, i.e. contacts, messages and flow results """ From 4540a15aab2c32be5b347182bb8f768a80ca7539 Mon Sep 17 00:00:00 2001 From: Roberta Moreira <30378788+Robi9@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:43:32 -0300 Subject: [PATCH 096/630] Slack channel fixes (#337) * Fix alphabetical order of schemes * Fix config page text --- temba/contacts/models.py | 2 +- templates/channels/types/slack/config.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/temba/contacts/models.py b/temba/contacts/models.py index 5bd9fa83051..7d23d60803b 100644 --- a/temba/contacts/models.py +++ b/temba/contacts/models.py @@ -84,6 +84,7 @@ class URN: (JIOCHAT_SCHEME, _("JioChat Identifier")), (LINE_SCHEME, _("LINE Identifier")), (ROCKETCHAT_SCHEME, _("RocketChat Identifier")), + (SLACK_SCHEME, _("Slack Identifier")), (TELEGRAM_SCHEME, _("Telegram Identifier")), (TWITTERID_SCHEME, _("Twitter ID")), (TWITTER_SCHEME, _("Twitter Handle")), @@ -92,7 +93,6 @@ class URN: (WECHAT_SCHEME, _("WeChat Identifier")), (WEBCHAT_SCHEME, _("Webchat Identifier")), (WHATSAPP_SCHEME, _("WhatsApp Identifier")), - (SLACK_SCHEME, _("Slack Identifier")), ) VALID_SCHEMES = {s[0] for s in SCHEME_CHOICES} diff --git a/templates/channels/types/slack/config.haml b/templates/channels/types/slack/config.haml index 599b08779b3..d43314ae762 100644 --- a/templates/channels/types/slack/config.haml +++ b/templates/channels/types/slack/config.haml @@ -43,4 +43,4 @@ From left side menu Features, access App Home, in "Show Tabs" card section, turn on "Messages Tab". %li -blocktrans trimmed - When Messages Tab is activated, will appear a checkbox, so check it to (Allow users to send Slash commands and messages from the messages tab). + When the Messages Tab is activated a checkbox will appear, check it to allow users to send Slash commands and messages. From 0e0eda1d39490f827e15589486392e488647c20b Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 5 Aug 2022 11:12:07 -0500 Subject: [PATCH 097/630] Improve cleaning of media filenames --- temba/msgs/models.py | 32 ++++++++++++++++++-------------- temba/msgs/tests.py | 4 ++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/temba/msgs/models.py b/temba/msgs/models.py index e13cd2c899e..929d40597c9 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -91,6 +91,16 @@ def get_storage_path(cls, org, uuid, filename): """ return f"{settings.STORAGE_ROOT_DIR}/{org.id}/media/{str(uuid)[0:4]}/{uuid}/{filename}" + @classmethod + def clean_name(cls, filename: str, content_type: str) -> str: + base_name, extension = os.path.splitext(filename) + base_name = re.sub(r"[^\w\-\[\]\(\) ]", "", base_name).strip()[:255] or "file" + + if not extension or not extension.isalnum(): + extension = mimetypes.guess_extension(content_type) or ".bin" + + return base_name + extension + @classmethod def from_upload(cls, org, user, file, process=True): """ @@ -101,19 +111,13 @@ def from_upload(cls, org, user, file, process=True): assert cls.is_allowed_type(file.content_type), "unsupported content type" - base_name, extension = os.path.splitext(file.name) - - # cleanup file name - base_name = re.sub(r"[^a-zA-Z0-9_ ]", "", base_name).strip()[:255] or "file" - - if not extension: - extension = mimetypes.guess_extension(file.content_type) or ".bin" + filename = cls.clean_name(file.name, file.content_type) # browsers might send m4a files but correct MIME type is audio/mp4 - if extension == ".m4a": + if filename.endswith(".m4a"): file.content_type = "audio/mp4" - media = cls._create(org, user, base_name + extension, file.content_type, file) + media = cls._create(org, user, filename, file.content_type, file) if process: on_transaction_commit(lambda: process_media_upload.delay(media.id)) @@ -121,7 +125,7 @@ def from_upload(cls, org, user, file, process=True): return media @classmethod - def create_alternate(cls, original, name: str, content_type: str, file, **kwargs): + def create_alternate(cls, original, filename: str, content_type: str, file, **kwargs): """ Creates a new alternate media instance for the given original. """ @@ -129,7 +133,7 @@ def create_alternate(cls, original, name: str, content_type: str, file, **kwargs return cls._create( original.org, original.created_by, - name, + filename, content_type, file, original=original, @@ -138,9 +142,9 @@ def create_alternate(cls, original, name: str, content_type: str, file, **kwargs ) @classmethod - def _create(cls, org, user, name: str, content_type: str, file, **kwargs): + def _create(cls, org, user, filename: str, content_type: str, file, **kwargs): uuid = uuid4() - path = cls.get_storage_path(org, uuid, name) + path = cls.get_storage_path(org, uuid, filename) path = public_file_storage.save(path, file) size = public_file_storage.size(path) @@ -148,7 +152,7 @@ def _create(cls, org, user, name: str, content_type: str, file, **kwargs): uuid=uuid, org=org, url=public_file_storage.url(path), - name=name, + name=filename, content_type=content_type, path=path, size=size, diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 24c4f8698b8..46d8eaa6f02 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -39,6 +39,10 @@ def tearDown(self): return super().tearDown() + def test_clean_name(self): + self.assertEqual("file.jpg", Media.clean_name("", "image/jpeg")) + self.assertEqual("tést[0].jpg", Media.clean_name("tést[0]/^..\\", "image/jpeg")) + @mock_uuids def test_from_upload(self): media = Media.from_upload( From 4fcf7e838d014e65c22620194891396f31475564 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Fri, 5 Aug 2022 11:23:34 -0500 Subject: [PATCH 098/630] Deprecate Media.name which can always be inferred from .path --- temba/msgs/media.py | 4 ++-- temba/msgs/migrations/0182_alter_media_name.py | 18 ++++++++++++++++++ temba/msgs/models.py | 10 ++++++++-- temba/msgs/tests.py | 3 +++ temba/msgs/views.py | 2 +- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 temba/msgs/migrations/0182_alter_media_name.py diff --git a/temba/msgs/media.py b/temba/msgs/media.py index ca7383e2a08..d6789725f68 100644 --- a/temba/msgs/media.py +++ b/temba/msgs/media.py @@ -94,12 +94,12 @@ def _create_alternate(original: Media, file, transform, new_content_type: str, n Creates a new media instance by transforming an original with an ffmpeg pipeline """ - new_name = _change_extension(original.name, new_extension) + filename = _change_extension(original.filename, new_extension) with NamedTemporaryFile(suffix="." + new_extension, delete=True) as temp: transform(file.name, temp.name) - return Media.create_alternate(original, new_name, new_content_type, temp, **kwargs) + return Media.create_alternate(original, filename, new_content_type, temp, **kwargs) def _get_stream_info(filename: str, stream_id: str) -> dict: diff --git a/temba/msgs/migrations/0182_alter_media_name.py b/temba/msgs/migrations/0182_alter_media_name.py new file mode 100644 index 00000000000..d211f634757 --- /dev/null +++ b/temba/msgs/migrations/0182_alter_media_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2022-08-05 16:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("msgs", "0181_remove_media_is_ready"), + ] + + operations = [ + migrations.AlterField( + model_name="media", + name="name", + field=models.CharField(max_length=255, null=True), + ), + ] diff --git a/temba/msgs/models.py b/temba/msgs/models.py index 929d40597c9..922e283f2b5 100644 --- a/temba/msgs/models.py +++ b/temba/msgs/models.py @@ -61,7 +61,6 @@ class Media(models.Model): uuid = models.UUIDField(default=uuid4, db_index=True, unique=True) org = models.ForeignKey(Org, on_delete=models.PROTECT) url = models.URLField(max_length=2048) - name = models.CharField(max_length=255) # filename including extension content_type = models.CharField(max_length=255) path = models.CharField(max_length=2048) size = models.IntegerField(default=0) # bytes @@ -76,6 +75,9 @@ class Media(models.Model): created_by = models.ForeignKey(User, on_delete=models.PROTECT) created_on = models.DateTimeField(default=timezone.now) + # TODO remove + name = models.CharField(max_length=255, null=True) + @classmethod def is_allowed_type(cls, content_type: str) -> bool: for allowed_type in cls.ALLOWED_CONTENT_TYPES: @@ -96,7 +98,7 @@ def clean_name(cls, filename: str, content_type: str) -> str: base_name, extension = os.path.splitext(filename) base_name = re.sub(r"[^\w\-\[\]\(\) ]", "", base_name).strip()[:255] or "file" - if not extension or not extension.isalnum(): + if not extension or len(extension) < 2 or not extension[1:].isalnum(): extension = mimetypes.guess_extension(content_type) or ".bin" return base_name + extension @@ -160,6 +162,10 @@ def _create(cls, org, user, filename: str, content_type: str, file, **kwargs): **kwargs, ) + @property + def filename(self) -> str: + return os.path.basename(self.path) + def process_upload(self): from .media import process_upload diff --git a/temba/msgs/tests.py b/temba/msgs/tests.py index 46d8eaa6f02..81358a6601b 100644 --- a/temba/msgs/tests.py +++ b/temba/msgs/tests.py @@ -41,6 +41,9 @@ def tearDown(self): def test_clean_name(self): self.assertEqual("file.jpg", Media.clean_name("", "image/jpeg")) + self.assertEqual("foo.jpg", Media.clean_name("foo", "image/jpeg")) + self.assertEqual("file.png", Media.clean_name("*.png", "image/png")) + self.assertEqual("passwd.jpg", Media.clean_name(".passwd", "image/jpeg")) self.assertEqual("tést[0].jpg", Media.clean_name("tést[0]/^..\\", "image/jpeg")) @mock_uuids diff --git a/temba/msgs/views.py b/temba/msgs/views.py index 1d24c77fab8..ca5fce232ac 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -1005,7 +1005,7 @@ def post(self, request, *args, **kwargs): "content_type": media.content_type, "type": media.content_type, # deprecated "url": media.url, - "name": media.name, + "name": media.filename, "size": media.size, } ) From 8cc45544562083df04043c4591018b068604cd28 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Mon, 8 Aug 2022 13:09:18 +0700 Subject: [PATCH 099/630] removed block subtitle from org manage accounts template --- templates/orgs/org_manage_accounts.haml | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/orgs/org_manage_accounts.haml b/templates/orgs/org_manage_accounts.haml index 30768093486..3778ce9f608 100644 --- a/templates/orgs/org_manage_accounts.haml +++ b/templates/orgs/org_manage_accounts.haml @@ -7,9 +7,6 @@ -else {{user_org.name|capfirst}} --block subtitle - -trans "Manage Logins" - -block extra-style {{block.super}} :css From c5a66060456b109506358f7a7724a91b8dedef0d Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Mon, 8 Aug 2022 12:20:01 +0200 Subject: [PATCH 100/630] Require the instagram_basic permission as we need the channel address as IG ID for matching incoming messages --- temba/channels/types/instagram/views.py | 2 ++ templates/channels/types/instagram/claim.haml | 2 +- templates/channels/types/instagram/refresh_token.haml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/temba/channels/types/instagram/views.py b/temba/channels/types/instagram/views.py index ccd8438c985..827f169af1c 100644 --- a/temba/channels/types/instagram/views.py +++ b/temba/channels/types/instagram/views.py @@ -108,6 +108,8 @@ def clean(self): self.cleaned_data["page_access_token"] = page_access_token self.cleaned_data["name"] = name + # requires instagram_basic permission + # https://developers.facebook.com/docs/instagram-api/reference/page#read url = f"https://graph.facebook.com/{page_id}?fields=instagram_business_account" params = {"access_token": page_access_token} diff --git a/templates/channels/types/instagram/claim.haml b/templates/channels/types/instagram/claim.haml index 7a445e059fc..70debf298bb 100644 --- a/templates/channels/types/instagram/claim.haml +++ b/templates/channels/types/instagram/claim.haml @@ -76,7 +76,7 @@ :javascript $(document).ready(function(){ $(".connect-facebook").click(function(evt){ - location.replace("https://www.facebook.com/v12.0/dialog/oauth?client_id={{ facebook_app_id }}&redirect_uri=" + window.location.origin + window.location.pathname + "&scope=instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list&response_type=token") + location.replace("https://www.facebook.com/v12.0/dialog/oauth?client_id={{ facebook_app_id }}&redirect_uri=" + window.location.origin + window.location.pathname + "&scope=instagram_basic,instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list&response_type=token") }); var hash = window.location.hash.substring(1) diff --git a/templates/channels/types/instagram/refresh_token.haml b/templates/channels/types/instagram/refresh_token.haml index 161a6818aaa..1e875b3beed 100644 --- a/templates/channels/types/instagram/refresh_token.haml +++ b/templates/channels/types/instagram/refresh_token.haml @@ -52,7 +52,7 @@ } }, - {scope: 'instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list'}); + {scope: 'instagram_basic,instagram_manage_messages,pages_manage_metadata,pages_messaging,pages_read_engagement,pages_show_list'}); }) }); \ No newline at end of file From 83fe6ae7c7f362159a3ec43a9203ad87a81e7dec Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Mon, 8 Aug 2022 14:42:27 +0200 Subject: [PATCH 101/630] Make sure to use the user token for getting the instagram user ID --- temba/channels/types/instagram/tests.py | 2 +- temba/channels/types/instagram/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/temba/channels/types/instagram/tests.py b/temba/channels/types/instagram/tests.py index d2bbdfd7618..667b65c59c6 100644 --- a/temba/channels/types/instagram/tests.py +++ b/temba/channels/types/instagram/tests.py @@ -116,7 +116,7 @@ def test_claim(self, mock_get, mock_post): mock_get.assert_any_call( "https://graph.facebook.com/123456?fields=instagram_business_account", params={ - "access_token": self.long_life_page_token, + "access_token": f"long-life-user-{self.token}", }, ) diff --git a/temba/channels/types/instagram/views.py b/temba/channels/types/instagram/views.py index 827f169af1c..965c2c6123e 100644 --- a/temba/channels/types/instagram/views.py +++ b/temba/channels/types/instagram/views.py @@ -111,7 +111,7 @@ def clean(self): # requires instagram_basic permission # https://developers.facebook.com/docs/instagram-api/reference/page#read url = f"https://graph.facebook.com/{page_id}?fields=instagram_business_account" - params = {"access_token": page_access_token} + params = {"access_token": auth_token} response = requests.get(url, params=params) From 1c690bb0acd67feccf8d54c726248e57e53dba86 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 11:22:04 -0500 Subject: [PATCH 102/630] Fix migration conflict --- ...y => 0183_alter_exportmessagestask_uuid_alter_label_uuid.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename temba/msgs/migrations/{0182_alter_exportmessagestask_uuid_alter_label_uuid.py => 0183_alter_exportmessagestask_uuid_alter_label_uuid.py} (92%) diff --git a/temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py b/temba/msgs/migrations/0183_alter_exportmessagestask_uuid_alter_label_uuid.py similarity index 92% rename from temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py rename to temba/msgs/migrations/0183_alter_exportmessagestask_uuid_alter_label_uuid.py index bbcef1d42ea..5a0bd15c10c 100644 --- a/temba/msgs/migrations/0182_alter_exportmessagestask_uuid_alter_label_uuid.py +++ b/temba/msgs/migrations/0183_alter_exportmessagestask_uuid_alter_label_uuid.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ - ("msgs", "0181_remove_media_is_ready"), + ("msgs", "0182_alter_media_name"), ] operations = [ From 93e7e1688d75771f2417a499b5558d868ef3675c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 11:54:53 -0500 Subject: [PATCH 103/630] Update CHANGELOG.md for v7.5.14 --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b66ad8a7cd..91148bc7735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v7.5.14 +---------- + * Deprecate Media.name which can always be inferred from .path + * Improve cleaning of media filenames + * Convert legacy UUID fields on exports and labels + * Request instagram_basic permission for IG channels + v7.5.11 ---------- * Don't allow creating of labels with parents or editing labels to have a parent diff --git a/pyproject.toml b/pyproject.toml index 2cb6dd8c192..9089fba6fb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.11" +version = "7.5.14" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 41abe6a60e0dbb6c6bc21a6223d15be24a91d4e4 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 17:37:30 -0500 Subject: [PATCH 104/630] Fix URL for media uploads which was previously conflicting with media directory --- temba/msgs/views.py | 1 + templates/flows/flow_editor.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/temba/msgs/views.py b/temba/msgs/views.py index 126f17b8780..05545fe0658 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -985,6 +985,7 @@ def post(self, request, *args, **kwargs): class MediaCRUDL(SmartCRUDL): model = Media + path = "msgmedia" # so we don't conflict with the /media directory actions = ("upload", "list") class Upload(OrgPermsMixin, SmartCreateView): diff --git a/templates/flows/flow_editor.haml b/templates/flows/flow_editor.haml index 6b6d8a23628..8e5871c2406 100644 --- a/templates/flows/flow_editor.haml +++ b/templates/flows/flow_editor.haml @@ -259,7 +259,7 @@ // TODO: migrate to API? revisions: '/flow/revisions/{{object.uuid}}/', recents: '/flow/recent_contacts/{{object.uuid}}/', - attachments: '/media/upload/', + attachments: '{% url "msgs.media_upload" %}', languages: base + 'language', environment: base + 'environment', activity: '/flow/activity/{{object.uuid}}/', From 134a3743a32eac11bae564c65e8b9ccf63bbc2a3 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Mon, 8 Aug 2022 18:02:12 -0500 Subject: [PATCH 105/630] Update CHANGELOG.md for v7.5.15 --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91148bc7735..4f1fb100347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v7.5.15 +---------- + * Fix URL for media uploads which was previously conflicting with media directory + v7.5.14 ---------- * Deprecate Media.name which can always be inferred from .path diff --git a/pyproject.toml b/pyproject.toml index 9089fba6fb2..3f6689016a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.14" +version = "7.5.15" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 8e6592852f81887c74754d7ca84ca5e85662d1cd Mon Sep 17 00:00:00 2001 From: susanm74 Date: Tue, 9 Aug 2022 12:59:03 +0700 Subject: [PATCH 106/630] added 'authentication' to the temba anchor URL text --- templates/orgs/user_account.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/orgs/user_account.haml b/templates/orgs/user_account.haml index 67287b89e2b..75805b8c581 100644 --- a/templates/orgs/user_account.haml +++ b/templates/orgs/user_account.haml @@ -37,7 +37,7 @@ %temba-alert.mb-4(level="info") {% url "orgs.user_two_factor_enable" as otp_url %} -blocktrans with brand=brand.name - {{brand}} recommends that you enable two factor authentication. + {{brand}} recommends that you enable two factor authentication. -include "formax.haml" From 014405063eb4ee3b959a78c6126e17e3e31796b6 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 9 Aug 2022 16:28:56 +0200 Subject: [PATCH 107/630] Validate channel name is not more than 64 characters --- temba/channels/types/facebookapp/tests.py | 8 +++++++- temba/channels/types/facebookapp/views.py | 2 +- temba/channels/types/freshchat/tests.py | 5 +++++ temba/channels/types/freshchat/views.py | 5 ++++- temba/channels/types/instagram/tests.py | 8 +++++++- temba/channels/types/instagram/views.py | 2 +- temba/channels/types/line/tests.py | 5 +++++ temba/channels/types/line/views.py | 2 +- temba/channels/types/vk/tests.py | 12 ++++++++++++ temba/channels/types/vk/views.py | 2 +- 10 files changed, 44 insertions(+), 7 deletions(-) diff --git a/temba/channels/types/facebookapp/tests.py b/temba/channels/types/facebookapp/tests.py index fb2aa44806b..f3b55e070ec 100644 --- a/temba/channels/types/facebookapp/tests.py +++ b/temba/channels/types/facebookapp/tests.py @@ -59,8 +59,14 @@ def test_claim(self, mock_get, mock_post): post_data = response.context["form"].initial post_data["user_access_token"] = token post_data["page_id"] = "123456" - post_data["page_name"] = "Temba" + post_data["page_name"] = "Temba" * 20 + response = self.client.post(url, post_data, follow=True) + self.assertFormError( + response, "form", "page_name", "Ensure this value has at most 64 characters (it has 100)." + ) + + post_data["page_name"] = "Temba" response = self.client.post(url, post_data, follow=True) # assert our channel got created diff --git a/temba/channels/types/facebookapp/views.py b/temba/channels/types/facebookapp/views.py index 00e30cec0e4..fa43310f20c 100644 --- a/temba/channels/types/facebookapp/views.py +++ b/temba/channels/types/facebookapp/views.py @@ -15,7 +15,7 @@ class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): user_access_token = forms.CharField(min_length=32, required=True, help_text=_("The User Access Token")) - page_name = forms.CharField(required=True, help_text=_("The name of the Facebook page")) + page_name = forms.CharField(required=True, max_length=64, help_text=_("The name of the Facebook page")) page_id = forms.IntegerField(required=True, help_text="The Facebook Page ID") def clean(self): diff --git a/temba/channels/types/freshchat/tests.py b/temba/channels/types/freshchat/tests.py index 87b34c1ebf0..20e6fa3b8da 100644 --- a/temba/channels/types/freshchat/tests.py +++ b/temba/channels/types/freshchat/tests.py @@ -42,6 +42,11 @@ def test_claim(self): post_data["webhook_key"] = "-----BEGIN RSA PUBLIC KEY----- MIIBIDAQAB -----END RSA PUBLIC KEY-----" post_data["auth_token"] = "eyJVTI0LTm5WZ2Ut" post_data["agent_id"] = "c0534f78-b6e9-4f79-8853-11cedfc1f35b" + post_data["title"] = "FreshChat" * 20 + + response = self.client.post(url, post_data, follow=True) + self.assertFormError(response, "form", "title", "Ensure this value has at most 64 characters (it has 180).") + post_data["title"] = "FreshChat" response = self.client.post(url, post_data, follow=True) diff --git a/temba/channels/types/freshchat/views.py b/temba/channels/types/freshchat/views.py index 13539a9768e..ab4cc61c137 100644 --- a/temba/channels/types/freshchat/views.py +++ b/temba/channels/types/freshchat/views.py @@ -10,7 +10,10 @@ class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): title = forms.CharField( - required=True, label=_("FreshChat Environment Title"), help_text=_("The name of your environment") + max_length=64, + required=True, + label=_("FreshChat Environment Title"), + help_text=_("The name of your environment"), ) webhook_key = forms.CharField( diff --git a/temba/channels/types/instagram/tests.py b/temba/channels/types/instagram/tests.py index 667b65c59c6..adf1ce5fc41 100644 --- a/temba/channels/types/instagram/tests.py +++ b/temba/channels/types/instagram/tests.py @@ -73,8 +73,14 @@ def test_claim(self, mock_get, mock_post): post_data = response.context["form"].initial post_data["user_access_token"] = self.token post_data["page_id"] = "123456" - post_data["page_name"] = "Temba" + post_data["page_name"] = "Temba" * 20 + response = self.client.post(url, post_data, follow=True) + self.assertFormError( + response, "form", "page_name", "Ensure this value has at most 64 characters (it has 100)." + ) + + post_data["page_name"] = "Temba" response = self.client.post(url, post_data, follow=True) # assert our channel got created diff --git a/temba/channels/types/instagram/views.py b/temba/channels/types/instagram/views.py index 965c2c6123e..37c9a9ee0f3 100644 --- a/temba/channels/types/instagram/views.py +++ b/temba/channels/types/instagram/views.py @@ -20,7 +20,7 @@ class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): user_access_token = forms.CharField(min_length=32, required=True, help_text=_("The User Access Token")) - page_name = forms.CharField(required=True, help_text=_("The name of the Facebook page")) + page_name = forms.CharField(required=True, max_length=64, help_text=_("The name of the Facebook page")) page_id = forms.IntegerField(required=True, help_text="The Facebook Page ID") def clean(self): diff --git a/temba/channels/types/line/tests.py b/temba/channels/types/line/tests.py index de2b74870fd..40996c3dda5 100644 --- a/temba/channels/types/line/tests.py +++ b/temba/channels/types/line/tests.py @@ -30,6 +30,11 @@ def test_claim(self): response = self.client.get(reverse("channels.channel_claim")) self.assertContains(response, url) + payload = {"access_token": "abcdef123456", "secret": "123456", "channel_id": "123456789", "name": "Temba" * 20} + + response = self.client.post(url, payload, follow=True) + self.assertFormError(response, "form", "name", "Ensure this value has at most 64 characters (it has 100).") + payload = {"access_token": "abcdef123456", "secret": "123456", "channel_id": "123456789", "name": "Temba"} response = self.client.post(url, payload, follow=True) diff --git a/temba/channels/types/line/views.py b/temba/channels/types/line/views.py index ffce9f3ab79..92986819af6 100644 --- a/temba/channels/types/line/views.py +++ b/temba/channels/types/line/views.py @@ -14,7 +14,7 @@ class Form(ClaimViewMixin.Form): channel_id = forms.CharField( label=_("Channel ID"), required=True, help_text=_("The Channel ID of the LINE channel for the Bot") ) - name = forms.CharField(label=_("Name"), required=True, help_text=_("The Name of the Bot")) + name = forms.CharField(label=_("Name"), max_length=64, required=True, help_text=_("The Name of the Bot")) access_token = forms.CharField( label=_("Access Token"), required=True, help_text=_("The Access Token of the LINE Bot") ) diff --git a/temba/channels/types/vk/tests.py b/temba/channels/types/vk/tests.py index b515db4fdd2..c8305de1c7f 100644 --- a/temba/channels/types/vk/tests.py +++ b/temba/channels/types/vk/tests.py @@ -36,6 +36,18 @@ def test_claim(self): token = "x" * 200 + data = { + "community_access_token": token, + "community_id": "123456", + "community_name": "Temba" * 20, + "callback_verification_string": "123456", + } + + response = self.client.post(url, data, follow=True) + self.assertFormError( + response, "form", "community_name", "Ensure this value has at most 64 characters (it has 100)." + ) + data = { "community_access_token": token, "community_id": "123456", diff --git a/temba/channels/types/vk/views.py b/temba/channels/types/vk/views.py index 3215dfc656e..7fcca0689fc 100644 --- a/temba/channels/types/vk/views.py +++ b/temba/channels/types/vk/views.py @@ -12,7 +12,7 @@ class Form(ClaimViewMixin.Form): community_access_token = forms.CharField( min_length=32, required=True, help_text=_("The Community Access Token") ) - community_name = forms.CharField(required=True, help_text=_("The name of the Community")) + community_name = forms.CharField(required=True, max_length=64, help_text=_("The name of the Community")) community_id = forms.IntegerField(required=True, help_text=_("The Community ID")) callback_verification_string = forms.CharField(required=True, help_text=_("The callback verification string")) From 4ae995f8872ea4728f4e0f5f0b4bee935d147c59 Mon Sep 17 00:00:00 2001 From: Norbert Kwizera Date: Tue, 9 Aug 2022 16:57:23 +0200 Subject: [PATCH 108/630] Truncate channel name to not exceed field limit --- temba/channels/types/facebookapp/tests.py | 56 ++++++++++++++++--- temba/channels/types/facebookapp/views.py | 5 +- temba/channels/types/instagram/tests.py | 68 ++++++++++++++++++++--- temba/channels/types/instagram/views.py | 5 +- 4 files changed, 116 insertions(+), 18 deletions(-) diff --git a/temba/channels/types/facebookapp/tests.py b/temba/channels/types/facebookapp/tests.py index f3b55e070ec..c3ad51abfe0 100644 --- a/temba/channels/types/facebookapp/tests.py +++ b/temba/channels/types/facebookapp/tests.py @@ -6,6 +6,7 @@ from temba.tests import MockResponse, TembaTest from temba.triggers.models import Trigger from temba.utils import json +from temba.utils.text import truncate from ...models import Channel @@ -59,14 +60,8 @@ def test_claim(self, mock_get, mock_post): post_data = response.context["form"].initial post_data["user_access_token"] = token post_data["page_id"] = "123456" - post_data["page_name"] = "Temba" * 20 - - response = self.client.post(url, post_data, follow=True) - self.assertFormError( - response, "form", "page_name", "Ensure this value has at most 64 characters (it has 100)." - ) - post_data["page_name"] = "Temba" + response = self.client.post(url, post_data, follow=True) # assert our channel got created @@ -125,6 +120,53 @@ def test_claim(self, mock_get, mock_post): "Sorry your Facebook channel could not be connected. Please try again", ) + @override_settings(FACEBOOK_APPLICATION_ID="FB_APP_ID", FACEBOOK_APPLICATION_SECRET="FB_APP_SECRET") + @patch("requests.post") + @patch("requests.get") + def test_claim_long_name(self, mock_get, mock_post): + token = "x" * 200 + long_name = "Temba" * 20 + + truncated_name = truncate(long_name, 64) + + mock_get.side_effect = [ + MockResponse(200, json.dumps({"data": {"user_id": "098765", "expired_at": 100}})), + MockResponse(200, json.dumps({"access_token": f"long-life-user-{token}"})), + MockResponse( + 200, + json.dumps({"data": [{"name": long_name, "id": "123456", "access_token": f"page-long-life-{token}"}]}), + ), + ] + + mock_post.return_value = MockResponse(200, json.dumps({"success": True})) + + url = reverse("channels.types.facebookapp.claim") + + self.login(self.admin) + + # check that claim page URL appears on claim list page + response = self.client.get(reverse("channels.channel_claim")) + self.assertContains(response, url) + + # can fetch the claim page + response = self.client.get(url) + self.assertContains(response, "Connect Facebook") + self.assertEqual(response.context["facebook_app_id"], "FB_APP_ID") + self.assertEqual(response.context["claim_url"], url) + + post_data = response.context["form"].initial + post_data["user_access_token"] = token + post_data["page_id"] = "123456" + post_data["page_name"] = long_name + + response = self.client.post(url, post_data, follow=True) + + # assert our channel got created + channel = Channel.objects.get(address="123456", channel_type="FBA") + self.assertEqual(channel.config[Channel.CONFIG_AUTH_TOKEN], f"page-long-life-{token}") + self.assertEqual(channel.config[Channel.CONFIG_PAGE_NAME], truncated_name) + self.assertEqual(channel.address, "123456") + @patch("requests.delete") def test_release(self, mock_delete): mock_delete.return_value = MockResponse(200, json.dumps({"success": True})) diff --git a/temba/channels/types/facebookapp/views.py b/temba/channels/types/facebookapp/views.py index fa43310f20c..99a5ec24c4c 100644 --- a/temba/channels/types/facebookapp/views.py +++ b/temba/channels/types/facebookapp/views.py @@ -7,6 +7,7 @@ from django.utils.translation import gettext_lazy as _ from temba.orgs.views import ModalMixin, OrgObjPermsMixin +from temba.utils.text import truncate from ...models import Channel from ...views import ClaimViewMixin @@ -15,7 +16,7 @@ class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): user_access_token = forms.CharField(min_length=32, required=True, help_text=_("The User Access Token")) - page_name = forms.CharField(required=True, max_length=64, help_text=_("The name of the Facebook page")) + page_name = forms.CharField(required=True, help_text=_("The name of the Facebook page")) page_id = forms.IntegerField(required=True, help_text="The Facebook Page ID") def clean(self): @@ -92,7 +93,7 @@ def clean(self): raise Exception("Failed to subscribe to app for webhook events") self.cleaned_data["page_access_token"] = page_access_token - self.cleaned_data["name"] = name + self.cleaned_data["name"] = truncate(name, Channel._meta.get_field("name").max_length) except Exception: raise forms.ValidationError( diff --git a/temba/channels/types/instagram/tests.py b/temba/channels/types/instagram/tests.py index adf1ce5fc41..5591f23e311 100644 --- a/temba/channels/types/instagram/tests.py +++ b/temba/channels/types/instagram/tests.py @@ -5,6 +5,7 @@ from temba.tests import MockResponse, TembaTest from temba.utils import json +from temba.utils.text import truncate from ...models import Channel @@ -73,14 +74,8 @@ def test_claim(self, mock_get, mock_post): post_data = response.context["form"].initial post_data["user_access_token"] = self.token post_data["page_id"] = "123456" - post_data["page_name"] = "Temba" * 20 - - response = self.client.post(url, post_data, follow=True) - self.assertFormError( - response, "form", "page_name", "Ensure this value has at most 64 characters (it has 100)." - ) - post_data["page_name"] = "Temba" + response = self.client.post(url, post_data, follow=True) # assert our channel got created @@ -147,6 +142,65 @@ def test_claim(self, mock_get, mock_post): "Sorry your Instagram channel could not be connected. Please try again", ) + @override_settings(FACEBOOK_APPLICATION_ID="FB_APP_ID", FACEBOOK_APPLICATION_SECRET="FB_APP_SECRET") + @patch("requests.post") + @patch("requests.get") + def test_claim_long_name(self, mock_get, mock_post): + long_name = "Temba" * 20 + truncated_name = truncate(long_name, 64) + + mock_get.side_effect = [ + MockResponse(200, json.dumps({"data": {"user_id": "098765", "expired_at": 100}})), + MockResponse(200, json.dumps({"access_token": f"long-life-user-{self.token}"})), + MockResponse( + 200, + json.dumps( + { + "data": [ + { + "name": long_name, + "id": "123456", + "access_token": self.long_life_page_token, + } + ] + } + ), + ), + MockResponse( + 200, + json.dumps({"instagram_business_account": {"id": "1234567"}, "id": "998776"}), + ), + ] + + mock_post.return_value = MockResponse(200, json.dumps({"success": True})) + + url = reverse("channels.types.instagram.claim") + + self.login(self.admin) + + # check that claim page URL appears on claim list page + response = self.client.get(reverse("channels.channel_claim")) + self.assertContains(response, url) + + # can fetch the claim page + response = self.client.get(url) + self.assertContains(response, "Connect Instagram") + self.assertEqual(response.context["facebook_app_id"], "FB_APP_ID") + self.assertEqual(response.context["claim_url"], url) + + post_data = response.context["form"].initial + post_data["user_access_token"] = self.token + post_data["page_id"] = "123456" + post_data["page_name"] = long_name + + response = self.client.post(url, post_data, follow=True) + + # assert our channel got created + channel = Channel.objects.get(address="1234567", channel_type="IG") # address is ig user + self.assertEqual(channel.config[Channel.CONFIG_AUTH_TOKEN], self.long_life_page_token) + self.assertEqual(channel.config[Channel.CONFIG_PAGE_NAME], truncated_name) + self.assertEqual(channel.address, "1234567") + @patch("requests.delete") def test_release(self, mock_delete): mock_delete.return_value = MockResponse(200, json.dumps({"success": True})) diff --git a/temba/channels/types/instagram/views.py b/temba/channels/types/instagram/views.py index 37c9a9ee0f3..d0a67a7b979 100644 --- a/temba/channels/types/instagram/views.py +++ b/temba/channels/types/instagram/views.py @@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _ from temba.orgs.views import ModalMixin, OrgObjPermsMixin +from temba.utils.text import truncate from ...models import Channel from ...views import ClaimViewMixin @@ -20,7 +21,7 @@ class ClaimView(ClaimViewMixin, SmartFormView): class Form(ClaimViewMixin.Form): user_access_token = forms.CharField(min_length=32, required=True, help_text=_("The User Access Token")) - page_name = forms.CharField(required=True, max_length=64, help_text=_("The name of the Facebook page")) + page_name = forms.CharField(required=True, help_text=_("The name of the Facebook page")) page_id = forms.IntegerField(required=True, help_text="The Facebook Page ID") def clean(self): @@ -106,7 +107,7 @@ def clean(self): raise Exception("Failed to subscribe to app for webhook events") self.cleaned_data["page_access_token"] = page_access_token - self.cleaned_data["name"] = name + self.cleaned_data["name"] = truncate(name, Channel._meta.get_field("name").max_length) # requires instagram_basic permission # https://developers.facebook.com/docs/instagram-api/reference/page#read From 74c6f2685f2ea7d1916df15f224aeffe5128565c Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 11:37:38 +0700 Subject: [PATCH 109/630] fixed zaper page title --- templates/orgs/org_resthooks.haml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/orgs/org_resthooks.haml b/templates/orgs/org_resthooks.haml index d2c9c73f54c..a551dbcda06 100644 --- a/templates/orgs/org_resthooks.haml +++ b/templates/orgs/org_resthooks.haml @@ -1,6 +1,9 @@ -extends 'smartmin/form.html' -load smartmin i18n +-block spa-title + Zapier + -block pre-form .mb-4 From 815c5496ee5f62c2b8191f2dd5dc7cb9fbd1b6ca Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 12:02:15 +0700 Subject: [PATCH 110/630] updated plain text to translated text --- templates/orgs/org_resthooks.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/orgs/org_resthooks.haml b/templates/orgs/org_resthooks.haml index a551dbcda06..b4639b1a848 100644 --- a/templates/orgs/org_resthooks.haml +++ b/templates/orgs/org_resthooks.haml @@ -2,8 +2,8 @@ -load smartmin i18n -block spa-title - Zapier - + -trans "Zapier" + -block pre-form .mb-4 From a65d913473d9edb9c50bcea38738ad91eb48b82c Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 13:56:28 +0700 Subject: [PATCH 111/630] fixed classifier page title --- temba/classifiers/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/temba/classifiers/views.py b/temba/classifiers/views.py index 840994e7528..423d4df6c5b 100644 --- a/temba/classifiers/views.py +++ b/temba/classifiers/views.py @@ -116,3 +116,6 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["classifier_types"] = Classifier.get_types() return context + + def derive_title(self): + return _("Connect a Classifier") From 853d343fc535eeb4be3d8d6c84df76c50d4cd411 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 14:00:10 +0700 Subject: [PATCH 112/630] fixed channel page title --- temba/channels/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/temba/channels/views.py b/temba/channels/views.py index 2a42beb8dd0..cd6497c83b4 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1242,6 +1242,9 @@ def get_context_data(self, **kwargs): context["channel_types"] = types_by_category context["only_regional_channels"] = only_regional_channels return context + + def derive_title(self): + return _("Add Channel"); class ClaimAll(Claim): def channel_types_groups(self): From 4769b248a5d7b40e60f901ca2a5dfe666fb9b954 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 14:10:34 +0700 Subject: [PATCH 113/630] minor tweak to derive_title return statement --- temba/channels/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temba/channels/views.py b/temba/channels/views.py index cd6497c83b4..e3edf17093f 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1244,7 +1244,7 @@ def get_context_data(self, **kwargs): return context def derive_title(self): - return _("Add Channel"); + return _("Add Channel") class ClaimAll(Claim): def channel_types_groups(self): From 4fb3af5db1a30bb947c81012f74a12791b7518c7 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 23:04:42 +0700 Subject: [PATCH 114/630] switched from using derive_title to title --- temba/channels/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/temba/channels/views.py b/temba/channels/views.py index e3edf17093f..576aef3cc30 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1243,8 +1243,7 @@ def get_context_data(self, **kwargs): context["only_regional_channels"] = only_regional_channels return context - def derive_title(self): - return _("Add Channel") + title = _("Add Channel") class ClaimAll(Claim): def channel_types_groups(self): From 6aedb188685a6b04050501a3ec7c41b3a75b4966 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 23:06:24 +0700 Subject: [PATCH 115/630] switched from using derive_title to title --- temba/classifiers/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/temba/classifiers/views.py b/temba/classifiers/views.py index 423d4df6c5b..5fbcb041e81 100644 --- a/temba/classifiers/views.py +++ b/temba/classifiers/views.py @@ -117,5 +117,4 @@ def get_context_data(self, **kwargs): context["classifier_types"] = Classifier.get_types() return context - def derive_title(self): - return _("Connect a Classifier") + title = _("Connect a Classifier") From 5a263781e738f255ee3fefe8ca1b96ea879c2173 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 23:09:32 +0700 Subject: [PATCH 116/630] switched from using spa-title to using title --- temba/orgs/views.py | 1 + templates/orgs/org_resthooks.haml | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/temba/orgs/views.py b/temba/orgs/views.py index a38fccac8bc..008069c138f 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -3159,6 +3159,7 @@ class Meta: form_class = ResthookForm success_message = "" + title = _("Zapier") def get_form(self): form = super().get_form() diff --git a/templates/orgs/org_resthooks.haml b/templates/orgs/org_resthooks.haml index b4639b1a848..d2c9c73f54c 100644 --- a/templates/orgs/org_resthooks.haml +++ b/templates/orgs/org_resthooks.haml @@ -1,9 +1,6 @@ -extends 'smartmin/form.html' -load smartmin i18n --block spa-title - -trans "Zapier" - -block pre-form .mb-4 From 27d8ab8dcd0c2d22cc00ce946bbe0c9e8fe89ad1 Mon Sep 17 00:00:00 2001 From: susanm74 Date: Wed, 10 Aug 2022 23:33:37 +0700 Subject: [PATCH 117/630] minor reformatting after running the code check --- temba/channels/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temba/channels/views.py b/temba/channels/views.py index 576aef3cc30..ffaccd8d2d8 100644 --- a/temba/channels/views.py +++ b/temba/channels/views.py @@ -1242,7 +1242,7 @@ def get_context_data(self, **kwargs): context["channel_types"] = types_by_category context["only_regional_channels"] = only_regional_channels return context - + title = _("Add Channel") class ClaimAll(Claim): From 6226495e11a77a7bed910036ce0b02f23f677913 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 09:29:00 -0500 Subject: [PATCH 118/630] Update CHANGELOG.md for v7.5.16 --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f1fb100347..3ef3a72b029 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.16 +---------- + * Fixed zaper page title + * Validate channel name is not more than 64 characters + * Added 'authentication' to the temba anchor URL text + v7.5.15 ---------- * Fix URL for media uploads which was previously conflicting with media directory diff --git a/pyproject.toml b/pyproject.toml index 3f6689016a7..2abc7d897d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.15" +version = "7.5.16" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 998ac3022d7bb6cba2c0ec3b3d9bf82aa82e9086 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 11:28:13 -0500 Subject: [PATCH 119/630] Update deps --- poetry.lock | 588 ++++++++++++------------------------------------- pyproject.toml | 2 +- 2 files changed, 144 insertions(+), 446 deletions(-) diff --git a/poetry.lock b/poetry.lock index 94873c7d4b8..2ef30efb1e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,13 +1,13 @@ [[package]] name = "amqp" -version = "5.0.9" +version = "5.1.1" description = "Low-level AMQP client for Python (fork of amqplib)." category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -vine = "5.0.0" +vine = ">=5.0.0" [[package]] name = "analytics-python" @@ -29,7 +29,7 @@ test = ["mock (==2.0.0)", "pylint (==1.9.3)", "flake8 (==3.7.9)"] [[package]] name = "asgiref" -version = "3.5.0" +version = "3.5.2" description = "ASGI specs, helper code, and adapters" category = "main" optional = false @@ -48,11 +48,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "beautifulsoup4" -version = "4.10.0" +version = "4.11.1" description = "Screen-scraping library" category = "dev" optional = false -python-versions = ">3.0.0" +python-versions = ">=3.6.0" [package.dependencies] soupsieve = ">1.2" @@ -71,7 +71,7 @@ python-versions = "*" [[package]] name = "black" -version = "22.1.0" +version = "22.6.0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -82,7 +82,7 @@ click = ">=8.0.0" mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = ">=1.1.0" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -93,43 +93,43 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.21.10" +version = "1.24.49" description = "The AWS SDK for Python" category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] -botocore = ">=1.24.10,<1.25.0" -jmespath = ">=0.7.1,<1.0.0" -s3transfer = ">=0.5.0,<0.6.0" +botocore = ">=1.27.49,<1.28.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.6.0,<0.7.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.24.10" +version = "1.27.49" description = "Low-level, data-driven core of boto 3." category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] -jmespath = ">=0.7.1,<1.0.0" +jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" [package.extras] -crt = ["awscrt (==0.12.5)"] +crt = ["awscrt (==0.13.8)"] [[package]] name = "celery" -version = "5.2.3" +version = "5.2.7" description = "Distributed Task Queue." category = "main" optional = false -python-versions = ">=3.7," +python-versions = ">=3.7" [package.dependencies] billiard = ">=3.6.4.0,<4.0" @@ -176,15 +176,15 @@ zstd = ["zstandard"] [[package]] name = "certifi" -version = "2021.10.8" +version = "2022.6.15" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "cffi" -version = "1.15.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -203,22 +203,22 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.4" +version = "8.1.3" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -275,7 +275,7 @@ requests = ">=2.7.9" [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.5" description = "Cross-platform colored terminal text." category = "main" optional = false @@ -335,7 +335,7 @@ python-versions = "*" [[package]] name = "django" -version = "4.0.6" +version = "4.0.7" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." category = "main" optional = false @@ -347,8 +347,8 @@ sqlparse = ">=0.2.2" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] +argon2 = ["argon2-cffi (>=19.1.0)"] [[package]] name = "django-appconf" @@ -376,7 +376,7 @@ rjsmin = "1.2.0" [[package]] name = "django-countries" -version = "7.3.1" +version = "7.3.2" description = "Provides a country field for Django models." category = "main" optional = false @@ -443,14 +443,14 @@ redis = ">=3.0.0" [[package]] name = "django-storages" -version = "1.12.3" +version = "1.13.1" description = "Support for many storage backends in Django" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [package.dependencies] -Django = ">=2.2" +Django = ">=3.2" [package.extras] azure = ["azure-storage-blob (>=12.0.0)"] @@ -489,7 +489,7 @@ pytz = "*" [[package]] name = "elasticsearch" -version = "7.17.1" +version = "7.17.4" description = "Python client for Elasticsearch" category = "main" optional = false @@ -500,10 +500,10 @@ certifi = "*" urllib3 = ">=1.21.1,<2" [package.extras] -async = ["aiohttp (>=3,<4)"] -develop = ["requests (>=2.0.0,<3.0.0)", "coverage", "mock", "pyyaml", "pytest", "pytest-cov", "sphinx (<1.7)", "sphinx-rtd-theme", "black", "jinja2"] -docs = ["sphinx (<1.7)", "sphinx-rtd-theme"] requests = ["requests (>=2.4.0,<3.0.0)"] +docs = ["sphinx-rtd-theme", "sphinx (<1.7)"] +develop = ["jinja2", "black", "sphinx-rtd-theme", "sphinx (<1.7)", "pytest-cov", "pytest", "pyyaml", "mock", "coverage", "requests (>=2.0.0,<3.0.0)"] +async = ["aiohttp (>=3,<4)"] [[package]] name = "elasticsearch-dsl" @@ -596,7 +596,7 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.11.2" +version = "4.12.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -606,9 +606,9 @@ python-versions = ">=3.7" zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["importlib-resources (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-black (>=0.3.7)", "pytest-perf (>=0.9.2)", "flufl.flake8", "pyfakefs", "packaging", "pytest-enabler (>=1.3)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +docs = ["rst.linker (>=1.9)", "jaraco.packaging (>=9)", "sphinx"] [[package]] name = "inflection" @@ -661,15 +661,15 @@ plugins = ["setuptools"] [[package]] name = "jmespath" -version = "0.10.0" +version = "1.0.1" description = "JSON Matching Expressions" category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.7" [[package]] name = "kombu" -version = "5.2.3" +version = "5.2.4" description = "Messaging library for Python." category = "main" optional = false @@ -705,11 +705,11 @@ python-versions = "*" [[package]] name = "markdown" -version = "3.3.6" +version = "3.4.1" description = "Python implementation of Markdown." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} @@ -756,7 +756,7 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openpyxl" -version = "3.0.9" +version = "3.0.10" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" category = "main" optional = false @@ -786,7 +786,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "phonenumbers" -version = "8.12.44" +version = "8.12.53" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." category = "main" optional = false @@ -794,15 +794,15 @@ python-versions = "*" [[package]] name = "platformdirs" -version = "2.5.1" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +test = ["pytest (>=6)", "pytest-mock (>=3.6)", "pytest-cov (>=2.7)", "appdirs (==1.4.4)"] +docs = ["sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)", "proselint (>=0.10.2)", "furo (>=2021.7.5b38)"] [[package]] name = "polib" @@ -814,7 +814,7 @@ python-versions = "*" [[package]] name = "prompt-toolkit" -version = "3.0.28" +version = "3.0.30" description = "Library for building powerful interactive command lines in Python" category = "main" optional = false @@ -965,14 +965,14 @@ python-versions = "*" [[package]] name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pysocks" @@ -1010,7 +1010,7 @@ six = "*" [[package]] name = "python-magic" -version = "0.4.25" +version = "0.4.27" description = "File type identification using libmagic" category = "main" optional = false @@ -1035,7 +1035,7 @@ socks = ["pysocks"] [[package]] name = "pytz" -version = "2021.3" +version = "2022.1" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -1062,7 +1062,7 @@ hiredis = ["hiredis (>=0.1.3)"] [[package]] name = "regex" -version = "2022.3.2" +version = "2022.7.25" description = "Alternative regular expression module, to replace re." category = "main" optional = false @@ -1070,21 +1070,21 @@ python-versions = ">=3.6" [[package]] name = "requests" -version = "2.27.1" +version = "2.28.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] [[package]] name = "requests-oauthlib" @@ -1138,11 +1138,11 @@ python-versions = "*" [[package]] name = "s3transfer" -version = "0.5.2" +version = "0.6.0" description = "An Amazon S3 Transfer Manager" category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" @@ -1152,7 +1152,7 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] [[package]] name = "sentry-sdk" -version = "1.5.6" +version = "1.9.4" description = "Python client for Sentry (https://sentry.io)" category = "main" optional = false @@ -1160,25 +1160,30 @@ python-versions = "*" [package.dependencies] certifi = "*" -urllib3 = ">=1.10.0" +urllib3 = [ + {version = ">=1.26.11", markers = "python_version >= \"3.6\""}, + {version = ">=1.26.9", markers = "python_version >= \"3.5\""}, +] [package.extras] -aiohttp = ["aiohttp (>=3.5)"] -beam = ["apache-beam (>=2.12)"] -bottle = ["bottle (>=0.12.13)"] -celery = ["celery (>=3)"] -chalice = ["chalice (>=1.16.0)"] -django = ["django (>=1.8)"] -falcon = ["falcon (>=1.4)"] -flask = ["flask (>=0.11)", "blinker (>=1.1)"] -httpx = ["httpx (>=0.16.0)"] -pure_eval = ["pure-eval", "executing", "asttokens"] -pyspark = ["pyspark (>=2.4.4)"] -quart = ["quart (>=0.16.1)", "blinker (>=1.1)"] -rq = ["rq (>=0.6)"] -sanic = ["sanic (>=0.8)"] -sqlalchemy = ["sqlalchemy (>=1.2)"] tornado = ["tornado (>=5)"] +starlette = ["starlette (>=0.19.1)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +sanic = ["sanic (>=0.8)"] +rq = ["rq (>=0.6)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +pyspark = ["pyspark (>=2.4.4)"] +pure_eval = ["asttokens", "executing", "pure-eval"] +httpx = ["httpx (>=0.16.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)"] +fastapi = ["fastapi (>=0.79.0)"] +falcon = ["falcon (>=1.4)"] +django = ["django (>=1.8)"] +chalice = ["chalice (>=1.16.0)"] +celery = ["celery (>=3)"] +bottle = ["bottle (>=0.12.13)"] +beam = ["apache-beam (>=2.12)"] +aiohttp = ["aiohttp (>=3.5)"] [[package]] name = "six" @@ -1207,7 +1212,7 @@ xlwt = ">=1.3.0,<2.0.0" [[package]] name = "soupsieve" -version = "2.3.1" +version = "2.3.2.post1" description = "A modern CSS selector implementation for Beautiful Soup." category = "dev" optional = false @@ -1223,7 +1228,7 @@ python-versions = ">=3.5" [[package]] name = "stripe" -version = "2.67.0" +version = "2.76.0" description = "Python bindings for the Stripe API" category = "main" optional = false @@ -1242,11 +1247,11 @@ python-versions = "*" [[package]] name = "tomli" -version = "1.2.3" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "twilio" @@ -1277,15 +1282,15 @@ requests_oauthlib = ">=0.4.0" [[package]] name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "tzdata" -version = "2021.5" +version = "2022.1" description = "Provider of IANA time zone data" category = "main" optional = false @@ -1293,16 +1298,16 @@ python-versions = ">=2" [[package]] name = "urllib3" -version = "1.26.8" +version = "1.26.11" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +secure = ["ipaddress", "certifi", "idna (>=2.0.0)", "cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] +brotli = ["brotlipy (>=0.6.0)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] [[package]] name = "vine" @@ -1336,7 +1341,7 @@ python-versions = "*" [[package]] name = "wrapt" -version = "1.13.3" +version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." category = "main" optional = false @@ -1368,151 +1373,49 @@ python-versions = "*" [[package]] name = "zipp" -version = "3.7.0" +version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "f9c943e0438fba490d6d2114b710ac4e05618987605fb6dd613fe0f7dbdd58e4" +content-hash = "0932e7b61c407f54715e7b0dfc00a732e350b64f623d523bf7cc59a43cc36771" [metadata.files] -amqp = [ - {file = "amqp-5.0.9-py3-none-any.whl", hash = "sha256:9cd81f7b023fc04bbb108718fbac674f06901b77bfcdce85b10e2a5d0ee91be5"}, - {file = "amqp-5.0.9.tar.gz", hash = "sha256:1e5f707424e544078ca196e72ae6a14887ce74e02bd126be54b7c03c971bef18"}, -] +amqp = [] analytics-python = [ {file = "analytics-python-1.4.0.tar.gz", hash = "sha256:a65141ab6e47db396f5bc5708b1db93ff9a99882d81fe808228afd5ebb6dfe5f"}, {file = "analytics_python-1.4.0-py2.py3-none-any.whl", hash = "sha256:3bff972beeb8a3f26607ccd9153484aa4f12eeeea4a693be685bf45aa66ddf99"}, ] -asgiref = [ - {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"}, - {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"}, -] +asgiref = [] backoff = [ {file = "backoff-1.10.0-py2.py3-none-any.whl", hash = "sha256:5e73e2cbe780e1915a204799dba0a01896f45f4385e636bcca7a0614d879d0cd"}, {file = "backoff-1.10.0.tar.gz", hash = "sha256:b8fba021fac74055ac05eb7c7bfce4723aedde6cd0a504e5326bcb0bdd6d19a4"}, ] -beautifulsoup4 = [ - {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, - {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, -] +beautifulsoup4 = [] billiard = [ {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, ] -black = [ - {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, - {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, - {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, - {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, - {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, - {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, - {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, - {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, - {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, - {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, - {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, - {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, - {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, - {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, - {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, - {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, - {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, - {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, - {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, -] -boto3 = [ - {file = "boto3-1.21.10-py3-none-any.whl", hash = "sha256:0122f8428a23efd29283c9ec92e7da1a8f35a69ddfd0635131cc5ca558723c4f"}, - {file = "boto3-1.21.10.tar.gz", hash = "sha256:365156a9e55f08f2394e0bc84fc953f2a200f63adb08091c2ea06d7b025ea80b"}, -] -botocore = [ - {file = "botocore-1.24.10-py3-none-any.whl", hash = "sha256:fc4bf1c71fabd84c35b7fb728268a6f9f491493e9ee7a5efb603425bfe8a0277"}, - {file = "botocore-1.24.10.tar.gz", hash = "sha256:7429f6e54851d3f40fa9147ca1517f5f54101865ae4e79ba2095f580ff85333e"}, -] -celery = [ - {file = "celery-5.2.3-py3-none-any.whl", hash = "sha256:8aacd02fc23a02760686d63dde1eb0daa9f594e735e73ea8fb15c2ff15cb608c"}, - {file = "celery-5.2.3.tar.gz", hash = "sha256:e2cd41667ad97d4f6a2f4672d1c6a6ebada194c619253058b5f23704aaadaa82"}, -] -certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, -] -cffi = [ - {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, - {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, - {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, - {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, - {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, - {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, - {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, - {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, - {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, - {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, - {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, - {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, - {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, - {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, - {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, - {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, - {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, -] +black = [] +boto3 = [] +botocore = [] +celery = [] +certifi = [] +cffi = [] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] -charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, -] -click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, -] +charset-normalizer = [] +click = [] click-didyoumean = [ {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, @@ -1530,10 +1433,7 @@ codecov = [ {file = "codecov-2.1.12-py3.8.egg", hash = "sha256:782a8e5352f22593cbc5427a35320b99490eb24d9dcfa2155fd99d2b75cfb635"}, {file = "codecov-2.1.12.tar.gz", hash = "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1"}, ] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] +colorama = [] coverage = [ {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, @@ -1612,10 +1512,7 @@ dj-database-url = [ {file = "dj-database-url-0.5.0.tar.gz", hash = "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163"}, {file = "dj_database_url-0.5.0-py2.py3-none-any.whl", hash = "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9"}, ] -django = [ - {file = "Django-4.0.6-py3-none-any.whl", hash = "sha256:ca54ebedfcbc60d191391efbf02ba68fb52165b8bf6ccd6fe71f098cac1fe59e"}, - {file = "Django-4.0.6.tar.gz", hash = "sha256:a67a793ff6827fd373555537dca0da293a63a316fe34cb7f367f898ccca3c3ae"}, -] +django = [] django-appconf = [ {file = "django-appconf-1.0.5.tar.gz", hash = "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4"}, {file = "django_appconf-1.0.5-py3-none-any.whl", hash = "sha256:ae9f864ee1958c815a965ed63b3fba4874eec13de10236ba063a788f9a17389d"}, @@ -1624,10 +1521,7 @@ django-compressor = [ {file = "django_compressor-3.1-py2.py3-none-any.whl", hash = "sha256:89f7ba86777b30672c2f9c7557bf2aff87c5890903c73b1fa3ae38acd143e855"}, {file = "django_compressor-3.1.tar.gz", hash = "sha256:c4a87bf65f9a534cfaf1c321a000a229c24e50c6d62ba6ab089482db42e819d9"}, ] -django-countries = [ - {file = "django-countries-7.3.1.tar.gz", hash = "sha256:b6b439cc5c7e766ec2335615160fdcebb9f2774ccc17aaa5e173306832d77594"}, - {file = "django_countries-7.3.1-py3-none-any.whl", hash = "sha256:5a4ee958f77810bcc38ae96605e47d76a707e81f53cf2938743ef45faafd2fce"}, -] +django-countries = [] django-hamlpy = [ {file = "django-hamlpy-1.4.4.tar.gz", hash = "sha256:76252ebb4475c2bffbd2671fc64e9add519dfe53489d48d0727ba7a64c7a9c0b"}, {file = "django_hamlpy-1.4.4-py3-none-any.whl", hash = "sha256:1cd39ab5bb2af7ee23d1669fa719d5bf4bc0385ebbb827a08471d8a88541b304"}, @@ -1644,10 +1538,7 @@ django-redis = [ {file = "django-redis-4.12.1.tar.gz", hash = "sha256:306589c7021e6468b2656edc89f62b8ba67e8d5a1c8877e2688042263daa7a63"}, {file = "django_redis-4.12.1-py3-none-any.whl", hash = "sha256:1133b26b75baa3664164c3f44b9d5d133d1b8de45d94d79f38d1adc5b1d502e5"}, ] -django-storages = [ - {file = "django-storages-1.12.3.tar.gz", hash = "sha256:a475edb2f0f04c4f7e548919a751ecd50117270833956ed5bd585c0575d2a5e7"}, - {file = "django_storages-1.12.3-py3-none-any.whl", hash = "sha256:204a99f218b747c46edbfeeb1310d357f83f90fa6a6024d8d0a3f422570cee84"}, -] +django-storages = [] django-timezone-field = [ {file = "django-timezone-field-4.2.3.tar.gz", hash = "sha256:5dd5bd9249382bef8847d3e7e4c32b7be182a4b538f354130d1252ed228892f8"}, {file = "django_timezone_field-4.2.3-py3-none-any.whl", hash = "sha256:7552d2b0f145684b7de3fb5046101c7efd600cc6ba951b15c630fa1e1b83558e"}, @@ -1656,10 +1547,7 @@ djangorestframework = [ {file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"}, {file = "djangorestframework-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"}, ] -elasticsearch = [ - {file = "elasticsearch-7.17.1-py2.py3-none-any.whl", hash = "sha256:8c79fe145f23826df144d1adc406a131e5cf3f41f302869fb5a1263b381e5ee2"}, - {file = "elasticsearch-7.17.1.tar.gz", hash = "sha256:0061c49c3d4202802c09fba6734e48699a47cfeb737747acecc932ea73b7d318"}, -] +elasticsearch = [] elasticsearch-dsl = [ {file = "elasticsearch-dsl-7.4.0.tar.gz", hash = "sha256:c4a7b93882918a413b63bed54018a1685d7410ffd8facbc860ee7fd57f214a6d"}, {file = "elasticsearch_dsl-7.4.0-py2.py3-none-any.whl", hash = "sha256:046ea10820b94c075081b528b4526c5bc776bda4226d702f269a5f203232064b"}, @@ -1688,10 +1576,7 @@ idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] -importlib-metadata = [ - {file = "importlib_metadata-4.11.2-py3-none-any.whl", hash = "sha256:d16e8c1deb60de41b8e8ed21c1a7b947b0bc62fab7e1d470bcdf331cea2e6735"}, - {file = "importlib_metadata-4.11.2.tar.gz", hash = "sha256:b36ffa925fe3139b2f6ff11d6925ffd4fa7bc47870165e3ac260ac7b4f91e6ac"}, -] +importlib-metadata = [] inflection = [ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, @@ -1711,22 +1596,13 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -jmespath = [ - {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, - {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, -] -kombu = [ - {file = "kombu-5.2.3-py3-none-any.whl", hash = "sha256:eeaeb8024f3a5cfc71c9250e45cddb8493f269d74ada2f74909a93c59c4b4179"}, - {file = "kombu-5.2.3.tar.gz", hash = "sha256:81a90c1de97e08d3db37dbf163eaaf667445e1068c98bfd89f051a40e9f6dbbd"}, -] +jmespath = [] +kombu = [] lml = [ {file = "lml-0.1.0-py2.py3-none-any.whl", hash = "sha256:ec06e850019942a485639c8c2a26bdb99eae24505bee7492b649df98a0bed101"}, {file = "lml-0.1.0.tar.gz", hash = "sha256:57a085a29bb7991d70d41c6c3144c560a8e35b4c1030ffb36d85fa058773bcc5"}, ] -markdown = [ - {file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"}, - {file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"}, -] +markdown = [] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -1743,10 +1619,7 @@ oauthlib = [ {file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"}, {file = "oauthlib-3.2.0.tar.gz", hash = "sha256:23a8208d75b902797ea29fd31fa80a15ed9dc2c6c16fe73f5d346f83f6fa27a2"}, ] -openpyxl = [ - {file = "openpyxl-3.0.9-py2.py3-none-any.whl", hash = "sha256:8f3b11bd896a95468a4ab162fc4fcd260d46157155d1f8bfaabb99d88cfcf79f"}, - {file = "openpyxl-3.0.9.tar.gz", hash = "sha256:40f568b9829bf9e446acfffce30250ac1fa39035124d55fc024025c41481c90f"}, -] +openpyxl = [] packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, @@ -1755,22 +1628,13 @@ pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] -phonenumbers = [ - {file = "phonenumbers-8.12.44-py2.py3-none-any.whl", hash = "sha256:cc1299cf37b309ecab6214297663ab86cb3d64ae37fd5b88e904fe7983a874a6"}, - {file = "phonenumbers-8.12.44.tar.gz", hash = "sha256:26cfd0257d1704fe2f88caff2caabb70d16a877b1e65b6aae51f9fbbe10aa8ce"}, -] -platformdirs = [ - {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, - {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, -] +phonenumbers = [] +platformdirs = [] polib = [ {file = "polib-1.1.1-py2.py3-none-any.whl", hash = "sha256:d3ee85e0c6788f789353416b1612c6c92d75fe6ccfac0029711974d6abd0f86d"}, {file = "polib-1.1.1.tar.gz", hash = "sha256:e02c355ae5e054912e3b0d16febc56510eff7e49d60bf22aecb463bd2f2a2dfa"}, ] -prompt-toolkit = [ - {file = "prompt_toolkit-3.0.28-py3-none-any.whl", hash = "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c"}, - {file = "prompt_toolkit-3.0.28.tar.gz", hash = "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650"}, -] +prompt-toolkit = [] psycopg2-binary = [ {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"}, @@ -1872,10 +1736,7 @@ pyotp = [ {file = "pyotp-2.4.1-py2.py3-none-any.whl", hash = "sha256:ef07c393660529261e66902e788b32e46260d2c29eb740978df778260a1c2b4c"}, {file = "pyotp-2.4.1.tar.gz", hash = "sha256:038a3f70b34eaad3f72459e8b411662ef8dfcdd95f7d9203fa489e987a75584b"}, ] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] +pyparsing = [] pysocks = [ {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, @@ -1887,18 +1748,12 @@ python-dateutil = [ python-intercom = [ {file = "python-intercom-3.1.0.tar.gz", hash = "sha256:77df3573228128a0ad1b9fcd469404813248f5864221717e082f959c5a6f28fc"}, ] -python-magic = [ - {file = "python-magic-0.4.25.tar.gz", hash = "sha256:21f5f542aa0330f5c8a64442528542f6215c8e18d2466b399b0d9d39356d83fc"}, - {file = "python_magic-0.4.25-py2.py3-none-any.whl", hash = "sha256:1a2c81e8f395c744536369790bd75094665e9644110a6623bcc3bbea30f03973"}, -] +python-magic = [] python-telegram-bot = [ {file = "python-telegram-bot-11.1.0.tar.gz", hash = "sha256:cca4e32ebb8da7fdf35ab2fa2b3edd441211364819c5592fc253acdb7561ea5b"}, {file = "python_telegram_bot-11.1.0-py2.py3-none-any.whl", hash = "sha256:78695b1f6e147e9b360ccfb1ac92b542cab27870ccaf04065a88ee601ffa58b6"}, ] -pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, -] +pytz = [] rcssmin = [ {file = "rcssmin-1.1.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2211a5c91ea14a5937b57904c9121f8bfef20987825e55368143da7d25446e3b"}, {file = "rcssmin-1.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7085d1b51dd2556f3aae03947380f6e9e1da29fb1eeadfa6766b7f105c54c9ff"}, @@ -1925,86 +1780,8 @@ redis = [ {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] -regex = [ - {file = "regex-2022.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab69b4fe09e296261377d209068d52402fb85ef89dc78a9ac4a29a895f4e24a7"}, - {file = "regex-2022.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5bc5f921be39ccb65fdda741e04b2555917a4bced24b4df14eddc7569be3b493"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43eba5c46208deedec833663201752e865feddc840433285fbadee07b84b464d"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c68d2c04f7701a418ec2e5631b7f3552efc32f6bcc1739369c6eeb1af55f62e0"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:caa2734ada16a44ae57b229d45091f06e30a9a52ace76d7574546ab23008c635"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef806f684f17dbd6263d72a54ad4073af42b42effa3eb42b877e750c24c76f86"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be319f4eb400ee567b722e9ea63d5b2bb31464e3cf1b016502e3ee2de4f86f5c"}, - {file = "regex-2022.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:42bb37e2b2d25d958c25903f6125a41aaaa1ed49ca62c103331f24b8a459142f"}, - {file = "regex-2022.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fbc88d3ba402b5d041d204ec2449c4078898f89c4a6e6f0ed1c1a510ef1e221d"}, - {file = "regex-2022.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:91e0f7e7be77250b808a5f46d90bf0032527d3c032b2131b63dee54753a4d729"}, - {file = "regex-2022.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:cb3652bbe6720786b9137862205986f3ae54a09dec8499a995ed58292bdf77c2"}, - {file = "regex-2022.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:878c626cbca3b649e14e972c14539a01191d79e58934e3f3ef4a9e17f90277f8"}, - {file = "regex-2022.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6df070a986fc064d865c381aecf0aaff914178fdf6874da2f2387e82d93cc5bd"}, - {file = "regex-2022.3.2-cp310-cp310-win32.whl", hash = "sha256:b549d851f91a4efb3e65498bd4249b1447ab6035a9972f7fc215eb1f59328834"}, - {file = "regex-2022.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:8babb2b5751105dc0aef2a2e539f4ba391e738c62038d8cb331c710f6b0f3da7"}, - {file = "regex-2022.3.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1977bb64264815d3ef016625adc9df90e6d0e27e76260280c63eca993e3f455f"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e73652057473ad3e6934944af090852a02590c349357b79182c1b681da2c772"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b22ff939a8856a44f4822da38ef4868bd3a9ade22bb6d9062b36957c850e404f"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:878f5d649ba1db9f52cc4ef491f7dba2d061cdc48dd444c54260eebc0b1729b9"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0008650041531d0eadecc96a73d37c2dc4821cf51b0766e374cb4f1ddc4e1c14"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06b1df01cf2aef3a9790858af524ae2588762c8a90e784ba00d003f045306204"}, - {file = "regex-2022.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57484d39447f94967e83e56db1b1108c68918c44ab519b8ecfc34b790ca52bf7"}, - {file = "regex-2022.3.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:74d86e8924835f863c34e646392ef39039405f6ce52956d8af16497af4064a30"}, - {file = "regex-2022.3.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:ae17fc8103f3b63345709d3e9654a274eee1c6072592aec32b026efd401931d0"}, - {file = "regex-2022.3.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5f92a7cdc6a0ae2abd184e8dfd6ef2279989d24c85d2c85d0423206284103ede"}, - {file = "regex-2022.3.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:5dcc4168536c8f68654f014a3db49b6b4a26b226f735708be2054314ed4964f4"}, - {file = "regex-2022.3.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:1e30762ddddb22f7f14c4f59c34d3addabc789216d813b0f3e2788d7bcf0cf29"}, - {file = "regex-2022.3.2-cp36-cp36m-win32.whl", hash = "sha256:286ff9ec2709d56ae7517040be0d6c502642517ce9937ab6d89b1e7d0904f863"}, - {file = "regex-2022.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d326ff80ed531bf2507cba93011c30fff2dd51454c85f55df0f59f2030b1687b"}, - {file = "regex-2022.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9d828c5987d543d052b53c579a01a52d96b86f937b1777bbfe11ef2728929357"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c87ac58b9baaf50b6c1b81a18d20eda7e2883aa9a4fb4f1ca70f2e443bfcdc57"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6c2441538e4fadd4291c8420853431a229fcbefc1bf521810fbc2629d8ae8c2"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f3356afbb301ec34a500b8ba8b47cba0b44ed4641c306e1dd981a08b416170b5"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d96eec8550fd2fd26f8e675f6d8b61b159482ad8ffa26991b894ed5ee19038b"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf668f26604e9f7aee9f8eaae4ca07a948168af90b96be97a4b7fa902a6d2ac1"}, - {file = "regex-2022.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb0e2845e81bdea92b8281a3969632686502565abf4a0b9e4ab1471c863d8f3"}, - {file = "regex-2022.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:87bc01226cd288f0bd9a4f9f07bf6827134dc97a96c22e2d28628e824c8de231"}, - {file = "regex-2022.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:09b4b6ccc61d4119342b26246ddd5a04accdeebe36bdfe865ad87a0784efd77f"}, - {file = "regex-2022.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:9557545c10d52c845f270b665b52a6a972884725aa5cf12777374e18f2ea8960"}, - {file = "regex-2022.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:0be0c34a39e5d04a62fd5342f0886d0e57592a4f4993b3f9d257c1f688b19737"}, - {file = "regex-2022.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7b103dffb9f6a47ed7ffdf352b78cfe058b1777617371226c1894e1be443afec"}, - {file = "regex-2022.3.2-cp37-cp37m-win32.whl", hash = "sha256:f8169ec628880bdbca67082a9196e2106060a4a5cbd486ac51881a4df805a36f"}, - {file = "regex-2022.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:4b9c16a807b17b17c4fa3a1d8c242467237be67ba92ad24ff51425329e7ae3d0"}, - {file = "regex-2022.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:67250b36edfa714ba62dc62d3f238e86db1065fccb538278804790f578253640"}, - {file = "regex-2022.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5510932596a0f33399b7fff1bd61c59c977f2b8ee987b36539ba97eb3513584a"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f7ee2289176cb1d2c59a24f50900f8b9580259fa9f1a739432242e7d254f93"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d7a68fa53688e1f612c3246044157117403c7ce19ebab7d02daf45bd63913e"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf5317c961d93c1a200b9370fb1c6b6836cc7144fef3e5a951326912bf1f5a3"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad397bc7d51d69cb07ef89e44243f971a04ce1dca9bf24c992c362406c0c6573"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:297c42ede2c81f0cb6f34ea60b5cf6dc965d97fa6936c11fc3286019231f0d66"}, - {file = "regex-2022.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:af4d8cc28e4c7a2f6a9fed544228c567340f8258b6d7ea815b62a72817bbd178"}, - {file = "regex-2022.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:452519bc4c973e961b1620c815ea6dd8944a12d68e71002be5a7aff0a8361571"}, - {file = "regex-2022.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cb34c2d66355fb70ae47b5595aafd7218e59bb9c00ad8cc3abd1406ca5874f07"}, - {file = "regex-2022.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d146e5591cb67c5e836229a04723a30af795ef9b70a0bbd913572e14b7b940f"}, - {file = "regex-2022.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:03299b0bcaa7824eb7c0ebd7ef1e3663302d1b533653bfe9dc7e595d453e2ae9"}, - {file = "regex-2022.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9ccb0a4ab926016867260c24c192d9df9586e834f5db83dfa2c8fffb3a6e5056"}, - {file = "regex-2022.3.2-cp38-cp38-win32.whl", hash = "sha256:f7e8f1ee28e0a05831c92dc1c0c1c94af5289963b7cf09eca5b5e3ce4f8c91b0"}, - {file = "regex-2022.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35ed2f3c918a00b109157428abfc4e8d1ffabc37c8f9abc5939ebd1e95dabc47"}, - {file = "regex-2022.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:55820bc631684172b9b56a991d217ec7c2e580d956591dc2144985113980f5a3"}, - {file = "regex-2022.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:83f03f0bd88c12e63ca2d024adeee75234d69808b341e88343b0232329e1f1a1"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42d6007722d46bd2c95cce700181570b56edc0dcbadbfe7855ec26c3f2d7e008"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:320c2f4106962ecea0f33d8d31b985d3c185757c49c1fb735501515f963715ed"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd3fe37353c62fd0eb19fb76f78aa693716262bcd5f9c14bb9e5aca4b3f0dc4"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17e51ad1e6131c496b58d317bc9abec71f44eb1957d32629d06013a21bc99cac"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72bc3a5effa5974be6d965ed8301ac1e869bc18425c8a8fac179fbe7876e3aee"}, - {file = "regex-2022.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e5602a9b5074dcacc113bba4d2f011d2748f50e3201c8139ac5b68cf2a76bd8b"}, - {file = "regex-2022.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:729aa8ca624c42f309397c5fc9e21db90bf7e2fdd872461aabdbada33de9063c"}, - {file = "regex-2022.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d6ecfd1970b3380a569d7b3ecc5dd70dba295897418ed9e31ec3c16a5ab099a5"}, - {file = "regex-2022.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:13bbf0c9453c6d16e5867bda7f6c0c7cff1decf96c5498318bb87f8136d2abd4"}, - {file = "regex-2022.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:58ba41e462653eaf68fc4a84ec4d350b26a98d030be1ab24aba1adcc78ffe447"}, - {file = "regex-2022.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c0446b2871335d5a5e9fcf1462f954586b09a845832263db95059dcd01442015"}, - {file = "regex-2022.3.2-cp39-cp39-win32.whl", hash = "sha256:20e6a27959f162f979165e496add0d7d56d7038237092d1aba20b46de79158f1"}, - {file = "regex-2022.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9efa41d1527b366c88f265a227b20bcec65bda879962e3fc8a2aee11e81266d7"}, - {file = "regex-2022.3.2.tar.gz", hash = "sha256:79e5af1ff258bc0fe0bdd6f69bc4ae33935a898e3cbefbbccf22e88a27fa053b"}, -] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] +regex = [] +requests = [] requests-oauthlib = [ {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, @@ -2039,14 +1816,8 @@ rjsmin = [ {file = "rjsmin-1.2.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8944a8a55ac825b8e5ec29f341ecb7574697691ef416506885898d2f780fb4ca"}, {file = "rjsmin-1.2.0.tar.gz", hash = "sha256:6c529feb6c400984452494c52dd9fdf59185afeacca2afc5174a28ab37751a1b"}, ] -s3transfer = [ - {file = "s3transfer-0.5.2-py3-none-any.whl", hash = "sha256:7a6f4c4d1fdb9a2b640244008e142cbc2cd3ae34b386584ef044dd0f27101971"}, - {file = "s3transfer-0.5.2.tar.gz", hash = "sha256:95c58c194ce657a5f4fb0b9e60a84968c808888aed628cd98ab8771fe1db98ed"}, -] -sentry-sdk = [ - {file = "sentry-sdk-1.5.6.tar.gz", hash = "sha256:ac2a50128409d57655279817aedcb7800cace1f76b266f3dd62055d5afd6e098"}, - {file = "sentry_sdk-1.5.6-py2.py3-none-any.whl", hash = "sha256:1ab34e3851a34aeb3d1af1a0f77cec73978c4e9698e5210d050e4932953cb241"}, -] +s3transfer = [] +sentry-sdk = [] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -2055,26 +1826,17 @@ smartmin = [ {file = "smartmin-4.1.0-py3-none-any.whl", hash = "sha256:3667eaf2b2c9a6d7b4ccccc58efd36a6eef8cd1c17bcf43ab2c76defb25abe92"}, {file = "smartmin-4.1.0.tar.gz", hash = "sha256:8a8fae03da769b72f301e5bf28b13b3de0d6e316522fabeae19b6eac2073436b"}, ] -soupsieve = [ - {file = "soupsieve-2.3.1-py3-none-any.whl", hash = "sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb"}, - {file = "soupsieve-2.3.1.tar.gz", hash = "sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9"}, -] +soupsieve = [] sqlparse = [ {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, ] -stripe = [ - {file = "stripe-2.67.0-py2.py3-none-any.whl", hash = "sha256:7efaee187a0615ce9361b6009122f89488a874c3175b5262dd9741a49088db18"}, - {file = "stripe-2.67.0.tar.gz", hash = "sha256:718b93d6a18105243bce0c9b48e518f72f1f083d27f07e07b8bdb3a541fe3835"}, -] +stripe = [] texttable = [ {file = "texttable-1.6.4-py2.py3-none-any.whl", hash = "sha256:dd2b0eaebb2a9e167d1cefedab4700e5dcbdb076114eed30b58b97ed6b37d6f2"}, {file = "texttable-1.6.4.tar.gz", hash = "sha256:42ee7b9e15f7b225747c3fa08f43c5d6c83bc899f80ff9bae9319334824076e9"}, ] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] +tomli = [] twilio = [ {file = "twilio-6.24.0-py2.py3-none-any.whl", hash = "sha256:68323becb99a9b960c9a0b92164288bceba4886ca0230daf4f591286bb224916"}, {file = "twilio-6.24.0.tar.gz", hash = "sha256:cff699b660dcfb0f1e225a37b1586cd0ebcae634c3af91cd7a07b787807d744a"}, @@ -2082,18 +1844,9 @@ twilio = [ twython = [ {file = "twython-3.5.0.tar.gz", hash = "sha256:01ad5ed21f3da641a3dc58a814b435aac4cf91c691b1afc5a8dc0ca4e1affe47"}, ] -typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, -] -tzdata = [ - {file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"}, - {file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"}, -] -urllib3 = [ - {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, - {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, -] +typing-extensions = [] +tzdata = [] +urllib3 = [] vine = [ {file = "vine-5.0.0-py2.py3-none-any.whl", hash = "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30"}, {file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"}, @@ -2106,59 +1859,7 @@ wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] -wrapt = [ - {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, - {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, - {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, - {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, - {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, - {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, - {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, - {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, - {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, - {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, - {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, - {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, - {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, - {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, - {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, - {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, - {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, - {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, - {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, -] +wrapt = [] xlrd = [ {file = "xlrd-1.2.0-py2.py3-none-any.whl", hash = "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"}, {file = "xlrd-1.2.0.tar.gz", hash = "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2"}, @@ -2171,7 +1872,4 @@ xlwt = [ {file = "xlwt-1.3.0-py2.py3-none-any.whl", hash = "sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e"}, {file = "xlwt-1.3.0.tar.gz", hash = "sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88"}, ] -zipp = [ - {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, - {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, -] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index 2abc7d897d1..acf371755ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ repository = "http://github.com/rapidpro/rapidpro" [tool.poetry.dependencies] python = "^3.9" -Django = "^4.0.6" +Django = "^4.0.7" django-compressor = "^3.1" django-countries = "^7.0" django-hamlpy = "^1.4.4" From 3771b5ad5c619b42f0b25f0dfe0753724f992abc Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 11:42:55 -0500 Subject: [PATCH 120/630] Only show option to delete runs to users who have that perm, and give editors that perm --- temba/settings_common.py | 1 + templates/flows/flow_run_table.haml | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/temba/settings_common.py b/temba/settings_common.py index f7ed4f7f811..dd50e9a37b3 100644 --- a/temba/settings_common.py +++ b/temba/settings_common.py @@ -763,6 +763,7 @@ "csv_imports.importtask.*", "flows.flow.*", "flows.flowlabel.*", + "flows.flowrun_delete", "flows.flowstart_api", "flows.flowstart_list", "globals.global_api", diff --git a/templates/flows/flow_run_table.haml b/templates/flows/flow_run_table.haml index e01b0b65d00..72623fdf4fd 100644 --- a/templates/flows/flow_run_table.haml +++ b/templates/flows/flow_run_table.haml @@ -1,4 +1,4 @@ --load contacts tz i18n +-load contacts tz i18n temba -for run in runs %td .details.nobreak - .remove.icon-close{ onclick: 'deleteRun({{run.id}});' } - {{run.modified_on}} + -if org_perms.flows.flowrun_delete + .remove.icon-close{ onclick: 'deleteRun({{run.id}});' } + {% format_datetime run.modified_on %} %td .details.breaks From 843f5617c3a09f6aeb83f6c2ccd778277215e5c4 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 13:29:34 -0500 Subject: [PATCH 121/630] Show send history of scheduled broadcasts in correct order and update modified_on/by when updating schedules --- temba/msgs/views.py | 2 +- temba/schedules/models.py | 8 ++++--- temba/schedules/tests.py | 47 ++++++++++++++++++++++++++------------- temba/schedules/views.py | 1 + temba/triggers/views.py | 1 + 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/temba/msgs/views.py b/temba/msgs/views.py index 05545fe0658..fbf2758899f 100644 --- a/temba/msgs/views.py +++ b/temba/msgs/views.py @@ -262,7 +262,7 @@ def derive_title(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["object_list"] = self.get_object().children.all() + context["object_list"] = self.get_object().children.order_by("-created_on") return context def derive_formax_sections(self, formax, context): diff --git a/temba/schedules/models.py b/temba/schedules/models.py index ebaa160cd57..dd214c37719 100644 --- a/temba/schedules/models.py +++ b/temba/schedules/models.py @@ -82,17 +82,17 @@ class Schedule(SmartModel): @classmethod def create_blank_schedule(cls, org, user): - return Schedule.create_schedule(org, user, None, Schedule.REPEAT_NEVER) + return cls.create_schedule(org, user, None, cls.REPEAT_NEVER) @classmethod def create_schedule(cls, org, user, start_time, repeat_period, repeat_days_of_week=None, now=None): assert not repeat_days_of_week or set(repeat_days_of_week).issubset(cls.DAYS_OF_WEEK_OFFSET) schedule = Schedule(repeat_period=repeat_period, created_by=user, modified_by=user, org=org) - schedule.update_schedule(start_time, repeat_period, repeat_days_of_week, now=now) + schedule.update_schedule(user, start_time, repeat_period, repeat_days_of_week, now=now) return schedule - def update_schedule(self, start_time, repeat_period, repeat_days_of_week, now=None): + def update_schedule(self, user, start_time, repeat_period, repeat_days_of_week, now=None): assert self.org is not None if not now: @@ -141,6 +141,8 @@ def update_schedule(self, start_time, repeat_period, repeat_days_of_week, now=No else: self.next_fire = start_time + self.modified_by = user + self.modified_on = timezone.now() self.save() def get_broadcast(self): diff --git a/temba/schedules/tests.py b/temba/schedules/tests.py index c4a74d40807..ee2f57e63ef 100644 --- a/temba/schedules/tests.py +++ b/temba/schedules/tests.py @@ -232,11 +232,12 @@ def test_schedule_ui(self): response = self.client.post(reverse("msgs.broadcast_send"), post_data, follow=True) self.assertContains(response, "This field is required") - # finally create our message - post_data = dict(text="A scheduled message to Joe", omnibox=omnibox, sender=self.channel.pk, schedule=True) - - headers = {"HTTP_X_PJAX": "True"} - response = self.client.post(reverse("msgs.broadcast_send"), post_data, **headers) + # finally create our scheduled broadcast + response = self.client.post( + reverse("msgs.broadcast_send"), + {"text": "A scheduled message to Joe", "omnibox": omnibox, "sender": self.channel.id, "schedule": True}, + HTTP_X_PJAX=True, + ) self.assertIn("/broadcast/schedule_read", response["Temba-Success"]) # should have a schedule with no next fire @@ -245,29 +246,42 @@ def test_schedule_ui(self): self.assertIsNone(schedule.next_fire) self.assertEqual(Schedule.REPEAT_NEVER, schedule.repeat_period) + self.assertEqual(self.admin, schedule.modified_by) # fetch our formax page response = self.client.get(response["Temba-Success"]) self.assertContains(response, "id-schedule") - broadcast = response.context["object"] + self.assertEqual(bcast, response.context["object"]) # update our message - omnibox = omnibox_serialize(self.org, [], [self.joe], json_encode=True) - post_data = dict(message="An updated scheduled message", omnibox=omnibox) - self.client.post(reverse("msgs.broadcast_update", args=[broadcast.pk]), post_data) - self.assertEqual(Broadcast.objects.get(id=broadcast.id).text, {"base": "An updated scheduled message"}) + update_bcast_url = reverse("msgs.broadcast_update", args=[bcast.id]) + + self.login(self.editor) + self.client.post( + update_bcast_url, + { + "message": "An updated scheduled message", + "omnibox": omnibox_serialize(self.org, [], [self.joe], json_encode=True), + }, + ) + + bcast.refresh_from_db() + self.assertEqual({"base": "An updated scheduled message"}, bcast.text) + self.assertEqual(self.editor, bcast.modified_by) start = datetime(2045, 9, 19, hour=10, minute=15, second=0, microsecond=0) start = pytz.utc.normalize(self.org.timezone.localize(start)) # update the schedule - post_data = dict( - repeat_period=Schedule.REPEAT_WEEKLY, - repeat_days_of_week="W", - start="later", - start_datetime=datetime_to_str(start, "%Y-%m-%d %H:%M", self.org.timezone), + response = self.client.post( + reverse("schedules.schedule_update", args=[bcast.schedule.id]), + { + "repeat_period": Schedule.REPEAT_WEEKLY, + "repeat_days_of_week": "W", + "start": "later", + "start_datetime": datetime_to_str(start, "%Y-%m-%d %H:%M", self.org.timezone), + }, ) - response = self.client.post(reverse("schedules.schedule_update", args=[broadcast.schedule.pk]), post_data) # assert out next fire was updated properly schedule.refresh_from_db() @@ -276,6 +290,7 @@ def test_schedule_ui(self): self.assertEqual(10, schedule.repeat_hour_of_day) self.assertEqual(15, schedule.repeat_minute_of_hour) self.assertEqual(start, schedule.next_fire) + self.assertEqual(self.editor, schedule.modified_by) # manually set our fire in the past schedule.next_fire = timezone.now() - timedelta(days=1) diff --git a/temba/schedules/views.py b/temba/schedules/views.py index 8deb3592fb8..f0d7ccad33c 100644 --- a/temba/schedules/views.py +++ b/temba/schedules/views.py @@ -101,6 +101,7 @@ def get_success_url(self): def save(self, *args, **kwargs): self.object.update_schedule( + self.request.user, self.form.cleaned_data["start_datetime"], self.form.cleaned_data["repeat_period"], self.form.cleaned_data.get("repeat_days_of_week"), diff --git a/temba/triggers/views.py b/temba/triggers/views.py index b82a5a34af1..aa807a7aab5 100644 --- a/temba/triggers/views.py +++ b/temba/triggers/views.py @@ -412,6 +412,7 @@ def derive_initial(self): def form_valid(self, form): if self.object.trigger_type == Trigger.TYPE_SCHEDULE: self.object.schedule.update_schedule( + self.request.user, form.cleaned_data["start_datetime"], form.cleaned_data["repeat_period"], form.cleaned_data.get("repeat_days_of_week"), From 7750ea84640ff6c69f21779dfc6cbf42ec4c3707 Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 11 Aug 2022 15:13:59 -0500 Subject: [PATCH 122/630] Update CHANGELOG.md for v7.5.17 --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef3a72b029..6fcdd33bb36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v7.5.17 +---------- + * Show send history of scheduled broadcasts in correct order + * Only show option to delete runs to users who have that perm, and give editors that perm + * Update deps + v7.5.16 ---------- * Fixed zaper page title diff --git a/pyproject.toml b/pyproject.toml index acf371755ca..fc400a4eb96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "temba" -version = "7.5.16" +version = "7.5.17" description = "Hosted service for visually building interactive messaging applications" authors = ["Nyaruka "] license = "AGPL-3" From 23f5777523f7577248135a4fa58bbbf6638d0447 Mon Sep 17 00:00:00 2001 From: Eric Newcomer Date: Thu, 11 Aug 2022 17:01:05 -0700 Subject: [PATCH 123/630] Switch manage to look for is_staff, add org read page for staff --- static/js/urls.js | 9 +- temba/orgs/models.py | 2 - temba/orgs/urls.py | 2 +- temba/orgs/views.py | 172 ++++++++++++++--------- temba/utils/templatetags/temba.py | 5 + templates/contacts/contact_read_spa.haml | 2 +- templates/frame.haml | 3 +- templates/includes/nav.haml | 8 +- templates/msgs/message_box_spa.haml | 2 +- templates/orgs/org_manage.haml | 8 +- templates/orgs/org_manage_spa.haml | 11 ++ templates/orgs/org_read.haml | 37 +++++ templates/orgs/org_read_spa.haml | 1 + templates/orgs/org_update.haml | 1 + templates/orgs/org_update_spa.haml | 2 + templates/orgs/user_account.haml | 11 +- templates/orgs/user_list.haml | 1 + templates/orgs/user_list_spa.haml | 11 ++ templates/smartmin/base.html | 9 -- templates/smartmin/list.haml | 7 +- templates/spa_frame.haml | 33 +++-- templates/spa_page_menu.haml | 5 + templates/triggers/trigger_list_spa.haml | 2 +- 23 files changed, 235 insertions(+), 109 deletions(-) create mode 100644 templates/orgs/org_manage_spa.haml create mode 100644 templates/orgs/org_read.haml create mode 100644 templates/orgs/org_read_spa.haml create mode 100644 templates/orgs/org_update_spa.haml create mode 100644 templates/orgs/user_list_spa.haml diff --git a/static/js/urls.js b/static/js/urls.js index 71af93abca1..57e45b839b9 100644 --- a/static/js/urls.js +++ b/static/js/urls.js @@ -6,7 +6,7 @@ window.urls = [ { old: /\/contact\/read\/(.*)/, new: /\/contacts\/read\/(.*)/ }, { old: /\/contact\/filter\/(.*)/, new: /\/contacts\/groups\/(.*)/ }, { old: /\/contact\//, new: /\/contacts\// }, - { old: /\/flow\/editor\/(.*)\//, new: /\/flows\/editor\/(.*)/ }, + { old: /\/flow\/editor\/(.*)/, new: /\/flows\/editor\/(.*)/ }, { old: /\/flow\/filter\/(.*)\//, new: /\/flows\/labels\/(.*)/ }, { old: /\/flow\//, new: /\/flows\/active/ }, { old: /\/flow\/(.*)\//, new: /\/flows\/(.*)\// }, @@ -23,8 +23,11 @@ window.urls = [ { old: /\/channels\/types\/(.*)\/claim/, new: /\/settings\/channel\/(.*)/ }, { old: /\/org\/manage_accounts\/(.*)/, new: /\/settings\/logins/ }, { old: /\/user\/account\//, new: /\/settings\/account/ }, - { old: /\/user\/two_factor_disable\//, new: /\/settings\/authentication\/2fa-disable/ } -] + { old: /\/user\/two_factor_disable\//, new: /\/settings\/authentication\/2fa-disable/ }, + { old: /\/user\/update\/(.*)/, new: /\/staff\/users\/(.*)/ }, + { old: /\/org\/read\/(.*)/, new: /\/staff\/workspaces\/(.*)/ }, + { old: /\/org\/update\/(.*)/, new: /\/staff\/workspaces\/(.*)\/update/ }, +]; window.mapUrl = function (path, reverse) { var findDirection = reverse ? 'new' : 'old'; diff --git a/temba/orgs/models.py b/temba/orgs/models.py index abcde74ee9c..5caa5d7cc25 100644 --- a/temba/orgs/models.py +++ b/temba/orgs/models.py @@ -467,7 +467,6 @@ class Org(SmartModel): verbose_name=_("Plan"), max_length=16, default=settings.DEFAULT_PLAN, - help_text=_("What plan your organization is on"), ) plan_start = models.DateTimeField(null=True) plan_end = models.DateTimeField(null=True) @@ -553,7 +552,6 @@ class Org(SmartModel): max_length=128, default=settings.DEFAULT_BRAND, verbose_name=_("Brand"), - help_text=_("The brand used in emails"), ) surveyor_password = models.CharField( diff --git a/temba/orgs/urls.py b/temba/orgs/urls.py index 92e7f51bc31..80b538047bb 100644 --- a/temba/orgs/urls.py +++ b/temba/orgs/urls.py @@ -32,7 +32,7 @@ spa = SpaView.as_view() -sections = r"campaigns|contacts|tickets|triggers|messages|channels|flows|plugins|settings" +sections = r"campaigns|contacts|tickets|triggers|messages|channels|flows|plugins|settings|staff" level_0 = rf"^(?P{sections})/" level_1 = rf"{level_0}(?P.+)/" level_2 = rf"{level_1}(?P.+)/" diff --git a/temba/orgs/views.py b/temba/orgs/views.py index a38fccac8bc..f273d9bed35 100644 --- a/temba/orgs/views.py +++ b/temba/orgs/views.py @@ -108,6 +108,16 @@ def check_login(request): return HttpResponseRedirect(settings.LOGIN_URL) +class StaffMixin: + """ + Views that only staff should be able to access + """ + + def has_permission(self, request, *args, **kwargs): + print(request, self.request.user.is_staff) + return self.request.user.is_staff + + class OrgPermsMixin: """ Get the organisation and the user within the inheriting view so that it be come easy to decide @@ -500,7 +510,7 @@ class Meta: fields = "__all__" -class LoginView(Login): +class LoginView(SpaMixin, Login): """ Overrides the smartmin login view to redirect users with 2FA enabled to a second verification view. """ @@ -702,7 +712,7 @@ class UserCRUDL(SmartCRUDL): "account", ) - class List(SmartListView): + class List(StaffMixin, SpaMixin, SmartListView): fields = ("email", "name", "orgs", "date_joined") ordering = ("-date_joined",) search_fields = ("email", "first_name", "last_name") @@ -713,7 +723,7 @@ def dispatch(self, *args, **kwargs): return super().dispatch(*args, **kwargs) def get_email(self, user): - return mark_safe(f"{user.username}") + return user.email def get_orgs(self, user): orgs = user.get_orgs()[0:6] @@ -744,7 +754,7 @@ def get_context_data(self, **kwargs): context["filters"] = self.filters return context - class Update(ComponentFormMixin, ContentMenuMixin, SmartUpdateView): + class Update(StaffMixin, SpaMixin, ComponentFormMixin, ContentMenuMixin, SmartUpdateView): class Form(UserUpdateForm): groups = forms.ModelMultipleChoiceField( widget=SelectMultipleWidget( @@ -788,7 +798,7 @@ def post_save(self, obj): return obj - class Delete(ModalMixin, SmartDeleteView): + class Delete(StaffMixin, SpaMixin, ModalMixin, SmartDeleteView): fields = ("id",) permission = "orgs.user_update" submit_button_name = _("Delete") @@ -803,13 +813,14 @@ def get_context_data(self, **kwargs): def post(self, request, *args, **kwargs): user = self.get_object() - username = user.username brand = self.request.branding.get("brand") user.release(self.request.user, brand=brand) - messages.success(self.request, _(f"Deleted user {username}")) - return HttpResponseRedirect(reverse("orgs.user_list", args=())) + messages.info(request, self.derive_success_message()) + response = HttpResponse() + response["Temba-Success"] = reverse("orgs.user_list") + return response class Forget(SmartFormView): class ForgetForm(forms.Form): @@ -1142,6 +1153,7 @@ def create_menu_item( perm=None, items=[], inline=False, + bottom=False, ): if perm and not self.has_org_perm(perm): # pragma: no cover @@ -1149,6 +1161,7 @@ def create_menu_item( menu_item = {"name": name, "inline": inline} menu_item["id"] = menu_id if menu_id else slugify(name) + menu_item["bottom"] = bottom if icon: menu_item["icon"] = icon @@ -1189,6 +1202,7 @@ class OrgCRUDL(SmartCRUDL): actions = ( "signup", "home", + "read", "token", "edit", "edit_sub_org", @@ -1342,7 +1356,7 @@ def derive_menu(self): child_orgs = Org.objects.filter(parent=org, is_active=True).order_by("name") if child_orgs: - menu.append(self.create_section(_("Child Workspaces"))) + menu.append(self.create_section(_("Workspaces"))) for child in child_orgs: menu.append( @@ -1966,8 +1980,68 @@ def get_context_data(self, **kwargs): context["from_email_custom"] = from_email_custom return context - class Manage(SmartListView): - fields = ("plan", "name", "owner", "created_on", "service") + class Read(StaffMixin, SpaMixin, ContentMenuMixin, SmartReadView): + def build_content_menu(self, menu): + if not self.object.is_active: + return + + menu.add_url_post( + _("Service"), + f'{reverse("orgs.org_service")}?organization={self.object.id}&redirect_url={reverse("msgs.msg_inbox", args=[])}', + ) + + if self.request.user.is_staff: + menu.add_modax( + _("Edit"), + "update-workspace", + reverse("orgs.org_update", args=[self.object.id]), + title=_("Edit Workspace"), + ) + + menu.add_link(_("Topups"), f"{reverse('orgs.topup_manage')}?org={self.object.id}") + + if self.object.is_flagged: + menu.add_url_post(_("Unflag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=unflag") + else: # pragma: needs cover + menu.add_url_post(_("Flag"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=flag") + + if not self.object.is_verified(): + menu.add_url_post(_("Verify"), f"{reverse('orgs.org_update', args=[self.object.id])}?action=verify") + + if self.request.user.has_perm("orgs.org_delete"): + menu.add_modax( + _("Delete"), + "delete-org", + reverse("orgs.org_delete", args=[self.object.id]), + title=_("Delete Workspace"), + ) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + org = self.get_object() + + users_roles = [] + for role in OrgRole: + role_users = list(org.get_users(roles=[role]).values("id", "email")) + if role_users: + users_roles.append(dict(role_display=role.display_plural, users=role_users)) + + context["users_roles"] = users_roles + workspaces = Org.objects.filter(parent=org, is_active=True).order_by("-created_on", "name") + + children = {} + for workspace in workspaces: + plan_workspaces = children.get(workspace.plan, []) + plan_workspaces.append(workspace) + children[workspace.plan] = plan_workspaces + + context["children"] = children + + return context + + class Manage(StaffMixin, SpaMixin, SmartListView): + fields = ("name", "owner", "created_on", "service") field_config = {"service": {"label": ""}} default_order = ("-credits", "-created_on") search_fields = ("name__icontains", "created_by__email__iexact", "config__icontains") @@ -1977,7 +2051,7 @@ class Manage(SmartListView): ("anon", _("Anonymous")), ("flagged", _("Flagged")), ("suspended", _("Suspended")), - ("nyaruka", "Nyaruka"), + ("verified", _("Verified")), ) @csrf_exempt @@ -2029,11 +2103,7 @@ def get_service(self, obj): ) def get_name(self, obj): - flagged = '(Flagged)' if obj.is_flagged else "" - - return mark_safe( - f"