sendethic: add send ethic sms connector (#81143)
gitea/passerelle/pipeline/head This commit looks good
Details
gitea/passerelle/pipeline/head This commit looks good
Details
This commit is contained in:
parent
5fe9b9a1e6
commit
199075ed80
|
@ -0,0 +1,116 @@
|
|||
# Generated by Django 3.2.18 on 2023-09-18 17:55
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
import passerelle.sms.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('base', '0030_resourcelog_base_resour_appname_298cbc_idx'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SendEthicSMSGateway',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||
('description', models.TextField(verbose_name='Description')),
|
||||
(
|
||||
'default_country_code',
|
||||
models.CharField(
|
||||
default='33',
|
||||
max_length=3,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
'^[0-9]*$', 'The country must only contain numbers'
|
||||
)
|
||||
],
|
||||
verbose_name='Default country code',
|
||||
),
|
||||
),
|
||||
(
|
||||
'default_trunk_prefix',
|
||||
models.CharField(
|
||||
default='0',
|
||||
max_length=2,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
'^[0-9]*$', 'The trunk prefix must only contain numbers'
|
||||
)
|
||||
],
|
||||
verbose_name='Default trunk prefix',
|
||||
),
|
||||
),
|
||||
(
|
||||
'max_message_length',
|
||||
models.IntegerField(
|
||||
default=2000,
|
||||
help_text='Messages over this limit will be truncated.',
|
||||
verbose_name='Maximum message length',
|
||||
),
|
||||
),
|
||||
(
|
||||
'authorized',
|
||||
django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.CharField(
|
||||
choices=[
|
||||
('fr-metro', 'France mainland (+33 [67])'),
|
||||
('fr-domtom', 'France DOM/TOM (+262, etc.)'),
|
||||
('be', 'Belgian (+32 4[5-9]) '),
|
||||
('all', 'All'),
|
||||
],
|
||||
max_length=32,
|
||||
null=True,
|
||||
),
|
||||
default=passerelle.sms.models.authorized_default,
|
||||
size=None,
|
||||
verbose_name='Authorized Countries',
|
||||
),
|
||||
),
|
||||
(
|
||||
'credit_threshold_alert',
|
||||
models.PositiveIntegerField(default=500, verbose_name='Credit alert threshold'),
|
||||
),
|
||||
(
|
||||
'credit_left',
|
||||
models.PositiveIntegerField(default=0, editable=False, verbose_name='Credit left'),
|
||||
),
|
||||
(
|
||||
'alert_emails',
|
||||
django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.EmailField(blank=True, max_length=254),
|
||||
blank=True,
|
||||
null=True,
|
||||
size=None,
|
||||
verbose_name='Email addresses list to send credit alerts to, separated by comma',
|
||||
),
|
||||
),
|
||||
('credit_alert_timestamp', models.DateTimeField(editable=False, null=True)),
|
||||
('account_id', models.CharField(max_length=255, verbose_name='Account ID')),
|
||||
('api_key', models.CharField(max_length=255, verbose_name='API Key')),
|
||||
(
|
||||
'users',
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name='_sendethic_sendethicsmsgateway_users_+',
|
||||
related_query_name='+',
|
||||
to='base.ApiUser',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Sendethic',
|
||||
'db_table': 'sms_send_ethic',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,141 @@
|
|||
# passerelle - uniform access to multiple data sources and services
|
||||
# Copyright (C) 2022 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# 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 urllib.parse
|
||||
|
||||
import requests
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passerelle.sms.models import TrackCreditSMSResource
|
||||
from passerelle.utils.jsonresponse import APIError
|
||||
|
||||
|
||||
class SendEthicSMSGateway(TrackCreditSMSResource):
|
||||
account_id = models.CharField(verbose_name=_('Account ID'), max_length=255)
|
||||
api_key = models.CharField(verbose_name=_('API Key'), max_length=255)
|
||||
|
||||
# unecessary field
|
||||
allow_premium_rate = None
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Sendethic'
|
||||
db_table = 'sms_send_ethic'
|
||||
|
||||
TEST_DEFAULTS = {
|
||||
'create_kwargs': {
|
||||
'account_id': 'yyy',
|
||||
'api_key': 'www',
|
||||
'credit_threshold_alert': 1000,
|
||||
},
|
||||
'test_vectors': [
|
||||
{
|
||||
'status_code': 400,
|
||||
'response': {'Message': 'Grève des PTT.'},
|
||||
'result': {
|
||||
'err': 1,
|
||||
'err_desc': 'Sendethic error: some destinations failed',
|
||||
'data': [],
|
||||
},
|
||||
},
|
||||
{
|
||||
'status_code': 400,
|
||||
'response': {'no_error_field_in_message': True},
|
||||
'result': {
|
||||
'err': 1,
|
||||
'err_desc': 'Sendethic error: some destinations failed',
|
||||
'data': [],
|
||||
},
|
||||
},
|
||||
{
|
||||
'status_code': 200,
|
||||
'response': '"OK"',
|
||||
'result': {
|
||||
'err': 0,
|
||||
'data': {},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
URL = 'https://services.message-business.com/api/rest/v4/'
|
||||
|
||||
TEST_CREDIT_LEFT = {
|
||||
'create_kwargs': {
|
||||
'account_id': 'yyy',
|
||||
'api_key': 'www',
|
||||
},
|
||||
'url': urllib.parse.urljoin(URL, 'account/remainingcredits/sms'),
|
||||
'get_credit_left_payload': lambda x: {'used': 1, 'remaining': x, 'total': 2000},
|
||||
}
|
||||
|
||||
def request(self, method, endpoint, **kwargs):
|
||||
url = urllib.parse.urljoin(self.URL, endpoint)
|
||||
|
||||
headers = {'Accept': 'application/json'}
|
||||
|
||||
try:
|
||||
response = self.requests.request(
|
||||
method,
|
||||
url,
|
||||
headers=headers,
|
||||
auth=(self.account_id, self.api_key),
|
||||
**kwargs,
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
return False, 'Request failed, %s' % e
|
||||
|
||||
try:
|
||||
result = response.json()
|
||||
if not response.ok:
|
||||
result = result['Message']
|
||||
except (ValueError, KeyError):
|
||||
return False, 'Bad JSON response'
|
||||
|
||||
return response.ok, result
|
||||
|
||||
def send_msg(self, text, sender, destinations, **kwargs):
|
||||
# Destination numbers received here were normalized through
|
||||
# self.clean_number() : they are of the form 00612345678. Remove
|
||||
# the trailing 00 and replace it with '+', so Sendethic accepts them.
|
||||
destinations = [f'+{dest[2:]}' for dest in destinations]
|
||||
errors = []
|
||||
|
||||
for dest in destinations:
|
||||
params = {
|
||||
'message': text,
|
||||
'mobile': dest,
|
||||
}
|
||||
|
||||
if sender:
|
||||
params['oadc'] = sender
|
||||
|
||||
success, message = self.request('post', 'sms/send/', json=params)
|
||||
if not success:
|
||||
errors.append(message)
|
||||
|
||||
if errors:
|
||||
raise APIError('Sendethic error: some destinations failed', data=errors)
|
||||
|
||||
def update_credit_left(self):
|
||||
success, result = self.request('get', endpoint='account/remainingcredits/sms/')
|
||||
|
||||
if not success:
|
||||
self.logger.warning('Cannot retrieve credits for Sendethic connector: %s', result)
|
||||
|
||||
try:
|
||||
self.credit_left = int(result['remaining'])
|
||||
self.save(update_fields=['credit_left'])
|
||||
except KeyError:
|
||||
self.logger.warning('Cannot retrieve credits for Sendethic connector: %s', result)
|
|
@ -186,6 +186,7 @@ INSTALLED_APPS = (
|
|||
'passerelle.apps.solis',
|
||||
'passerelle.apps.twilio',
|
||||
'passerelle.apps.vivaticket',
|
||||
'passerelle.apps.sendethic',
|
||||
# backoffice templates and static
|
||||
'gadjo',
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue