ovh: update credit left (#46316)
This commit is contained in:
parent
fa1f64f85f
commit
153a91373d
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.18 on 2020-10-08 09:26
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ovh', '0009_auto_20200730_1047'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='ovhsmsgateway',
|
||||
name='credit_left',
|
||||
field=models.PositiveIntegerField(default=0, editable=False, verbose_name='Credit left'),
|
||||
),
|
||||
]
|
|
@ -2,6 +2,7 @@ import hashlib
|
|||
import json
|
||||
import requests
|
||||
import time
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from django.db import models
|
||||
from django.utils.encoding import force_text
|
||||
|
@ -13,8 +14,8 @@ from passerelle.utils.jsonresponse import APIError
|
|||
|
||||
class OVHSMSGateway(SMSResource):
|
||||
documentation_url = 'https://doc-publik.entrouvert.com/admin-fonctionnel/les-tutos/configuration-envoi-sms/'
|
||||
hide_description_fields = ['account']
|
||||
API_URL = 'https://eu.api.ovh.com/1.0/sms/%(serviceName)s/users/%(login)s/jobs/'
|
||||
hide_description_fields = ['account', 'credit_left']
|
||||
API_URL = 'https://eu.api.ovh.com/1.0/sms/%(serviceName)s/'
|
||||
URL = 'https://www.ovh.com/cgi-bin/sms/http2sms.cgi'
|
||||
MESSAGES_CLASSES = (
|
||||
(0, _('Message are directly shown to users on phone screen '
|
||||
|
@ -53,23 +54,24 @@ class OVHSMSGateway(SMSResource):
|
|||
)
|
||||
|
||||
username = models.CharField(
|
||||
verbose_name=_('Username'),
|
||||
verbose_name=_('Username (deprecated)'),
|
||||
max_length=64,
|
||||
help_text=_('API user created on the SMS account.'),
|
||||
help_text=_('API user created on the SMS account. This field is obsolete once keys and secret '
|
||||
'fields above are filled.'),
|
||||
)
|
||||
password = models.CharField(
|
||||
verbose_name=_('Password (deprecated)'),
|
||||
max_length=64,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
'Password for legacy API. This field is obsolete once keys and secret fields below are filled.'
|
||||
'Password for legacy API. This field is obsolete once keys and secret fields above are filled.'
|
||||
),
|
||||
)
|
||||
msg_class = models.IntegerField(choices=MESSAGES_CLASSES, default=1,
|
||||
verbose_name=_('Message class'))
|
||||
credit_threshold_alert = models.PositiveIntegerField(verbose_name=_('Credit alert threshold'),
|
||||
default=100)
|
||||
credit_left = models.PositiveIntegerField(verbose_name=_('Credit left'), default=0)
|
||||
credit_left = models.PositiveIntegerField(verbose_name=_('Credit left'), default=0, editable=False)
|
||||
|
||||
TEST_DEFAULTS = {
|
||||
'create_kwargs': {
|
||||
|
@ -114,24 +116,19 @@ class OVHSMSGateway(SMSResource):
|
|||
verbose_name = 'OVH'
|
||||
db_table = 'sms_ovh'
|
||||
|
||||
def send_msg(self, text, sender, destinations, **kwargs):
|
||||
if not (self.application_key and self.consumer_key and self.application_secret):
|
||||
return self.send_msg_legacy(text, sender, destinations, **kwargs)
|
||||
@property
|
||||
def uses_new_api(self):
|
||||
return self.application_key and self.consumer_key and self.application_secret
|
||||
|
||||
def request(self, method, endpoint, **kwargs):
|
||||
url = self.API_URL % {'serviceName': self.account, 'login': self.username}
|
||||
body = {
|
||||
'sender': sender,
|
||||
'receivers': destinations,
|
||||
'message': text,
|
||||
'class': self.NEW_MESSAGES_CLASSES[self.msg_class],
|
||||
}
|
||||
if not kwargs['stop']:
|
||||
body.update({'noStopClause': True})
|
||||
url = urljoin(url, endpoint)
|
||||
|
||||
# sign request
|
||||
body = json.dumps(kwargs['json']) if 'json' in kwargs else ''
|
||||
now = str(int(time.time()))
|
||||
signature = hashlib.sha1()
|
||||
to_sign = "+".join((self.application_secret, self.consumer_key, 'POST', url, json.dumps(body), now))
|
||||
to_sign = "+".join((self.application_secret, self.consumer_key, method.upper(), url, body, now))
|
||||
signature.update(to_sign.encode())
|
||||
|
||||
headers = {
|
||||
|
@ -142,7 +139,7 @@ class OVHSMSGateway(SMSResource):
|
|||
}
|
||||
|
||||
try:
|
||||
response = self.requests.post(url, headers=headers, json=body)
|
||||
response = self.requests.request(method, url, headers=headers, **kwargs)
|
||||
except requests.RequestException as e:
|
||||
raise APIError('OVH error: POST failed, %s' % e)
|
||||
else:
|
||||
|
@ -154,6 +151,22 @@ class OVHSMSGateway(SMSResource):
|
|||
response.raise_for_status()
|
||||
except requests.RequestException as e:
|
||||
raise APIError('OVH error: %s "%s"' % (e, result))
|
||||
return result
|
||||
|
||||
def send_msg(self, text, sender, destinations, **kwargs):
|
||||
if not self.uses_new_api:
|
||||
return self.send_msg_legacy(text, sender, destinations, **kwargs)
|
||||
|
||||
body = {
|
||||
'sender': sender,
|
||||
'receivers': destinations,
|
||||
'message': text,
|
||||
'class': self.NEW_MESSAGES_CLASSES[self.msg_class],
|
||||
}
|
||||
if not kwargs['stop']:
|
||||
body.update({'noStopClause': True})
|
||||
|
||||
result = self.request('post', 'jobs/', json=body)
|
||||
|
||||
ret = {}
|
||||
credits_removed = result['totalCreditsRemoved']
|
||||
|
@ -161,7 +174,7 @@ class OVHSMSGateway(SMSResource):
|
|||
self.credit_left -= credits_removed
|
||||
if self.credit_left < 0:
|
||||
self.credit_left = 0
|
||||
self.save()
|
||||
self.save(update_credit=False)
|
||||
if self.credit_left < self.credit_threshold_alert:
|
||||
ret['warning'] = 'credit level too low for %s: %s (threshold %s)' % (
|
||||
self.slug,
|
||||
|
@ -174,6 +187,22 @@ class OVHSMSGateway(SMSResource):
|
|||
|
||||
return ret
|
||||
|
||||
def update_credit_left(self):
|
||||
if not self.uses_new_api:
|
||||
return
|
||||
result = self.request('get', endpoint='')
|
||||
self.credit_left = result['creditsLeft']
|
||||
self.save(update_credit=False)
|
||||
|
||||
def hourly(self):
|
||||
super().hourly()
|
||||
self.update_credit_left()
|
||||
|
||||
def save(self, *args, update_credit=True, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if update_credit:
|
||||
self.add_job('update_credit_left')
|
||||
|
||||
def send_msg_legacy(self, text, sender, destinations, **kwargs):
|
||||
"""Send a SMS using the HTTP2 endpoint"""
|
||||
if not self.password:
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{% extends "passerelle/manage/messages_service_view.html" %}
|
||||
{% load i18n passerelle %}
|
||||
|
||||
{% block description %}
|
||||
{{ block.super }}
|
||||
{% if object.uses_new_api %}
|
||||
<p>
|
||||
{% if object.credit_left %}
|
||||
<b>{% trans "Credit left:" %}</b> {{ object.credit_left }}
|
||||
{% else %}
|
||||
<b>{% trans "There is no credit left." %}</b>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -69,14 +69,14 @@ def test_connectors(app, connector, freezer):
|
|||
test_vectors = getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', [])
|
||||
total = len(test_vectors)
|
||||
nb_failed = 0
|
||||
assert Job.objects.count() == 0
|
||||
assert Job.objects.filter(method_name='send_job').count() == 0
|
||||
for test_vector in test_vectors:
|
||||
|
||||
# register job
|
||||
freezer.move_to('2019-01-01 00:00:00')
|
||||
result = app.post_json(path, params=payload)
|
||||
assert result.json['err'] == 0
|
||||
job_id = Job.objects.get(status='registered').id
|
||||
job_id = Job.objects.get(method_name='send_job', status='registered').id
|
||||
|
||||
# perform job
|
||||
freezer.move_to('2019-01-01 01:00:03')
|
||||
|
@ -92,7 +92,7 @@ def test_connectors(app, connector, freezer):
|
|||
nb_failed += 1
|
||||
else:
|
||||
assert job.status == 'completed'
|
||||
assert Job.objects.count() == total
|
||||
assert Job.objects.filter(method_name='send_job').count() == total
|
||||
assert SMSLog.objects.count() == total - nb_failed
|
||||
|
||||
|
||||
|
@ -186,7 +186,7 @@ def test_sms_nostop_parameter(app, connector):
|
|||
|
||||
def test_ovh_new_api(app, freezer):
|
||||
connector = OVHSMSGateway.objects.create(
|
||||
slug='ovh', account='sms-test42', username='john',
|
||||
slug='ovh', account='sms-test42',
|
||||
application_key='RHrTdU2oTsrVC0pu',
|
||||
application_secret='CLjtS69tTcPgCKxedeoZlgMSoQGSiXMa',
|
||||
consumer_key='iF0zi0MJrbjNcI3hvuvwkhNk8skrigxz'
|
||||
|
@ -208,7 +208,7 @@ def test_ovh_new_api(app, freezer):
|
|||
path = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
|
||||
result = app.post_json(path, params=payload)
|
||||
assert result.json['err'] == 0
|
||||
job_id = Job.objects.get(status='registered').id
|
||||
job_id = Job.objects.get(method_name='send_job', status='registered').id
|
||||
|
||||
# perform job
|
||||
freezer.move_to('2019-01-01 01:00:03')
|
||||
|
@ -218,7 +218,8 @@ def test_ovh_new_api(app, freezer):
|
|||
'ids': [241615100],
|
||||
'invalidReceivers': []
|
||||
}
|
||||
url = connector.API_URL % {'serviceName': 'sms-test42', 'login': 'john'}
|
||||
base_url = connector.API_URL % {'serviceName': 'sms-test42'}
|
||||
url = base_url + 'jobs/'
|
||||
with utils.mock_url(url, resp, 200) as mocked:
|
||||
connector.jobs()
|
||||
job = Job.objects.get(id=job_id)
|
||||
|
@ -255,3 +256,36 @@ def test_sms_test_send(admin_user, app, connector):
|
|||
}
|
||||
assert resp.status_code == 302
|
||||
assert resp.location == url
|
||||
|
||||
|
||||
def test_ovh_new_api_credit(app, freezer):
|
||||
connector = OVHSMSGateway.objects.create(
|
||||
slug='ovh', account='sms-test42',
|
||||
application_key='RHrTdU2oTsrVC0pu',
|
||||
application_secret='CLjtS69tTcPgCKxedeoZlgMSoQGSiXMa',
|
||||
consumer_key='iF0zi0MJrbjNcI3hvuvwkhNk8skrigxz'
|
||||
)
|
||||
|
||||
manager_url = '/%s/%s/' % (connector.get_connector_slug(), connector.slug)
|
||||
resp = app.get(manager_url)
|
||||
assert 'no credit left' in resp.text
|
||||
|
||||
# a job to update credit was added on connector creation
|
||||
resp = {
|
||||
'creditsLeft': 123,
|
||||
}
|
||||
ovh_url = connector.API_URL % {'serviceName': 'sms-test42'}
|
||||
with utils.mock_url(ovh_url, resp, 200) as mocked:
|
||||
connector.jobs()
|
||||
assert connector.credit_left == 123
|
||||
|
||||
resp = app.get(manager_url)
|
||||
assert '123' in resp.text
|
||||
|
||||
# hourly update
|
||||
resp = {
|
||||
'creditsLeft': 456,
|
||||
}
|
||||
with utils.mock_url(ovh_url, resp, 200) as mocked:
|
||||
connector.hourly()
|
||||
assert connector.credit_left == 456
|
||||
|
|
Loading…
Reference in New Issue