From bb40941bc33d87c16f80c3a2c7982a11d360f03c Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 16 Sep 2020 16:23:49 +0200
Subject: [PATCH] sms: add a button to test sending sms (#45333)

---
 passerelle/sms/forms.py                       |  8 ++++
 passerelle/sms/models.py                      |  5 +++
 .../manage/messages_service_test_send.html    | 18 ++++++++
 .../manage/messages_service_view.html         |  7 ++++
 passerelle/sms/urls.py                        |  8 ++++
 passerelle/sms/views.py                       | 41 +++++++++++++++++++
 tests/test_sms.py                             | 30 ++++++++++++++
 7 files changed, 117 insertions(+)
 create mode 100644 passerelle/sms/forms.py
 create mode 100644 passerelle/sms/templates/passerelle/manage/messages_service_test_send.html
 create mode 100644 passerelle/sms/urls.py
 create mode 100644 passerelle/sms/views.py

diff --git a/passerelle/sms/forms.py b/passerelle/sms/forms.py
new file mode 100644
index 00000000..f0baa355
--- /dev/null
+++ b/passerelle/sms/forms.py
@@ -0,0 +1,8 @@
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+
+class SmsTestSendForm(forms.Form):
+    number = forms.CharField(label=_('To'), max_length=12)
+    sender = forms.CharField(label=_('From'), max_length=12)
+    message = forms.CharField(label=_('Message'), max_length=128)
diff --git a/passerelle/sms/models.py b/passerelle/sms/models.py
index 12c27fe6..23e183b4 100644
--- a/passerelle/sms/models.py
+++ b/passerelle/sms/models.py
@@ -13,16 +13,17 @@
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import logging
 import re
 
 from django.db import models
 from django.utils import six
+from django.utils.module_loading import import_string
 from django.utils.translation import ugettext_lazy as _
 
 from passerelle.base.models import BaseResource
 from passerelle.compat import json_loads
 from passerelle.utils.api import endpoint
 from passerelle.utils.jsonresponse import APIError
 
 SEND_SCHEMA = {
@@ -60,16 +61,20 @@ class SMSResource(BaseResource):
                                             default=u'33')
     default_trunk_prefix = models.CharField(verbose_name=_('Default trunk prefix'), max_length=2,
                                             default=u'0')  # Yeah France first !
     # FIXME: add regexp field, to check destination and from format
     max_message_length = models.IntegerField(_('Maximum message length'), default=160)
 
     manager_view_template_name = 'passerelle/manage/messages_service_view.html'
 
+    @classmethod
+    def get_management_urls(cls):
+        return import_string('passerelle.sms.urls.management_urlpatterns')
+
     def clean_numbers(self, destinations):
         numbers = []
         for dest in destinations:
             # most gateways needs the number prefixed by the country code, this is
             # really unfortunate.
             dest = dest.strip()
             number = ''.join(re.findall('[0-9]', dest))
             if dest.startswith('+'):
diff --git a/passerelle/sms/templates/passerelle/manage/messages_service_test_send.html b/passerelle/sms/templates/passerelle/manage/messages_service_test_send.html
new file mode 100644
index 00000000..010d8f96
--- /dev/null
+++ b/passerelle/sms/templates/passerelle/manage/messages_service_test_send.html
@@ -0,0 +1,18 @@
+{% extends "passerelle/base.html" %}
+{% load i18n %}
+
+{% block appbar %}
+<h2>{% trans "Sending a test SMS" %}</h2>
+{% endblock %}
+
+{% block content %}
+
+<form method="post" enctype="multipart/form-data">
+  {% csrf_token %}
+  {{ form.as_p }}
+  <div class="buttons">
+    <button>{% trans "Send SMS" %}</button>
+    <a class="cancel" href="{% url 'manage-home' %}">{% trans 'Cancel' %}</a>
+  </div>
+</form>
+{% endblock %}
diff --git a/passerelle/sms/templates/passerelle/manage/messages_service_view.html b/passerelle/sms/templates/passerelle/manage/messages_service_view.html
index 55beacb3..8c37c1cc 100644
--- a/passerelle/sms/templates/passerelle/manage/messages_service_view.html
+++ b/passerelle/sms/templates/passerelle/manage/messages_service_view.html
@@ -1,6 +1,13 @@
 {% extends "passerelle/manage/service_view.html" %}
 {% load i18n passerelle %}
 
 {% block endpoints %}
 {{ block.super }}
+{% if perms.base.view_accessright %}
+<div>
+  <a rel="popup" href="/manage{{ object.get_absolute_url }}test-send/">
+    {% trans 'Send a test message' %}
+  </a>
+</div>
+{% endif %}
 {% endblock %}
diff --git a/passerelle/sms/urls.py b/passerelle/sms/urls.py
new file mode 100644
index 00000000..c58df515
--- /dev/null
+++ b/passerelle/sms/urls.py
@@ -0,0 +1,8 @@
+from django.conf.urls import url
+
+from . import views
+
+management_urlpatterns = [
+    url(r'^(?P<slug>[\w,-]+)/test-send/$',
+        views.SmsTestSendView.as_view(), name='sms-test-send'),
+]
diff --git a/passerelle/sms/views.py b/passerelle/sms/views.py
new file mode 100644
index 00000000..054dc3d1
--- /dev/null
+++ b/passerelle/sms/views.py
@@ -0,0 +1,41 @@
+from django.apps import apps
+from django.contrib import messages
+from django.utils.translation import ugettext_lazy as _
+from django.views.generic import FormView
+
+from passerelle.utils.jsonresponse import APIError
+from passerelle.views import GenericConnectorMixin
+
+from .forms import SmsTestSendForm
+
+
+class SmsTestSendView(GenericConnectorMixin, FormView):
+    form_class = SmsTestSendForm
+    template_name = 'passerelle/manage/messages_service_test_send.html'
+
+    def init_stuff(self, request, *args, **kwargs):
+        form_class = self.form_class
+        super(SmsTestSendView, self).init_stuff(request, *args, **kwargs)
+        self.form_class = form_class
+
+    def get_object(self):
+        return self.model.objects.get(slug=self.kwargs['slug'])
+
+    def get_success_url(self):
+        connector = self.get_object()
+        return connector.get_absolute_url()
+
+    def form_valid(self, form):
+        number = form.cleaned_data['number']
+        sender = form.cleaned_data['sender']
+        message = form.cleaned_data['message']
+        connector = self.get_object()
+        try:
+            number = connector.clean_numbers([number])[0]
+            connector.send_msg(
+                text=message, sender=sender, destinations=[number], stop=False)
+        except APIError as exc:
+            messages.error(self.request, _('Sending SMS fails: %s' % exc))
+        else:
+            messages.success(self.request, _('An SMS was just sent'))
+        return super(SmsTestSendView, self).form_valid(form)
diff --git a/tests/test_sms.py b/tests/test_sms.py
index ee47cb42..dcb68b4e 100644
--- a/tests/test_sms.py
+++ b/tests/test_sms.py
@@ -1,14 +1,15 @@
 import isodate
 import mock
 import pytest
 from requests import RequestException
 
 from django.contrib.contenttypes.models import ContentType
+from django.core.urlresolvers import reverse
 
 from passerelle.apps.ovh.models import OVHSMSGateway
 from passerelle.base.models import ApiUser, AccessRight, Job
 from passerelle.sms.models import SMSResource, SMSLog
 from passerelle.utils.jsonresponse import APIError
 
 from test_manager import login, admin_user
 
@@ -220,8 +221,37 @@ def test_ovh_new_api(app, freezer):
     url = connector.API_URL % {'serviceName': 'sms-test42', 'login': 'john'}
     with utils.mock_url(url, resp, 200) as mocked:
         connector.jobs()
     job = Job.objects.get(id=job_id)
     assert job.status == 'completed'
 
     request = mocked.handlers[0].call['requests'][0]
     assert 'X-Ovh-Signature' in request.headers
+
+
+@pytest.mark.parametrize('connector', [OVHSMSGateway], indirect=True)
+def test_sms_test_send(admin_user, app, connector):
+    url = '/%s/%s/' % (connector.get_connector_slug(), connector.slug)
+    resp = app.get(url)
+    link = resp.html.find('div', {'id': 'endpoints'}).find_all('a')[-1]
+    assert 'Send a test message' not in link.text
+
+    app = login(app)
+    resp = app.get(url)
+    link = resp.html.find('div', {'id': 'endpoints'}).find_all('a')[-1]
+    assert 'Send a test message' in link.text
+    assert link['href'] == reverse('sms-test-send', kwargs={
+        'connector': connector.get_connector_slug(), 'slug': connector.slug})
+
+    resp = app.get(link['href'])
+    resp.form['number'] = '+33688888888'
+    resp.form['sender'] = '+33699999999'
+    resp.form['message'] = 'hello'
+    with mock.patch.object(OVHSMSGateway, 'send_msg') as send_function:
+        send_function.return_value = {}
+        resp = resp.form.submit()
+        assert send_function.call_args[1] == {
+            'text': 'hello', 'sender': '+33699999999', 'destinations': ['0033688888888'],
+            'stop': False,
+        }
+    assert resp.status_code == 302
+    assert resp.location == url
-- 
2.28.0

