0001-remove-tlmcom-connector-39778.patch
passerelle/contrib/tlmcom/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 |
import passerelle.pbx.models |
|
6 | ||
7 | ||
8 |
class Migration(migrations.Migration): |
|
9 | ||
10 |
dependencies = [ |
|
11 |
('base', '0002_auto_20151009_0326'), |
|
12 |
] |
|
13 | ||
14 |
operations = [ |
|
15 |
migrations.CreateModel( |
|
16 |
name='TlmCom', |
|
17 |
fields=[ |
|
18 |
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), |
|
19 |
('title', models.CharField(verbose_name='Title', max_length=50)), |
|
20 |
('slug', models.SlugField(verbose_name='Identifier', unique=True)), |
|
21 |
('description', models.TextField(verbose_name='Description')), |
|
22 |
('welco_url', models.URLField(default=passerelle.pbx.models.get_default_welco_url, max_length=120, verbose_name='welco URL')), |
|
23 |
('users', models.ManyToManyField(to='base.ApiUser', related_name='_tlmcom_users_+', related_query_name='+', blank=True)), |
|
24 |
], |
|
25 |
options={ |
|
26 |
'verbose_name': 'TLM COM gateway', |
|
27 |
'verbose_name_plural': 'TLM COM gateways', |
|
28 |
}, |
|
29 |
bases=(models.Model,), |
|
30 |
), |
|
31 |
] |
passerelle/contrib/tlmcom/migrations/0002_auto_20151222_0732.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('tlmcom', '0001_initial'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AlterModelOptions( |
|
15 |
name='tlmcom', |
|
16 |
options={'verbose_name': 'TLM COM PBX', 'verbose_name_plural': 'TLM COM PBX'}, |
|
17 |
), |
|
18 |
] |
passerelle/contrib/tlmcom/migrations/0003_tlmcom_log_level.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import models, migrations |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('tlmcom', '0002_auto_20151222_0732'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AddField( |
|
15 |
model_name='tlmcom', |
|
16 |
name='log_level', |
|
17 |
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]), |
|
18 |
preserve_default=True, |
|
19 |
), |
|
20 |
] |
passerelle/contrib/tlmcom/migrations/0004_auto_20170920_0951.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 |
from django.db import migrations, models |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('tlmcom', '0003_tlmcom_log_level'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.AlterField( |
|
15 |
model_name='tlmcom', |
|
16 |
name='slug', |
|
17 |
field=models.SlugField(verbose_name='Identifier', unique=True), |
|
18 |
), |
|
19 |
] |
passerelle/contrib/tlmcom/migrations/0005_remove_tlmcom_log_level.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.12 on 2018-11-18 14:07 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
from django.db import migrations |
|
6 | ||
7 | ||
8 |
class Migration(migrations.Migration): |
|
9 | ||
10 |
dependencies = [ |
|
11 |
('tlmcom', '0004_auto_20170920_0951'), |
|
12 |
] |
|
13 | ||
14 |
operations = [ |
|
15 |
migrations.RemoveField( |
|
16 |
model_name='tlmcom', |
|
17 |
name='log_level', |
|
18 |
), |
|
19 |
] |
passerelle/contrib/tlmcom/models.py | ||
---|---|---|
1 |
from passerelle.pbx.models import PBXMixin |
|
2 | ||
3 |
from django.utils.translation import ugettext_lazy as _ |
|
4 | ||
5 | ||
6 |
class TlmCom(PBXMixin): |
|
7 |
class Meta: |
|
8 |
verbose_name = _('TLM COM PBX') |
|
9 |
verbose_name_plural = _('TLM COM PBX') |
passerelle/contrib/tlmcom/templates/passerelle/contrib/tlmcom/detail.html | ||
---|---|---|
1 |
{% extends "passerelle/manage/service_view.html" %} |
|
2 |
{% load i18n passerelle %} |
|
3 | ||
4 |
{% block description %} |
|
5 |
{% endblock %} |
|
6 | ||
7 |
{% block endpoints %} |
|
8 |
<ul> |
|
9 |
<li>{% trans 'Call started' %} <a href="{% url 'tlmcom-call-start' slug=object.slug %}?caller=%2B3392323232&callee=102" |
|
10 |
>{{ site_base_uri }}{% url 'tlmcom-call-start' slug=object.slug %}?caller=+3392323232&callee=102</a></li> |
|
11 |
<li>{% trans 'Call stopped:' %} <a href="{% url 'tlmcom-call-stop' slug=object.slug %}?caller=%2B3392323232&callee=102" |
|
12 |
>{{ site_base_uri }}{% url 'tlmcom-call-stop' slug=object.slug %}?caller=+3392323232&callee=102</a></li> |
|
13 |
</ul> |
|
14 |
{% endblock %} |
|
15 | ||
16 |
{% block security %} |
|
17 |
<p> |
|
18 |
{% trans 'Access is limited to the following API users:' %} |
|
19 |
</p> |
|
20 |
{% access_rights_table resource=object permission='can_access' %} |
|
21 |
{% endblock %} |
passerelle/contrib/tlmcom/urls.py | ||
---|---|---|
1 |
# passerelle - uniform access to multiple data sources and services |
|
2 |
# Copyright (C) 2015 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.conf.urls import url |
|
18 |
from .views import TlmComDetailView, CallStart, CallStop |
|
19 | ||
20 |
urlpatterns = [ |
|
21 |
url(r'^(?P<slug>[\w,-]+)/$', |
|
22 |
TlmComDetailView.as_view(), name='tlmcom-view'), |
|
23 |
url(r'^(?P<slug>[\w,-]+)/call-start/$', |
|
24 |
CallStart.as_view(), name='tlmcom-call-start'), |
|
25 |
url(r'^(?P<slug>[\w,-]+)/call-stop/$', |
|
26 |
CallStop.as_view(), name='tlmcom-call-stop'), |
|
27 |
] |
passerelle/contrib/tlmcom/views.py | ||
---|---|---|
1 |
# passerelle - uniform access to multiple data sources and services |
|
2 |
# Copyright (C) 2015 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.views.generic import DetailView |
|
18 |
from django.views.generic.base import View |
|
19 |
from django.views.generic.detail import SingleObjectMixin |
|
20 |
from django.http import HttpResponse, HttpResponseBadRequest |
|
21 | ||
22 |
from .models import TlmCom |
|
23 | ||
24 | ||
25 |
class TlmComDetailView(DetailView): |
|
26 |
model = TlmCom |
|
27 |
template_name = 'passerelle/contrib/tlmcom/detail.html' |
|
28 | ||
29 | ||
30 |
class CallStart(SingleObjectMixin, View): |
|
31 |
event = 'start' |
|
32 |
model = TlmCom |
|
33 | ||
34 |
def get(self, request, *args, **kwargs): |
|
35 |
try: |
|
36 |
caller = request.GET['caller'] |
|
37 |
callee = request.GET['callee'] |
|
38 |
except KeyError: |
|
39 |
return HttpResponseBadRequest('caller and callee are mandatory') |
|
40 |
username = request.GET.get('id') |
|
41 |
if username: |
|
42 |
# "id" is a tlmcom dirty hack: the real username is just the part after the dot |
|
43 |
username = username.split('.', 1).pop() |
|
44 |
data = dict(request.GET.items()) |
|
45 |
for key in ['caller', 'callee', 'id']: |
|
46 |
data.pop(key, None) |
|
47 |
self.get_object().notify_welco(self.event, caller, username or callee, data) |
|
48 |
return HttpResponse('ok') |
|
49 | ||
50 | ||
51 |
class CallStop(CallStart): |
|
52 |
event = 'stop' |
passerelle/pbx/models.py | ||
---|---|---|
1 |
import json |
|
2 |
import logging |
|
3 | ||
4 |
from django.db import models |
|
5 |
from django.conf import settings |
|
6 |
from django.utils.encoding import force_text |
|
7 |
from django.utils.six import string_types |
|
8 |
from django.utils.translation import ugettext_lazy as _ |
|
9 | ||
10 |
import requests |
|
11 | ||
12 |
from passerelle.base.models import BaseResource |
|
13 | ||
14 | ||
15 |
def get_default_welco_url(): |
|
16 |
'''Get default welco URL from a setting than can be set in a Publik |
|
17 |
setting. |
|
18 |
''' |
|
19 |
return getattr(settings, 'PASSERELLE_DEFAULT_WELCO_URL', '') |
|
20 | ||
21 | ||
22 |
class PBXMixin(BaseResource): |
|
23 |
welco_url = models.URLField( |
|
24 |
verbose_name=_('welco URL'), |
|
25 |
default=get_default_welco_url, |
|
26 |
max_length=120) |
|
27 | ||
28 |
category = _('Telephony') |
|
29 | ||
30 |
def notify_welco(self, event, caller, callee, data=None): |
|
31 |
assert event in ('start', 'stop') |
|
32 |
assert isinstance(caller, string_types) |
|
33 |
assert isinstance(callee, string_types) |
|
34 |
assert not data or isinstance(data, dict) |
|
35 |
caller = force_text(caller) |
|
36 |
callee = force_text(callee) |
|
37 |
event = force_text(event) |
|
38 | ||
39 |
payload = { |
|
40 |
'event': event, |
|
41 |
'caller': caller, |
|
42 |
'callee': callee, |
|
43 |
} |
|
44 |
if data: |
|
45 |
payload['data'] = data |
|
46 |
requests.post(self.welco_url, data=json.dumps(payload), |
|
47 |
headers={'content-type': 'application/json'}) |
|
48 |
self.logger.info(u'notified welco of event %s from %s to %s', |
|
49 |
event, caller, callee) |
|
50 | ||
51 |
class Meta: |
|
52 |
abstract = True |
tests/settings.py | ||
---|---|---|
35 | 35 |
'passerelle.contrib.strasbourg_eu', |
36 | 36 |
'passerelle.contrib.stub_invoices', |
37 | 37 |
'passerelle.contrib.teamnet_axel', |
38 |
'passerelle.contrib.tlmcom', |
|
39 | 38 |
'passerelle.contrib.tcl', |
40 | 39 |
'passerelle.contrib.toulouse_axel', |
41 | 40 |
'passerelle.contrib.lille_kimoce', |
tests/test_tlmcom.py | ||
---|---|---|
1 |
import json |
|
2 |
import pytest |
|
3 |
import mock |
|
4 | ||
5 |
from django.core.urlresolvers import reverse |
|
6 | ||
7 |
from passerelle.contrib.tlmcom.models import TlmCom |
|
8 | ||
9 |
pytestmark = pytest.mark.django_db |
|
10 | ||
11 | ||
12 |
@mock.patch('requests.post') |
|
13 |
def test_call_start(requests_post, client): |
|
14 |
URL = 'http://welco.example.net/' |
|
15 |
TlmCom.objects.create(slug='tlmcom', description='tlmcom', welco_url=URL) |
|
16 |
url = reverse('tlmcom-call-start', kwargs={'slug': 'tlmcom'}) \ |
|
17 |
+ '?caller=0033699999999&callee=102&user=zozo' |
|
18 |
response = client.get(url) |
|
19 |
assert response.status_code == 200 |
|
20 |
assert response.content == b'ok' |
|
21 |
assert requests_post.call_count == 1 |
|
22 | ||
23 |
assert requests_post.call_args == mock.call(URL, data=mock.ANY, headers={'content-type': 'application/json'}) |
|
24 |
payload = json.loads(requests_post.call_args[1]['data']) |
|
25 |
assert isinstance(payload, dict) |
|
26 |
assert set(payload.keys()) == set(['data', 'caller', 'callee', 'event']) |
|
27 |
assert payload['event'] == 'start' |
|
28 |
assert payload['data'] == {'user': 'zozo'} |
|
29 |
assert payload['callee'] == '102' |
|
30 |
assert payload['caller'] == '0033699999999' |
|
31 | ||
32 |
@mock.patch('requests.post') |
|
33 |
def test_call_stop(requests_post, client): |
|
34 |
URL = 'http://welco.example.net/' |
|
35 |
TlmCom.objects.create(slug='tlmcom', description='tlmcom', welco_url=URL) |
|
36 |
url = reverse('tlmcom-call-stop', kwargs={'slug': 'tlmcom'}) \ |
|
37 |
+ '?caller=0033699999999&callee=102&user=zozo' |
|
38 |
response = client.get(url) |
|
39 |
assert response.status_code == 200 |
|
40 |
assert response.content == b'ok' |
|
41 |
assert requests_post.call_count == 1 |
|
42 | ||
43 |
assert requests_post.call_args == mock.call(URL, data=mock.ANY, headers={'content-type': 'application/json'}) |
|
44 |
payload = json.loads(requests_post.call_args[1]['data']) |
|
45 |
assert isinstance(payload, dict) |
|
46 |
assert set(payload.keys()) == set(['data', 'caller', 'callee', 'event']) |
|
47 |
assert payload['event'] == 'stop' |
|
48 |
assert payload['data'] == {'user': 'zozo'} |
|
49 |
assert payload['callee'] == '102' |
|
50 |
assert payload['caller'] == '0033699999999' |
|
51 | ||
52 |
@mock.patch('requests.post') |
|
53 |
def test_call_start_with_id(requests_post, client): |
|
54 |
URL = 'http://welco.example.net/' |
|
55 |
TlmCom.objects.create(slug='tlmcom', description='tlmcom', welco_url=URL) |
|
56 |
url = reverse('tlmcom-call-start', kwargs={'slug': 'tlmcom'}) \ |
|
57 |
+ '?caller=0033699999999&callee=102&id=.zozo&idTLMCOM=XXXXXX01' |
|
58 |
response = client.get(url) |
|
59 |
assert response.status_code == 200 |
|
60 |
assert response.content == b'ok' |
|
61 |
assert requests_post.call_count == 1 |
|
62 | ||
63 |
assert requests_post.call_args == mock.call(URL, data=mock.ANY, headers={'content-type': 'application/json'}) |
|
64 |
payload = json.loads(requests_post.call_args[1]['data']) |
|
65 |
assert isinstance(payload, dict) |
|
66 |
assert set(payload.keys()) == set(['caller', 'callee', 'event', 'data']) |
|
67 |
assert payload['event'] == 'start' |
|
68 |
assert payload['callee'] == 'zozo' |
|
69 |
assert payload['caller'] == '0033699999999' |
|
70 |
assert payload['data'] == {'idTLMCOM': 'XXXXXX01'} |
|
71 | ||
72 |
@mock.patch('requests.post') |
|
73 |
def test_call_stop_with_id(requests_post, client): |
|
74 |
URL = 'http://welco.example.net/' |
|
75 |
TlmCom.objects.create(slug='tlmcom', description='tlmcom', welco_url=URL) |
|
76 |
url = reverse('tlmcom-call-stop', kwargs={'slug': 'tlmcom'}) \ |
|
77 |
+ '?caller=0033699999999&callee=102&id=.zozo&idTLMCOM=XXXXXX01' |
|
78 |
response = client.get(url) |
|
79 |
assert response.status_code == 200 |
|
80 |
assert response.content == b'ok' |
|
81 |
assert requests_post.call_count == 1 |
|
82 | ||
83 |
assert requests_post.call_args == mock.call(URL, data=mock.ANY, headers={'content-type': 'application/json'}) |
|
84 |
payload = json.loads(requests_post.call_args[1]['data']) |
|
85 |
assert isinstance(payload, dict) |
|
86 |
assert set(payload.keys()) == set(['caller', 'callee', 'event', 'data']) |
|
87 |
assert payload['event'] == 'stop' |
|
88 |
assert payload['callee'] == 'zozo' |
|
89 |
assert payload['caller'] == '0033699999999' |
|
90 |
assert payload['data'] == {'idTLMCOM': 'XXXXXX01'} |
|
91 |
- |