Browse Source

feat: upgrade phonenumberslite (#16919)

josh 5 years ago
parent
commit
e15f6b5061

+ 1 - 1
requirements-base.txt

@@ -32,7 +32,7 @@ mmh3>=2.3.1,<2.4
 msgpack>=0.6.1,<0.7.0
 parsimonious==0.8.0
 petname>=2.6,<2.7
-phonenumberslite<8.0
+phonenumberslite>=8.11.0,<8.12.0
 Pillow>=6.2.1,<7.0.0
 progressbar2>=3.10,<3.11
 psycopg2-binary>=2.7.0,<2.9.0

+ 4 - 1
src/sentry_plugins/twilio/plugin.py

@@ -40,6 +40,9 @@ def basic_auth(user, password):
     return "Basic " + (user + ":" + password).encode("base64").replace("\n", "")
 
 
+# XXX: can likely remove the dedupe here after notify_users has test coverage;
+#      in theory only cleaned data would make it to the plugin via the form,
+#      and cleaned numbers are deduped already.
 def split_sms_to(data):
     return set(filter(bool, re.split(r"\s*,\s*|\s+", data)))
 
@@ -82,7 +85,7 @@ class TwilioConfigurationForm(forms.Form):
         for phone in phones:
             if not validate_phone(phone):
                 raise forms.ValidationError("{0} is not a valid phone number.".format(phone))
-        return ",".join(sorted(map(clean_phone, phones)))
+        return ",".join(sorted(set(map(clean_phone, phones))))
 
     def clean(self):
         # TODO: Ping Twilio and check credentials (?)

+ 1 - 0
tests/sentry_plugins/twilio/__init__.py

@@ -0,0 +1 @@
+from __future__ import absolute_import

+ 68 - 0
tests/sentry_plugins/twilio/test_plugin.py

@@ -0,0 +1,68 @@
+from __future__ import absolute_import
+
+from exam import fixture
+from sentry.testutils import TestCase, PluginTestCase
+from sentry_plugins.twilio.plugin import TwilioConfigurationForm, TwilioPlugin
+
+
+class TwilioConfigurationFormTest(TestCase):
+    def test_valid_form(self):
+        form = TwilioConfigurationForm(
+            data={
+                "sms_from": "3305093095",
+                "sms_to": "330-509-3095, (330)-509-3095, +13305093095, 4045550144",
+                "auth_token": "foo",
+                "account_sid": "bar",
+            }
+        )
+
+        self.assertTrue(form.is_valid())
+        self.assertDictEqual(
+            form.clean(),
+            {
+                "auth_token": u"foo",
+                "sms_to": u"+13305093095,+14045550144",
+                "sms_from": u"+13305093095",
+                "account_sid": u"bar",
+            },
+        )
+
+    def test_invalid_form(self):
+        form = TwilioConfigurationForm(data={"sms_from": "foobar", "sms_to": "911"})
+        self.assertFalse(form.is_valid())
+        errors = form.errors.as_data()
+
+        # extracting the message from django.forms.ValidationError
+        # is the easiest and simplest way I've found to assert as_data
+        for e in errors:
+            errors[e] = list(map(lambda x: x.message, errors[e]))
+
+        self.assertDictEqual(
+            errors,
+            {
+                "auth_token": [u"This field is required."],
+                "account_sid": [u"This field is required."],
+                "sms_from": [u"foobar is not a valid phone number."],
+                "sms_to": [u"911 is not a valid phone number."],
+            },
+        )
+
+
+class TwilioPluginTest(PluginTestCase):
+    # TODO: actually test the plugin
+
+    @fixture
+    def plugin(self):
+        return TwilioPlugin()
+
+    def test_conf_key(self):
+        assert self.plugin.conf_key == "twilio"
+
+    def test_entry_point(self):
+        self.assertPluginInstalled("twilio", self.plugin)
+
+    def test_is_configured(self):
+        assert self.plugin.is_configured(self.project) is False
+        for o in ("account_sid", "auth_token", "sms_from", "sms_to"):
+            self.plugin.set_option(o, "foo", self.project)
+        assert self.plugin.is_configured(self.project) is True