add basic connector for lille urban card (#33863)
This commit is contained in:
parent
e2eff9d82a
commit
06a05d5a9b
|
@ -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',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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}
|
|
@ -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',
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue