From 616a1798c3ffc6a9700c97d73b7ffeaf9736b025 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Thu, 15 Oct 2020 18:18:34 +0200 Subject: [PATCH] ovh: ease setup with new API (#47851) --- .../ovh/migrations/0012_auto_20201019_1556.py | 25 ++++++++++ passerelle/apps/ovh/models.py | 5 +- .../templates/ovh/ovhsmsgateway_detail.html | 7 +++ passerelle/apps/ovh/urls.py | 10 ++++ passerelle/apps/ovh/views.py | 48 +++++++++++++++++++ tests/test_sms.py | 33 +++++++++++++ 6 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 passerelle/apps/ovh/migrations/0012_auto_20201019_1556.py create mode 100644 passerelle/apps/ovh/urls.py create mode 100644 passerelle/apps/ovh/views.py diff --git a/passerelle/apps/ovh/migrations/0012_auto_20201019_1556.py b/passerelle/apps/ovh/migrations/0012_auto_20201019_1556.py new file mode 100644 index 00000000..fba712f1 --- /dev/null +++ b/passerelle/apps/ovh/migrations/0012_auto_20201019_1556.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2020-10-19 13:56 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ovh', '0011_auto_20201008_1731'), + ] + + operations = [ + migrations.AlterField( + model_name='ovhsmsgateway', + name='application_key', + field=models.CharField(blank=True, max_length=16, verbose_name='Application key'), + ), + migrations.AlterField( + model_name='ovhsmsgateway', + name='consumer_key', + field=models.CharField(blank=True, help_text='Automatically obtained from OVH, should not be filled manually.', max_length=32, verbose_name='Consumer key'), + ), + ] diff --git a/passerelle/apps/ovh/models.py b/passerelle/apps/ovh/models.py index b47ca939..33469846 100644 --- a/passerelle/apps/ovh/models.py +++ b/passerelle/apps/ovh/models.py @@ -44,7 +44,6 @@ class OVHSMSGateway(SMSResource): verbose_name=_('Application key'), max_length=16, blank=True, - help_text=_('Random token obtained from OVH.'), ) application_secret = models.CharField( verbose_name=_('Application secret'), @@ -56,7 +55,7 @@ class OVHSMSGateway(SMSResource): verbose_name=_('Consumer key'), max_length=32, blank=True, - help_text=_('Obtained at the same time as "Application key".'), + help_text=_('Automatically obtained from OVH, should not be filled manually.'), ) username = models.CharField( @@ -131,7 +130,7 @@ class OVHSMSGateway(SMSResource): @property def uses_new_api(self): - return self.application_key and self.consumer_key and self.application_secret + return self.application_key and self.application_secret def request(self, method, endpoint, **kwargs): url = self.API_URL % {'serviceName': self.account, 'login': self.username} diff --git a/passerelle/apps/ovh/templates/ovh/ovhsmsgateway_detail.html b/passerelle/apps/ovh/templates/ovh/ovhsmsgateway_detail.html index 926dfdf8..6279de79 100644 --- a/passerelle/apps/ovh/templates/ovh/ovhsmsgateway_detail.html +++ b/passerelle/apps/ovh/templates/ovh/ovhsmsgateway_detail.html @@ -2,7 +2,14 @@ {% load i18n passerelle %} {% block description %} +{% if object.uses_new_api and not object.consumer_key %} +
{% trans "Connector is not operational yet, as access needs to be obtained from OVH for the specified account." %} +{% trans "Click here to request access." %} +
+{% endif %} + {{ block.super }} + {% if object.uses_new_api %}

{% if object.credit_left %} diff --git a/passerelle/apps/ovh/urls.py b/passerelle/apps/ovh/urls.py new file mode 100644 index 00000000..5d800b2b --- /dev/null +++ b/passerelle/apps/ovh/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import url + +from . import views + +management_urlpatterns = [ + url(r'^(?P[\w,-]+)/request_token/$', + views.RequestTokenView.as_view(), name='ovh-request-token'), + url(r'^(?P[\w,-]+)/confirm_token/(?P[a-z0-9-]+)/$', + views.ConfirmTokenView.as_view(), name='ovh-confirm-token'), +] diff --git a/passerelle/apps/ovh/views.py b/passerelle/apps/ovh/views.py new file mode 100644 index 00000000..c1828b39 --- /dev/null +++ b/passerelle/apps/ovh/views.py @@ -0,0 +1,48 @@ +import requests +import uuid +from urllib.parse import urljoin + +from django.conf import settings +from django.contrib import messages +from django.shortcuts import reverse +from django.utils.translation import ugettext_lazy as _ +from django.views.generic.base import RedirectView + +from .models import OVHSMSGateway + + +class RequestTokenView(RedirectView): + def get_redirect_url(self, *args, **kwargs): + connector = OVHSMSGateway.objects.get(slug=kwargs["slug"]) + + request_id = uuid.uuid4() + confirm_token_url = reverse('ovh-confirm-token', kwargs={'slug': connector.slug, 'uuid': request_id}) + data = { + "accessRules": [ + {"method": "GET", "path": "/sms/%s/" % connector.account}, + {"method": "POST", "path": "/sms/%s/jobs/" % connector.account}, + ], + "redirection": urljoin(settings.SITE_BASE_URL, confirm_token_url), + } + headers = {"X-Ovh-Application": connector.application_key} + + resp = requests.post('https://eu.api.ovh.com/1.0/auth/credential', json=data, headers=headers) + result = resp.json() + + self.request.session['ovh-token-%s' % request_id] = result['consumerKey'] + return result['validationUrl'] + + +class ConfirmTokenView(RedirectView): + def get_redirect_url(self, *args, **kwargs): + connector = OVHSMSGateway.objects.get(slug=kwargs["slug"]) + consumer_key = self.request.session.get('ovh-token-%s' % kwargs['uuid']) + + if consumer_key: + connector.consumer_key = consumer_key + connector.save() + messages.success(self.request, _('Successfuly completed connector configuration.')) + else: + messages.warning(self.request, _('Could not complete connector configuration, please try again.')) + + return connector.get_absolute_url() diff --git a/tests/test_sms.py b/tests/test_sms.py index 20f2fa2b..3cf90e81 100644 --- a/tests/test_sms.py +++ b/tests/test_sms.py @@ -1,8 +1,10 @@ import isodate +import json import mock import pytest from requests import RequestException +from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse @@ -368,3 +370,34 @@ def test_ovh_alert_emails(app, freezer, mailoutbox): with utils.mock_url(ovh_url, resp, 200) as mocked: connector.hourly() assert len(mailoutbox) == 1 + + +def test_ovh_token_request(admin_user, app): + connector = OVHSMSGateway.objects.create( + slug='test-ovh', title='Test OVH', account='sms-test42', + application_key='RHrTdU2oTsrVC0pu', + application_secret='CLjtS69tTcPgCKxedeoZlgMSoQGSiXMa', + ) + + app = login(app) + resp = app.get(connector.get_absolute_url()) + assert 'not operational yet' in resp.text + + ovh_request_token_url = 'https://eu.api.ovh.com/1.0/auth/credential' + ovh_response = { + 'consumerKey': 'xyz', + 'validationUrl': 'https://eu.api.ovh.com/auth/?credentialToken=iQ1joJE', + } + with utils.mock_url(ovh_request_token_url, ovh_response, 302) as mocked: + resp = resp.click('request access') + assert resp.url == 'https://eu.api.ovh.com/auth/?credentialToken=iQ1joJE' + + request = mocked.handlers[0].call['requests'][0] + body = json.loads(request.body) + assert 'accessRules' in body + redirect_url = body['redirection'][len(settings.SITE_BASE_URL):] + + resp = app.get(redirect_url).follow() + assert 'Successfuly completed connector configuration' in resp.text + connector.refresh_from_db() + assert connector.consumer_key == 'xyz' -- 2.20.1