add orange contact everyone SMS backend (#9163)

This commit is contained in:
Benjamin Dauvergne 2015-12-02 16:13:59 +01:00
parent 2fceba9aa4
commit fae0e39070
12 changed files with 259 additions and 0 deletions

View File

@ -5,6 +5,7 @@ recursive-include passerelle/apps/*/static *
# locales
recursive-include passerelle/locale *.po *.mo
include passerelle/apps/orange/orange.pem
include LICENSE
include MANIFEST.in
include VERSION

View File

View File

@ -0,0 +1,14 @@
from django.utils.text import slugify
from django import forms
from .models import OrangeSMSGateway
class OrangeSMSGatewayForm(forms.ModelForm):
class Meta:
model = OrangeSMSGateway
exclude = ('slug', 'users')
def save(self, commit=True):
if not self.instance.slug:
self.instance.slug = slugify(self.instance.title)
return super(OrangeSMSGatewayForm, self).save(commit=commit)

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import passerelle.sms
class Migration(migrations.Migration):
dependencies = [
('base', '0002_auto_20151009_0326'),
]
operations = [
migrations.CreateModel(
name='OrangeSMSGateway',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=50)),
('slug', models.SlugField()),
('description', models.TextField()),
('keystore', models.FileField(help_text='Certificate and private key in PEM format', upload_to=b'orange', null=True, verbose_name='Keystore', blank=True)),
('users', models.ManyToManyField(to='base.ApiUser', blank=True)),
],
options={
'db_table': 'sms_orange',
'verbose_name': 'Orange',
},
bases=(models.Model, passerelle.sms.SMSGatewayMixin),
),
]

View File

@ -0,0 +1,60 @@
import re
import urllib
import urllib2
import logging
import json
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.core.urlresolvers import reverse
from passerelle.base.models import BaseResource
from passerelle.sms import SMSGatewayMixin
from . import soap
class OrangeError(Exception):
pass
class OrangeSMSGateway(BaseResource, SMSGatewayMixin):
keystore = models.FileField(upload_to='orange',
blank=True, null=True,
verbose_name=_('Keystore'),
help_text=_('Certificate and private key in PEM format'))
default_country_code = '33'
class Meta:
verbose_name = 'Orange'
db_table = 'sms_orange'
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
@classmethod
def get_icon_class(cls):
return 'phone'
def get_absolute_url(self):
return reverse('orange-view', kwargs={'slug': self.slug})
@classmethod
def get_add_url(cls):
return reverse('orange-add')
def get_edit_url(self):
return reverse('orange-edit', kwargs={'slug': self.slug})
def get_delete_url(self):
return reverse('orange-delete', kwargs={'slug': self.slug})
def send(self, text, sender, destinations):
logger = logging.getLogger('passerelle.apps.orange')
"""Send a SMS using the Orange provider"""
# unfortunately it lacks a batch API...
destinations = self.clean_numbers(destinations, self.default_country_code)
logger.info(u'sending sms with sender %s to %s', sender, u', '.join(destinations))
logger.debug(u'sms content: %s', text)
soap.ContactEveryoneSoap(instance=self).send_advanced_message(destinations, sender, text)

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICWzCCAcQCAQAwDQYJKoZIhvcNAQEEBQAwdjELMAkGA1UEBhMCRlIxDzANBgNV
BAgTBkZyYW5jZTENMAsGA1UEBxMEQ2FlbjEXMBUGA1UEChMORnJhbmNlIFRlbGVj
b20xDDAKBgNVBAsTA0RQUzEMMAoGA1UEAxMDRERQMRIwEAYJKoZIhvcNAQkBFgNE
SU0wHhcNMDYxMTA4MjAyNDUxWhcNMTYxMTA1MjAyNDUxWjB2MQswCQYDVQQGEwJG
UjEPMA0GA1UECBMGRnJhbmNlMQ0wCwYDVQQHEwRDYWVuMRcwFQYDVQQKEw5GcmFu
Y2UgVGVsZWNvbTEMMAoGA1UECxMDRFBTMQwwCgYDVQQDEwNERFAxEjAQBgkqhkiG
9w0BCQEWA0RJTTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxp5nnfYr4ZsV
QgIzYkz42Urc+0z49cm8JL5DQAcceIUpWYnCOSjDCEivvkYlBGEaSQhx6goLgpAk
6264BhFIa9tFJBz0VCbZ5erGANNFpi1zK9nglfGMkfgQmPXFcVF+hi9ztff+WHGR
SknuxzXAICG0/PfPy/LcpVC9E35IkG8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQAk
plMn6da0Yu2YZ7dSP9UBrWygN3iD93Krk5H9KcJCFKXRcZsKw/871J+fFxOFxe5u
l/wraMBF+oo9aMBIsrHwzPkPr6/T3+cYScJAcoP0vRqGjbhio1BvoSvH4lsfmJsF
L9cgc58xgDNwztKHqggDtiFCWVEBpYk2jbMnoy7/xg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,76 @@
import logging
import datetime
import os.path
from passerelle.soap import Soap
from passerelle.xml_builder import XmlBuilder
class ContactEveryoneSoap(Soap):
WSDL_URL = ('https://www.api-contact-everyone.fr.orange-business.com/'
'ContactEveryone/services/MultiDiffusionWS?wsdl')
ORANGE_CERTIFICATE = os.path.join(os.path.dirname(__file__), 'orange.pem')
url = WSDL_URL
class ProfileListBuilder(XmlBuilder):
schema = (
'PROFILE_LIST',
('?loop', 'recipients',
('PROFILE',
('DEST_NAME', 'name_{to}'),
('DEST_FORENAME', 'forename_{to}'),
('DEST_ID', 'ID_{to}'),
('TERMINAL_GROUP',
('TERMINAL',
('TERMINAL_NAME', 'mobile1'),
('TERMINAL_ADDR', '{to}'),
('MEDIA_TYPE_GROUP',
('MEDIA_TYPE', 'sms')))))))
encoding = 'latin1'
@property
def verify(self):
# Do not break if certificate is not updated
if datetime.datetime.now() < datetime.datetime(2016, 11, 5):
return self.ORANGE_CERTIFICATE
else:
return False
def send_message(self, recipients, content):
client = self.get_client()
message = client.factory.create('WSMessage')
message.fullContenu = True
message.content = content
message.subject = content
message.resumeContent = content
message.strategy = 'sms'
send_profiles = self.ProfileListBuilder().string(
context={'recipients': [{'to': to} for to in recipients]})
message.sendProfiles = send_profiles
# XXX: handle webfault and other problems
try:
client.service.sendMessage(message)
except Exception, e:
logging.getLogger(__name__).exception('failed to send sms')
raise
def send_advanced_message(self, recipients, sender, content):
client = self.get_client()
message = client.factory.create('WSAdvancedMessage')
message.fullContenu = True
message.content = content
message.subject = content
message.resumeContent = content
message.strategy = 'sms'
message.smsReplyTo = sender
send_profiles = self.ProfileListBuilder().string(
context={'recipients': [{'to': to} for to in recipients]})
message.sendProfiles = send_profiles
# XXX: handle webfault and other problems
try:
return client.service.sendAdvancedMessage(message)
except Exception, e:
logging.getLogger(__name__).exception('failed to send sms')
raise

View File

@ -0,0 +1,13 @@
from django.conf.urls import patterns, url
from views import *
urlpatterns = patterns('',
url(r'^(?P<slug>[\w,-]+)/$', OrangeDetailView.as_view(), name='orange-view'),
url(r'^(?P<slug>[\w,-]+)/send$', OrangeSendView.as_view(), name='orange-send'),
)
management_urlpatterns = patterns('',
url(r'^add$', OrangeCreateView.as_view(), name='orange-add'),
url(r'^(?P<slug>[\w,-]+)/edit$', OrangeUpdateView.as_view(), name='orange-edit'),
url(r'^(?P<slug>[\w,-]+)/delete$', OrangeDeleteView.as_view(), name='orange-delete'),
)

View File

@ -0,0 +1,37 @@
from django.core.urlresolvers import reverse
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from passerelle.base.views import ResourceView
from passerelle.sms.views import SendView
from .models import OrangeSMSGateway
from .forms import OrangeSMSGatewayForm
class OrangeDetailView(ResourceView):
model = OrangeSMSGateway
template_name = 'passerelle/manage/messages_service_view.html'
class OrangeCreateView(CreateView):
model = OrangeSMSGateway
template_name = 'passerelle/manage/service_form.html'
form_class = OrangeSMSGatewayForm
class OrangeUpdateView(UpdateView):
model = OrangeSMSGateway
template_name = 'passerelle/manage/service_form.html'
form_class = OrangeSMSGatewayForm
class OrangeDeleteView(DeleteView):
model = OrangeSMSGateway
template_name = 'passerelle/manage/service_confirm_delete.html'
def get_success_url(self):
return reverse('manage-home')
class OrangeSendView(SendView):
model = OrangeSMSGateway

View File

@ -111,6 +111,7 @@ INSTALLED_APPS = (
'bdp',
'base_adresse',
'csvdatasource',
'orange',
# backoffice templates and static
'gadjo',
)
@ -123,6 +124,7 @@ PASSERELLE_APP_CHOOSIT_ENABLED = True
PASSERELLE_APP_OXYD_ENABLED = True
PASSERELLE_APP_OVH_ENABLED = True
PASSERELLE_APP_MOBYT_ENABLED = True
PASSERELLE_APP_ORANGE_ENABLED = True
PASSERELLE_APP_BDP_ENABLED = False
PASSERELLE_APP_GDC_ENABLED = False

View File

@ -22,6 +22,7 @@ import pastell.urls
import concerto.urls
import bdp.urls
import base_adresse.urls
import orange.urls
admin.autodiscover()
@ -131,6 +132,15 @@ urlpatterns += required(
)
)
urlpatterns += required(
app_enabled('orange'),
patterns('',
url(r'^orange/', include(orange.urls.urlpatterns)),
url(r'^manage/orange/',
decorated_includes(login_required, include(orange.urls.management_urlpatterns))),
)
)
# add patterns from apps
urlpatterns = register_apps_urls(urlpatterns)