0001-cityweb-add-cityweb-connector-15883.patch
debian/control | ||
---|---|---|
24 | 24 |
python-magic, |
25 | 25 |
python-suds, |
26 | 26 |
python-cmislib (>= 0.5), python-cmislib (< 0.6), |
27 |
python-lxml |
|
27 | 28 |
Recommends: python-soappy, python-phpserialize |
28 | 29 |
Suggests: python-sqlalchemy, python-mako |
29 | 30 |
Description: Uniform access to multiple data sources and services (Python module) |
passerelle/apps/cityweb/cityweb.py | ||
---|---|---|
1 |
# Copyright (C) 2017 Entr'ouvert |
|
2 |
# |
|
3 |
# This program is free software: you can redistribute it and/or modify it |
|
4 |
# under the terms of the GNU Affero General Public License as published |
|
5 |
# by the Free Software Foundation, either version 3 of the License, or |
|
6 |
# (at your option) any later version. |
|
7 |
# |
|
8 |
# This program is distributed in the hope that it will be useful, |
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
# GNU Affero General Public License for more details. |
|
12 |
# |
|
13 |
# You should have received a copy of the GNU Affero General Public License |
|
14 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 | ||
16 |
import os |
|
17 |
import zipfile |
|
18 |
from dateutil.parser import parse as dateutil_parse |
|
19 |
from lxml import etree, objectify as xobject |
|
20 | ||
21 |
from django.core.files.storage import default_storage |
|
22 |
from django.core.files.base import ContentFile |
|
23 | ||
24 |
from passerelle.utils.jsonresponse import APIError |
|
25 | ||
26 | ||
27 |
def is_clean(element): |
|
28 |
if not element.getchildren() and element.text is None: |
|
29 |
return False |
|
30 |
return all(is_clean(child) for child in element.iterchildren()) |
|
31 | ||
32 | ||
33 |
class BaseType(object): |
|
34 |
"""Base data binding object |
|
35 |
""" |
|
36 |
tagname = None |
|
37 | ||
38 |
def __repr__(self): |
|
39 |
return '<%s>' % self.tagname |
|
40 | ||
41 |
@classmethod |
|
42 |
def make_element(cls, tagname, value=None, namespace=None, nsmap=None): |
|
43 |
M = xobject.ElementMaker(annotate=False, namespace=namespace, |
|
44 |
nsmap=nsmap) |
|
45 |
return M(tagname, value) |
|
46 | ||
47 |
@property |
|
48 |
def xml(self): |
|
49 |
if isinstance(self, (SimpleType, DateType)): |
|
50 |
return self.make_element(self.tagname, self.value, namespace=self.namespace) |
|
51 |
tag = self.make_element(self.tagname, namespace=self.namespace, nsmap=self.nsmap) |
|
52 |
for subelt in self.sequence: |
|
53 |
attr = getattr(self, subelt, None) |
|
54 |
if not attr: |
|
55 |
continue |
|
56 |
if isinstance(attr, (str, unicode)) and attr: |
|
57 |
tag.append(self.make_element(subelt, attr, namespace=self.namespace)) |
|
58 |
else: |
|
59 |
xml = attr.xml |
|
60 |
if not is_clean(xml): |
|
61 |
continue |
|
62 |
tag.append(xml) |
|
63 |
xobject.deannotate(tag, xsi_nil=True) |
|
64 |
return tag |
|
65 | ||
66 |
def __str__(self): |
|
67 |
return etree.tostring(self.xml, pretty_print=True) |
|
68 | ||
69 | ||
70 |
class CityWebType(BaseType): |
|
71 |
namespace = 'http://tempuri.org/XMLSchema.xsd' |
|
72 |
nsmap = {'xs': 'http://tempuri.org/XMLSchema.xsd'} |
|
73 | ||
74 | ||
75 |
class SimpleType(CityWebType): |
|
76 |
"""Data binding class for SimpleType |
|
77 |
""" |
|
78 |
allowed_values = None |
|
79 | ||
80 |
def __init__(self, value): |
|
81 |
if value not in self.allowed_values: |
|
82 |
raise APIError('<%s> value (%s) not in %s' % (self.tagname, value, |
|
83 |
self.allowed_values)) |
|
84 |
self.value = value |
|
85 | ||
86 | ||
87 |
class DateType(CityWebType): |
|
88 | ||
89 |
def __init__(self, value): |
|
90 |
try: |
|
91 |
self.value = dateutil_parse(value).date().isoformat() |
|
92 |
except (ValueError,) as exc: |
|
93 |
raise APIError(exc.message) |
|
94 | ||
95 | ||
96 |
class ComplexType(CityWebType): |
|
97 |
"""Data binding class for ComplexType |
|
98 |
""" |
|
99 |
sequence = None |
|
100 |
pattern = None |
|
101 | ||
102 |
def __init__(self, data): |
|
103 |
if self.pattern: |
|
104 |
data = self.extract_by_pattern(data) |
|
105 |
self.data = data |
|
106 | ||
107 |
def extract_by_pattern(self, data): |
|
108 |
data = {key: value for key, value in data.iteritems() if self.pattern in key} |
|
109 |
data = {key.replace(self.pattern, ''): value for key, value in data.iteritems()} |
|
110 |
return data |
|
111 | ||
112 | ||
113 |
class BirthDate(DateType): |
|
114 |
tagname = 'date' |
|
115 | ||
116 | ||
117 |
class StartDate(DateType): |
|
118 |
tagname = 'dateDebut' |
|
119 | ||
120 | ||
121 |
class EndDate(DateType): |
|
122 |
tagname = 'dateFin' |
|
123 | ||
124 | ||
125 |
# SIMPLE TYPES |
|
126 | ||
127 | ||
128 |
class Document(SimpleType): |
|
129 |
tagname = 'natureDocument' |
|
130 |
allowed_values = ('CPI', 'EXTAF', 'EXTSF', 'EXTPL') |
|
131 | ||
132 | ||
133 |
class Origin(SimpleType): |
|
134 |
tagname = 'origine' |
|
135 |
allowed_values = ('internet', 'guichet', 'courrier') |
|
136 | ||
137 | ||
138 |
class Title(SimpleType): |
|
139 |
tagname = 'genre' |
|
140 |
allowed_values = ('M', 'Mme', 'Mlle') |
|
141 | ||
142 | ||
143 |
class Sex(SimpleType): |
|
144 |
tagname = 'sexe' |
|
145 |
allowed_values = ('F', 'M', 'NA') |
|
146 | ||
147 | ||
148 |
class Certificate(SimpleType): |
|
149 |
tagname = 'natureEvenement' |
|
150 |
allowed_values = ('NAI', 'DEC', 'MAR', 'REC') |
|
151 | ||
152 | ||
153 |
class ConcernedKind(SimpleType): |
|
154 |
tagname = 'typeInteresse' |
|
155 |
allowed_values = ('reconnu', 'auteur') |
|
156 | ||
157 | ||
158 |
# COMPLEX TYPES |
|
159 | ||
160 | ||
161 |
class Names(ComplexType): |
|
162 |
tagname = 'noms' |
|
163 |
sequence = ('nomDeFamille', 'nomUsgae', 'typeUsage') |
|
164 | ||
165 |
def __init__(self, data): |
|
166 |
super(Names, self).__init__(data) |
|
167 |
if self.data.get('lastname'): |
|
168 |
self.nomDeFamille = self.data['lastname'] |
|
169 |
self.nomUsage = self.data.get('usual_name', '') |
|
170 |
self.typeUsage = self.data.get('name_usage', '') |
|
171 | ||
172 | ||
173 |
class Place(ComplexType): |
|
174 |
tagname = 'lieu' |
|
175 |
sequence = ('ville', 'province', 'pays') |
|
176 | ||
177 |
def __init__(self, data): |
|
178 |
super(Place, self).__init__(data) |
|
179 |
if self.data.get('city'): |
|
180 |
self.ville = self.data['city'] |
|
181 |
self.province = self.data.get('county', '') |
|
182 |
self.pays = self.data.get('country', '') |
|
183 | ||
184 | ||
185 |
class Address(ComplexType): |
|
186 |
tagname = 'adresse' |
|
187 |
sequence = ('ligneAdr1', 'ligneAdr2', 'codePostal', |
|
188 |
'lieu', 'mail', 'tel') |
|
189 |
pattern = 'address_' |
|
190 | ||
191 |
def __init__(self, data): |
|
192 |
super(Address, self).__init__(data) |
|
193 |
self.ligneAdr1 = self.data.get('street', '') |
|
194 |
self.ligneAdr2 = self.data.get('complement', '') |
|
195 |
self.lieu = Place(self.data) |
|
196 |
self.mail = self.data.get('email', '') |
|
197 |
self.tel = self.data.get('phone', '') |
|
198 | ||
199 | ||
200 |
class Birth(ComplexType): |
|
201 |
tagname = 'naissance' |
|
202 |
sequence = ('date', 'lieu') |
|
203 |
pattern = 'birth_' |
|
204 | ||
205 |
def __init__(self, data): |
|
206 |
super(Birth, self).__init__(data) |
|
207 |
birthdate = self.data.get('date', None) |
|
208 |
if birthdate: |
|
209 |
self.date = BirthDate(birthdate) |
|
210 |
self.lieu = Place(self.data) |
|
211 | ||
212 | ||
213 |
class EventDate(ComplexType): |
|
214 |
tagname = 'dateEvenement' |
|
215 |
sequence = ('dateDebut', 'dateFin') |
|
216 | ||
217 |
def __init__(self, data): |
|
218 |
super(EventDate, self).__init__(data) |
|
219 |
self.dateDebut = StartDate(self.data['event_date_start']) |
|
220 |
if data.get('event_date_end', None): |
|
221 |
self.dateFin = EndDate(self.data['event_date_end']) |
|
222 | ||
223 | ||
224 |
class EventPlace(Place): |
|
225 |
tagname = 'lieuEvenement' |
|
226 |
pattern = 'event_' |
|
227 | ||
228 | ||
229 |
class Person(ComplexType): |
|
230 |
sequence = ('noms', 'prenoms', 'genre', 'adresse', 'sexe', |
|
231 |
'pere', 'mere', 'naissance') |
|
232 | ||
233 |
def __init__(self, data): |
|
234 |
super(Person, self).__init__(data) |
|
235 |
self.noms = Names(self.data) |
|
236 |
self.prenoms = self.data.get('firstnames', '') |
|
237 |
if self.data.get('title', None): |
|
238 |
self.genre = Title(self.data['title']) |
|
239 |
self.adresse = Address(self.data) |
|
240 |
if self.data.get('sex', None): |
|
241 |
self.sexe = Sex(self.data['sex']) |
|
242 |
self.naissance = Birth(self.data) |
|
243 | ||
244 | ||
245 |
class ApplicantPerson(Person): |
|
246 |
tagname = 'individu' |
|
247 |
pattern = 'applicant_' |
|
248 |
sequence = ('noms', 'prenoms', 'genre', 'adresse') |
|
249 | ||
250 | ||
251 |
class Parent(Person): |
|
252 |
sequence = ('noms', 'prenoms', 'genre') |
|
253 | ||
254 |
def __init__(self, data, pattern): |
|
255 |
self.pattern = pattern |
|
256 |
super(Parent, self).__init__(data) |
|
257 |
sex = self.data.get('sex') |
|
258 |
if sex: |
|
259 |
if sex == 'M': |
|
260 |
self.tagname = 'pere' |
|
261 |
else: |
|
262 |
self.tagname = 'mere' |
|
263 |
else: |
|
264 |
if pattern.startswith('parent1'): |
|
265 |
self.tagname = 'pere' |
|
266 |
else: |
|
267 |
self.tagname = 'mere' |
|
268 | ||
269 | ||
270 |
class ConcernedCommon(Person): |
|
271 |
sequence = ('noms', 'prenoms', 'genre', 'sexe', |
|
272 |
'parent1', 'parent2', 'naissance') |
|
273 | ||
274 |
def __init__(self, data): |
|
275 |
super(ConcernedCommon, self).__init__(data) |
|
276 |
self.parent1 = Parent(self.data, 'parent1_') |
|
277 |
self.parent2 = Parent(self.data, 'parent2_') |
|
278 | ||
279 | ||
280 |
class Concerned(ConcernedCommon): |
|
281 |
tagname = 'interesse' |
|
282 |
pattern = 'concerned_' |
|
283 | ||
284 | ||
285 |
class Partner(ConcernedCommon): |
|
286 |
tagname = 'conjoint' |
|
287 |
pattern = 'partner_' |
|
288 | ||
289 | ||
290 |
class Applicant(ComplexType): |
|
291 |
tagname = 'demandeur' |
|
292 |
sequence = ('qualiteDemandeur', 'individu') |
|
293 | ||
294 |
def __init__(self, data): |
|
295 |
self.qualiteDemandeur = data.get('applicant_status', '') |
|
296 |
self.individu = ApplicantPerson(data) |
|
297 | ||
298 | ||
299 |
class Event(ComplexType): |
|
300 |
tagname = 'evenement' |
|
301 |
sequence = ('interesse', 'conjoint', 'natureEvenement', |
|
302 |
'typeInteresse', 'dateEvenement', 'lieuEvenement') |
|
303 | ||
304 |
def __init__(self, data): |
|
305 |
certificate_type = data['certificate_type'] |
|
306 |
self.interesse = Concerned(data) |
|
307 |
if certificate_type == 'MAR': |
|
308 |
self.conjoint = Partner(data) |
|
309 |
self.natureEvenement = Certificate(data['certificate_type']) |
|
310 |
if data.get('concerned_kind', None): |
|
311 |
self.typeInteresse = ConcernedKind(data['concerned_kind']) |
|
312 |
self.dateEvenement = EventDate(data) |
|
313 |
self.lieuEvenement = EventPlace(data) |
|
314 | ||
315 | ||
316 |
class CivilStatusApplication(ComplexType): |
|
317 |
tagname = 'demandeEtatCivil' |
|
318 |
sequence = ( |
|
319 |
'identifiant', 'demandeur', 'natureDocument', 'nbExemplaire', |
|
320 |
'dateDemande', 'evenement', 'motif', 'origine', 'commentaire') |
|
321 | ||
322 |
def __init__(self, data): |
|
323 |
self.identifiant = data['application_id'] |
|
324 |
self.demandeur = Applicant(data) |
|
325 |
self.natureDocument = Document(data['document_type']) |
|
326 |
self.nbExemplaire = data['document_copies'] |
|
327 |
self.dateDemande = data['application_time'] |
|
328 |
self.evenement = Event(data) |
|
329 |
self.motif = data.get('application_reason', '') |
|
330 |
if data.get('application_origin', None): |
|
331 |
self.origine = Origin(data['application_origin']) |
|
332 |
self.commentaire = data.get('application_comment', '') |
|
333 | ||
334 |
def zip(self, path, filename): |
|
335 |
basename = os.path.join(path, filename) |
|
336 |
archname = basename + '.zip' |
|
337 |
filepath = basename + '.xml' |
|
338 |
content = etree.tostring(self.xml, pretty_print=True) |
|
339 |
default_storage.save(filepath, ContentFile(content)) |
|
340 |
with zipfile.ZipFile(archname, 'w') as zipf: |
|
341 |
zipf.write(filepath, os.path.basename(filepath)) |
|
342 |
return archname |
passerelle/apps/cityweb/migrations/0001_initial.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 |
('base', '0005_resourcelog'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.CreateModel( |
|
15 |
name='CityWeb', |
|
16 |
fields=[ |
|
17 |
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), |
|
18 |
('title', models.CharField(max_length=50)), |
|
19 |
('slug', models.SlugField()), |
|
20 |
('description', models.TextField()), |
|
21 |
('log_level', models.CharField(default=b'INFO', 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'), (b'FATAL', b'FATAL')])), |
|
22 |
('users', models.ManyToManyField(to='base.ApiUser', blank=True)), |
|
23 |
], |
|
24 |
options={ |
|
25 |
'verbose_name': "CityWeb - Demande d'acte d'\xe9tat civil", |
|
26 |
}, |
|
27 |
), |
|
28 |
migrations.CreateModel( |
|
29 |
name='Demand', |
|
30 |
fields=[ |
|
31 |
('created_at', models.DateTimeField(auto_now_add=True)), |
|
32 |
('updated_at', models.DateTimeField(auto_now=True)), |
|
33 |
('received_at', models.DateTimeField()), |
|
34 |
('demand_id', models.CharField(max_length=32, serialize=False, primary_key=True)), |
|
35 |
('kind', models.CharField(max_length=32)), |
|
36 |
('resource', models.ForeignKey(to='cityweb.CityWeb')), |
|
37 |
], |
|
38 |
), |
|
39 |
] |
passerelle/apps/cityweb/models.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Copyright (C) 2017 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 os |
|
18 |
import json |
|
19 | ||
20 |
from dateutil.parser import parse as dateutil_parse |
|
21 | ||
22 |
from django.db import models |
|
23 |
from django.utils.translation import ugettext_lazy as _ |
|
24 |
from django.core.files.storage import default_storage |
|
25 | ||
26 |
from passerelle.base.models import BaseResource |
|
27 |
from passerelle.utils.api import endpoint |
|
28 |
from passerelle.utils.jsonresponse import APIError |
|
29 | ||
30 |
from .cityweb import CivilStatusApplication |
|
31 | ||
32 | ||
33 |
CERTIFICATE_TYPES = [ |
|
34 |
{"id": "NAI", "text": "Naissance"}, |
|
35 |
{"id": "MAR", "text": "Mariage"}, |
|
36 |
{"id": "REC", "text": "Reconnaissance"}, |
|
37 |
{"id": "DEC", "text": "Décès"} |
|
38 |
] |
|
39 | ||
40 |
SEXES = [ |
|
41 |
{"id": "M", "text": "Homme"}, |
|
42 |
{"id": "F", "text": "Femme"}, |
|
43 |
{"id": "NA", "text": "Autre"} |
|
44 |
] |
|
45 | ||
46 |
TITLES = [ |
|
47 |
{"id": "M", "text": "Monsieur"}, |
|
48 |
{"id": "Mme", "text": "Madame"}, |
|
49 |
{"id": "Mlle", "text": "Mademoiselle"} |
|
50 |
] |
|
51 | ||
52 |
DOCUMENT_TYPES = [ |
|
53 |
{"id": "CPI", "text": "Copie intégrale"}, |
|
54 |
{"id": "EXTAF", "text": "Extrait avec filiation"}, |
|
55 |
{"id": "EXTSF", "text": "Extrait sans filiation"}, |
|
56 |
{"id": "EXTPL", "text": "Extrait plurilingue"} |
|
57 |
] |
|
58 | ||
59 |
CONCERNED = [ |
|
60 |
{"id": "reconnu", "text": "Reconnu"}, |
|
61 |
{"id": "auteur", "text": "Auteur"} |
|
62 |
] |
|
63 | ||
64 |
ORIGINS = [ |
|
65 |
{"id": "internet", "text": "Internet"}, |
|
66 |
{"id": "guichet", "text": "Guichet"}, |
|
67 |
{"id": "courrier", "text": "Courrier"} |
|
68 |
] |
|
69 | ||
70 | ||
71 |
class CityWeb(BaseResource): |
|
72 |
category = _('Business Process Connectors') |
|
73 | ||
74 |
class Meta: |
|
75 |
verbose_name = "CityWeb - Demande d'acte d'état civil" |
|
76 | ||
77 |
@classmethod |
|
78 |
def get_verbose_name(cls): |
|
79 |
return cls._meta.verbose_name |
|
80 | ||
81 |
@endpoint(perm='can_access', methods=['post'], description=_('Create a demand')) |
|
82 |
def create(self, request, *args, **kwargs): |
|
83 |
payload = json.loads(request.body) |
|
84 |
# check mandatory keys |
|
85 |
for key in ('application_id', 'application_time', 'certificate_type'): |
|
86 |
if key not in payload: |
|
87 |
raise APIError('<%s> is required' % key) |
|
88 | ||
89 |
attrs = { |
|
90 |
'demand_id': '%s-%s' % (payload['application_id'], payload['certificate_type']), |
|
91 |
'kind': payload['certificate_type'], 'resource': self, |
|
92 |
'received_at': dateutil_parse(payload['application_time'])} |
|
93 | ||
94 |
demand, created = Demand.objects.get_or_create(**attrs) |
|
95 |
result = demand.create(payload) |
|
96 |
return {'data': {'demand_id': result}} |
|
97 | ||
98 |
@endpoint(perm='can_access', description=_('Get title list')) |
|
99 |
def titles(self, request): |
|
100 |
return {'data': TITLES} |
|
101 | ||
102 |
@endpoint(perm='can_access', description=_('Get sex list')) |
|
103 |
def sexes(self, request): |
|
104 |
return {'data': SEXES} |
|
105 | ||
106 |
@endpoint(perm='can_access', description=_('Get concerned status list')) |
|
107 |
def concerned(self, request): |
|
108 |
return {'data': CONCERNED} |
|
109 | ||
110 |
@endpoint(perm='can_access', description=_('Get application origin list')) |
|
111 |
def origins(self, request): |
|
112 |
return {'data': ORIGINS} |
|
113 | ||
114 |
@endpoint(name='certificate-types', perm='can_access', |
|
115 |
description=_('Get certificate type list'), parameters={'exclude': {'example_value': 'REC'}}) |
|
116 |
def certificate_types(self, request, exclude=''): |
|
117 |
return {'data': [item for item in CERTIFICATE_TYPES |
|
118 |
if item.get('id') not in exclude.split(',')]} |
|
119 | ||
120 |
@endpoint(name='document-types', perm='can_access', |
|
121 |
description=_('Get document type list'), parameters={'exclude': {'example_value': 'EXTPL'}}) |
|
122 |
def document_types(self, request, exclude=''): |
|
123 |
return {'data': [item for item in DOCUMENT_TYPES |
|
124 |
if item.get('id') not in exclude.split(',')]} |
|
125 | ||
126 | ||
127 |
class Demand(models.Model): |
|
128 |
created_at = models.DateTimeField(auto_now_add=True) |
|
129 |
updated_at = models.DateTimeField(auto_now=True) |
|
130 |
received_at = models.DateTimeField() |
|
131 |
resource = models.ForeignKey(CityWeb) |
|
132 |
demand_id = models.CharField(max_length=32, primary_key=True) |
|
133 |
kind = models.CharField(max_length=32) |
|
134 | ||
135 |
def __unicode__(self): |
|
136 |
return '%s - %s' % (self.resource.slug, self.demand_id) |
|
137 | ||
138 |
@property |
|
139 |
def basepath(self): |
|
140 |
return os.path.join( |
|
141 |
default_storage.path('cityweb'), self.resource.slug) |
|
142 | ||
143 |
def create(self, data): |
|
144 |
application = CivilStatusApplication(data) |
|
145 |
application.zip(self.basepath, self.demand_id) |
|
146 |
return self.demand_id |
passerelle/settings.py | ||
---|---|---|
116 | 116 |
'passerelle.apps.airquality', |
117 | 117 |
'passerelle.apps.okina', |
118 | 118 |
'passerelle.apps.cmis', |
119 |
'passerelle.apps.cityweb', |
|
119 | 120 |
# backoffice templates and static |
120 | 121 |
'gadjo', |
121 | 122 |
) |
setup.py | ||
---|---|---|
98 | 98 |
'pyexcel-xls >= 0.4, <0.5', |
99 | 99 |
'cmislib >= 0.5, <0.6', |
100 | 100 |
'feedparser', |
101 |
'lxml' |
|
101 | 102 |
], |
102 | 103 |
cmdclass={ |
103 | 104 |
'build': build, |
tests/data/cityweb/cityweb.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8"?> |
|
2 |
<!-- edited with XMLSpy v2005 U (http://www.xmlspy.com) by judlin (digitech) --> |
|
3 |
<xs:schema xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified"> |
|
4 |
<xs:element name="demandeEtatCivil"> |
|
5 |
<xs:annotation> |
|
6 |
<xs:documentation>Root element</xs:documentation> |
|
7 |
</xs:annotation> |
|
8 |
<xs:complexType> |
|
9 |
<xs:sequence> |
|
10 |
<xs:element name="identifiant" type="xs:string" /> |
|
11 |
<xs:element name="demandeur" type="demandeurType" minOccurs="0"> |
|
12 |
<xs:annotation> |
|
13 |
<xs:documentation>utile si différent de l'interessé</xs:documentation> |
|
14 |
</xs:annotation> |
|
15 |
</xs:element> |
|
16 |
<xs:element name="natureDocument" type="natureDocumentType"> |
|
17 |
<xs:annotation> |
|
18 |
<xs:documentation>copie intégrale, extrait avec ou sans filiation, plurilingue</xs:documentation> |
|
19 |
</xs:annotation> |
|
20 |
</xs:element> |
|
21 |
<xs:element name="nbExemplaire" type="xs:int" minOccurs="0" /> |
|
22 |
<xs:element name="dateDemande" type="xs:dateTime" /> |
|
23 |
<xs:element name="evenement" type="evenementType" /> |
|
24 |
<xs:element name="motif" type="xs:string" minOccurs="0" /> |
|
25 |
<xs:element name="origine" type="origineECType" minOccurs="0"> |
|
26 |
<xs:annotation> |
|
27 |
<xs:documentation>origine de la demande pour l'état civil : courrier, guichet ou internet</xs:documentation> |
|
28 |
</xs:annotation> |
|
29 |
</xs:element> |
|
30 |
<xs:element name="commentaire" type="xs:string" minOccurs="0" > |
|
31 |
<xs:annotation> |
|
32 |
<xs:documentation>champ commentaire</xs:documentation> |
|
33 |
</xs:annotation> |
|
34 |
</xs:element> |
|
35 |
</xs:sequence> |
|
36 |
<xs:attribute name="version" type="xs:string" default="1.0"/> |
|
37 |
</xs:complexType> |
|
38 |
</xs:element> |
|
39 |
<xs:simpleType name="natureEvenementType"> |
|
40 |
<xs:annotation> |
|
41 |
<xs:documentation>Naissance, mariage, décès, reconnaissance</xs:documentation> |
|
42 |
</xs:annotation> |
|
43 |
<xs:restriction base="xs:string"> |
|
44 |
<xs:enumeration value="NAI"/> |
|
45 |
<xs:enumeration value="DEC"/> |
|
46 |
<xs:enumeration value="MAR"/> |
|
47 |
<xs:enumeration value="REC"/> |
|
48 |
</xs:restriction> |
|
49 |
</xs:simpleType> |
|
50 |
<xs:complexType name="individuType"> |
|
51 |
<xs:sequence> |
|
52 |
<xs:element name="noms" type="nomsType"/> |
|
53 |
<xs:element name="prenoms" type="xs:string" minOccurs="0"/> |
|
54 |
<xs:element name="genre" type="genreType" minOccurs="0"/> |
|
55 |
<xs:element name="adresse" type="adresseType" minOccurs="0"/> |
|
56 |
<xs:element name="sexe" type="sexeType" minOccurs="0"/> |
|
57 |
<xs:element name="pere" type="individuType" minOccurs="0"/> |
|
58 |
<xs:element name="mere" type="individuType" minOccurs="0"/> |
|
59 |
<xs:element name="naissance" type="naissanceType" minOccurs="0"/> |
|
60 |
</xs:sequence> |
|
61 |
</xs:complexType> |
|
62 |
<xs:complexType name="demandeurType"> |
|
63 |
<xs:annotation> |
|
64 |
<xs:documentation>Informations sur le demandeur</xs:documentation> |
|
65 |
</xs:annotation> |
|
66 |
<xs:sequence> |
|
67 |
<xs:element name="qualiteDemandeur" type="xs:string"> |
|
68 |
<xs:annotation> |
|
69 |
<xs:documentation>avocat, notaire, père, mère...</xs:documentation> |
|
70 |
</xs:annotation> |
|
71 |
</xs:element> |
|
72 |
<xs:element name="individu" type="individuType"/> |
|
73 |
</xs:sequence> |
|
74 |
</xs:complexType> |
|
75 |
<xs:simpleType name="sexeType"> |
|
76 |
<xs:annotation> |
|
77 |
<xs:documentation>permet de gérer le sexe indeterminé</xs:documentation> |
|
78 |
</xs:annotation> |
|
79 |
<xs:restriction base="xs:string"> |
|
80 |
<xs:enumeration value="F"/> |
|
81 |
<xs:enumeration value="M"/> |
|
82 |
<xs:enumeration value="NA"/> |
|
83 |
</xs:restriction> |
|
84 |
</xs:simpleType> |
|
85 |
<xs:simpleType name="genreType"> |
|
86 |
<xs:restriction base="xs:string"> |
|
87 |
<xs:enumeration value="M"/> |
|
88 |
<xs:enumeration value="Mme"/> |
|
89 |
<xs:enumeration value="Mlle"/> |
|
90 |
</xs:restriction> |
|
91 |
</xs:simpleType> |
|
92 |
<xs:complexType name="adresseType"> |
|
93 |
<xs:sequence> |
|
94 |
<xs:element name="ligneAdr1" type="xs:string" minOccurs="0"/> |
|
95 |
<xs:element name="ligneAdr2" type="xs:string" minOccurs="0"/> |
|
96 |
<xs:element name="codePostal" type="xs:string" minOccurs="0"/> |
|
97 |
<xs:element name="lieu" type="lieuType"/> |
|
98 |
<xs:element name="mail" type="xs:string" minOccurs="0"/> |
|
99 |
<xs:element name="tel" type="xs:string" minOccurs="0"/> |
|
100 |
</xs:sequence> |
|
101 |
</xs:complexType> |
|
102 |
<xs:simpleType name="typeInteresseType"> |
|
103 |
<xs:restriction base="xs:string"> |
|
104 |
<xs:enumeration value="reconnu"/> |
|
105 |
<xs:enumeration value="auteur"/> |
|
106 |
</xs:restriction> |
|
107 |
</xs:simpleType> |
|
108 |
<xs:simpleType name="natureDocumentType"> |
|
109 |
<xs:restriction base="xs:string"> |
|
110 |
<xs:enumeration value="CPI"/> |
|
111 |
<xs:enumeration value="EXTAF"/> |
|
112 |
<xs:enumeration value="EXTSF"/> |
|
113 |
<xs:enumeration value="EXTPL"/> |
|
114 |
</xs:restriction> |
|
115 |
</xs:simpleType> |
|
116 |
<xs:simpleType name="origineECType"> |
|
117 |
<xs:restriction base="xs:string"> |
|
118 |
<xs:enumeration value="internet"/> |
|
119 |
<xs:enumeration value="guichet"/> |
|
120 |
<xs:enumeration value="courrier"/> |
|
121 |
</xs:restriction> |
|
122 |
</xs:simpleType> |
|
123 |
<xs:complexType name="evenementType"> |
|
124 |
<xs:sequence> |
|
125 |
<xs:element name="interesse" type="individuType"/> |
|
126 |
<xs:element name="conjoint" type="individuType" minOccurs="0"> |
|
127 |
<xs:annotation> |
|
128 |
<xs:documentation>Seulement pour les mariages</xs:documentation> |
|
129 |
</xs:annotation> |
|
130 |
</xs:element> |
|
131 |
<xs:element name="natureEvenement" type="natureEvenementType"> |
|
132 |
<xs:annotation> |
|
133 |
<xs:documentation>naissance, mariage, décès, reconnaissance</xs:documentation> |
|
134 |
</xs:annotation> |
|
135 |
</xs:element> |
|
136 |
<xs:element name="typeInteresse" type="typeInteresseType" minOccurs="0"> |
|
137 |
<xs:annotation> |
|
138 |
<xs:documentation>necessaire pour les reconnaissances seulement, l'interessé pouvant etre le parent ou le reconnu, il faut donc préciser.</xs:documentation> |
|
139 |
</xs:annotation> |
|
140 |
</xs:element> |
|
141 |
<xs:element name="dateEvenement" type="dateEvenementType"/> |
|
142 |
<xs:element name="lieuEvenement" type="lieuType"/> |
|
143 |
</xs:sequence> |
|
144 |
</xs:complexType> |
|
145 |
<xs:complexType name="nomsType"> |
|
146 |
<xs:sequence> |
|
147 |
<xs:element name="nomDeFamille" type="xs:string"/> |
|
148 |
<xs:element name="nomUsage" type="xs:string" minOccurs="0"/> |
|
149 |
<xs:element name="typeUsage" type="xs:string" minOccurs="0"> |
|
150 |
<xs:annotation> |
|
151 |
<xs:documentation>précission sur le nom d'usage: nom d'épouse, veuve, d'usage...</xs:documentation> |
|
152 |
</xs:annotation> |
|
153 |
</xs:element> |
|
154 |
</xs:sequence> |
|
155 |
</xs:complexType> |
|
156 |
<xs:complexType name="naissanceType"> |
|
157 |
<xs:sequence> |
|
158 |
<xs:element name="date" type="dateCiviqueType"/> |
|
159 |
<xs:element name="lieu" type="lieuType" minOccurs="0"/> |
|
160 |
</xs:sequence> |
|
161 |
</xs:complexType> |
|
162 |
<xs:complexType name="lieuType"> |
|
163 |
<xs:sequence> |
|
164 |
<xs:element name="ville" type="xs:string"/> |
|
165 |
<xs:element name="province" type="xs:string" minOccurs="0"/> |
|
166 |
<xs:element name="pays" type="xs:string" minOccurs="0"/> |
|
167 |
</xs:sequence> |
|
168 |
</xs:complexType> |
|
169 |
<xs:complexType name="dateEvenementType"> |
|
170 |
<xs:sequence> |
|
171 |
<xs:element name="dateDebut" type="xs:date"/> |
|
172 |
<xs:element name="dateFin" type="xs:date" minOccurs="0"/> |
|
173 |
</xs:sequence> |
|
174 |
</xs:complexType> |
|
175 |
<xs:simpleType name="dateCiviqueType"> |
|
176 |
<xs:annotation> |
|
177 |
<xs:documentation>Permet de gérer les dates incomplètes</xs:documentation> |
|
178 |
</xs:annotation> |
|
179 |
<xs:union memberTypes="xs:date xs:gYear xs:gYearMonth"/> |
|
180 |
</xs:simpleType> |
|
181 |
</xs:schema> |
tests/data/cityweb/payload_birth.json | ||
---|---|---|
1 |
{ |
|
2 |
"applicant_address_city": "Nancy", |
|
3 |
"applicant_address_complement": "Bat A", |
|
4 |
"applicant_address_country": "France", |
|
5 |
"applicant_address_county": "Meurthe-et-Moselle", |
|
6 |
"applicant_address_email": "chelsea@whatever.com", |
|
7 |
"applicant_address_phone": "+33 6 55 44 22 11", |
|
8 |
"applicant_address_street": "37 Rue du Cheval Blanc", |
|
9 |
"applicant_address_zipcode": "54000", |
|
10 |
"applicant_firstnames": "Kim Chelsea", |
|
11 |
"applicant_lastname": "Whatever", |
|
12 |
"applicant_name_usage": "nom d'epouse", |
|
13 |
"applicant_status": "concerne", |
|
14 |
"applicant_title": "Mme", |
|
15 |
"applicant_title_label": "Madame", |
|
16 |
"applicant_usual_name": "Whatever", |
|
17 |
"application_id": "15-4", |
|
18 |
"application_origin": "internet", |
|
19 |
"application_reason": "They are just messy", |
|
20 |
"application_time": "2016-10-20T14:41:20Z", |
|
21 |
"certificate_type": "NAI", |
|
22 |
"certificate_type_label": "Acte de naissance", |
|
23 |
"concerned_birth_city": "Harare", |
|
24 |
"concerned_birth_country": "Zimbabwe", |
|
25 |
"concerned_birth_county": "", |
|
26 |
"concerned_birth_date": "1980-02-29", |
|
27 |
"concerned_firstnames": "Kevin", |
|
28 |
"concerned_lastname": "Whatever", |
|
29 |
"concerned_name_usage": "", |
|
30 |
"concerned_parent1_firstnames": "John Oliver", |
|
31 |
"concerned_parent1_lastname": "Smith", |
|
32 |
"concerned_parent1_name_usage": "Smith", |
|
33 |
"concerned_parent1_title": "M", |
|
34 |
"concerned_parent1_title_label": "Monsieur", |
|
35 |
"concerned_parent1_usual_name": "Smith", |
|
36 |
"concerned_parent2_firstnames": "Kim", |
|
37 |
"concerned_parent2_lastname": "Smith", |
|
38 |
"concerned_parent2_name_usage": "nom d'\u00e9pouse", |
|
39 |
"concerned_parent2_title": "Mme", |
|
40 |
"concerned_parent2_usual_name": "Smith", |
|
41 |
"concerned_sex": "M", |
|
42 |
"concerned_title": "M", |
|
43 |
"concerned_usual_name": "Whatever", |
|
44 |
"document_copies": "1", |
|
45 |
"document_type": "CPI", |
|
46 |
"document_type_label": "Copie Integrale", |
|
47 |
"event_city": "Nancy", |
|
48 |
"event_date_end": "", |
|
49 |
"event_date_start": "2012-07-14" |
|
50 |
} |
tests/data/cityweb/payload_death.json | ||
---|---|---|
1 |
{ |
|
2 |
"applicant_address_city": "Nancy", |
|
3 |
"applicant_address_complement": "Bat A", |
|
4 |
"applicant_address_country": "France", |
|
5 |
"applicant_address_county": "Meurthe-et-Moselle", |
|
6 |
"applicant_address_email": "chelsea@whatever.com", |
|
7 |
"applicant_address_phone": "+33 6 55 44 22 11", |
|
8 |
"applicant_address_street": "37 Rue du Cheval Blanc", |
|
9 |
"applicant_address_zipcode": "54000", |
|
10 |
"applicant_firstnames": "Kim Chelsea", |
|
11 |
"applicant_lastname": "Whatever", |
|
12 |
"applicant_name_usage": "nom d'epouse", |
|
13 |
"applicant_status": "concerne", |
|
14 |
"applicant_title": "Mme", |
|
15 |
"applicant_title_label": "Madame", |
|
16 |
"applicant_usual_name": "Whatever", |
|
17 |
"application_origin": "internet", |
|
18 |
"application_id": "17-1", |
|
19 |
"application_reason": "", |
|
20 |
"application_time": "2016-10-20T14:41:20Z", |
|
21 |
"certificate_type": "DEC", |
|
22 |
"certificate_type_label": "Acte de d\u00e9c\u00e8s", |
|
23 |
"concerned_birth_city": "Harare", |
|
24 |
"concerned_birth_country": "Zimbabwe", |
|
25 |
"concerned_birth_county": "", |
|
26 |
"concerned_birth_date": "1980-02-29", |
|
27 |
"concerned_firstnames": "Kevin", |
|
28 |
"concerned_lastname": "Whatever", |
|
29 |
"concerned_sex": "M", |
|
30 |
"concerned_title": "M", |
|
31 |
"concerned_usual_name": "Whatever", |
|
32 |
"document_copies": "1", |
|
33 |
"document_type": "EXTSF", |
|
34 |
"document_type_label": "Extrait sans filiation", |
|
35 |
"event_city": "Nancy", |
|
36 |
"event_date_start": "2012-07-14" |
|
37 |
} |
tests/data/cityweb/payload_mariage.json | ||
---|---|---|
1 |
{ |
|
2 |
"applicant_address_city": "Nancy", |
|
3 |
"applicant_address_complement": "Bat A", |
|
4 |
"applicant_address_country": "France", |
|
5 |
"applicant_address_county": "Meurthe-et-Moselle", |
|
6 |
"applicant_address_email": "chelsea@whatever.com", |
|
7 |
"applicant_address_phone": "+33 6 55 44 22 11", |
|
8 |
"applicant_address_street": "37 Rue du Cheval Blanc", |
|
9 |
"applicant_address_zipcode": "54000", |
|
10 |
"applicant_firstnames": "Kim Chelsea", |
|
11 |
"applicant_lastname": "Whatever", |
|
12 |
"applicant_name_usage": "nom d'epouse", |
|
13 |
"applicant_status": "concerne", |
|
14 |
"applicant_title": "Mme", |
|
15 |
"applicant_title_label": "Madame", |
|
16 |
"applicant_usual_name": "Whatever", |
|
17 |
"application_id": "16-1", |
|
18 |
"application_origin": "internet", |
|
19 |
"application_reason": "Happy mariage", |
|
20 |
"application_time": "2016-10-20T14:41:20Z", |
|
21 |
"certificate_type": "MAR", |
|
22 |
"certificate_type_label": "Acte de naissance", |
|
23 |
"concerned_birth_city": "Harare", |
|
24 |
"concerned_birth_country": "Zimbabwe", |
|
25 |
"concerned_birth_county": "", |
|
26 |
"concerned_birth_date": "1980-02-29", |
|
27 |
"concerned_parent1_firstnames": "John Oliver", |
|
28 |
"concerned_parent1_lastname": "Smith", |
|
29 |
"concerned_parent1_name_usage": "Smith", |
|
30 |
"concerned_parent1_title": "M", |
|
31 |
"concerned_parent1_title_label": "Monsieur", |
|
32 |
"concerned_parent1_usual_name": "Smith", |
|
33 |
"concerned_firstnames": "Kevin", |
|
34 |
"concerned_lastname": "Whatever", |
|
35 |
"concerned_parent2_firstnames": "Kim", |
|
36 |
"concerned_parent2_lastname": "Smith", |
|
37 |
"concerned_parent2_name_usage": "nom d'\u00e9pouse", |
|
38 |
"concerned_parent2_title": "Mme", |
|
39 |
"concerned_parent2_usual_name": "Smith", |
|
40 |
"concerned_name_usage": "", |
|
41 |
"concerned_sex": "M", |
|
42 |
"concerned_title": "M", |
|
43 |
"document_copies": "1", |
|
44 |
"document_type": "CPI", |
|
45 |
"document_type_label": "Copie Integrale", |
|
46 |
"event_city": "Nancy", |
|
47 |
"event_date_end": "", |
|
48 |
"event_date_start": "2012-07-14", |
|
49 |
"partner_birth_city": "Harare", |
|
50 |
"partner_birth_country": "Zimbabwe", |
|
51 |
"partner_birth_county": "", |
|
52 |
"partner_birth_date": "1984-02-29", |
|
53 |
"partner_parent1_firstnames": "Antonio", |
|
54 |
"partner_parent1_lastname": "Scaramucci", |
|
55 |
"partner_parent1_title": "M", |
|
56 |
"partner_parent1_title_label": "Monsieur", |
|
57 |
"partner_firstnames": "Chelsea", |
|
58 |
"partner_lastname": "Contrao", |
|
59 |
"partner_parent2_firstnames": "Marguerite", |
|
60 |
"partner_parent2_lastname": "Scaramucci", |
|
61 |
"partner_parent2_name_usage": "nom d'\u00e9pouse", |
|
62 |
"partner_parent2_title": "Mme", |
|
63 |
"partner_parent2_usual_name": "Gaye", |
|
64 |
"partner_name_usage": "", |
|
65 |
"partner_sex": "F", |
|
66 |
"partner_title": "Mme", |
|
67 |
"partner_usual_name": "Scaramucci" |
|
68 |
} |
tests/test_cityweb.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Passerelle - uniform access to data and services |
|
3 |
# Copyright (C) 2017 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; exclude 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.deepcopy of the GNU Affero General Public License |
|
16 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 |
from __future__ import unicode_literals |
|
18 | ||
19 |
import os |
|
20 |
import json |
|
21 |
import shutil |
|
22 | ||
23 |
import pytest |
|
24 |
import mock |
|
25 |
from lxml import etree, objectify as xobject |
|
26 | ||
27 |
import utils |
|
28 | ||
29 |
from passerelle.apps.cityweb.models import CityWeb |
|
30 | ||
31 | ||
32 |
def get_test_base_dir(name): |
|
33 |
return os.path.join(os.path.dirname(__file__), 'data', name) |
|
34 | ||
35 | ||
36 |
def get_file_from_test_base_dir(filename): |
|
37 |
path = os.path.join(get_test_base_dir('cityweb'), filename) |
|
38 |
with open(path, 'rb') as fd: |
|
39 |
return fd.read() |
|
40 | ||
41 | ||
42 |
@pytest.fixture |
|
43 |
def setup(db): |
|
44 |
return utils.setup_access_rights(CityWeb.objects.create(slug='test')) |
|
45 | ||
46 | ||
47 |
PAYLOAD = [ |
|
48 |
{ |
|
49 |
'birth': json.loads(get_file_from_test_base_dir('payload_birth.json')) |
|
50 |
}, |
|
51 |
{ |
|
52 |
'mariage': json.loads(get_file_from_test_base_dir('payload_mariage.json')) |
|
53 |
}, |
|
54 |
{ |
|
55 |
'death': json.loads(get_file_from_test_base_dir('payload_death.json')) |
|
56 |
} |
|
57 |
] |
|
58 | ||
59 | ||
60 |
@pytest.fixture(params=PAYLOAD) |
|
61 |
def payload(request): |
|
62 |
return request.param |
|
63 | ||
64 | ||
65 |
def assert_xml_doc(doc): |
|
66 |
schema = etree.XMLSchema( |
|
67 |
etree.parse(os.path.join(get_test_base_dir('cityweb'), 'cityweb.xsd'))) |
|
68 |
schema.assertValid(doc) |
|
69 | ||
70 | ||
71 |
@mock.patch('passerelle.apps.cityweb.models.default_storage.path', get_test_base_dir) |
|
72 |
def test_demand_creation(app, setup, payload): |
|
73 |
url = '/cityweb/test/create/' |
|
74 |
if 'birth' in payload: |
|
75 |
response = app.post_json(url, params=payload['birth']) |
|
76 |
assert response.json['data']['demand_id'] == '15-4-NAI' |
|
77 |
doc = xobject.parse( |
|
78 |
os.path.join(get_test_base_dir('cityweb'), 'test', '15-4-NAI.xml')) |
|
79 |
assert_xml_doc(doc) |
|
80 | ||
81 |
elif 'mariage' in payload: |
|
82 |
response = app.post_json(url, params=payload['mariage']) |
|
83 |
assert response.json['data']['demand_id'] == '16-1-MAR' |
|
84 |
doc = etree.parse( |
|
85 |
os.path.join(get_test_base_dir('cityweb'), 'test', '16-1-MAR.xml')) |
|
86 |
assert_xml_doc(doc) |
|
87 |
else: |
|
88 |
response = app.post_json(url, params=payload['death']) |
|
89 |
assert response.json['data']['demand_id'] == '17-1-DEC' |
|
90 |
doc = etree.parse( |
|
91 |
os.path.join(get_test_base_dir('cityweb'), 'test', '17-1-DEC.xml')) |
|
92 |
assert_xml_doc(doc) |
|
93 | ||
94 | ||
95 |
def test_datasource_titles(app, setup): |
|
96 |
response = app.get('/cityweb/test/titles/') |
|
97 |
data = response.json['data'] |
|
98 |
assert len(data) == 3 |
|
99 |
for datum in data: |
|
100 |
if datum['id'] == 'M': |
|
101 |
assert datum['text'] == 'Monsieur' |
|
102 |
elif datum['id'] == 'Mme': |
|
103 |
assert datum['text'] == 'Madame' |
|
104 |
else: |
|
105 |
assert datum['id'] == 'Mlle' |
|
106 |
assert datum['text'] == 'Mademoiselle' |
|
107 | ||
108 | ||
109 |
def test_datasource_sexes(app, setup): |
|
110 |
response = app.get('/cityweb/test/sexes/') |
|
111 |
data = response.json['data'] |
|
112 |
assert len(data) == 3 |
|
113 |
for datum in data: |
|
114 |
if datum['id'] == 'M': |
|
115 |
assert datum['text'] |
|
116 |
elif datum['id'] == 'F': |
|
117 |
assert datum['text'] == 'Femme' |
|
118 |
else: |
|
119 |
assert datum['id'] == 'NA' |
|
120 |
assert datum['text'] == 'Autre' |
|
121 | ||
122 | ||
123 |
def test_datasource_concerned(app, setup): |
|
124 |
response = app.get('/cityweb/test/concerned/') |
|
125 |
data = response.json['data'] |
|
126 |
assert len(data) == 2 |
|
127 |
for datum in data: |
|
128 |
if datum['id'] == 'reconnu': |
|
129 |
assert datum['text'] == 'Reconnu' |
|
130 |
else: |
|
131 |
assert datum['id'] == 'auteur' |
|
132 |
assert datum['text'] == 'Auteur' |
|
133 | ||
134 | ||
135 |
def test_datasource_origins(app, setup): |
|
136 |
response = app.get('/cityweb/test/origins/') |
|
137 |
data = response.json['data'] |
|
138 |
assert len(data) == 3 |
|
139 |
for datum in data: |
|
140 |
if datum['id'] == 'internet': |
|
141 |
assert datum['text'] == 'Internet' |
|
142 |
elif datum['id'] == 'guichet': |
|
143 |
assert datum['text'] == 'Guichet' |
|
144 |
else: |
|
145 |
assert datum['id'] == 'courrier' |
|
146 |
assert datum['text'] == 'Courrier' |
|
147 | ||
148 | ||
149 |
def test_datasource_document_types(app, setup): |
|
150 |
response = app.get('/cityweb/test/document-types/') |
|
151 |
data = response.json['data'] |
|
152 |
assert len(data) == 4 |
|
153 |
for datum in data: |
|
154 |
if datum['id'] == 'CPI': |
|
155 |
assert datum['text'] == 'Copie intégrale' |
|
156 |
elif datum['id'] == 'EXTAF': |
|
157 |
assert datum['text'] == 'Extrait avec filiation' |
|
158 |
elif datum['id'] == 'EXTSF': |
|
159 |
assert datum['text'] == 'Extrait sans filiation' |
|
160 |
else: |
|
161 |
datum['id'] == 'EXTPL' |
|
162 |
datum['text'] == 'Extrait plurilingue' |
|
163 | ||
164 |
params = {'exclude': 'EXTAF,EXTSF,EXTPL'} |
|
165 |
response = app.get('/cityweb/test/document-types/', params=params) |
|
166 |
data = response.json['data'] |
|
167 |
assert len(data) == 1 |
|
168 |
assert data[0]['id'] == 'CPI' |
|
169 |
assert data[0]['text'] == 'Copie intégrale' |
|
170 | ||
171 | ||
172 |
def test_datasource_certificate_types(app, setup): |
|
173 |
response = app.get('/cityweb/test/certificate-types/') |
|
174 |
data = response.json['data'] |
|
175 |
assert len(data) == 4 |
|
176 |
for datum in data: |
|
177 |
if datum['id'] == 'NAI': |
|
178 |
assert datum['text'] == 'Naissance' |
|
179 |
elif datum['id'] == 'MAR': |
|
180 |
assert datum['text'] == 'Mariage' |
|
181 |
elif datum['id'] == 'REC': |
|
182 |
assert datum['text'] == 'Reconnaissance' |
|
183 |
else: |
|
184 |
assert datum['id'] == 'DEC' |
|
185 |
assert datum['text'] == 'Décès' |
|
186 | ||
187 | ||
188 |
def teardown_module(module): |
|
189 |
shutil.rmtree(os.path.join(get_test_base_dir('cityweb'), 'test'), ignore_errors=True) |
tox.ini | ||
---|---|---|
23 | 23 |
pylint |
24 | 24 |
pylint-django |
25 | 25 |
django-webtest |
26 |
lxml |
|
26 | 27 |
commands = |
27 | 28 |
./getmagic.sh |
28 | 29 |
py.test {env:FAST:} {env:COVERAGE:} {posargs:tests/} |
29 |
- |