add basic connector for lille urban card (#33863)

This commit is contained in:
Frédéric Péters 2019-06-12 10:02:07 +02:00
parent e2eff9d82a
commit 06a05d5a9b
6 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2019-06-12 05:57
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('base', '0013_delete_templatevar'),
]
operations = [
migrations.CreateModel(
name='LilleUrbanCard',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50, verbose_name='Title')),
('description', models.TextField(verbose_name='Description')),
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
('base_url', models.URLField(help_text='API base URL', max_length=256, verbose_name='Base URL')),
('username', models.CharField(max_length=128, verbose_name='Username')),
('password', models.CharField(max_length=128, verbose_name='Password')),
('users', models.ManyToManyField(blank=True, related_name='_lilleurbancard_users_+', related_query_name='+', to='base.ApiUser')),
],
options={
'verbose_name': 'Lille Urban Card',
},
),
]

View File

@ -0,0 +1,107 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2019 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 json
import re
from django.db import models
from django.utils.six.moves.urllib_parse import urljoin
from django.utils.translation import ugettext_lazy as _
from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
from passerelle.utils.http_authenticators import HttpBearerAuth
from passerelle.utils.jsonresponse import APIError
from passerelle.sms import SMSGatewayMixin
class TokenError(APIError):
pass
class LilleUrbanCard(BaseResource):
base_url = models.URLField(max_length=256, blank=False,
verbose_name=_('Base URL'),
help_text=_('API base URL'))
username = models.CharField(max_length=128, verbose_name=_('Username'))
password = models.CharField(max_length=128, verbose_name=_('Password'))
category = 'Lille'
class Meta:
verbose_name = _('Lille Urban Card')
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
def check_status(self):
self.get_token()
def get_token(self):
response = self.requests.post(
urljoin(self.base_url, '/clu/ws/auth/connexion'),
json={'login': self.username, 'password': self.password}).json()
if response.get('erreur'):
self.logger.error('error getting token (%r)', response['erreur'])
raise TokenError(response['erreur'])
return response['token']
@endpoint(perm='can_access', description=_('Card Request'), methods=['post'])
def card_request(self, request, *args, **kwargs):
data = json.loads(request.body)
for kind_of_optional_field in ('nom_naissance', 'telephone', 'complement_numero_voie'):
if not data.get(kind_of_optional_field):
data[kind_of_optional_field] = ''
for boolean_field in ('recevoir_journal_senior', 'recevoir_msg_info_senior'):
if data.get(boolean_field) == 'Oui':
data[boolean_field] = 1
else:
data[boolean_field] = 0
if data.get('telephone'):
data['telephone'] = ''.join(re.findall(r'\d', data['telephone']))
if data['civilite'] == 'Monsieur':
data['civilite'] = 1
else:
data['civilite'] = 2
data['code_postal'] = int(data['code_postal'])
data['ville'] = data['ville'].upper()
data['photo'] = data['photo']['content']
services = {}
for key in sorted(data.keys()):
if key.startswith('service_'):
service = key.split('_')[1]
if key.count('_') == 1: # ex: service_zoo
if data[key] == 'Oui':
services[service] = {'service': service}
else: # ex: service_zoo_newsletter
attr = key.split('_')[2]
if data[key] == 'Oui':
services[service][attr] = 1
else:
services[service][attr] = 0
del data[key]
data['services'] = services.values()
response = self.requests.post(
urljoin(self.base_url, '/clu/ws/demanderCarte'),
json=data,
auth=HttpBearerAuth(self.get_token())).json()
if response.get('erreur'):
self.logger.error('error requesting card (%r)', response['erreur'])
raise APIError(response['erreur'])
return {'data': response} # {"n_demande_clu":10000005}

View File

@ -25,6 +25,7 @@ INSTALLED_APPS += (
'passerelle.contrib.grenoble_gru',
'passerelle.contrib.iparapheur',
'passerelle.contrib.iws',
'passerelle.contrib.lille_urban_card',
'passerelle.contrib.maarch',
'passerelle.contrib.mdel',
'passerelle.contrib.mdph13',

View File

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
from httmock import HTTMock
import json
import mock
import pytest
from passerelle.contrib.lille_urban_card.models import LilleUrbanCard
from passerelle.utils.jsonresponse import APIError
import utils
@pytest.fixture
def connector(db):
return utils.setup_access_rights(
LilleUrbanCard.objects.create(
slug='test',
base_url='http://localhost',
username='test',
password='secret'))
TOKEN_ERROR_RESPONSE = '{"erreur":"Authentification échouée"}'
TOKEN_RESPONSE = '{"token": "eyJhbGciO..."}'
def mocked_http(url, request):
if url.path == '/clu/ws/auth/connexion':
return {'content': TOKEN_RESPONSE, 'status_code': 200}
if url.path == '/clu/ws/demanderCarte':
content = {
'n_demande_clu': 10000005,
'request': json.loads(request.body), # for tests
}
return {'content': json.dumps(content), 'status_code': 200}
@mock.patch('passerelle.utils.Request.post')
def test_get_token(mocked_post, app, connector):
with pytest.raises(APIError):
mocked_post.return_value = utils.FakedResponse(content=TOKEN_ERROR_RESPONSE, status_code=400)
connector.get_token()
mocked_post.return_value = utils.FakedResponse(content=TOKEN_RESPONSE, status_code=200)
connector.get_token()
def test_card_request(app, connector):
endpoint = utils.generic_endpoint_url('lille-urban-card', 'card_request', slug=connector.slug)
with HTTMock(mocked_http):
resp = app.post_json(endpoint, params={
'civilite': 'Monsieur',
'code_postal': '59000',
'ville': 'Lille',
'photo': {'content': 'xxx'},
'telephone': '01.02.03.04.05',
'recevoir_journal_senior': 'Non',
'service_zoo': 'Oui',
'service_zoo_newsletter': 'Non',
})
request = resp.json['data']['request']
assert request['civilite'] == 1
assert request['code_postal'] == 59000
assert request['ville'] == 'LILLE'
assert request['photo'] == 'xxx'
assert request['telephone'] == '0102030405'
assert request['services'] == [{'service': 'zoo', 'newsletter': 0}]
assert resp.json['data']['n_demande_clu'] == 10000005