0002-caluire-axel-link-endpoint-53704.patch
functests/caluire_axel/conftest.py | ||
---|---|---|
1 |
import pytest |
|
2 | ||
3 | ||
4 |
def pytest_addoption(parser): |
|
5 |
parser.addoption("--url", help="Url of a passerelle Caluire Axel connector instance") |
|
6 |
parser.addoption("--nameid", help="Publik Name ID") |
|
7 |
parser.addoption("--firstname", help="first name of a user") |
|
8 |
parser.addoption("--lastname", help="Last name of a user") |
|
9 |
parser.addoption("--family", help="Family ID") |
|
10 | ||
11 | ||
12 |
@pytest.fixture(scope='session') |
|
13 |
def conn(request): |
|
14 |
return request.config.getoption("--url") |
|
15 | ||
16 | ||
17 |
@pytest.fixture(scope='session') |
|
18 |
def user(request): |
|
19 |
return { |
|
20 |
'name_id': request.config.getoption("--nameid"), |
|
21 |
'first_name': request.config.getoption("--firstname"), |
|
22 |
'last_name': request.config.getoption("--lastname"), |
|
23 |
'family': request.config.getoption("--family"), |
|
24 |
} |
functests/caluire_axel/test_caluire_axel.py | ||
---|---|---|
1 |
import pprint |
|
2 | ||
3 |
import requests |
|
4 | ||
5 | ||
6 |
def test_link(conn, user): |
|
7 |
name_id = user['name_id'] |
|
8 |
url = conn + '/link?NameID=%s' % name_id |
|
9 |
payload = { |
|
10 |
'IDENTFAMILLE': user['family'], |
|
11 |
'NOM': user['last_name'], |
|
12 |
'PRENOM': user['first_name'], |
|
13 |
} |
|
14 |
print("Creating link with the following payload:") |
|
15 |
pprint.pprint(payload) |
|
16 |
resp = requests.post(url, json=payload) |
|
17 |
resp.raise_for_status() |
|
18 |
res = resp.json() |
|
19 |
pprint.pprint(res) |
|
20 |
assert res['err'] == 0 |
|
21 |
print('\n') |
passerelle/contrib/caluire_axel/migrations/0001_initial.py | ||
---|---|---|
1 |
import django.db.models.deletion |
|
2 |
from django.db import migrations, models |
|
3 | ||
4 | ||
5 |
class Migration(migrations.Migration): |
|
6 | ||
7 |
initial = True |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('base', '0029_auto_20210202_1627'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.CreateModel( |
|
15 |
name='CaluireAxel', |
|
16 |
fields=[ |
|
17 |
( |
|
18 |
'id', |
|
19 |
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
|
20 |
), |
|
21 |
('title', models.CharField(max_length=50, verbose_name='Title')), |
|
22 |
('slug', models.SlugField(unique=True, verbose_name='Identifier')), |
|
23 |
('description', models.TextField(verbose_name='Description')), |
|
24 |
( |
|
25 |
'wsdl_url', |
|
26 |
models.CharField( |
|
27 |
help_text='Caluire Axel WSDL URL', max_length=128, verbose_name='WSDL URL' |
|
28 |
), |
|
29 |
), |
|
30 |
( |
|
31 |
'users', |
|
32 |
models.ManyToManyField( |
|
33 |
blank=True, |
|
34 |
related_name='_caluireaxel_users_+', |
|
35 |
related_query_name='+', |
|
36 |
to='base.ApiUser', |
|
37 |
), |
|
38 |
), |
|
39 |
], |
|
40 |
options={ |
|
41 |
'verbose_name': 'Caluire Axel', |
|
42 |
}, |
|
43 |
), |
|
44 |
migrations.CreateModel( |
|
45 |
name='Link', |
|
46 |
fields=[ |
|
47 |
( |
|
48 |
'id', |
|
49 |
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
|
50 |
), |
|
51 |
('name_id', models.CharField(max_length=256)), |
|
52 |
('family_id', models.CharField(max_length=128)), |
|
53 |
('person_id', models.CharField(max_length=128)), |
|
54 |
( |
|
55 |
'resource', |
|
56 |
models.ForeignKey( |
|
57 |
on_delete=django.db.models.deletion.CASCADE, to='caluire_axel.CaluireAxel' |
|
58 |
), |
|
59 |
), |
|
60 |
], |
|
61 |
options={ |
|
62 |
'unique_together': {('resource', 'name_id')}, |
|
63 |
}, |
|
64 |
), |
|
65 |
] |
passerelle/contrib/caluire_axel/models.py | ||
---|---|---|
1 |
# passerelle - uniform access to multiple data sources and services |
|
2 |
# Copyright (C) 2021 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.db import models |
|
18 |
from django.utils.translation import ugettext_lazy as _ |
|
19 | ||
20 |
from passerelle.base.models import BaseResource |
|
21 |
from passerelle.contrib.utils import axel |
|
22 |
from passerelle.utils.api import endpoint |
|
23 |
from passerelle.utils.jsonresponse import APIError |
|
24 | ||
25 |
from . import schemas |
|
26 | ||
27 | ||
28 |
class CaluireAxel(BaseResource): |
|
29 | ||
30 |
wsdl_url = models.CharField( |
|
31 |
max_length=128, blank=False, verbose_name=_('WSDL URL'), help_text=_('Caluire Axel WSDL URL') |
|
32 |
) |
|
33 | ||
34 |
category = _('Business Process Connectors') |
|
35 |
_category_ordering = [_('Family')] |
|
36 | ||
37 |
class Meta: |
|
38 |
verbose_name = _('Caluire Axel') |
|
39 | ||
40 |
def check_status(self): |
|
41 |
response = self.requests.get(self.wsdl_url) |
|
42 |
response.raise_for_status() |
|
43 | ||
44 |
def check_individu(self, post_data): |
|
45 |
family_id = post_data.pop('IDENTFAMILLE') |
|
46 |
for key in ['NAISSANCE', 'CODEPOSTAL', 'VILLE', 'TEL', 'MAIL']: |
|
47 |
post_data[key] = None |
|
48 |
try: |
|
49 |
result = schemas.find_individus(self, {'PORTAIL': {'FINDINDIVIDU': post_data}}) |
|
50 |
except axel.AxelError as e: |
|
51 |
raise APIError( |
|
52 |
'Axel error: %s' % e, |
|
53 |
err_code='error', |
|
54 |
data={'xml_request': e.xml_request, 'xml_response': e.xml_response}, |
|
55 |
) |
|
56 |
data = result.json_response['DATA']['PORTAIL']['FINDINDIVIDUS'] |
|
57 |
for individu in data.get('INDIVIDU') or []: |
|
58 |
for famille in individu['FAMILLE']: |
|
59 |
if famille['IDENTFAMILLE'] == family_id: |
|
60 |
place = famille['PLACE'] |
|
61 |
if place not in ['1', '2']: |
|
62 |
# not RL1 or RL2 |
|
63 |
raise APIError('Wrong place in family', err_code='family-place-error-%s' % place) |
|
64 |
return individu, result |
|
65 | ||
66 |
raise APIError('Person not found', err_code='not-found') |
|
67 | ||
68 |
@endpoint( |
|
69 |
display_category=_('Family'), |
|
70 |
display_order=1, |
|
71 |
description=_('Create link between user and Caluire Axel'), |
|
72 |
perm='can_access', |
|
73 |
parameters={ |
|
74 |
'NameID': {'description': _('Publik ID')}, |
|
75 |
}, |
|
76 |
post={ |
|
77 |
'request_body': { |
|
78 |
'schema': { |
|
79 |
'application/json': schemas.LINK_SCHEMA, |
|
80 |
} |
|
81 |
} |
|
82 |
}, |
|
83 |
) |
|
84 |
def link(self, request, NameID, post_data): |
|
85 |
if not NameID: |
|
86 |
raise APIError('NameID is empty', err_code='bad-request', http_status=400) |
|
87 | ||
88 |
family_id = post_data['IDENTFAMILLE'] |
|
89 |
try: |
|
90 |
data, result = self.check_individu(post_data) |
|
91 |
except APIError as e: |
|
92 |
if not hasattr(e, 'err_code') or e.err_code == 'error': |
|
93 |
raise |
|
94 |
raise APIError('Person not found', err_code='not-found') |
|
95 | ||
96 |
link, created = self.link_set.get_or_create( |
|
97 |
name_id=NameID, defaults={'family_id': family_id, 'person_id': data['IDENT']} |
|
98 |
) |
|
99 |
if not created and (link.family_id != family_id or link.person_id != data['IDENT']): |
|
100 |
raise APIError('Data conflict', err_code='conflict') |
|
101 |
return { |
|
102 |
'link': link.pk, |
|
103 |
'created': created, |
|
104 |
'family_id': link.family_id, |
|
105 |
'data': { |
|
106 |
'xml_request': result.xml_request, |
|
107 |
'xml_response': result.xml_response, |
|
108 |
}, |
|
109 |
} |
|
110 | ||
111 | ||
112 |
class Link(models.Model): |
|
113 |
resource = models.ForeignKey(CaluireAxel, on_delete=models.CASCADE) |
|
114 |
name_id = models.CharField(blank=False, max_length=256) |
|
115 |
family_id = models.CharField(blank=False, max_length=128) |
|
116 |
person_id = models.CharField(blank=False, max_length=128) |
|
117 | ||
118 |
class Meta: |
|
119 |
unique_together = ('resource', 'name_id') |
passerelle/contrib/caluire_axel/schemas.py | ||
---|---|---|
1 |
# passerelle - uniform access to multiple data sources and services |
|
2 |
# Copyright (C) 2021 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 |
import copy |
|
18 |
import os |
|
19 | ||
20 |
from passerelle.contrib.utils import axel |
|
21 | ||
22 |
BASE_XSD_PATH = os.path.join(os.path.dirname(__file__), 'xsd') |
|
23 | ||
24 | ||
25 |
class Operation(axel.Operation): |
|
26 |
base_xsd_path = BASE_XSD_PATH |
|
27 | ||
28 | ||
29 |
find_individus = Operation('FindIndividus') |
|
30 | ||
31 | ||
32 |
LINK_SCHEMA = copy.deepcopy( |
|
33 |
find_individus.request_schema['properties']['PORTAIL']['properties']['FINDINDIVIDU'] |
|
34 |
) |
|
35 |
for key in ['NAISSANCE', 'CODEPOSTAL', 'VILLE', 'TEL', 'MAIL']: |
|
36 |
LINK_SCHEMA['properties'].pop(key) |
|
37 |
LINK_SCHEMA['required'].remove(key) |
|
38 |
LINK_SCHEMA['properties']['IDENTFAMILLE'] = {'type': 'string', 'maxLength': 8} |
|
39 |
LINK_SCHEMA['required'].append('IDENTFAMILLE') |
passerelle/contrib/caluire_axel/xsd/Adresse.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema xmlns:all="urn:AllAxelTypes" targetNamespace="urn:Adresse" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:adr="urn:Adresse"> |
|
3 |
|
|
4 |
<xsd:import schemaLocation="./AllAxelTypes.xsd" namespace="urn:AllAxelTypes"/> |
|
5 |
|
|
6 |
<xsd:simpleType name="NPAIType"> |
|
7 |
<xsd:union memberTypes="all:ONType all:empty-string" /> |
|
8 |
</xsd:simpleType> |
|
9 |
|
|
10 |
<xsd:complexType name="ADRESSEType"> |
|
11 |
<xsd:sequence> |
|
12 |
<xsd:element name="ADRESSE3" type="all:COMPLEMENTType"/> |
|
13 |
<xsd:element name="ADRESSE4" type="all:COMPLEMENTType"/> |
|
14 |
<xsd:element name="NORUE" type="all:NUMVOIEType"/> |
|
15 |
<xsd:element name="ADRESSE1" type="all:COMPLEMENTType"/> |
|
16 |
<xsd:element name="ADRESSE2" type="all:COMPLEMENTType"/> |
|
17 |
<xsd:element name="CODEPOSTAL" type="all:CODEPOSTALType"/> |
|
18 |
<xsd:element name="VILLE" type="all:VILLEType"/> |
|
19 |
<xsd:element name="PAYS" type="all:PAYSType"/> |
|
20 |
<xsd:element name="NPAI" type="adr:NPAIType"/> |
|
21 |
</xsd:sequence> |
|
22 |
</xsd:complexType> |
|
23 |
</xsd:schema> |
passerelle/contrib/caluire_axel/xsd/AllAxelTypes.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema targetNamespace="urn:AllAxelTypes" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes"> |
|
3 |
|
|
4 |
<xsd:simpleType name="empty-string"> |
|
5 |
<xsd:restriction base="xsd:string"> |
|
6 |
<xsd:enumeration value="" /> |
|
7 |
</xsd:restriction> |
|
8 |
</xsd:simpleType> |
|
9 |
|
|
10 |
<xsd:simpleType name="decimal-or-empty"> |
|
11 |
<xsd:union memberTypes="xsd:decimal all:empty-string" /> |
|
12 |
</xsd:simpleType> |
|
13 |
|
|
14 |
<xsd:simpleType name="unsignedInt-or-empty"> |
|
15 |
<xsd:union memberTypes="xsd:unsignedInt all:empty-string" /> |
|
16 |
</xsd:simpleType> |
|
17 |
|
|
18 |
<xsd:simpleType name="TELREQUIREDType"> |
|
19 |
<xsd:restriction base="xsd:string"> |
|
20 |
<xsd:minLength value="1" /> |
|
21 |
<xsd:maxLength value="10" /> |
|
22 |
</xsd:restriction> |
|
23 |
</xsd:simpleType> |
|
24 |
|
|
25 |
<xsd:simpleType name="TEL2REQUIREDType"> |
|
26 |
<xsd:restriction base="xsd:string"> |
|
27 |
<xsd:minLength value="1" /> |
|
28 |
<xsd:maxLength value="16" /> |
|
29 |
</xsd:restriction> |
|
30 |
</xsd:simpleType> |
|
31 |
|
|
32 |
<xsd:simpleType name="COURRIELREQUIREDType"> |
|
33 |
<xsd:restriction base="xsd:string" > |
|
34 |
<xsd:pattern value="[^@]+@[^\.]+\..+" /> |
|
35 |
</xsd:restriction> |
|
36 |
</xsd:simpleType> |
|
37 |
|
|
38 |
<xsd:simpleType name="NOMREQUIREDType"> |
|
39 |
<xsd:restriction base="xsd:string"> |
|
40 |
<xsd:minLength value="1" /> |
|
41 |
<xsd:maxLength value="50" /> |
|
42 |
</xsd:restriction> |
|
43 |
</xsd:simpleType> |
|
44 |
|
|
45 |
<xsd:simpleType name="PRENOMREQUIREDType"> |
|
46 |
<xsd:restriction base="xsd:string"> |
|
47 |
<xsd:minLength value="1" /> |
|
48 |
<xsd:maxLength value="30" /> |
|
49 |
</xsd:restriction> |
|
50 |
</xsd:simpleType> |
|
51 |
|
|
52 |
<xsd:simpleType name="NOMType"> |
|
53 |
<xsd:restriction base="xsd:string"> |
|
54 |
<xsd:minLength value="0" /> |
|
55 |
<xsd:maxLength value="50" /> |
|
56 |
</xsd:restriction> |
|
57 |
</xsd:simpleType> |
|
58 |
|
|
59 |
<xsd:simpleType name="PRENOMType"> |
|
60 |
<xsd:restriction base="xsd:string"> |
|
61 |
<xsd:minLength value="0" /> |
|
62 |
<xsd:maxLength value="30" /> |
|
63 |
</xsd:restriction> |
|
64 |
</xsd:simpleType> |
|
65 |
|
|
66 |
<xsd:simpleType name="DATEREQUIREDType"> |
|
67 |
<xsd:restriction base="xsd:string"> |
|
68 |
<xsd:pattern value="((0[1-9])|([12][0-9])|(3[01]))/((0[1-9])|(1[012]))/((000[1-9])|(00[1-9][0-9])|(0[1-9][0-9]{2})|([1-9][0-9]{3}))" /> |
|
69 |
</xsd:restriction> |
|
70 |
</xsd:simpleType> |
|
71 |
|
|
72 |
<xsd:simpleType name="DATEType"> |
|
73 |
<xsd:union memberTypes="all:DATEREQUIREDType all:empty-string" /> |
|
74 |
</xsd:simpleType> |
|
75 |
|
|
76 |
<xsd:simpleType name="DATETIMEType"> |
|
77 |
<xsd:restriction base="xsd:string"> |
|
78 |
<xsd:pattern value="((0[1-9])|([12][0-9])|(3[01]))/((0[1-9])|(1[012]))/((000[1-9])|(00[1-9][0-9])|(0[1-9][0-9]{2})|([1-9][0-9]{3})) (([01][0-9])|(2[0-3]))(:[0-5][0-9]){2}(\.[0-9]+)?" /> |
|
79 |
</xsd:restriction> |
|
80 |
</xsd:simpleType> |
|
81 |
|
|
82 |
<xsd:simpleType name="TIMEType"> |
|
83 |
<xsd:restriction base="xsd:string"> |
|
84 |
<xsd:pattern value="(([01][0-9])|(2[0-3]))(:[0-5][0-9])" /> |
|
85 |
</xsd:restriction> |
|
86 |
</xsd:simpleType> |
|
87 |
|
|
88 |
<xsd:simpleType name="IDENTType"> |
|
89 |
<xsd:restriction base="xsd:string"> |
|
90 |
<xsd:maxLength value="8" /> |
|
91 |
</xsd:restriction> |
|
92 |
</xsd:simpleType> |
|
93 |
|
|
94 |
<xsd:simpleType name="IDENTREQUIREDType"> |
|
95 |
<xsd:restriction base="xsd:string"> |
|
96 |
<xsd:minLength value="1"/> |
|
97 |
<xsd:maxLength value="8"/> |
|
98 |
</xsd:restriction> |
|
99 |
</xsd:simpleType> |
|
100 |
|
|
101 |
<xsd:simpleType name="IDType"> |
|
102 |
<xsd:restriction base="xsd:string"> |
|
103 |
<xsd:maxLength value="10" /> |
|
104 |
</xsd:restriction> |
|
105 |
</xsd:simpleType> |
|
106 |
|
|
107 |
<xsd:simpleType name="IDREQUIREDType"> |
|
108 |
<xsd:restriction base="xsd:string"> |
|
109 |
<xsd:minLength value="1"/> |
|
110 |
<xsd:maxLength value="10"/> |
|
111 |
</xsd:restriction> |
|
112 |
</xsd:simpleType> |
|
113 |
|
|
114 |
<xsd:simpleType name="TELType"> |
|
115 |
<xsd:union memberTypes="all:TELREQUIREDType all:empty-string" /> |
|
116 |
</xsd:simpleType> |
|
117 |
|
|
118 |
<xsd:simpleType name="TEL2Type"> |
|
119 |
<xsd:union memberTypes="all:TEL2REQUIREDType all:empty-string" /> |
|
120 |
</xsd:simpleType> |
|
121 |
|
|
122 |
<xsd:simpleType name="COURRIELType" > |
|
123 |
<xsd:union memberTypes="all:COURRIELREQUIREDType all:empty-string" /> |
|
124 |
</xsd:simpleType> |
|
125 |
|
|
126 |
<xsd:simpleType name="ANNEEType"> |
|
127 |
<xsd:restriction base="xsd:string"> |
|
128 |
<xsd:pattern value="[0-9]{4}"/> |
|
129 |
</xsd:restriction> |
|
130 |
</xsd:simpleType> |
|
131 |
|
|
132 |
<xsd:simpleType name="MOISType"> |
|
133 |
<xsd:restriction base="xsd:string"> |
|
134 |
<xsd:pattern value="[0-1][0-9]"/> |
|
135 |
</xsd:restriction> |
|
136 |
</xsd:simpleType> |
|
137 |
|
|
138 |
<xsd:simpleType name="OUINONREQUIREDType"> |
|
139 |
<xsd:restriction base="xsd:string"> |
|
140 |
<xsd:pattern value="[Oo][Uu][Ii]" /> |
|
141 |
<xsd:pattern value="[Nn][Oo][Nn]" /> |
|
142 |
</xsd:restriction> |
|
143 |
</xsd:simpleType> |
|
144 |
|
|
145 |
<xsd:simpleType name="BOOLEANREQUIREDType"> |
|
146 |
<xsd:restriction base="xsd:string"> |
|
147 |
<xsd:pattern value="0" /> |
|
148 |
<xsd:pattern value="1" /> |
|
149 |
</xsd:restriction> |
|
150 |
</xsd:simpleType> |
|
151 |
|
|
152 |
<xsd:simpleType name="OUINONType"> |
|
153 |
<xsd:restriction base="xsd:string"> |
|
154 |
<xsd:pattern value="|" /> |
|
155 |
<xsd:pattern value="[Oo][Uu][Ii]" /> |
|
156 |
<xsd:pattern value="[Nn][Oo][Nn]" /> |
|
157 |
</xsd:restriction> |
|
158 |
</xsd:simpleType> |
|
159 |
|
|
160 |
<xsd:simpleType name="NUMVOIEREQUIREDType"> |
|
161 |
<xsd:restriction base="xsd:string"> |
|
162 |
<xsd:minLength value="1" /> |
|
163 |
<xsd:maxLength value="5" /> |
|
164 |
</xsd:restriction> |
|
165 |
</xsd:simpleType> |
|
166 |
|
|
167 |
<xsd:simpleType name="NUMVOIEType"> |
|
168 |
<xsd:union memberTypes="all:NUMVOIEREQUIREDType all:empty-string" /> |
|
169 |
</xsd:simpleType> |
|
170 |
|
|
171 |
<xsd:simpleType name="COMPLEMENTNUMType"> |
|
172 |
<xsd:restriction base="xsd:string"> |
|
173 |
<xsd:pattern value="|" /> |
|
174 |
<xsd:pattern value="[Bb][Ii][Ss]" /> |
|
175 |
<xsd:pattern value="[Tt][Ee][Rr]" /> |
|
176 |
<xsd:pattern value="[Qq][Uu][Aa][Tt][Ee][Rr]" /> |
|
177 |
<xsd:pattern value="[Qq][Uu][Ii][Nn][Qq][Uu][Ii][Ee][Ss]" /> |
|
178 |
</xsd:restriction> |
|
179 |
</xsd:simpleType> |
|
180 |
|
|
181 |
<xsd:simpleType name="TYPEVOIEType"> |
|
182 |
<xsd:restriction base="xsd:string"> |
|
183 |
<xsd:pattern value="[Aa][Vv][Ee][Nn][Uu][Ee]" /> |
|
184 |
<xsd:pattern value="[Rr][Uu][Ee]" /> |
|
185 |
<xsd:pattern value="[Ff][Aa][Uu][Bb][Oo][Uu][Rr][Gg]" /> |
|
186 |
<xsd:pattern value="[Cc][Hh][Ee][Mm][Ii][Nn]" /> |
|
187 |
<xsd:pattern value="[Cc][Oo][Uu][Rr][Ss]" /> |
|
188 |
<xsd:pattern value="[Bb][Oo][Uu][Ll][Ee][Vv][Aa][Rr][Dd]" /> |
|
189 |
<xsd:pattern value="[Ii][Mm][Pp][Aa][Ss][Ss][Ee]" /> |
|
190 |
<xsd:pattern value="[Ll][Ii][Ee][Uu] [Dd][Ii][Tt]" /> |
|
191 |
</xsd:restriction> |
|
192 |
</xsd:simpleType> |
|
193 |
|
|
194 |
<xsd:simpleType name="COMPLEMENTREQUIREDType"> |
|
195 |
<xsd:restriction base="xsd:string"> |
|
196 |
<xsd:minLength value="1" /> |
|
197 |
<xsd:maxLength value="40" /> |
|
198 |
</xsd:restriction> |
|
199 |
</xsd:simpleType> |
|
200 |
|
|
201 |
<xsd:simpleType name="COMPLEMENTType"> |
|
202 |
<xsd:union memberTypes="all:COMPLEMENTREQUIREDType all:empty-string" /> |
|
203 |
</xsd:simpleType> |
|
204 |
|
|
205 |
<xsd:simpleType name="CODEPOSTALREQUIREDType"> |
|
206 |
<xsd:restriction base="xsd:string"> |
|
207 |
<xsd:pattern value="[0-9]{5}"/> |
|
208 |
</xsd:restriction> |
|
209 |
</xsd:simpleType> |
|
210 |
|
|
211 |
<xsd:simpleType name="VILLEREQUIREDType"> |
|
212 |
<xsd:restriction base="xsd:string"> |
|
213 |
<xsd:minLength value="1" /> |
|
214 |
<xsd:maxLength value="35" /> |
|
215 |
</xsd:restriction> |
|
216 |
</xsd:simpleType> |
|
217 |
|
|
218 |
<xsd:simpleType name="PAYSREQUIREDType"> |
|
219 |
<xsd:restriction base="xsd:string"> |
|
220 |
<xsd:minLength value="1" /> |
|
221 |
<xsd:maxLength value="30" /> |
|
222 |
</xsd:restriction> |
|
223 |
</xsd:simpleType> |
|
224 |
|
|
225 |
<xsd:simpleType name="CODEPOSTALType"> |
|
226 |
<xsd:union memberTypes="all:CODEPOSTALREQUIREDType all:empty-string" /> |
|
227 |
</xsd:simpleType> |
|
228 |
|
|
229 |
<xsd:simpleType name="VILLEType"> |
|
230 |
<xsd:union memberTypes="all:VILLEREQUIREDType all:empty-string" /> |
|
231 |
</xsd:simpleType> |
|
232 |
|
|
233 |
<xsd:simpleType name="PAYSType"> |
|
234 |
<xsd:union memberTypes="all:PAYSREQUIREDType all:empty-string" /> |
|
235 |
</xsd:simpleType> |
|
236 |
|
|
237 |
<xsd:simpleType name="CODEINSEEVILLEREQUIREDType"> |
|
238 |
<xsd:restriction base="xsd:string"> |
|
239 |
<xsd:pattern value="[0-9]{5}"/> |
|
240 |
</xsd:restriction> |
|
241 |
</xsd:simpleType> |
|
242 |
|
|
243 |
<xsd:simpleType name="CODEINSEEVILLEType"> |
|
244 |
<xsd:union memberTypes="all:CODEINSEEVILLEREQUIREDType all:empty-string" /> |
|
245 |
</xsd:simpleType> |
|
246 |
|
|
247 |
<xsd:simpleType name="ONEmptyType"> |
|
248 |
<xsd:union memberTypes="all:ONType all:empty-string" /> |
|
249 |
</xsd:simpleType> |
|
250 |
|
|
251 |
<xsd:simpleType name="ONType"> |
|
252 |
<xsd:restriction base="xsd:string"> |
|
253 |
<xsd:pattern value="[Oo]" /> |
|
254 |
<xsd:pattern value="[Nn]" /> |
|
255 |
</xsd:restriction> |
|
256 |
</xsd:simpleType> |
|
257 |
|
|
258 |
<xsd:simpleType name="MONTANTREQUIREDType"> |
|
259 |
<xsd:restriction base="xsd:decimal"> |
|
260 |
<xsd:totalDigits value="10"/> |
|
261 |
<xsd:fractionDigits value="2"/> |
|
262 |
</xsd:restriction> |
|
263 |
</xsd:simpleType> |
|
264 |
|
|
265 |
<xsd:simpleType name="MONTANTType"> |
|
266 |
<xsd:union memberTypes="all:MONTANTREQUIREDType all:empty-string" /> |
|
267 |
</xsd:simpleType> |
|
268 |
|
|
269 |
<xsd:simpleType name="PRIXREQUIREDType"> |
|
270 |
<xsd:restriction base="xsd:decimal"> |
|
271 |
<xsd:totalDigits value="10"/> |
|
272 |
<xsd:fractionDigits value="5"/> |
|
273 |
</xsd:restriction> |
|
274 |
</xsd:simpleType> |
|
275 |
|
|
276 |
<xsd:simpleType name="PRIXType"> |
|
277 |
<xsd:union memberTypes="all:PRIXREQUIREDType all:empty-string" /> |
|
278 |
</xsd:simpleType> |
|
279 |
|
|
280 |
<xsd:simpleType name="LIBELLEType"> |
|
281 |
<xsd:restriction base="xsd:string"> |
|
282 |
<xsd:minLength value="0" /> |
|
283 |
<xsd:maxLength value="40" /> |
|
284 |
</xsd:restriction> |
|
285 |
</xsd:simpleType> |
|
286 |
|
|
287 |
<xsd:simpleType name="LIBELLE100Type"> |
|
288 |
<xsd:restriction base="xsd:string"> |
|
289 |
<xsd:minLength value="0" /> |
|
290 |
<xsd:maxLength value="100" /> |
|
291 |
</xsd:restriction> |
|
292 |
</xsd:simpleType> |
|
293 |
|
|
294 |
<xsd:simpleType name="FOOBARType"><!-- CUSTOM --> |
|
295 |
<xsd:restriction base="xsd:string"> |
|
296 |
<xsd:minLength value="0" /> |
|
297 |
<xsd:maxLength value="256" /> |
|
298 |
</xsd:restriction> |
|
299 |
</xsd:simpleType> |
|
300 |
|
|
301 |
</xsd:schema> |
passerelle/contrib/caluire_axel/xsd/Individu.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema xmlns:adr="urn:Adresse" xmlns:all="urn:AllAxelTypes" targetNamespace="urn:Individu" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ind="urn:Individu" > |
|
3 |
|
|
4 |
<xsd:import schemaLocation="./AllAxelTypes.xsd" namespace="urn:AllAxelTypes" /> |
|
5 |
<xsd:import schemaLocation="./Adresse.xsd" namespace="urn:Adresse" /> |
|
6 |
|
|
7 |
<xsd:simpleType name="SEXEType"> |
|
8 |
<xsd:restriction base="xsd:string"> |
|
9 |
<xsd:enumeration value="" /> |
|
10 |
<xsd:enumeration value="M" /> |
|
11 |
<xsd:enumeration value="F" /> |
|
12 |
</xsd:restriction> |
|
13 |
</xsd:simpleType> |
|
14 |
|
|
15 |
<xsd:simpleType name="CIVILITEType"> |
|
16 |
<xsd:restriction base="xsd:string"> |
|
17 |
<xsd:minLength value="0" /> |
|
18 |
<xsd:maxLength value="4" /> |
|
19 |
</xsd:restriction> |
|
20 |
</xsd:simpleType> |
|
21 |
|
|
22 |
<xsd:complexType name="INDIVIDUType"> |
|
23 |
<xsd:sequence> |
|
24 |
<xsd:element name="IDENT" type="all:IDENTType"/> |
|
25 |
<xsd:element name="CIVILITE" type="ind:CIVILITEType"/> |
|
26 |
<xsd:element name="NOM" type="all:NOMREQUIREDType"/> |
|
27 |
<xsd:element name="PRENOM" type="all:PRENOMType"/> |
|
28 |
<xsd:element name="NAISSANCE" type="all:DATEType"/> |
|
29 |
<xsd:element name="SEXE" type="ind:SEXEType"/> |
|
30 |
<xsd:element name="NOMJF" type="all:NOMType"/> |
|
31 |
<xsd:element name="TELFIXE" type="all:TEL2Type"/> |
|
32 |
<xsd:element name="TELPORTABLE" type="all:TEL2Type"/> |
|
33 |
<xsd:element name="MAIL" type="all:COURRIELType"/> |
|
34 |
<xsd:element name="CSP" type="all:FOOBARType"/><!-- CUSTOM --> |
|
35 |
<xsd:element name="EMPLOYEUR" type="all:FOOBARType"/><!-- CUSTOM --> |
|
36 |
<xsd:element name="VILLEEMP" type="all:FOOBARType"/><!-- CUSTOM --> |
|
37 |
<xsd:element name="PAI" type="all:FOOBARType"/><!-- CUSTOM --> |
|
38 |
<xsd:element name="GARDEALTERNEE" type="all:FOOBARType"/><!-- CUSTOM --> |
|
39 |
<xsd:element name="ADRESSE" type="adr:ADRESSEType" minOccurs="0" maxOccurs="1"/> |
|
40 |
</xsd:sequence> |
|
41 |
</xsd:complexType> |
|
42 |
|
|
43 |
</xsd:schema> |
passerelle/contrib/caluire_axel/xsd/Q_FindIndividus.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes"> |
|
3 |
|
|
4 |
<xsd:import schemaLocation="./AllAxelTypes.xsd" namespace="urn:AllAxelTypes" /> |
|
5 |
|
|
6 |
|
|
7 |
<xsd:complexType name="FINDINDIVIDUType"> |
|
8 |
<xsd:sequence> |
|
9 |
<xsd:element ref="NOM" /> |
|
10 |
<xsd:element ref="PRENOM" /> |
|
11 |
<xsd:element ref="NAISSANCE" /> |
|
12 |
<xsd:element ref="CODEPOSTAL" /> |
|
13 |
<xsd:element ref="VILLE" /> |
|
14 |
<xsd:element ref="TEL" /> |
|
15 |
<xsd:element ref="MAIL" /> |
|
16 |
</xsd:sequence> |
|
17 |
</xsd:complexType> |
|
18 |
|
|
19 |
<xsd:complexType name="PORTAILType"> |
|
20 |
<xsd:sequence> |
|
21 |
<xsd:element ref="FINDINDIVIDU" minOccurs="0" maxOccurs="1"/> |
|
22 |
</xsd:sequence> |
|
23 |
</xsd:complexType> |
|
24 |
|
|
25 |
<xsd:element name="NOM" type="all:NOMREQUIREDType"/> |
|
26 |
<xsd:element name="PRENOM" type="all:PRENOMREQUIREDType"/> <!-- CUSTOM, it should be PRENOMType --> |
|
27 |
<xsd:element name="NAISSANCE" type="all:DATEType"/> |
|
28 |
<xsd:element name="CODEPOSTAL" type="all:CODEPOSTALType"/> |
|
29 |
<xsd:element name="VILLE" type="all:VILLEType"/> |
|
30 |
<xsd:element name="TEL" type="all:TEL2Type"/> |
|
31 |
<xsd:element name="MAIL" type="all:COURRIELType"/> |
|
32 |
|
|
33 |
<xsd:element name="FINDINDIVIDU" type="FINDINDIVIDUType"/> |
|
34 |
|
|
35 |
<xsd:element name="PORTAIL" type="PORTAILType"/> |
|
36 |
|
|
37 |
</xsd:schema> |
passerelle/contrib/caluire_axel/xsd/R_FindIndividus.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema xmlns:all="urn:AllAxelTypes" xmlns:ind="urn:Individu" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > |
|
3 |
|
|
4 |
<xsd:import schemaLocation="./Individu.xsd" namespace="urn:Individu" /> |
|
5 |
<xsd:import schemaLocation="./AllAxelTypes.xsd" namespace="urn:AllAxelTypes" /> |
|
6 |
|
|
7 |
<xsd:redefine schemaLocation="./R_ShemaResultat.xsd"> |
|
8 |
<xsd:simpleType name="TYPEType"> |
|
9 |
<xsd:restriction base="TYPEType"> |
|
10 |
<xsd:enumeration value="FindIndividus" /> |
|
11 |
</xsd:restriction> |
|
12 |
</xsd:simpleType> |
|
13 |
|
|
14 |
<xsd:complexType name="PORTAILType"> |
|
15 |
<xsd:complexContent> |
|
16 |
<xsd:extension base="PORTAILType"> |
|
17 |
<xsd:sequence> |
|
18 |
<xsd:element ref="FINDINDIVIDUS" minOccurs="0" maxOccurs="1"/> |
|
19 |
</xsd:sequence> |
|
20 |
</xsd:extension> |
|
21 |
</xsd:complexContent> |
|
22 |
</xsd:complexType> |
|
23 |
</xsd:redefine> |
|
24 |
|
|
25 |
<xsd:complexType name="INDIType"> |
|
26 |
<xsd:complexContent> |
|
27 |
<xsd:extension base="ind:INDIVIDUType"> |
|
28 |
<xsd:sequence> |
|
29 |
<xsd:element ref="FAMILLE" minOccurs="0" maxOccurs="unbounded"/> |
|
30 |
</xsd:sequence> |
|
31 |
</xsd:extension> |
|
32 |
</xsd:complexContent> |
|
33 |
</xsd:complexType> |
|
34 |
|
|
35 |
<xsd:complexType name="FAMILLEType"> |
|
36 |
<xsd:sequence> |
|
37 |
<xsd:element ref="IDENTFAMILLE" /> |
|
38 |
<xsd:element ref="PLACE"/> |
|
39 |
<xsd:element ref="SITUATION" minOccurs="0" maxOccurs="1"/><!-- CUSTOM --> |
|
40 |
</xsd:sequence> |
|
41 |
</xsd:complexType> |
|
42 |
|
|
43 |
<xsd:simpleType name="PLACEType"> |
|
44 |
<xsd:restriction base="xsd:string"> |
|
45 |
<xsd:enumeration value="" /> |
|
46 |
<xsd:enumeration value="1" /> |
|
47 |
<xsd:enumeration value="2" /> |
|
48 |
<xsd:enumeration value="3" /> |
|
49 |
</xsd:restriction> |
|
50 |
</xsd:simpleType> |
|
51 |
|
|
52 |
<xsd:complexType name="FINDINDIVIDUSType"> |
|
53 |
<xsd:sequence> |
|
54 |
<xsd:element ref="CODE" /> |
|
55 |
<xsd:element ref="INDIVIDU" minOccurs="0" maxOccurs="unbounded" /> |
|
56 |
</xsd:sequence> |
|
57 |
</xsd:complexType> |
|
58 |
|
|
59 |
<xsd:element name="CODE" type="xsd:integer"/> |
|
60 |
<xsd:element name="INDIVIDU" type="INDIType"/> |
|
61 |
<xsd:element name="FAMILLE" type="FAMILLEType"/> |
|
62 |
<xsd:element name="IDENTFAMILLE" type="all:IDENTType"/> |
|
63 |
<xsd:element name="PLACE" type="PLACEType"/> |
|
64 |
<xsd:element name="SITUATION" type="all:FOOBARType"/><!-- CUSTOM --> |
|
65 |
|
|
66 |
<xsd:element name="FINDINDIVIDUS" type="FINDINDIVIDUSType"/> |
|
67 |
|
|
68 |
</xsd:schema> |
passerelle/contrib/caluire_axel/xsd/R_ShemaResultat.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?> |
|
2 |
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes"> |
|
3 |
|
|
4 |
<xsd:import schemaLocation="./AllAxelTypes.xsd" namespace="urn:AllAxelTypes" /> |
|
5 |
|
|
6 |
<xsd:simpleType name="TYPEType"> |
|
7 |
<xsd:restriction base="xsd:string"> |
|
8 |
</xsd:restriction> |
|
9 |
</xsd:simpleType> |
|
10 |
|
|
11 |
<xsd:simpleType name="STATUSType"> |
|
12 |
<xsd:restriction base="xsd:string"> |
|
13 |
<xsd:enumeration value="OK" /> |
|
14 |
<xsd:enumeration value="NOK" /> |
|
15 |
</xsd:restriction> |
|
16 |
</xsd:simpleType> |
|
17 |
|
|
18 |
<xsd:complexType name="PORTAILType"> |
|
19 |
</xsd:complexType> |
|
20 |
|
|
21 |
<xsd:complexType name="RESULTATType"> |
|
22 |
<xsd:sequence> |
|
23 |
<xsd:element ref="TYPE" /> |
|
24 |
<xsd:element ref="STATUS" /> |
|
25 |
<xsd:element ref="DATE" /> |
|
26 |
<xsd:element ref="COMMENTAIRES" /> |
|
27 |
</xsd:sequence> |
|
28 |
</xsd:complexType> |
|
29 |
|
|
30 |
<xsd:complexType name="DATAType"> |
|
31 |
<xsd:sequence> |
|
32 |
<xsd:element ref="PORTAIL"/> |
|
33 |
</xsd:sequence> |
|
34 |
</xsd:complexType> |
|
35 |
|
|
36 |
<xsd:complexType name="PORTAILSERVICEType"> |
|
37 |
<xsd:sequence> |
|
38 |
<xsd:element ref="RESULTAT" /> |
|
39 |
<xsd:element ref="DATA" /> |
|
40 |
</xsd:sequence> |
|
41 |
</xsd:complexType> |
|
42 |
|
|
43 |
<xsd:element name="TYPE" type="TYPEType"/> |
|
44 |
<xsd:element name="STATUS" type="STATUSType"/> |
|
45 |
<xsd:element name="DATE" type="all:DATETIMEType"/> |
|
46 |
<xsd:element name="COMMENTAIRES" type="xsd:string"/> |
|
47 |
|
|
48 |
<xsd:element name="PORTAIL" type="PORTAILType"/> |
|
49 |
|
|
50 |
<xsd:element name="RESULTAT" type="RESULTATType"/> |
|
51 |
<xsd:element name="DATA" type="DATAType"/> |
|
52 |
|
|
53 |
<xsd:element name="PORTAILSERVICE" type="PORTAILSERVICEType"/> |
|
54 |
</xsd:schema> |
tests/settings.py | ||
---|---|---|
16 | 16 |
# include all contrib apps |
17 | 17 |
INSTALLED_APPS += ( |
18 | 18 |
'passerelle.contrib.adict', |
19 |
'passerelle.contrib.caluire_axel', |
|
19 | 20 |
'passerelle.contrib.dpark', |
20 | 21 |
'passerelle.contrib.fake_family', |
21 | 22 |
'passerelle.contrib.gdema', |
tests/test_caluire_axel.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# passerelle - uniform access to multiple data sources and services |
|
3 |
# Copyright (C) 2021 Entr'ouvert |
|
4 |
# |
|
5 |
# This program is free software: you can redistribute it and/or modify it |
|
6 |
# under the terms of the GNU Affero General Public License as published |
|
7 |
# by the Free Software Foundation, either version 3 of the License, or |
|
8 |
# (at your option) any later version. |
|
9 |
# |
|
10 |
# This program is distributed in the hope that it will be useful, |
|
11 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
# GNU Affero General Public License for more details. |
|
14 |
# |
|
15 |
# You should have received a copy of the GNU Affero General Public License |
|
16 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 | ||
18 |
from contextlib import contextmanager |
|
19 | ||
20 |
import mock |
|
21 |
import pytest |
|
22 |
import utils |
|
23 |
import xmlschema |
|
24 | ||
25 |
from passerelle.contrib.caluire_axel import schemas |
|
26 |
from passerelle.contrib.caluire_axel.models import CaluireAxel, Link |
|
27 |
from passerelle.contrib.utils.axel import AxelError |
|
28 |
from passerelle.utils.soap import SOAPError |
|
29 | ||
30 | ||
31 |
@pytest.fixture |
|
32 |
def resource(db): |
|
33 |
return utils.make_resource( |
|
34 |
CaluireAxel, slug='test', wsdl_url='http://example.net/AXEL_WS/AxelWS.php?wsdl' |
|
35 |
) |
|
36 | ||
37 | ||
38 |
@pytest.fixture |
|
39 |
def link_params(): |
|
40 |
return { |
|
41 |
'IDENTFAMILLE': '12345', |
|
42 |
'NOM': 'Doe', |
|
43 |
'PRENOM': 'John', |
|
44 |
} |
|
45 | ||
46 | ||
47 |
@contextmanager |
|
48 |
def mock_getdata(content, operation): |
|
49 |
with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client: |
|
50 |
resp = ''' |
|
51 |
<?xml version="1.0"?> |
|
52 |
<PORTAILSERVICE> |
|
53 |
<RESULTAT> |
|
54 |
<TYPE>%s</TYPE> |
|
55 |
<STATUS>OK</STATUS> |
|
56 |
<DATE>10/10/2010 10:10:01</DATE> |
|
57 |
<COMMENTAIRES><![CDATA[]]></COMMENTAIRES> |
|
58 |
</RESULTAT> |
|
59 |
<DATA> |
|
60 |
%s |
|
61 |
</DATA> |
|
62 |
</PORTAILSERVICE> |
|
63 |
'''.strip() % ( |
|
64 |
operation, |
|
65 |
content, |
|
66 |
) |
|
67 |
client.return_value.service.getData.return_value = resp |
|
68 |
yield |
|
69 | ||
70 | ||
71 |
def test_operation_status_error(resource): |
|
72 |
resp = ''' |
|
73 |
<?xml version="1.0"?> |
|
74 |
<PORTAILSERVICE> |
|
75 |
<RESULTAT> |
|
76 |
<TYPE>FindIndividus</TYPE> |
|
77 |
<STATUS>NOK</STATUS> |
|
78 |
<COMMENTAIRES><![CDATA[Foo reason]]></COMMENTAIRES> |
|
79 |
</RESULTAT> |
|
80 |
<DATA> |
|
81 |
<PORTAIL/> |
|
82 |
</DATA> |
|
83 |
</PORTAILSERVICE> |
|
84 |
'''.strip() |
|
85 |
with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client: |
|
86 |
client.return_value.service.getData.return_value = resp |
|
87 |
with pytest.raises(AxelError, match='Foo reason'): |
|
88 |
schemas.find_individus( |
|
89 |
resource, |
|
90 |
{ |
|
91 |
'PORTAIL': { |
|
92 |
'FINDINDIVIDU': { |
|
93 |
'NOM': 'Doe', |
|
94 |
'PRENOM': 'John', |
|
95 |
'NAISSANCE': None, |
|
96 |
'CODEPOSTAL': None, |
|
97 |
'VILLE': None, |
|
98 |
'TEL': None, |
|
99 |
'MAIL': None, |
|
100 |
} |
|
101 |
} |
|
102 |
}, |
|
103 |
) |
|
104 | ||
105 | ||
106 |
@pytest.mark.parametrize( |
|
107 |
'content', |
|
108 |
[ |
|
109 |
'<PORTAIL><FINDINDIVIDUS/></PORTAIL>', |
|
110 |
], |
|
111 |
) |
|
112 |
def test_operation_find_individus(resource, content): |
|
113 |
with mock_getdata(content, 'FindIndividus'): |
|
114 |
with pytest.raises(AxelError): |
|
115 |
schemas.find_individus( |
|
116 |
resource, |
|
117 |
{ |
|
118 |
'PORTAIL': { |
|
119 |
'FINDINDIVIDU': { |
|
120 |
'NOM': 'Doe', |
|
121 |
'PRENOM': 'John', |
|
122 |
'NAISSANCE': None, |
|
123 |
'CODEPOSTAL': None, |
|
124 |
'VILLE': None, |
|
125 |
'TEL': None, |
|
126 |
'MAIL': None, |
|
127 |
} |
|
128 |
} |
|
129 |
}, |
|
130 |
) |
|
131 | ||
132 | ||
133 |
def test_link_endpoint_nameid_empty(app, resource, link_params): |
|
134 |
resp = app.post_json('/caluire-axel/test/link?NameID=', params=link_params, status=400) |
|
135 |
assert resp.json['err_desc'] == "NameID is empty" |
|
136 |
assert resp.json['err'] == 'bad-request' |
|
137 | ||
138 | ||
139 |
def test_link_endpoint_axel_error(app, resource, link_params): |
|
140 |
with mock.patch('passerelle.contrib.caluire_axel.schemas.find_individus') as operation: |
|
141 |
operation.side_effect = AxelError('FooBar') |
|
142 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
143 |
assert resp.json['err_desc'] == "Axel error: FooBar" |
|
144 |
assert resp.json['err'] == 'error' |
|
145 |
assert resp.json['data'] == {'xml_request': None, 'xml_response': None} |
|
146 | ||
147 |
# test xml_request and xml_response only for this endpoint |
|
148 |
xml_request = """<PORTAIL> |
|
149 |
<FINDINDIVIDU> |
|
150 |
<NOM>Doe</NOM> |
|
151 |
<PRENOM>John</PRENOM> |
|
152 |
<NAISSANCE /> |
|
153 |
<CODEPOSTAL /> |
|
154 |
<VILLE /> |
|
155 |
<TEL /> |
|
156 |
<MAIL /> |
|
157 |
</FINDINDIVIDU> |
|
158 |
</PORTAIL> |
|
159 |
""" |
|
160 | ||
161 |
with mock_getdata('', 'FindIndividus'): |
|
162 |
with mock.patch('xmlschema.XMLSchema.validate') as xml_validate: |
|
163 |
xml_validate.side_effect = xmlschema.XMLSchemaValidationError(None, None) |
|
164 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
165 |
assert resp.json['err_desc'].startswith("Axel error: invalid request") |
|
166 |
assert resp.json['err'] == 'error' |
|
167 |
assert resp.json['data']['xml_request'] == xml_request |
|
168 |
assert resp.json['data']['xml_response'] is None |
|
169 | ||
170 |
xml_response = """<PORTAILSERVICE> |
|
171 |
<RESULTAT> |
|
172 |
<TYPE>FINDINDIVIDUS</TYPE> |
|
173 |
<STATUS>NOK</STATUS> |
|
174 |
<COMMENTAIRES>Foo reason</COMMENTAIRES> |
|
175 |
</RESULTAT> |
|
176 |
<DATA> |
|
177 |
<PORTAIL /> |
|
178 |
</DATA> |
|
179 |
</PORTAILSERVICE>""" |
|
180 |
response = """ |
|
181 |
<?xml version="1.0"?> |
|
182 |
<PORTAILSERVICE> |
|
183 |
<RESULTAT> |
|
184 |
<TYPE>FINDINDIVIDUS</TYPE> |
|
185 |
<STATUS>NOK</STATUS> |
|
186 |
<COMMENTAIRES><![CDATA[Foo reason]]></COMMENTAIRES> |
|
187 |
</RESULTAT> |
|
188 |
<DATA> |
|
189 |
<PORTAIL/> |
|
190 |
</DATA> |
|
191 |
</PORTAILSERVICE> |
|
192 |
""".strip() |
|
193 |
with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client: |
|
194 |
client.return_value.service.getData.return_value = response |
|
195 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
196 |
assert resp.json['err_desc'] == 'Axel error: Foo reason' |
|
197 |
assert resp.json['err'] == 'error' |
|
198 |
assert resp.json['data']['xml_request'] == xml_request |
|
199 |
assert resp.json['data']['xml_response'] == xml_response |
|
200 | ||
201 |
content = """<PORTAIL> |
|
202 |
<FINDINDIVIDUS> |
|
203 |
<INDIVIDU> |
|
204 |
<IDENT>123</IDENT> |
|
205 |
<NOM>Doe</NOM> |
|
206 |
<PRENOM>John</PRENOM> |
|
207 |
<FAMILLE> |
|
208 |
<IDENTFAMILLE>12345</IDENTFAMILLE> |
|
209 |
<PLACE>2</PLACE> |
|
210 |
</FAMILLE> |
|
211 |
</INDIVIDU> |
|
212 |
</FINDINDIVIDUS> |
|
213 |
</PORTAIL>""" |
|
214 |
xml_response = ( |
|
215 |
"""<PORTAILSERVICE> |
|
216 |
<RESULTAT> |
|
217 |
<TYPE>FindIndividus</TYPE> |
|
218 |
<STATUS>OK</STATUS> |
|
219 |
<DATE>10/10/2010 10:10:01</DATE> |
|
220 |
<COMMENTAIRES /> |
|
221 |
</RESULTAT> |
|
222 |
<DATA> |
|
223 |
%s |
|
224 |
</DATA> |
|
225 |
</PORTAILSERVICE>""" |
|
226 |
% content |
|
227 |
) |
|
228 |
with mock_getdata(content, 'FindIndividus'): |
|
229 |
with mock.patch('passerelle.contrib.utils.axel.AxelSchema.decode') as decode: |
|
230 |
decode.side_effect = xmlschema.XMLSchemaValidationError(None, None) |
|
231 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
232 |
assert resp.json['err_desc'].startswith("Axel error: invalid response") |
|
233 |
assert resp.json['err'] == 'error' |
|
234 |
assert resp.json['data']['xml_request'] == xml_request |
|
235 |
assert resp.json['data']['xml_response'] == xml_response |
|
236 | ||
237 |
with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client: |
|
238 |
client.side_effect = SOAPError('SOAP service is down') |
|
239 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
240 |
assert resp.json['err_desc'] == "SOAP service is down" |
|
241 | ||
242 | ||
243 |
@pytest.mark.parametrize( |
|
244 |
'xml_response', |
|
245 |
[ |
|
246 |
'', |
|
247 |
"""<INDIVIDU> |
|
248 |
<IDENT>123</IDENT> |
|
249 |
<CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI/><GARDEALTERNEE/> |
|
250 |
<FAMILLE> |
|
251 |
<IDENTFAMILLE>12346</IDENTFAMILLE> |
|
252 |
<PLACE>2</PLACE> |
|
253 |
<SITUATION/> |
|
254 |
</FAMILLE> |
|
255 |
<FAMILLE> |
|
256 |
<IDENTFAMILLE>12347</IDENTFAMILLE> |
|
257 |
<PLACE>1</PLACE> |
|
258 |
</FAMILLE> |
|
259 |
</INDIVIDU>""", |
|
260 |
"""<INDIVIDU> |
|
261 |
<IDENT>123</IDENT> |
|
262 |
<CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI/><GARDEALTERNEE/> |
|
263 |
<FAMILLE> |
|
264 |
<IDENTFAMILLE>12345</IDENTFAMILLE> |
|
265 |
<PLACE>3</PLACE> |
|
266 |
<SITUATION/> |
|
267 |
</FAMILLE> |
|
268 |
</INDIVIDU>""", |
|
269 |
], |
|
270 |
) |
|
271 |
def test_link_endpoint_no_result(app, resource, link_params, xml_response): |
|
272 |
content = ( |
|
273 |
'''<PORTAIL> |
|
274 |
<FINDINDIVIDUS> |
|
275 |
<CODE>42</CODE> |
|
276 |
%s |
|
277 |
</FINDINDIVIDUS> |
|
278 |
</PORTAIL>''' |
|
279 |
% xml_response |
|
280 |
) |
|
281 |
with mock_getdata(content, 'FindIndividus'): |
|
282 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
283 |
assert resp.json['err_desc'] == "Person not found" |
|
284 |
assert resp.json['err'] == 'not-found' |
|
285 | ||
286 | ||
287 |
def test_link_endpoint_conflict(app, resource, link_params): |
|
288 |
content = """<PORTAIL><FINDINDIVIDUS> |
|
289 |
<CODE>42</CODE> |
|
290 |
<INDIVIDU> |
|
291 |
<IDENT>123</IDENT> |
|
292 |
<CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI/><GARDEALTERNEE/> |
|
293 |
<FAMILLE> |
|
294 |
<IDENTFAMILLE>12345</IDENTFAMILLE> |
|
295 |
<PLACE>2</PLACE> |
|
296 |
<SITUATION/> |
|
297 |
</FAMILLE> |
|
298 |
</INDIVIDU> |
|
299 |
</FINDINDIVIDUS></PORTAIL>""" |
|
300 |
# existing link but family_id is wrong |
|
301 |
link = Link.objects.create(resource=resource, name_id='yyy', family_id='YYY', person_id='42') |
|
302 |
with mock_getdata(content, 'FindIndividus'): |
|
303 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
304 |
assert resp.json['err_desc'] == "Data conflict" |
|
305 |
assert resp.json['err'] == 'conflict' |
|
306 | ||
307 |
# existing link but person_id is wrong |
|
308 |
link.family_id = '12345' |
|
309 |
link.person_id = '35' |
|
310 |
link.save() |
|
311 |
with mock_getdata(content, 'FindIndividus'): |
|
312 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
313 |
assert resp.json['err_desc'] == "Data conflict" |
|
314 |
assert resp.json['err'] == 'conflict' |
|
315 | ||
316 | ||
317 |
@pytest.mark.parametrize('place', [1, 2]) |
|
318 |
def test_link_endpoint(app, resource, link_params, place): |
|
319 |
content = ( |
|
320 |
"""<PORTAIL><FINDINDIVIDUS> |
|
321 |
<CODE>42</CODE> |
|
322 |
<INDIVIDU> |
|
323 |
<IDENT>123</IDENT> |
|
324 |
<CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI/><GARDEALTERNEE/> |
|
325 |
<FAMILLE> |
|
326 |
<IDENTFAMILLE>12345</IDENTFAMILLE> |
|
327 |
<PLACE>%s</PLACE> |
|
328 |
<SITUATION/> |
|
329 |
</FAMILLE> |
|
330 |
</INDIVIDU> |
|
331 |
</FINDINDIVIDUS></PORTAIL>""" |
|
332 |
% place |
|
333 |
) |
|
334 |
with mock_getdata(content, 'FindIndividus'): |
|
335 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
336 |
assert set(resp.json.keys()) == set(['err', 'link', 'created', 'family_id', 'data']) |
|
337 |
assert resp.json['err'] == 0 |
|
338 |
assert resp.json['family_id'] == '12345' |
|
339 |
assert resp.json['created'] is True |
|
340 |
assert 'xml_request' in resp.json['data'] |
|
341 |
assert 'xml_response' in resp.json['data'] |
|
342 | ||
343 |
# again |
|
344 |
with mock_getdata(content, 'FindIndividus'): |
|
345 |
resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params) |
|
346 |
assert set(resp.json.keys()) == set(['err', 'link', 'created', 'family_id', 'data']) |
|
347 |
assert resp.json['err'] == 0 |
|
348 |
assert resp.json['family_id'] == '12345' |
|
349 |
assert resp.json['created'] is False # link already exists |
|
350 |
assert 'xml_request' in resp.json['data'] |
|
351 |
assert 'xml_response' in resp.json['data'] |
|
0 |
- |